blob: df0d27e2466eb59350cc15dadf21ba12cc5b370a [file] [log] [blame]
adamdunkels0170b082003-10-01 11:25:37 +00001/**
2 * \addtogroup uip
3 * @{
4 */
5
6/**
7 * \file
8 * The uIP TCP/IP stack code.
9 * \author Adam Dunkels <adam@dunkels.com>
10 */
11
adamdunkelsca9ddcb2003-03-19 14:13:31 +000012/*
adamdunkels0170b082003-10-01 11:25:37 +000013 * Copyright (c) 2001-2003, Adam Dunkels.
adamdunkelsca9ddcb2003-03-19 14:13:31 +000014 * All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
adamdunkels0170b082003-10-01 11:25:37 +000024 * 3. The name of the author may not be used to endorse or promote
adamdunkelsca9ddcb2003-03-19 14:13:31 +000025 * products derived from this software without specific prior
26 * written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
29 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
32 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
34 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
36 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * This file is part of the uIP TCP/IP stack.
41 *
adamdunkels75b9d002004-09-17 20:48:39 +000042 * $Id: uip.c,v 1.16 2004/09/17 20:48:39 adamdunkels Exp $
adamdunkelsca9ddcb2003-03-19 14:13:31 +000043 *
44 */
45
46/*
47This is a small implementation of the IP and TCP protocols (as well as
48some basic ICMP stuff). The implementation couples the IP, TCP and the
49application layers very tightly. To keep the size of the compiled code
50down, this code also features heavy usage of the goto statement.
51
52The principle is that we have a small buffer, called the uip_buf, in
53which the device driver puts an incoming packet. The TCP/IP stack
54parses the headers in the packet, and calls upon the application. If
55the remote host has sent data to the application, this data is present
56in the uip_buf and the application read the data from there. It is up
57to the application to put this data into a byte stream if needed. The
58application will not be fed with data that is out of sequence.
59
60If the application whishes to send data to the peer, it should put its
61data into the uip_buf, 40 bytes from the start of the buffer. The
62TCP/IP stack will calculate the checksums, and fill in the necessary
63header fields and finally send the packet back to the peer.
64*/
65
66#include "uip.h"
67#include "uipopt.h"
68#include "uip_arch.h"
69
70/*-----------------------------------------------------------------------------------*/
71/* Variable definitions. */
72
73
74/* The IP address of this host. If it is defined to be fixed (by setting UIP_FIXEDADDR to 1 in uipopt.h), the address is set here. Otherwise, the address */
75#if UIP_FIXEDADDR > 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +000076const u16_t uip_hostaddr[2] =
adamdunkels47ec7fa2003-03-28 12:11:17 +000077 {HTONS((UIP_IPADDR0 << 8) | UIP_IPADDR1),
78 HTONS((UIP_IPADDR2 << 8) | UIP_IPADDR3)};
adamdunkels9fad4132004-06-06 06:14:19 +000079const u16_t uip_draddr[2] =
adamdunkelsb489e7a2003-10-14 11:12:50 +000080 {HTONS((UIP_DRIPADDR0 << 8) | UIP_DRIPADDR1),
81 HTONS((UIP_DRIPADDR2 << 8) | UIP_DRIPADDR3)};
adamdunkels9fad4132004-06-06 06:14:19 +000082const u16_t uip_netmask[2] =
adamdunkelsb489e7a2003-10-14 11:12:50 +000083 {HTONS((UIP_NETMASK0 << 8) | UIP_NETMASK1),
84 HTONS((UIP_NETMASK2 << 8) | UIP_NETMASK3)};
adamdunkelsca9ddcb2003-03-19 14:13:31 +000085#else
adamdunkelsca9ddcb2003-03-19 14:13:31 +000086u16_t uip_hostaddr[2];
adamdunkels9fad4132004-06-06 06:14:19 +000087u16_t uip_draddr[2], uip_netmask[2];
adamdunkelsca9ddcb2003-03-19 14:13:31 +000088#endif /* UIP_FIXEDADDR */
89
adamdunkelsa49d1dc2003-08-21 22:26:57 +000090u8_t uip_buf[UIP_BUFSIZE+2]; /* The packet buffer that contains
adamdunkelsca9ddcb2003-03-19 14:13:31 +000091 incoming packets. */
adamdunkels9fad4132004-06-06 06:14:19 +000092u8_t *uip_appdata; /* The uip_appdata pointer points to
adamdunkelsca9ddcb2003-03-19 14:13:31 +000093 application data. */
adamdunkels9fad4132004-06-06 06:14:19 +000094u8_t *uip_sappdata; /* The uip_appdata pointer points to the
adamdunkels0170b082003-10-01 11:25:37 +000095 application data which is to be sent. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +000096#if UIP_URGDATA > 0
adamdunkels9fad4132004-06-06 06:14:19 +000097u8_t *uip_urgdata; /* The uip_urgdata pointer points to
adamdunkelsca9ddcb2003-03-19 14:13:31 +000098 urgent data (out-of-band data), if
99 present. */
adamdunkels9fad4132004-06-06 06:14:19 +0000100u8_t uip_urglen, uip_surglen;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000101#endif /* UIP_URGDATA > 0 */
102
adamdunkels9fad4132004-06-06 06:14:19 +0000103u16_t uip_len, uip_slen;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000104 /* The uip_len is either 8 or 16 bits,
105 depending on the maximum packet
106 size. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000107
adamdunkels9fad4132004-06-06 06:14:19 +0000108u8_t uip_flags; /* The uip_flags variable is used for
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000109 communication between the TCP/IP stack
110 and the application program. */
111struct uip_conn *uip_conn; /* uip_conn always points to the current
112 connection. */
113
114struct uip_conn uip_conns[UIP_CONNS];
115 /* The uip_conns array holds all TCP
116 connections. */
117u16_t uip_listenports[UIP_LISTENPORTS];
118 /* The uip_listenports list all currently
119 listning ports. */
120#if UIP_UDP
121struct uip_udp_conn *uip_udp_conn;
122struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
123#endif /* UIP_UDP */
124
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000125static u16_t ipid; /* Ths ipid variable is an increasing
126 number that is used for the IP ID
127 field. */
128
129static u8_t iss[4]; /* The iss variable is used for the TCP
130 initial sequence number. */
131
132#if UIP_ACTIVE_OPEN
adamdunkelsb489e7a2003-10-14 11:12:50 +0000133static u16_t lastport; /* Keeps track of the last port used for
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000134 a new connection. */
135#endif /* UIP_ACTIVE_OPEN */
136
137/* Temporary variables. */
adamdunkels9fad4132004-06-06 06:14:19 +0000138u8_t uip_acc32[4];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000139static u8_t c, opt;
adamdunkels0170b082003-10-01 11:25:37 +0000140static u16_t tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000141
142/* Structures and definitions. */
143#define TCP_FIN 0x01
144#define TCP_SYN 0x02
145#define TCP_RST 0x04
146#define TCP_PSH 0x08
147#define TCP_ACK 0x10
148#define TCP_URG 0x20
149#define TCP_CTL 0x3f
150
151#define ICMP_ECHO_REPLY 0
152#define ICMP_ECHO 8
153
154/* Macros. */
155#define BUF ((uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
156#define FBUF ((uip_tcpip_hdr *)&uip_reassbuf[0])
157#define ICMPBUF ((uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
158#define UDPBUF ((uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])
159
160#if UIP_STATISTICS == 1
161struct uip_stats uip_stat;
162#define UIP_STAT(s) s
163#else
164#define UIP_STAT(s)
165#endif /* UIP_STATISTICS == 1 */
166
167#if UIP_LOGGING == 1
168#include <stdio.h>
169void uip_log(char *msg);
170#define UIP_LOG(m) uip_log(m)
171#else
172#define UIP_LOG(m)
173#endif /* UIP_LOGGING == 1 */
174
175/*-----------------------------------------------------------------------------------*/
176void
177uip_init(void)
178{
179 for(c = 0; c < UIP_LISTENPORTS; ++c) {
180 uip_listenports[c] = 0;
181 }
182 for(c = 0; c < UIP_CONNS; ++c) {
183 uip_conns[c].tcpstateflags = CLOSED;
184 }
185#if UIP_ACTIVE_OPEN
186 lastport = 1024;
187#endif /* UIP_ACTIVE_OPEN */
188
189#if UIP_UDP
190 for(c = 0; c < UIP_UDP_CONNS; ++c) {
191 uip_udp_conns[c].lport = 0;
192 }
193#endif /* UIP_UDP */
194
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000195
196 /* IPv4 initialization. */
197#if UIP_FIXEDADDR == 0
198 uip_hostaddr[0] = uip_hostaddr[1] = 0;
199#endif /* UIP_FIXEDADDR */
adamdunkelsa38da252003-08-20 20:56:54 +0000200
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000201}
202/*-----------------------------------------------------------------------------------*/
203#if UIP_ACTIVE_OPEN
204struct uip_conn *
205uip_connect(u16_t *ripaddr, u16_t rport)
206{
adamdunkelsa38da252003-08-20 20:56:54 +0000207 register struct uip_conn *conn, *cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000208
209 /* Find an unused local port. */
210 again:
211 ++lastport;
212
213 if(lastport >= 32000) {
214 lastport = 4096;
215 }
adamdunkels1e45c6d2003-09-02 21:47:27 +0000216
217 /* Check if this port is already in use, and if so try to find
218 another one. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000219 for(c = 0; c < UIP_CONNS; ++c) {
adamdunkels23664022003-08-05 13:51:50 +0000220 conn = &uip_conns[c];
221 if(conn->tcpstateflags != CLOSED &&
adamdunkels1e45c6d2003-09-02 21:47:27 +0000222 conn->lport == htons(lastport)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000223 goto again;
adamdunkelsa38da252003-08-20 20:56:54 +0000224 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000225 }
226
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000227 conn = 0;
228 for(c = 0; c < UIP_CONNS; ++c) {
adamdunkelsa38da252003-08-20 20:56:54 +0000229 cconn = &uip_conns[c];
230 if(cconn->tcpstateflags == CLOSED) {
231 conn = cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000232 break;
233 }
adamdunkelsa38da252003-08-20 20:56:54 +0000234 if(cconn->tcpstateflags == TIME_WAIT) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000235 if(conn == 0 ||
adamdunkels75b9d002004-09-17 20:48:39 +0000236 cconn->timer > conn->timer) {
adamdunkelsa38da252003-08-20 20:56:54 +0000237 conn = cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000238 }
239 }
240 }
241
242 if(conn == 0) {
243 return 0;
244 }
245
246 conn->tcpstateflags = SYN_SENT;
247
248 conn->snd_nxt[0] = iss[0];
249 conn->snd_nxt[1] = iss[1];
250 conn->snd_nxt[2] = iss[2];
251 conn->snd_nxt[3] = iss[3];
252
adamdunkels0170b082003-10-01 11:25:37 +0000253 conn->initialmss = conn->mss = UIP_TCP_MSS;
adamdunkelsd962db42003-08-21 18:10:21 +0000254
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000255 conn->len = 1; /* TCP length of the SYN is one. */
256 conn->nrtx = 0;
257 conn->timer = 1; /* Send the SYN next time around. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000258 conn->rto = UIP_RTO;
259 conn->sa = 0;
260 conn->sv = 16;
adamdunkels1e45c6d2003-09-02 21:47:27 +0000261 conn->lport = htons(lastport);
262 conn->rport = rport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000263 conn->ripaddr[0] = ripaddr[0];
264 conn->ripaddr[1] = ripaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000265
266 return conn;
267}
268#endif /* UIP_ACTIVE_OPEN */
269/*-----------------------------------------------------------------------------------*/
270#if UIP_UDP
271struct uip_udp_conn *
272uip_udp_new(u16_t *ripaddr, u16_t rport)
273{
adamdunkels23664022003-08-05 13:51:50 +0000274 register struct uip_udp_conn *conn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000275
276 /* Find an unused local port. */
277 again:
278 ++lastport;
279
280 if(lastport >= 32000) {
281 lastport = 4096;
282 }
283
284 for(c = 0; c < UIP_UDP_CONNS; ++c) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000285 if(uip_udp_conns[c].lport == lastport) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000286 goto again;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000287 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000288 }
289
290
291 conn = 0;
292 for(c = 0; c < UIP_UDP_CONNS; ++c) {
293 if(uip_udp_conns[c].lport == 0) {
294 conn = &uip_udp_conns[c];
295 break;
296 }
297 }
298
299 if(conn == 0) {
300 return 0;
301 }
302
adamdunkels47ec7fa2003-03-28 12:11:17 +0000303 conn->lport = HTONS(lastport);
adamdunkels75b9d002004-09-17 20:48:39 +0000304 conn->rport = rport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000305 conn->ripaddr[0] = ripaddr[0];
306 conn->ripaddr[1] = ripaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000307
308 return conn;
309}
310#endif /* UIP_UDP */
311/*-----------------------------------------------------------------------------------*/
312void
adamdunkelscd8c3a22003-08-13 22:52:48 +0000313uip_unlisten(u16_t port)
314{
315 for(c = 0; c < UIP_LISTENPORTS; ++c) {
316 if(uip_listenports[c] == port) {
317 uip_listenports[c] = 0;
318 return;
319 }
320 }
321}
322/*-----------------------------------------------------------------------------------*/
323void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000324uip_listen(u16_t port)
325{
326 for(c = 0; c < UIP_LISTENPORTS; ++c) {
327 if(uip_listenports[c] == 0) {
adamdunkels1e45c6d2003-09-02 21:47:27 +0000328 uip_listenports[c] = port;
adamdunkelscd8c3a22003-08-13 22:52:48 +0000329 return;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000330 }
331 }
332}
333/*-----------------------------------------------------------------------------------*/
adamdunkelsb489e7a2003-10-14 11:12:50 +0000334/* XXX: IP fragment reassembly: not well-tested. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000335
336#if UIP_REASSEMBLY
337#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)
338static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];
339static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];
340static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f,
341 0x0f, 0x07, 0x03, 0x01};
342static u16_t uip_reasslen;
343static u8_t uip_reassflags;
344#define UIP_REASS_FLAG_LASTFRAG 0x01
345static u8_t uip_reasstmr;
346
347#define IP_HLEN 20
adamdunkelsb489e7a2003-10-14 11:12:50 +0000348#define IP_MF 0x20
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000349
350static u8_t
351uip_reass(void)
352{
353 u16_t offset, len;
354 u16_t i;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000355
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000356 /* If ip_reasstmr is zero, no packet is present in the buffer, so we
357 write the IP header of the fragment into the reassembly
358 buffer. The timer is updated with the maximum age. */
359 if(uip_reasstmr == 0) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000360 memcpy(uip_reassbuf, &BUF->vhl, IP_HLEN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000361 uip_reasstmr = UIP_REASS_MAXAGE;
362 uip_reassflags = 0;
363 /* Clear the bitmap. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000364 memset(uip_reassbitmap, sizeof(uip_reassbitmap), 0);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000365 }
366
367 /* Check if the incoming fragment matches the one currently present
368 in the reasembly buffer. If so, we proceed with copying the
369 fragment into the buffer. */
370 if(BUF->srcipaddr[0] == FBUF->srcipaddr[0] &&
adamdunkelsb489e7a2003-10-14 11:12:50 +0000371 BUF->srcipaddr[1] == FBUF->srcipaddr[1] &&
372 BUF->destipaddr[0] == FBUF->destipaddr[0] &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000373 BUF->destipaddr[1] == FBUF->destipaddr[1] &&
adamdunkelsb489e7a2003-10-14 11:12:50 +0000374 BUF->ipid[0] == FBUF->ipid[0] &&
375 BUF->ipid[1] == FBUF->ipid[1]) {
376
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000377 len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4;
378 offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8;
379
380 /* If the offset or the offset + fragment length overflows the
381 reassembly buffer, we discard the entire packet. */
382 if(offset > UIP_REASS_BUFSIZE ||
383 offset + len > UIP_REASS_BUFSIZE) {
384 uip_reasstmr = 0;
385 goto nullreturn;
386 }
387
388 /* Copy the fragment into the reassembly buffer, at the right
389 offset. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000390 memcpy(&uip_reassbuf[IP_HLEN + offset],
391 (char *)BUF + (int)((BUF->vhl & 0x0f) * 4),
392 len);
393
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000394 /* Update the bitmap. */
395 if(offset / (8 * 8) == (offset + len) / (8 * 8)) {
396 /* If the two endpoints are in the same byte, we only update
397 that byte. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000398
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000399 uip_reassbitmap[offset / (8 * 8)] |=
adamdunkelsb489e7a2003-10-14 11:12:50 +0000400 bitmap_bits[(offset / 8 ) & 7] &
401 ~bitmap_bits[((offset + len) / 8 ) & 7];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000402 } else {
403 /* If the two endpoints are in different bytes, we update the
404 bytes in the endpoints and fill the stuff inbetween with
405 0xff. */
406 uip_reassbitmap[offset / (8 * 8)] |=
407 bitmap_bits[(offset / 8 ) & 7];
408 for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
409 uip_reassbitmap[i] = 0xff;
410 }
411 uip_reassbitmap[(offset + len) / (8 * 8)] |=
412 ~bitmap_bits[((offset + len) / 8 ) & 7];
413 }
414
415 /* If this fragment has the More Fragments flag set to zero, we
416 know that this is the last fragment, so we can calculate the
417 size of the entire packet. We also set the
418 IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
419 the final fragment. */
420
421 if((BUF->ipoffset[0] & IP_MF) == 0) {
422 uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
423 uip_reasslen = offset + len;
424 }
425
426 /* Finally, we check if we have a full packet in the buffer. We do
427 this by checking if we have the last fragment and if all bits
428 in the bitmap are set. */
429 if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) {
430 /* Check all bytes up to and including all but the last byte in
431 the bitmap. */
432 for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) {
433 if(uip_reassbitmap[i] != 0xff) {
434 goto nullreturn;
435 }
436 }
437 /* Check the last byte in the bitmap. It should contain just the
438 right amount of bits. */
439 if(uip_reassbitmap[uip_reasslen / (8 * 8)] !=
440 (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) {
441 goto nullreturn;
442 }
443
444 /* If we have come this far, we have a full packet in the
445 buffer, so we allocate a pbuf and copy the packet into it. We
446 also reset the timer. */
447 uip_reasstmr = 0;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000448 memcpy(BUF, FBUF, uip_reasslen);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000449
450 /* Pretend to be a "normal" (i.e., not fragmented) IP packet
451 from now on. */
452 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000453 BUF->len[0] = uip_reasslen >> 8;
454 BUF->len[1] = uip_reasslen & 0xff;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000455 BUF->ipchksum = 0;
456 BUF->ipchksum = ~(uip_ipchksum());
457
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000458 return uip_reasslen;
459 }
460 }
461
462 nullreturn:
463 return 0;
464}
adamdunkelsb489e7a2003-10-14 11:12:50 +0000465#endif /* UIP_REASSEMBL */
466/*-----------------------------------------------------------------------------------*/
467static void
468uip_add_rcv_nxt(u16_t n)
469{
470 uip_add32(uip_conn->rcv_nxt, n);
471 uip_conn->rcv_nxt[0] = uip_acc32[0];
472 uip_conn->rcv_nxt[1] = uip_acc32[1];
473 uip_conn->rcv_nxt[2] = uip_acc32[2];
474 uip_conn->rcv_nxt[3] = uip_acc32[3];
475}
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000476/*-----------------------------------------------------------------------------------*/
477void
478uip_process(u8_t flag)
479{
480 register struct uip_conn *uip_connr = uip_conn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000481
482 uip_appdata = &uip_buf[40 + UIP_LLH_LEN];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000483
484 /* Check if we were invoked because of the perodic timer fireing. */
485 if(flag == UIP_TIMER) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000486#if UIP_REASSEMBLY
487 if(uip_reasstmr != 0) {
488 --uip_reasstmr;
489 }
490#endif /* UIP_REASSEMBLY */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000491 /* Increase the initial sequence number. */
492 if(++iss[3] == 0) {
493 if(++iss[2] == 0) {
494 if(++iss[1] == 0) {
495 ++iss[0];
496 }
497 }
498 }
499 uip_len = 0;
500 if(uip_connr->tcpstateflags == TIME_WAIT ||
501 uip_connr->tcpstateflags == FIN_WAIT_2) {
502 ++(uip_connr->timer);
503 if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) {
504 uip_connr->tcpstateflags = CLOSED;
505 }
506 } else if(uip_connr->tcpstateflags != CLOSED) {
507 /* If the connection has outstanding data, we increase the
508 connection's timer and see if it has reached the RTO value
509 in which case we retransmit. */
510 if(uip_outstanding(uip_connr)) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000511 if(uip_connr->timer-- == 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000512 if(uip_connr->nrtx == UIP_MAXRTX ||
513 ((uip_connr->tcpstateflags == SYN_SENT ||
514 uip_connr->tcpstateflags == SYN_RCVD) &&
515 uip_connr->nrtx == UIP_MAXSYNRTX)) {
516 uip_connr->tcpstateflags = CLOSED;
517
518 /* We call UIP_APPCALL() with uip_flags set to
519 UIP_TIMEDOUT to inform the application that the
520 connection has timed out. */
521 uip_flags = UIP_TIMEDOUT;
522 UIP_APPCALL();
523
524 /* We also send a reset packet to the remote host. */
525 BUF->flags = TCP_RST | TCP_ACK;
526 goto tcp_send_nodata;
527 }
528
529 /* Exponential backoff. */
adamdunkels47ec7fa2003-03-28 12:11:17 +0000530 uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4?
531 4:
532 uip_connr->nrtx);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000533 ++(uip_connr->nrtx);
534
535 /* Ok, so we need to retransmit. We do this differently
536 depending on which state we are in. In ESTABLISHED, we
537 call upon the application so that it may prepare the
538 data for the retransmit. In SYN_RCVD, we resend the
539 SYNACK that we sent earlier and in LAST_ACK we have to
540 retransmit our FINACK. */
541 UIP_STAT(++uip_stat.tcp.rexmit);
542 switch(uip_connr->tcpstateflags & TS_MASK) {
543 case SYN_RCVD:
544 /* In the SYN_RCVD state, we should retransmit our
545 SYNACK. */
546 goto tcp_send_synack;
547
548#if UIP_ACTIVE_OPEN
549 case SYN_SENT:
550 /* In the SYN_SENT state, we retransmit out SYN. */
551 BUF->flags = 0;
552 goto tcp_send_syn;
553#endif /* UIP_ACTIVE_OPEN */
554
555 case ESTABLISHED:
556 /* In the ESTABLISHED state, we call upon the application
557 to do the actual retransmit after which we jump into
558 the code for sending out the packet (the apprexmit
559 label). */
560 uip_len = 0;
561 uip_slen = 0;
562 uip_flags = UIP_REXMIT;
563 UIP_APPCALL();
564 goto apprexmit;
565
566 case FIN_WAIT_1:
567 case CLOSING:
568 case LAST_ACK:
569 /* In all these states we should retransmit a FINACK. */
570 goto tcp_send_finack;
571
572 }
573 }
574 } else if((uip_connr->tcpstateflags & TS_MASK) == ESTABLISHED) {
575 /* If there was no need for a retransmission, we poll the
576 application for new data. */
577 uip_len = 0;
578 uip_slen = 0;
579 uip_flags = UIP_POLL;
580 UIP_APPCALL();
581 goto appsend;
582 }
583 }
584 goto drop;
585 }
586#if UIP_UDP
587 if(flag == UIP_UDP_TIMER) {
588 if(uip_udp_conn->lport != 0) {
adamdunkels399a0782004-02-16 20:52:07 +0000589 uip_conn = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000590 uip_appdata = &uip_buf[UIP_LLH_LEN + 28];
591 uip_len = uip_slen = 0;
592 uip_flags = UIP_POLL;
593 UIP_UDP_APPCALL();
594 goto udp_send;
595 } else {
596 goto drop;
597 }
598 }
599#endif
600
601 /* This is where the input processing starts. */
602 UIP_STAT(++uip_stat.ip.recv);
603
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000604
605 /* Start of IPv4 input header processing code. */
606
607 /* Check validity of the IP header. */
608 if(BUF->vhl != 0x45) { /* IP version and header length. */
609 UIP_STAT(++uip_stat.ip.drop);
610 UIP_STAT(++uip_stat.ip.vhlerr);
611 UIP_LOG("ip: invalid version or header length.");
612 goto drop;
613 }
614
615 /* Check the size of the packet. If the size reported to us in
adamdunkels9fad4132004-06-06 06:14:19 +0000616 uip_len doesn't match the size reported in the IP header, the
617 packet has been padded by the network device. We correct the
618 uip_len variable based on the reported length in the IP
619 header. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000620
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000621 if(BUF->len[0] != (uip_len >> 8)) { /* IP length, high byte. */
622 uip_len = (uip_len & 0xff) | (BUF->len[0] << 8);
623 }
624 if(BUF->len[1] != (uip_len & 0xff)) { /* IP length, low byte. */
625 uip_len = (uip_len & 0xff00) | BUF->len[1];
626 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000627
adamdunkelsb489e7a2003-10-14 11:12:50 +0000628 /* Check the fragment flag. */
629 if((BUF->ipoffset[0] & 0x3f) != 0 ||
630 BUF->ipoffset[1] != 0) {
631#if UIP_REASSEMBLY
632 uip_len = uip_reass();
633 if(uip_len == 0) {
634 goto drop;
635 }
636#else
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000637 UIP_STAT(++uip_stat.ip.drop);
638 UIP_STAT(++uip_stat.ip.fragerr);
639 UIP_LOG("ip: fragment dropped.");
640 goto drop;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000641#endif /* UIP_REASSEMBLY */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000642 }
643
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000644 if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
adamdunkels75b9d002004-09-17 20:48:39 +0000645 /* If we are configured to use ping IP address configuration and
646 hasn't been assigned an IP address yet, we accept all ICMP
647 packets. */
648#if UIP_PINGADDRCONF
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000649 if(BUF->proto == UIP_PROTO_ICMP) {
650 UIP_LOG("ip: possible ping config packet received.");
651 goto icmp_input;
652 } else {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000653 UIP_LOG("ip: packet dropped since no address assigned.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000654 goto drop;
adamdunkels75b9d002004-09-17 20:48:39 +0000655 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000656#endif /* UIP_PINGADDRCONF */
adamdunkels9fad4132004-06-06 06:14:19 +0000657
adamdunkels75b9d002004-09-17 20:48:39 +0000658 } else {
659 /* If IP broadcast support is configured, we check for a broadcast
660 UDP packet, which may be destined to us. */
adamdunkels9fad4132004-06-06 06:14:19 +0000661#if UIP_BROADCAST
adamdunkels75b9d002004-09-17 20:48:39 +0000662 if(BUF->proto == UIP_PROTO_UDP &&
663 BUF->destipaddr[0] == 0xffff &&
adamdunkels9fad4132004-06-06 06:14:19 +0000664 BUF->destipaddr[1] == 0xffff &&
adamdunkels75b9d002004-09-17 20:48:39 +0000665 uip_ipchksum() == 0xffff) {
666 goto udp_input;
667 }
adamdunkels9fad4132004-06-06 06:14:19 +0000668#endif /* UIP_BROADCAST */
adamdunkels75b9d002004-09-17 20:48:39 +0000669
670 /* Check if the packet is destined for our IP address. */
671 if(BUF->destipaddr[0] != uip_hostaddr[0]) {
672 UIP_STAT(++uip_stat.ip.drop);
673 /* UIP_LOG("ip: packet not for us."); */
674 goto drop;
675 }
676 if(BUF->destipaddr[1] != uip_hostaddr[1]) {
677 UIP_STAT(++uip_stat.ip.drop);
678 /* UIP_LOG("ip: packet not for us."); */
679 goto drop;
680 }
681 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000682
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000683 if(uip_ipchksum() != 0xffff) { /* Compute and check the IP header
684 checksum. */
685 UIP_STAT(++uip_stat.ip.drop);
686 UIP_STAT(++uip_stat.ip.chkerr);
adamdunkels9fad4132004-06-06 06:14:19 +0000687 UIP_LOG("ip: bad checksum.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000688 goto drop;
689 }
690
691 if(BUF->proto == UIP_PROTO_TCP) /* Check for TCP packet. If so, jump
692 to the tcp_input label. */
693 goto tcp_input;
694
695#if UIP_UDP
696 if(BUF->proto == UIP_PROTO_UDP)
697 goto udp_input;
698#endif /* UIP_UDP */
699
700 if(BUF->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from
701 here. */
702 UIP_STAT(++uip_stat.ip.drop);
703 UIP_STAT(++uip_stat.ip.protoerr);
704 UIP_LOG("ip: neither tcp nor icmp.");
705 goto drop;
706 }
707
708 icmp_input:
709 UIP_STAT(++uip_stat.icmp.recv);
710
711 /* ICMP echo (i.e., ping) processing. This is simple, we only change
712 the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
713 checksum before we return the packet. */
714 if(ICMPBUF->type != ICMP_ECHO) {
715 UIP_STAT(++uip_stat.icmp.drop);
716 UIP_STAT(++uip_stat.icmp.typeerr);
717 UIP_LOG("icmp: not icmp echo.");
718 goto drop;
719 }
720
721 /* If we are configured to use ping IP address assignment, we use
722 the destination IP address of this ping packet and assign it to
723 ourself. */
724#if UIP_PINGADDRCONF
725 if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
726 uip_hostaddr[0] = BUF->destipaddr[0];
727 uip_hostaddr[1] = BUF->destipaddr[1];
728 }
729#endif /* UIP_PINGADDRCONF */
730
731 ICMPBUF->type = ICMP_ECHO_REPLY;
732
adamdunkels47ec7fa2003-03-28 12:11:17 +0000733 if(ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) {
734 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000735 } else {
adamdunkels47ec7fa2003-03-28 12:11:17 +0000736 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000737 }
738
739 /* Swap IP addresses. */
adamdunkels0170b082003-10-01 11:25:37 +0000740 tmp16 = BUF->destipaddr[0];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000741 BUF->destipaddr[0] = BUF->srcipaddr[0];
adamdunkels0170b082003-10-01 11:25:37 +0000742 BUF->srcipaddr[0] = tmp16;
743 tmp16 = BUF->destipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000744 BUF->destipaddr[1] = BUF->srcipaddr[1];
adamdunkels0170b082003-10-01 11:25:37 +0000745 BUF->srcipaddr[1] = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000746
747 UIP_STAT(++uip_stat.icmp.sent);
748 goto send;
749
750 /* End of IPv4 input header processing code. */
751
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000752
753#if UIP_UDP
754 /* UDP input processing. */
755 udp_input:
756 /* UDP processing is really just a hack. We don't do anything to the
757 UDP/IP headers, but let the UDP application do all the hard
758 work. If the application sets uip_slen, it has a packet to
759 send. */
760#if UIP_UDP_CHECKSUMS
761 if(uip_udpchksum() != 0xffff) {
762 UIP_STAT(++uip_stat.udp.drop);
763 UIP_STAT(++uip_stat.udp.chkerr);
764 UIP_LOG("udp: bad checksum.");
765 goto drop;
766 }
767#endif /* UIP_UDP_CHECKSUMS */
768
769 /* Demultiplex this UDP packet between the UDP "connections". */
770 for(uip_udp_conn = &uip_udp_conns[0];
771 uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS];
772 ++uip_udp_conn) {
adamdunkels9fad4132004-06-06 06:14:19 +0000773 /* If the local UDP port is non-zero, the connection is considered
774 to be used. If so, the local port number is checked against the
775 destination port number in the received packet. If the two port
776 numbers match, the remote port number is checked if the
777 connection is bound to a remote port. Finally, if the
778 connection is bound to a remote IP address, the source IP
779 address of the packet is checked. */
780 if(uip_udp_conn->lport != 0 &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000781 UDPBUF->destport == uip_udp_conn->lport &&
782 (uip_udp_conn->rport == 0 ||
783 UDPBUF->srcport == uip_udp_conn->rport) &&
adamdunkels9fad4132004-06-06 06:14:19 +0000784 ((uip_udp_conn->ripaddr[0] | uip_udp_conn->ripaddr[1]) == 0 ||
785 (uip_udp_conn->ripaddr[0] == 0xffff &&
786 uip_udp_conn->ripaddr[1] == 0xffff) ||
787 uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000788 goto udp_found;
789 }
790 }
adamdunkels9fad4132004-06-06 06:14:19 +0000791 UIP_LOG("udp: no matching connection found");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000792 goto drop;
793
794 udp_found:
adamdunkels399a0782004-02-16 20:52:07 +0000795 uip_conn = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000796 uip_len = uip_len - 28;
797 uip_appdata = &uip_buf[UIP_LLH_LEN + 28];
798 uip_flags = UIP_NEWDATA;
799 uip_slen = 0;
800 UIP_UDP_APPCALL();
801 udp_send:
802 if(uip_slen == 0) {
803 goto drop;
804 }
805 uip_len = uip_slen + 28;
806
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000807 BUF->len[0] = (uip_len >> 8);
808 BUF->len[1] = (uip_len & 0xff);
adamdunkelsb489e7a2003-10-14 11:12:50 +0000809
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000810 BUF->proto = UIP_PROTO_UDP;
811
adamdunkels47ec7fa2003-03-28 12:11:17 +0000812 UDPBUF->udplen = HTONS(uip_slen + 8);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000813 UDPBUF->udpchksum = 0;
814#if UIP_UDP_CHECKSUMS
815 /* Calculate UDP checksum. */
816 UDPBUF->udpchksum = ~(uip_udpchksum());
817 if(UDPBUF->udpchksum == 0) {
818 UDPBUF->udpchksum = 0xffff;
819 }
820#endif /* UIP_UDP_CHECKSUMS */
821
822 BUF->srcport = uip_udp_conn->lport;
823 BUF->destport = uip_udp_conn->rport;
824
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000825 BUF->srcipaddr[0] = uip_hostaddr[0];
826 BUF->srcipaddr[1] = uip_hostaddr[1];
827 BUF->destipaddr[0] = uip_udp_conn->ripaddr[0];
828 BUF->destipaddr[1] = uip_udp_conn->ripaddr[1];
829
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000830 uip_appdata = &uip_buf[UIP_LLH_LEN + 40];
831 goto ip_send_nolen;
832#endif /* UIP_UDP */
833
834 /* TCP input processing. */
835 tcp_input:
836 UIP_STAT(++uip_stat.tcp.recv);
837
838 /* Start of TCP input header processing code. */
839
840 if(uip_tcpchksum() != 0xffff) { /* Compute and check the TCP
841 checksum. */
842 UIP_STAT(++uip_stat.tcp.drop);
843 UIP_STAT(++uip_stat.tcp.chkerr);
adamdunkels9fad4132004-06-06 06:14:19 +0000844 UIP_LOG("tcp: bad checksum.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000845 goto drop;
846 }
847
adamdunkels9fad4132004-06-06 06:14:19 +0000848
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000849 /* Demultiplex this segment. */
850 /* First check any active connections. */
851 for(uip_connr = &uip_conns[0]; uip_connr < &uip_conns[UIP_CONNS]; ++uip_connr) {
852 if(uip_connr->tcpstateflags != CLOSED &&
853 BUF->destport == uip_connr->lport &&
854 BUF->srcport == uip_connr->rport &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000855 BUF->srcipaddr[0] == uip_connr->ripaddr[0] &&
856 BUF->srcipaddr[1] == uip_connr->ripaddr[1]) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000857 goto found;
858 }
859 }
860
861 /* If we didn't find and active connection that expected the packet,
862 either this packet is an old duplicate, or this is a SYN packet
863 destined for a connection in LISTEN. If the SYN flag isn't set,
864 it is an old packet and we send a RST. */
865 if((BUF->flags & TCP_CTL) != TCP_SYN)
866 goto reset;
867
adamdunkels0170b082003-10-01 11:25:37 +0000868 tmp16 = BUF->destport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000869 /* Next, check listening connections. */
adamdunkelscd8c3a22003-08-13 22:52:48 +0000870 for(c = 0; c < UIP_LISTENPORTS; ++c) {
adamdunkels0170b082003-10-01 11:25:37 +0000871 if(tmp16 == uip_listenports[c])
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000872 goto found_listen;
873 }
874
875 /* No matching connection found, so we send a RST packet. */
876 UIP_STAT(++uip_stat.tcp.synrst);
877 reset:
878
879 /* We do not send resets in response to resets. */
880 if(BUF->flags & TCP_RST)
881 goto drop;
882
883 UIP_STAT(++uip_stat.tcp.rst);
884
885 BUF->flags = TCP_RST | TCP_ACK;
886 uip_len = 40;
887 BUF->tcpoffset = 5 << 4;
888
889 /* Flip the seqno and ackno fields in the TCP header. */
890 c = BUF->seqno[3];
891 BUF->seqno[3] = BUF->ackno[3];
892 BUF->ackno[3] = c;
893
894 c = BUF->seqno[2];
895 BUF->seqno[2] = BUF->ackno[2];
896 BUF->ackno[2] = c;
897
898 c = BUF->seqno[1];
899 BUF->seqno[1] = BUF->ackno[1];
900 BUF->ackno[1] = c;
901
902 c = BUF->seqno[0];
903 BUF->seqno[0] = BUF->ackno[0];
904 BUF->ackno[0] = c;
905
906 /* We also have to increase the sequence number we are
907 acknowledging. If the least significant byte overflowed, we need
908 to propagate the carry to the other bytes as well. */
909 if(++BUF->ackno[3] == 0) {
910 if(++BUF->ackno[2] == 0) {
911 if(++BUF->ackno[1] == 0) {
912 ++BUF->ackno[0];
913 }
914 }
915 }
916
917 /* Swap port numbers. */
adamdunkels0170b082003-10-01 11:25:37 +0000918 tmp16 = BUF->srcport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000919 BUF->srcport = BUF->destport;
adamdunkels0170b082003-10-01 11:25:37 +0000920 BUF->destport = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000921
922 /* Swap IP addresses. */
adamdunkels0170b082003-10-01 11:25:37 +0000923 tmp16 = BUF->destipaddr[0];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000924 BUF->destipaddr[0] = BUF->srcipaddr[0];
adamdunkels0170b082003-10-01 11:25:37 +0000925 BUF->srcipaddr[0] = tmp16;
926 tmp16 = BUF->destipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000927 BUF->destipaddr[1] = BUF->srcipaddr[1];
adamdunkels0170b082003-10-01 11:25:37 +0000928 BUF->srcipaddr[1] = tmp16;
adamdunkelsa38da252003-08-20 20:56:54 +0000929
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000930
931 /* And send out the RST packet! */
932 goto tcp_send_noconn;
933
934 /* This label will be jumped to if we matched the incoming packet
935 with a connection in LISTEN. In that case, we should create a new
936 connection and send a SYNACK in return. */
937 found_listen:
938 /* First we check if there are any connections avaliable. Unused
939 connections are kept in the same table as used connections, but
940 unused ones have the tcpstate set to CLOSED. Also, connections in
941 TIME_WAIT are kept track of and we'll use the oldest one if no
942 CLOSED connections are found. Thanks to Eddie C. Dost for a very
943 nice algorithm for the TIME_WAIT search. */
944 uip_connr = 0;
945 for(c = 0; c < UIP_CONNS; ++c) {
946 if(uip_conns[c].tcpstateflags == CLOSED) {
947 uip_connr = &uip_conns[c];
948 break;
949 }
950 if(uip_conns[c].tcpstateflags == TIME_WAIT) {
951 if(uip_connr == 0 ||
952 uip_conns[c].timer > uip_connr->timer) {
953 uip_connr = &uip_conns[c];
954 }
955 }
956 }
957
958 if(uip_connr == 0) {
959 /* All connections are used already, we drop packet and hope that
960 the remote end will retransmit the packet at a time when we
961 have more spare connections. */
962 UIP_STAT(++uip_stat.tcp.syndrop);
963 UIP_LOG("tcp: found no unused connections.");
964 goto drop;
965 }
966 uip_conn = uip_connr;
967
968 /* Fill in the necessary fields for the new connection. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000969 uip_connr->rto = uip_connr->timer = UIP_RTO;
970 uip_connr->sa = 0;
971 uip_connr->sv = 4;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000972 uip_connr->nrtx = 0;
973 uip_connr->lport = BUF->destport;
974 uip_connr->rport = BUF->srcport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000975 uip_connr->ripaddr[0] = BUF->srcipaddr[0];
976 uip_connr->ripaddr[1] = BUF->srcipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000977 uip_connr->tcpstateflags = SYN_RCVD;
978
979 uip_connr->snd_nxt[0] = iss[0];
980 uip_connr->snd_nxt[1] = iss[1];
981 uip_connr->snd_nxt[2] = iss[2];
982 uip_connr->snd_nxt[3] = iss[3];
983 uip_connr->len = 1;
984
985 /* rcv_nxt should be the seqno from the incoming packet + 1. */
986 uip_connr->rcv_nxt[3] = BUF->seqno[3];
987 uip_connr->rcv_nxt[2] = BUF->seqno[2];
988 uip_connr->rcv_nxt[1] = BUF->seqno[1];
989 uip_connr->rcv_nxt[0] = BUF->seqno[0];
990 uip_add_rcv_nxt(1);
991
992 /* Parse the TCP MSS option, if present. */
993 if((BUF->tcpoffset & 0xf0) > 0x50) {
994 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
995 opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c];
996 if(opt == 0x00) {
997 /* End of options. */
998 break;
999 } else if(opt == 0x01) {
1000 ++c;
1001 /* NOP option. */
1002 } else if(opt == 0x02 &&
1003 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0x04) {
1004 /* An MSS option with the right option length. */
adamdunkels0170b082003-10-01 11:25:37 +00001005 tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
1006 (u16_t)uip_buf[40 + UIP_LLH_LEN + 3 + c];
1007 uip_connr->initialmss = uip_connr->mss =
1008 tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001009
1010 /* And we are done processing options. */
1011 break;
1012 } else {
1013 /* All other options have a length field, so that we easily
1014 can skip past them. */
1015 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
1016 /* If the length field is zero, the options are malformed
1017 and we don't process them further. */
1018 break;
1019 }
1020 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
1021 }
1022 }
1023 }
1024
1025 /* Our response will be a SYNACK. */
1026#if UIP_ACTIVE_OPEN
1027 tcp_send_synack:
1028 BUF->flags = TCP_ACK;
1029
1030 tcp_send_syn:
1031 BUF->flags |= TCP_SYN;
1032#else /* UIP_ACTIVE_OPEN */
1033 tcp_send_synack:
1034 BUF->flags = TCP_SYN | TCP_ACK;
1035#endif /* UIP_ACTIVE_OPEN */
1036
1037 /* We send out the TCP Maximum Segment Size option with our
1038 SYNACK. */
1039 BUF->optdata[0] = 2;
1040 BUF->optdata[1] = 4;
1041 BUF->optdata[2] = (UIP_TCP_MSS) / 256;
1042 BUF->optdata[3] = (UIP_TCP_MSS) & 255;
1043 uip_len = 44;
1044 BUF->tcpoffset = 6 << 4;
1045 goto tcp_send;
1046
1047 /* This label will be jumped to if we found an active connection. */
1048 found:
1049 uip_conn = uip_connr;
1050 uip_flags = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001051 /* We do a very naive form of TCP reset processing; we just accept
1052 any RST and kill our connection. We should in fact check if the
1053 sequence number of this reset is wihtin our advertised window
1054 before we accept the reset. */
1055 if(BUF->flags & TCP_RST) {
1056 uip_connr->tcpstateflags = CLOSED;
1057 UIP_LOG("tcp: got reset, aborting connection.");
1058 uip_flags = UIP_ABORT;
1059 UIP_APPCALL();
1060 goto drop;
adamdunkels47ec7fa2003-03-28 12:11:17 +00001061 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001062 /* Calculated the length of the data, if the application has sent
1063 any data to us. */
1064 c = (BUF->tcpoffset >> 4) << 2;
1065 /* uip_len will contain the length of the actual TCP data. This is
1066 calculated by subtracing the length of the TCP header (in
1067 c) and the length of the IP header (20 bytes). */
1068 uip_len = uip_len - c - 20;
1069
1070 /* First, check if the sequence number of the incoming packet is
1071 what we're expecting next. If not, we send out an ACK with the
1072 correct numbers in. */
1073 if(uip_len > 0 &&
1074 (BUF->seqno[0] != uip_connr->rcv_nxt[0] ||
1075 BUF->seqno[1] != uip_connr->rcv_nxt[1] ||
1076 BUF->seqno[2] != uip_connr->rcv_nxt[2] ||
1077 BUF->seqno[3] != uip_connr->rcv_nxt[3])) {
1078 goto tcp_send_ack;
1079 }
1080
1081 /* Next, check if the incoming segment acknowledges any outstanding
1082 data. If so, we update the sequence number, reset the length of
1083 the outstanding data, calculate RTT estimations, and reset the
1084 retransmission timer. */
adamdunkels47ec7fa2003-03-28 12:11:17 +00001085 if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001086 uip_add32(uip_connr->snd_nxt, uip_connr->len);
adamdunkels08eac9e2004-09-12 07:17:37 +00001087
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001088 if(BUF->ackno[0] == uip_acc32[0] &&
1089 BUF->ackno[1] == uip_acc32[1] &&
1090 BUF->ackno[2] == uip_acc32[2] &&
1091 BUF->ackno[3] == uip_acc32[3]) {
1092 /* Update sequence number. */
1093 uip_connr->snd_nxt[0] = uip_acc32[0];
1094 uip_connr->snd_nxt[1] = uip_acc32[1];
1095 uip_connr->snd_nxt[2] = uip_acc32[2];
1096 uip_connr->snd_nxt[3] = uip_acc32[3];
adamdunkelsa38da252003-08-20 20:56:54 +00001097
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001098
1099 /* Do RTT estimation, unless we have done retransmissions. */
1100 if(uip_connr->nrtx == 0) {
1101 signed char m;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001102 m = uip_connr->rto - uip_connr->timer;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001103 /* This is taken directly from VJs original code in his paper */
1104 m = m - (uip_connr->sa >> 3);
1105 uip_connr->sa += m;
1106 if(m < 0) {
1107 m = -m;
1108 }
1109 m = m - (uip_connr->sv >> 2);
1110 uip_connr->sv += m;
1111 uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv;
1112
1113 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001114 /* Set the acknowledged flag. */
1115 uip_flags = UIP_ACKDATA;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001116 /* Reset the retransmission timer. */
adamdunkelsb489e7a2003-10-14 11:12:50 +00001117 uip_connr->timer = uip_connr->rto;
adamdunkels08eac9e2004-09-12 07:17:37 +00001118
1119 /* Reset length of outstanding data. */
1120 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001121 }
adamdunkelsab4b0822003-07-30 23:31:40 +00001122
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001123 }
1124
1125 /* Do different things depending on in what state the connection is. */
1126 switch(uip_connr->tcpstateflags & TS_MASK) {
1127 /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
1128 implemented, since we force the application to close when the
1129 peer sends a FIN (hence the application goes directly from
1130 ESTABLISHED to LAST_ACK). */
1131 case SYN_RCVD:
1132 /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and
1133 we are waiting for an ACK that acknowledges the data we sent
1134 out the last time. Therefore, we want to have the UIP_ACKDATA
1135 flag set. If so, we enter the ESTABLISHED state. */
1136 if(uip_flags & UIP_ACKDATA) {
1137 uip_connr->tcpstateflags = ESTABLISHED;
1138 uip_flags = UIP_CONNECTED;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001139 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001140 if(uip_len > 0) {
1141 uip_flags |= UIP_NEWDATA;
1142 uip_add_rcv_nxt(uip_len);
1143 }
1144 uip_slen = 0;
1145 UIP_APPCALL();
1146 goto appsend;
1147 }
1148 goto drop;
1149#if UIP_ACTIVE_OPEN
1150 case SYN_SENT:
1151 /* In SYN_SENT, we wait for a SYNACK that is sent in response to
1152 our SYN. The rcv_nxt is set to sequence number in the SYNACK
1153 plus one, and we send an ACK. We move into the ESTABLISHED
1154 state. */
1155 if((uip_flags & UIP_ACKDATA) &&
1156 BUF->flags == (TCP_SYN | TCP_ACK)) {
1157
1158 /* Parse the TCP MSS option, if present. */
1159 if((BUF->tcpoffset & 0xf0) > 0x50) {
1160 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
1161 opt = uip_buf[40 + UIP_LLH_LEN + c];
1162 if(opt == 0x00) {
1163 /* End of options. */
1164 break;
1165 } else if(opt == 0x01) {
1166 ++c;
1167 /* NOP option. */
1168 } else if(opt == 0x02 &&
1169 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0x04) {
1170 /* An MSS option with the right option length. */
adamdunkels0170b082003-10-01 11:25:37 +00001171 tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001172 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];
adamdunkels0170b082003-10-01 11:25:37 +00001173 uip_connr->initialmss =
1174 uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001175
1176 /* And we are done processing options. */
1177 break;
1178 } else {
1179 /* All other options have a length field, so that we easily
1180 can skip past them. */
1181 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
1182 /* If the length field is zero, the options are malformed
1183 and we don't process them further. */
1184 break;
1185 }
1186 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
1187 }
1188 }
1189 }
1190 uip_connr->tcpstateflags = ESTABLISHED;
1191 uip_connr->rcv_nxt[0] = BUF->seqno[0];
1192 uip_connr->rcv_nxt[1] = BUF->seqno[1];
1193 uip_connr->rcv_nxt[2] = BUF->seqno[2];
1194 uip_connr->rcv_nxt[3] = BUF->seqno[3];
1195 uip_add_rcv_nxt(1);
1196 uip_flags = UIP_CONNECTED | UIP_NEWDATA;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001197 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001198 uip_len = 0;
1199 uip_slen = 0;
1200 UIP_APPCALL();
1201 goto appsend;
1202 }
1203 goto reset;
1204#endif /* UIP_ACTIVE_OPEN */
1205
1206 case ESTABLISHED:
1207 /* In the ESTABLISHED state, we call upon the application to feed
1208 data into the uip_buf. If the UIP_ACKDATA flag is set, the
1209 application should put new data into the buffer, otherwise we are
1210 retransmitting an old segment, and the application should put that
1211 data into the buffer.
1212
1213 If the incoming packet is a FIN, we should close the connection on
1214 this side as well, and we send out a FIN and enter the LAST_ACK
1215 state. We require that there is no outstanding data; otherwise the
1216 sequence numbers will be screwed up. */
1217
1218 if(BUF->flags & TCP_FIN) {
1219 if(uip_outstanding(uip_connr)) {
1220 goto drop;
1221 }
1222 uip_add_rcv_nxt(1 + uip_len);
1223 uip_flags = UIP_CLOSE;
1224 if(uip_len > 0) {
1225 uip_flags |= UIP_NEWDATA;
1226 }
1227 UIP_APPCALL();
1228 uip_connr->len = 1;
1229 uip_connr->tcpstateflags = LAST_ACK;
1230 uip_connr->nrtx = 0;
1231 tcp_send_finack:
1232 BUF->flags = TCP_FIN | TCP_ACK;
1233 goto tcp_send_nodata;
1234 }
1235
1236 /* Check the URG flag. If this is set, the segment carries urgent
1237 data that we must pass to the application. */
adamdunkels9fad4132004-06-06 06:14:19 +00001238 if((BUF->flags & TCP_URG) != 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001239#if UIP_URGDATA > 0
1240 uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1];
1241 if(uip_urglen > uip_len) {
1242 /* There is more urgent data in the next segment to come. */
1243 uip_urglen = uip_len;
1244 }
1245 uip_add_rcv_nxt(uip_urglen);
1246 uip_len -= uip_urglen;
1247 uip_urgdata = uip_appdata;
1248 uip_appdata += uip_urglen;
1249 } else {
1250 uip_urglen = 0;
adamdunkels9fad4132004-06-06 06:14:19 +00001251#else /* UIP_URGDATA > 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001252 uip_appdata += (BUF->urgp[0] << 8) | BUF->urgp[1];
1253 uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1];
adamdunkels9fad4132004-06-06 06:14:19 +00001254#endif /* UIP_URGDATA > 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001255 }
adamdunkels9fad4132004-06-06 06:14:19 +00001256
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001257 /* If uip_len > 0 we have TCP data in the packet, and we flag this
1258 by setting the UIP_NEWDATA flag and update the sequence number
1259 we acknowledge. If the application has stopped the dataflow
1260 using uip_stop(), we must not accept any data packets from the
1261 remote host. */
1262 if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
1263 uip_flags |= UIP_NEWDATA;
1264 uip_add_rcv_nxt(uip_len);
1265 }
adamdunkels0170b082003-10-01 11:25:37 +00001266
1267 /* Check if the available buffer space advertised by the other end
1268 is smaller than the initial MSS for this connection. If so, we
1269 set the current MSS to the window size to ensure that the
1270 application does not send more data than the other end can
1271 handle.
1272
1273 If the remote host advertises a zero window, we set the MSS to
1274 the initial MSS so that the application will send an entire MSS
1275 of data. This data will not be acknowledged by the receiver,
1276 and the application will retransmit it. This is called the
1277 "persistent timer" and uses the retransmission mechanim.
1278 */
1279 tmp16 = ((u16_t)BUF->wnd[0] << 8) + (u16_t)BUF->wnd[1];
1280 if(tmp16 > uip_connr->initialmss ||
1281 tmp16 == 0) {
1282 tmp16 = uip_connr->initialmss;
1283 }
1284 uip_connr->mss = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001285
1286 /* If this packet constitutes an ACK for outstanding data (flagged
1287 by the UIP_ACKDATA flag, we should call the application since it
1288 might want to send more data. If the incoming packet had data
1289 from the peer (as flagged by the UIP_NEWDATA flag), the
1290 application must also be notified.
1291
1292 When the application is called, the global variable uip_len
1293 contains the length of the incoming data. The application can
1294 access the incoming data through the global pointer
1295 uip_appdata, which usually points 40 bytes into the uip_buf
1296 array.
1297
1298 If the application wishes to send any data, this data should be
1299 put into the uip_appdata and the length of the data should be
1300 put into uip_len. If the application don't have any data to
1301 send, uip_len must be set to 0. */
1302 if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) {
1303 uip_slen = 0;
1304 UIP_APPCALL();
1305
1306 appsend:
adamdunkels0170b082003-10-01 11:25:37 +00001307
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001308 if(uip_flags & UIP_ABORT) {
1309 uip_slen = 0;
1310 uip_connr->tcpstateflags = CLOSED;
1311 BUF->flags = TCP_RST | TCP_ACK;
1312 goto tcp_send_nodata;
1313 }
1314
1315 if(uip_flags & UIP_CLOSE) {
1316 uip_slen = 0;
1317 uip_connr->len = 1;
1318 uip_connr->tcpstateflags = FIN_WAIT_1;
1319 uip_connr->nrtx = 0;
1320 BUF->flags = TCP_FIN | TCP_ACK;
1321 goto tcp_send_nodata;
1322 }
1323
adamdunkelsb489e7a2003-10-14 11:12:50 +00001324 /* If uip_slen > 0, the application has data to be sent. */
1325 if(uip_slen > 0) {
1326
1327 /* If the connection has acknowledged data, the contents of
1328 the ->len variable should be discarded. */
1329 if((uip_flags & UIP_ACKDATA) != 0) {
1330 uip_connr->len = 0;
1331 }
1332
1333 /* If the ->len variable is non-zero the connection has
1334 already data in transit and cannot send anymore right
1335 now. */
1336 if(uip_connr->len == 0) {
1337
1338 /* The application cannot send more than what is allowed by
1339 the mss (the minumum of the MSS and the available
1340 window). */
1341 if(uip_slen > uip_connr->mss) {
1342 uip_slen = uip_connr->mss;
1343 }
1344
1345 /* Remember how much data we send out now so that we know
1346 when everything has been acknowledged. */
1347 uip_connr->len = uip_slen;
1348 } else {
1349
1350 /* If the application already had unacknowledged data, we
1351 make sure that the application does not send (i.e.,
1352 retransmit) out more than it previously sent out. */
1353 uip_slen = uip_connr->len;
1354 }
adamdunkelsab4b0822003-07-30 23:31:40 +00001355 } else {
adamdunkels08eac9e2004-09-12 07:17:37 +00001356 /* uip_connr->len = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001357 }
adamdunkelsb489e7a2003-10-14 11:12:50 +00001358 uip_connr->nrtx = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001359 apprexmit:
adamdunkels0170b082003-10-01 11:25:37 +00001360 uip_appdata = uip_sappdata;
1361
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001362 /* If the application has data to be sent, or if the incoming
1363 packet had new data in it, we must send out a packet. */
adamdunkels759185d2003-06-30 20:35:41 +00001364 if(uip_slen > 0 && uip_connr->len > 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001365 /* Add the length of the IP and TCP headers. */
1366 uip_len = uip_connr->len + UIP_TCPIP_HLEN;
1367 /* We always set the ACK flag in response packets. */
adamdunkels759185d2003-06-30 20:35:41 +00001368 BUF->flags = TCP_ACK | TCP_PSH;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001369 /* Send the packet. */
1370 goto tcp_send_noopts;
1371 }
adamdunkels759185d2003-06-30 20:35:41 +00001372 /* If there is no data to send, just send out a pure ACK if
1373 there is newdata. */
1374 if(uip_flags & UIP_NEWDATA) {
1375 uip_len = UIP_TCPIP_HLEN;
1376 BUF->flags = TCP_ACK;
1377 goto tcp_send_noopts;
1378 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001379 }
1380 goto drop;
1381 case LAST_ACK:
1382 /* We can close this connection if the peer has acknowledged our
1383 FIN. This is indicated by the UIP_ACKDATA flag. */
1384 if(uip_flags & UIP_ACKDATA) {
1385 uip_connr->tcpstateflags = CLOSED;
1386 uip_flags = UIP_CLOSE;
1387 UIP_APPCALL();
1388 }
1389 break;
1390
1391 case FIN_WAIT_1:
1392 /* The application has closed the connection, but the remote host
1393 hasn't closed its end yet. Thus we do nothing but wait for a
1394 FIN from the other side. */
1395 if(uip_len > 0) {
1396 uip_add_rcv_nxt(uip_len);
1397 }
1398 if(BUF->flags & TCP_FIN) {
1399 if(uip_flags & UIP_ACKDATA) {
1400 uip_connr->tcpstateflags = TIME_WAIT;
1401 uip_connr->timer = 0;
1402 uip_connr->len = 0;
1403 } else {
1404 uip_connr->tcpstateflags = CLOSING;
1405 }
1406 uip_add_rcv_nxt(1);
1407 uip_flags = UIP_CLOSE;
1408 UIP_APPCALL();
1409 goto tcp_send_ack;
1410 } else if(uip_flags & UIP_ACKDATA) {
1411 uip_connr->tcpstateflags = FIN_WAIT_2;
1412 uip_connr->len = 0;
1413 goto drop;
1414 }
1415 if(uip_len > 0) {
1416 goto tcp_send_ack;
1417 }
1418 goto drop;
1419
1420 case FIN_WAIT_2:
1421 if(uip_len > 0) {
1422 uip_add_rcv_nxt(uip_len);
1423 }
1424 if(BUF->flags & TCP_FIN) {
1425 uip_connr->tcpstateflags = TIME_WAIT;
1426 uip_connr->timer = 0;
1427 uip_add_rcv_nxt(1);
1428 uip_flags = UIP_CLOSE;
1429 UIP_APPCALL();
1430 goto tcp_send_ack;
1431 }
1432 if(uip_len > 0) {
1433 goto tcp_send_ack;
1434 }
1435 goto drop;
1436
1437 case TIME_WAIT:
1438 goto tcp_send_ack;
1439
1440 case CLOSING:
1441 if(uip_flags & UIP_ACKDATA) {
1442 uip_connr->tcpstateflags = TIME_WAIT;
1443 uip_connr->timer = 0;
1444 }
1445 }
1446 goto drop;
1447
1448
1449 /* We jump here when we are ready to send the packet, and just want
1450 to set the appropriate TCP sequence numbers in the TCP header. */
1451 tcp_send_ack:
1452 BUF->flags = TCP_ACK;
1453 tcp_send_nodata:
1454 uip_len = 40;
1455 tcp_send_noopts:
1456 BUF->tcpoffset = 5 << 4;
1457 tcp_send:
1458 /* We're done with the input processing. We are now ready to send a
1459 reply. Our job is to fill in all the fields of the TCP and IP
1460 headers before calculating the checksum and finally send the
1461 packet. */
1462 BUF->ackno[0] = uip_connr->rcv_nxt[0];
1463 BUF->ackno[1] = uip_connr->rcv_nxt[1];
1464 BUF->ackno[2] = uip_connr->rcv_nxt[2];
1465 BUF->ackno[3] = uip_connr->rcv_nxt[3];
1466
1467 BUF->seqno[0] = uip_connr->snd_nxt[0];
1468 BUF->seqno[1] = uip_connr->snd_nxt[1];
1469 BUF->seqno[2] = uip_connr->snd_nxt[2];
1470 BUF->seqno[3] = uip_connr->snd_nxt[3];
1471
1472 BUF->proto = UIP_PROTO_TCP;
1473
1474 BUF->srcport = uip_connr->lport;
1475 BUF->destport = uip_connr->rport;
1476
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001477 BUF->srcipaddr[0] = uip_hostaddr[0];
1478 BUF->srcipaddr[1] = uip_hostaddr[1];
1479 BUF->destipaddr[0] = uip_connr->ripaddr[0];
1480 BUF->destipaddr[1] = uip_connr->ripaddr[1];
1481
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001482
1483 if(uip_connr->tcpstateflags & UIP_STOPPED) {
1484 /* If the connection has issued uip_stop(), we advertise a zero
1485 window so that the remote host will stop sending data. */
1486 BUF->wnd[0] = BUF->wnd[1] = 0;
1487 } else {
adamdunkelsb489e7a2003-10-14 11:12:50 +00001488 BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8);
1489 BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001490 }
1491
1492 tcp_send_noconn:
1493
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001494 BUF->len[0] = (uip_len >> 8);
1495 BUF->len[1] = (uip_len & 0xff);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001496
adamdunkels9fad4132004-06-06 06:14:19 +00001497 BUF->urgp[0] = BUF->urgp[1] = 0;
1498
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001499 /* Calculate TCP checksum. */
1500 BUF->tcpchksum = 0;
1501 BUF->tcpchksum = ~(uip_tcpchksum());
1502
1503 ip_send_nolen:
1504
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001505 BUF->vhl = 0x45;
1506 BUF->tos = 0;
1507 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
1508 BUF->ttl = UIP_TTL;
1509 ++ipid;
1510 BUF->ipid[0] = ipid >> 8;
1511 BUF->ipid[1] = ipid & 0xff;
1512
1513 /* Calculate IP checksum. */
1514 BUF->ipchksum = 0;
1515 BUF->ipchksum = ~(uip_ipchksum());
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001516
1517 UIP_STAT(++uip_stat.tcp.sent);
1518 send:
adamdunkels9fad4132004-06-06 06:14:19 +00001519
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001520 UIP_STAT(++uip_stat.ip.sent);
1521 /* Return and let the caller do the actual transmission. */
1522 return;
1523 drop:
1524 uip_len = 0;
1525 return;
1526}
1527/*-----------------------------------------------------------------------------------*/
adamdunkels47ec7fa2003-03-28 12:11:17 +00001528u16_t
1529htons(u16_t val)
1530{
1531 return HTONS(val);
1532}
1533/*-----------------------------------------------------------------------------------*/
adamdunkels0170b082003-10-01 11:25:37 +00001534/** @} */