source: edk_user_repository/WARP/sw_services/WARPxilnet_v3_00_a/src/xilnet_tcp.c

Last change on this file was 1749, checked in by chunter, 12 years ago

Updated copyright information and improved handling of broadcast IP address

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