source: edk_user_repository/WARP/sw_services/WARPxilnet_v2_00_a/src/ipv4/tcp.c

Last change on this file was 526, checked in by murphpo, 17 years ago

Adding custom version of Xilinx's xilnet (WARPxilnet); it's required for the PHY prototyping project

File size: 10.9 KB
Line 
1////////////////////////////////////////////////////////////////////////////////
2// Copyright (c) 2004 Xilinx, Inc.  All rights reserved.
3//
4// Xilinx, Inc.
5// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
6// COURTESY TO YOU.  BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
7// ONE POSSIBLE   IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
8// STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
9// IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
10// FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
11// XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
12// THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
13// ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
14// FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
15// AND FITNESS FOR A PARTICULAR PURPOSE.
16//
17// File   : tcp.c
18// Date   : 2002, March 20.
19// Author : Sathya Thammanur
20// Company: Xilinx
21// Group  : Emerging Software Technologies
22//
23// Summary:
24// TCP layer specific functions
25//
26// $Id: tcp.c,v 1.2.8.6 2005/11/15 23:41:10 salindac Exp $
27//
28////////////////////////////////////////////////////////////////////////////////
29
30#include <net/xilsock.h>
31
32#ifndef NULL
33#define NULL 0
34#endif
35
36struct xilnet_tcp_conn xilnet_tcp_conns[MAX_TCP_CONNS];
37
38/*
39 * tcp packet handler:
40 * "buf" is a IP datagram
41 * tcp identifies the right connection the pkt is destined for
42 * returns "0", if pkt for existing conn
43 * returns "-1", if incorrect pkt
44 * returns XILSOCK_NEW_CONN for a new conn
45 */
46
47int xilnet_tcp(unsigned char* buf, int len) {
48   
49   struct xilnet_tcp_conn *curr_conn = NULL;
50   struct xilnet_tcp_hdr tcp_req;
51   unsigned char* tcp_reply = (sendbuf+LINK_HDR_LEN+(IP_HDR_LEN*4));
52   int tcpdata_in = 0;
53   int listen_conn_index = -1;
54   int reset = FALSE;
55   int i;
56   int iplen = 0;
57
58   // set the tcp_req to zero
59   memset((unsigned char*)&tcp_req, 0, sizeof(struct xilnet_tcp_hdr));
60   
61   // cpy buf to tcp_req
62   memcpy((unsigned char*)(&tcp_req), (buf+IP_HDR_LEN*4), (TCP_HDR_LEN*4));
63   
64   // check for active conns
65   for (i = 0; i < MAX_TCP_CONNS; i++) {
66      if (xilnet_tcp_conns[i].state != TCP_CLOSED) {
67         if ( (xilnet_tcp_conns[i].src_port == tcp_req.dst_port)) {
68            if ( (xilnet_tcp_conns[i].dst_port == tcp_req.src_port) &&
69                 (xilnet_tcp_conns[i].dst_ip[0] == buf[IP_SADDR_BASE]) &&
70                 (xilnet_tcp_conns[i].dst_ip[1] == buf[IP_SADDR_BASE+1]) &&
71                 (xilnet_tcp_conns[i].dst_ip[2] == buf[IP_SADDR_BASE+2]) &&
72                 (xilnet_tcp_conns[i].dst_ip[3] == buf[IP_SADDR_BASE+3])
73                 ) {
74               curr_conn = &(xilnet_tcp_conns[i]);
75               break;
76            }
77            else {
78               listen_conn_index = i;
79            }
80         }
81      }
82   }
83   
84   // no activeconn found. check for listening conn
85   if (!curr_conn) {
86      if (listen_conn_index < 0) {
87         reset = TRUE;
88      }
89      else {
90         if (tcp_req.syn) {
91            curr_conn = &(xilnet_tcp_conns[listen_conn_index]);
92            curr_conn->dst_port = tcp_req.src_port;
93            curr_conn->dst_ip[0] = buf[IP_SADDR_BASE] ;
94            curr_conn->dst_ip[1] = buf[IP_SADDR_BASE+1];
95            curr_conn->dst_ip[2] = buf[IP_SADDR_BASE+2] ;
96            curr_conn->dst_ip[3] = buf[IP_SADDR_BASE+3];
97         }
98         else
99            reset = TRUE;
100      }
101   }
102   
103   // check if reset flag is set and send a reset packet
104   if (reset) {
105      struct xilnet_tcp_conn conn = {0};
106      conn.src_port = tcp_req.dst_port;
107      conn.dst_port = tcp_req.src_port;
108      conn.seqno = tcp_req.ack_no;
109      conn.ack_seqno = tcp_req.seq_no;
110      conn.dst_ip[0] = buf[IP_SADDR_BASE];
111      conn.dst_ip[1] = buf[IP_SADDR_BASE+1];
112      conn.dst_ip[2] = buf[IP_SADDR_BASE+2] ;
113      conn.dst_ip[3] = buf[IP_SADDR_BASE+3];
114      memset(sendbuf, 0, LINK_FRAME_LEN);   
115      xilnet_tcp_send_pkt(&conn, sendbuf+LINK_HDR_LEN+IP_HDR_LEN*4, 0, TCP_RST);
116      xilnet_ip_header(sendbuf+LINK_HDR_LEN, (TCP_HDR_LEN*4)+IP_HDR_LEN*4, IP_PROTO_TCP, conn.dst_ip);
117      xilnet_eth_send_frame(sendbuf, (TCP_HDR_LEN*4)+IP_HDR_LEN*4+ETH_HDR_LEN, conn.dst_ip, NULL, ETH_PROTO_IP);
118      return 0;
119   }
120   
121   tcpdata_in = len - (IP_HDR_LEN*4) - (tcp_req.hdr_len*4);
122
123   // check for corr acknum if not a syn packet
124   if ( (!tcp_req.syn) && (tcp_req.ack_no != curr_conn->exp_acknum)) {
125    print("tcp: incorrect acknum \n");
126      return -1;
127   }
128   
129   switch (curr_conn->state) {
130     
131   case TCP_LISTEN:
132      // incoming SYN;send ACK and Seqno
133      if (tcp_req.syn) {
134         unsigned char flags = 0;
135         unsigned short check = 0;
136         
137         // set ack_seqno
138         curr_conn->ack_seqno = tcp_req.seq_no + 1;
139     curr_conn->state = TCP_SYN_RCVD;
140         xilsock_sockets[curr_conn->fd].recvbuf.buf = buf;
141         xilsock_sockets[curr_conn->fd].recvbuf.size = tcpdata_in;
142         return XILSOCK_NEW_CONN;
143      }
144      return -1;
145      break;   
146     
147   case TCP_SYN_RCVD:
148      // incoming ACK & no data;
149      if (tcp_req.ack && (!tcpdata_in)) {
150         // set the ack_seq
151         curr_conn->ack_seqno = tcp_req.seq_no + 1;
152         curr_conn->seqno = tcp_req.ack_no;
153         curr_conn->state = TCP_ESTABLISHED;
154         xilsock_sockets[curr_conn->fd].recvbuf.buf = buf;
155         xilsock_sockets[curr_conn->fd].recvbuf.size = tcpdata_in;
156         return XILSOCK_SYNACK_RCVD;
157      } 
158      return -1;
159      break;
160     
161   case TCP_ESTABLISHED:
162      // incoming ACK; data in;
163      if (tcp_req.ack && (tcpdata_in)) {
164         // set the ack seq
165         curr_conn->ack_seqno = tcp_req.seq_no + tcpdata_in;
166         curr_conn->seqno = tcp_req.ack_no;
167         
168         // strip tcp header
169         buf = buf + (IP_HDR_LEN*4) +(TCP_HDR_LEN*4);
170         
171         // update socket corr to this conn
172         xilsock_sockets[curr_conn->fd].recvbuf.buf = buf;
173         xilsock_sockets[curr_conn->fd].recvbuf.size = tcpdata_in;
174         return XILSOCK_TCP_DATA;
175      }
176      else if (tcp_req.ack && (!tcpdata_in)) {
177         // set the ack seq
178         curr_conn->ack_seqno = tcp_req.seq_no + 1;
179         curr_conn->seqno = tcp_req.ack_no; 
180         xilsock_sockets[curr_conn->fd].recvbuf.buf = buf;
181         xilsock_sockets[curr_conn->fd].recvbuf.size = tcpdata_in;
182         return XILSOCK_TCP_ACK;
183      } 
184      return -1;   
185      break;
186
187   case TCP_FIN_WAIT1:
188      // wait for fin ack
189      if (tcp_req.ack && (!tcpdata_in)) {
190         curr_conn->ack_seqno = tcp_req.seq_no + 1;
191         curr_conn->seqno = tcp_req.ack_no;
192         
193         if (tcp_req.fin) {
194           
195            // send ack for FIN
196            memset(sendbuf, 0, LINK_FRAME_LEN); 
197            xilnet_tcp_send_pkt(curr_conn, sendbuf+LINK_HDR_LEN+IP_HDR_LEN*4, 0, TCP_ACK);
198            xilnet_ip_header(sendbuf+LINK_HDR_LEN, (TCP_HDR_LEN*4)+IP_HDR_LEN*4, IP_PROTO_TCP, curr_conn->dst_ip);
199            xilnet_eth_send_frame(sendbuf, (TCP_HDR_LEN*4)+IP_HDR_LEN*4+ETH_HDR_LEN, curr_conn->dst_ip, NULL, ETH_PROTO_IP);
200           
201            // reset tcp conn state
202            xilsock_sockets[curr_conn->fd].closed = 1;
203            return XILSOCK_CLOSE_CONN;
204         }
205         curr_conn->state = TCP_FIN_WAIT2;
206         xilsock_sockets[curr_conn->fd].recvbuf.buf = buf;
207         xilsock_sockets[curr_conn->fd].recvbuf.size = tcpdata_in;
208      }
209      return -1;
210      break;
211     
212   case TCP_FIN_WAIT2:
213      // incoming FIN;
214      if (tcp_req.fin) {
215         // set the ack seq
216         curr_conn->ack_seqno = tcp_req.seq_no + 1;
217         curr_conn->seqno = tcp_req.ack_no;
218         
219         // send ack for FIN
220         memset(sendbuf, 0, LINK_FRAME_LEN);   
221         xilnet_tcp_send_pkt(curr_conn, sendbuf+LINK_HDR_LEN+IP_HDR_LEN*4, 0, TCP_ACK);
222         xilnet_ip_header(sendbuf+LINK_HDR_LEN, (TCP_HDR_LEN*4)+IP_HDR_LEN*4, IP_PROTO_TCP, curr_conn->dst_ip);
223         xilnet_eth_send_frame(sendbuf, (TCP_HDR_LEN*4)+IP_HDR_LEN*4+ETH_HDR_LEN, curr_conn->dst_ip, NULL, ETH_PROTO_IP);
224         
225         // reset tcp conn state
226         xilsock_sockets[curr_conn->fd].closed = 1;
227         return XILSOCK_CLOSE_CONN;
228      } 
229      break;
230   default:
231      return 0;
232      break;
233   }   
234}
235
236
237/*
238 * xilnet_tcp_send_pkt: sends a tcp packet from "conn", with flags
239 */
240
241void xilnet_tcp_send_pkt(struct xilnet_tcp_conn *conn, unsigned char* buf, int len, unsigned char flags) {
242   
243   unsigned short check = 0;
244   
245
246   // call tcp_header
247   xilnet_tcp_header(conn, buf, len, flags);
248   
249   // calculate checksum
250   check = xilnet_udp_tcp_calc_chksum(buf, len+(TCP_HDR_LEN*4), mb_ip_addr, conn->dst_ip, IP_PROTO_TCP); 
251   buf[TCP_CHECK_OFF] = (check & 0xff00) >> 8;
252   buf[TCP_CHECK_OFF+1] = (check & 0x00ff);
253   
254}
255
256
257/*
258 * xilnet_tcp_header: creates tcp header
259 */
260void xilnet_tcp_header(struct xilnet_tcp_conn *conn, unsigned char* buf, int len, unsigned char flags) {
261
262   struct xilnet_tcp_hdr tcph;
263
264   memset((unsigned char*) &tcph, 0, sizeof(struct xilnet_tcp_hdr));
265   if (conn) {
266      tcph.src_port = conn->src_port;
267      tcph.dst_port = conn->dst_port;
268      tcph.seq_no = conn->seqno;
269      conn->exp_acknum = conn->seqno + len;
270      tcph.ack_no = conn->ack_seqno;
271   }
272 
273   tcph.hdr_len = TCP_HDR_LEN;
274   tcph.reserved = 0;
275   tcph.urg  = (flags & TCP_URG) ? 1:0;
276   tcph.ack  = (flags & TCP_ACK) ? 1:0;
277   tcph.psh  = (flags & TCP_PSH) ? 1:0;
278   tcph.rst  = (flags & TCP_RST) ? 1:0;
279   tcph.syn  = (flags & TCP_SYN) ? 1:0;
280   if (flags & TCP_FIN) {
281      tcph.fin = 1;
282      tcph.ack_no -= 1;
283   }
284 
285   tcph.window_size[0] = TCP_WND_HIGH;
286   tcph.window_size[1] = TCP_WND_LOW;
287   tcph.check_sum = 0;
288   tcph.urg_ptr = 0;
289 
290   memcpy(buf, (unsigned char *) &tcph, (TCP_HDR_LEN*4));
291}
292
293
294/*****************************
295 * tcp connection management *
296 *****************************/
297
298/*
299 * initialise all tcp conns
300 */
301
302#define XILNET_TCP_SYS_PORT 8000
303unsigned char istcpinit = 0;
304void xilnet_tcp_init_conns() {
305   
306   int i;
307   
308   for (i = 0; i < MAX_TCP_CONNS; i++) {
309      xilnet_tcp_conns[i].state = TCP_CLOSED;     
310   }   
311}
312
313
314/*
315 * open a tcp conn:
316 * opens a new tcp conn and changes state to LISTEN
317 * returns connection index if able to open else -1 if not possible
318 */
319
320int xilnet_tcp_open_conn(unsigned short port) {
321
322   int i;
323   
324   if (!istcpinit) {
325    xilnet_tcp_init_conns();
326    istcpinit = 1; 
327      }
328   for (i = 0; i < MAX_TCP_CONNS; i++) {
329      if (xilnet_tcp_conns[i].state == TCP_CLOSED)
330         break;
331   }
332
333   if (i < MAX_TCP_CONNS) {
334      xilnet_tcp_conns[i].src_port = port;
335      xilnet_tcp_conns[i].state = TCP_LISTEN;
336      xilnet_tcp_conns[i].seqno = 0;
337      xilnet_tcp_conns[i].ack_seqno = 0;
338      xilnet_tcp_conns[i].exp_acknum = 0;
339      return i;
340   }
341   return -1;
342   
343}
344
345
346/* close a tcp conn:
347 * closes a tcp conn by changing state to TCP_CLOSED
348 * returns 1 if able to close else return -1
349 */
350
351int xilnet_tcp_close_conn(struct xilnet_tcp_conn *conn) {
352   
353   int i;
354   
355   for (i = 0; i < MAX_TCP_CONNS; i++) {
356      if ((xilnet_tcp_conns+i) == conn) {
357         xilnet_tcp_conns[i].state = TCP_CLOSED;
358         return 1;
359      }
360   }
361   return -1;
362}
Note: See TracBrowser for help on using the repository browser.