blob: 661e2b7c473dfb2c0667f7d4fb0425aa188e208f [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 *
adamdunkelsa7713622005-03-14 07:18:15 +000042 * $Id: uip.c,v 1.24 2005/03/14 07:18:15 adamdunkels Exp $
adamdunkelsca9ddcb2003-03-19 14:13:31 +000043 *
44 */
45
46/*
adamdunkels049a9122005-02-07 06:59:39 +000047This is a small implementation of the IP, UDP and TCP protocols (as
48well as some basic ICMP stuff). The implementation couples the IP,
49UDP, TCP and the application layers very tightly. To keep the size of
50the compiled code down, this code frequently uses the goto
51statement. While it would be possible to break the uip_process()
52function into many smaller functions, this would increase the code
53size because of the overhead of parameter passing and the fact that
54the optimier would not be as efficient.
adamdunkelsca9ddcb2003-03-19 14:13:31 +000055
56The principle is that we have a small buffer, called the uip_buf, in
57which the device driver puts an incoming packet. The TCP/IP stack
adamdunkels049a9122005-02-07 06:59:39 +000058parses the headers in the packet, and calls the application. If the
59remote host has sent data to the application, this data is present in
60the uip_buf and the application read the data from there. It is up to
61the application to put this data into a byte stream if needed. The
adamdunkelsca9ddcb2003-03-19 14:13:31 +000062application will not be fed with data that is out of sequence.
63
64If the application whishes to send data to the peer, it should put its
adamdunkels049a9122005-02-07 06:59:39 +000065data into the uip_buf. The uip_appdata pointer points to the first
66available byte. The TCP/IP stack will calculate the checksums, and
67fill in the necessary header fields and finally send the packet back
68to the peer.
adamdunkelsca9ddcb2003-03-19 14:13:31 +000069*/
70
71#include "uip.h"
72#include "uipopt.h"
73#include "uip_arch.h"
74
75/*-----------------------------------------------------------------------------------*/
76/* Variable definitions. */
77
78
79/* 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 */
80#if UIP_FIXEDADDR > 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +000081const u16_t uip_hostaddr[2] =
adamdunkels47ec7fa2003-03-28 12:11:17 +000082 {HTONS((UIP_IPADDR0 << 8) | UIP_IPADDR1),
83 HTONS((UIP_IPADDR2 << 8) | UIP_IPADDR3)};
adamdunkels9fad4132004-06-06 06:14:19 +000084const u16_t uip_draddr[2] =
adamdunkelsb489e7a2003-10-14 11:12:50 +000085 {HTONS((UIP_DRIPADDR0 << 8) | UIP_DRIPADDR1),
86 HTONS((UIP_DRIPADDR2 << 8) | UIP_DRIPADDR3)};
adamdunkels9fad4132004-06-06 06:14:19 +000087const u16_t uip_netmask[2] =
adamdunkelsb489e7a2003-10-14 11:12:50 +000088 {HTONS((UIP_NETMASK0 << 8) | UIP_NETMASK1),
89 HTONS((UIP_NETMASK2 << 8) | UIP_NETMASK3)};
adamdunkelsca9ddcb2003-03-19 14:13:31 +000090#else
adamdunkelsca9ddcb2003-03-19 14:13:31 +000091u16_t uip_hostaddr[2];
adamdunkels9fad4132004-06-06 06:14:19 +000092u16_t uip_draddr[2], uip_netmask[2];
adamdunkelsca9ddcb2003-03-19 14:13:31 +000093#endif /* UIP_FIXEDADDR */
94
adamdunkelsb380a3e2004-09-17 20:59:23 +000095#if UIP_FIXEDETHADDR
96const struct uip_eth_addr uip_ethaddr = {{UIP_ETHADDR0,
97 UIP_ETHADDR1,
98 UIP_ETHADDR2,
99 UIP_ETHADDR3,
100 UIP_ETHADDR4,
101 UIP_ETHADDR5}};
102#else
103struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}};
104#endif
105
oliverschmidt7cd06bb2005-02-23 17:30:27 +0000106#ifndef UIP_CONF_EXTERNAL_BUFFER
adamdunkels049a9122005-02-07 06:59:39 +0000107u8_t uip_buf[UIP_BUFSIZE + 2]; /* The packet buffer that contains
108 incoming packets. */
oliverschmidt7cd06bb2005-02-23 17:30:27 +0000109#endif /* UIP_CONF_EXTERNAL_BUFFER */
adamdunkels3335cd92005-02-27 09:44:33 +0000110
adamdunkels049a9122005-02-07 06:59:39 +0000111u8_t *uip_appdata; /* The uip_appdata pointer points to
112 application data. */
113u8_t *uip_sappdata; /* The uip_appdata pointer points to
114 the application data which is to
115 be sent. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000116#if UIP_URGDATA > 0
adamdunkels049a9122005-02-07 06:59:39 +0000117u8_t *uip_urgdata; /* The uip_urgdata pointer points to
118 urgent data (out-of-band data), if
119 present. */
120u16_t uip_urglen, uip_surglen;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000121#endif /* UIP_URGDATA > 0 */
122
adamdunkels3335cd92005-02-27 09:44:33 +0000123u16_t uip_len, uip_slen;
124 /* The uip_len is either 8 or 16 bits,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000125 depending on the maximum packet
126 size. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000127
adamdunkels3335cd92005-02-27 09:44:33 +0000128u8_t uip_flags; /* The uip_flags variable is used for
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000129 communication between the TCP/IP stack
130 and the application program. */
131struct uip_conn *uip_conn; /* uip_conn always points to the current
132 connection. */
133
134struct uip_conn uip_conns[UIP_CONNS];
135 /* The uip_conns array holds all TCP
136 connections. */
137u16_t uip_listenports[UIP_LISTENPORTS];
138 /* The uip_listenports list all currently
139 listning ports. */
140#if UIP_UDP
141struct uip_udp_conn *uip_udp_conn;
142struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
143#endif /* UIP_UDP */
144
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000145static u16_t ipid; /* Ths ipid variable is an increasing
146 number that is used for the IP ID
147 field. */
148
149static u8_t iss[4]; /* The iss variable is used for the TCP
150 initial sequence number. */
adamdunkels3335cd92005-02-27 09:44:33 +0000151
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000152#if UIP_ACTIVE_OPEN
adamdunkelsb489e7a2003-10-14 11:12:50 +0000153static u16_t lastport; /* Keeps track of the last port used for
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000154 a new connection. */
155#endif /* UIP_ACTIVE_OPEN */
156
157/* Temporary variables. */
adamdunkels9fad4132004-06-06 06:14:19 +0000158u8_t uip_acc32[4];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000159static u8_t c, opt;
adamdunkels0170b082003-10-01 11:25:37 +0000160static u16_t tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000161
162/* Structures and definitions. */
163#define TCP_FIN 0x01
164#define TCP_SYN 0x02
165#define TCP_RST 0x04
166#define TCP_PSH 0x08
167#define TCP_ACK 0x10
168#define TCP_URG 0x20
169#define TCP_CTL 0x3f
170
adamdunkels049a9122005-02-07 06:59:39 +0000171#define TCP_OPT_END 0 /* End of TCP options list */
172#define TCP_OPT_NOOP 1 /* "No-operation" TCP option */
173#define TCP_OPT_MSS 2 /* Maximum segment size TCP option */
174
175#define TCP_OPT_MSS_LEN 4 /* Length of TCP MSS option. */
176
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000177#define ICMP_ECHO_REPLY 0
178#define ICMP_ECHO 8
179
adamdunkels3335cd92005-02-27 09:44:33 +0000180
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000181/* Macros. */
182#define BUF ((uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
183#define FBUF ((uip_tcpip_hdr *)&uip_reassbuf[0])
184#define ICMPBUF ((uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
185#define UDPBUF ((uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])
186
adamdunkels3335cd92005-02-27 09:44:33 +0000187
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000188#if UIP_STATISTICS == 1
189struct uip_stats uip_stat;
190#define UIP_STAT(s) s
191#else
192#define UIP_STAT(s)
193#endif /* UIP_STATISTICS == 1 */
194
195#if UIP_LOGGING == 1
196#include <stdio.h>
197void uip_log(char *msg);
198#define UIP_LOG(m) uip_log(m)
199#else
200#define UIP_LOG(m)
201#endif /* UIP_LOGGING == 1 */
202
203/*-----------------------------------------------------------------------------------*/
204void
205uip_init(void)
206{
207 for(c = 0; c < UIP_LISTENPORTS; ++c) {
208 uip_listenports[c] = 0;
209 }
210 for(c = 0; c < UIP_CONNS; ++c) {
211 uip_conns[c].tcpstateflags = CLOSED;
212 }
213#if UIP_ACTIVE_OPEN
214 lastport = 1024;
215#endif /* UIP_ACTIVE_OPEN */
216
217#if UIP_UDP
218 for(c = 0; c < UIP_UDP_CONNS; ++c) {
219 uip_udp_conns[c].lport = 0;
220 }
221#endif /* UIP_UDP */
222
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000223
224 /* IPv4 initialization. */
225#if UIP_FIXEDADDR == 0
adamdunkels049a9122005-02-07 06:59:39 +0000226 /* uip_hostaddr[0] = uip_hostaddr[1] = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000227#endif /* UIP_FIXEDADDR */
adamdunkelsa38da252003-08-20 20:56:54 +0000228
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000229}
230/*-----------------------------------------------------------------------------------*/
231#if UIP_ACTIVE_OPEN
232struct uip_conn *
233uip_connect(u16_t *ripaddr, u16_t rport)
234{
adamdunkelsa38da252003-08-20 20:56:54 +0000235 register struct uip_conn *conn, *cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000236
237 /* Find an unused local port. */
238 again:
239 ++lastport;
240
241 if(lastport >= 32000) {
242 lastport = 4096;
243 }
adamdunkels1e45c6d2003-09-02 21:47:27 +0000244
245 /* Check if this port is already in use, and if so try to find
246 another one. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000247 for(c = 0; c < UIP_CONNS; ++c) {
adamdunkels23664022003-08-05 13:51:50 +0000248 conn = &uip_conns[c];
249 if(conn->tcpstateflags != CLOSED &&
adamdunkels1e45c6d2003-09-02 21:47:27 +0000250 conn->lport == htons(lastport)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000251 goto again;
adamdunkelsa38da252003-08-20 20:56:54 +0000252 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000253 }
254
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000255 conn = 0;
256 for(c = 0; c < UIP_CONNS; ++c) {
adamdunkelsa38da252003-08-20 20:56:54 +0000257 cconn = &uip_conns[c];
258 if(cconn->tcpstateflags == CLOSED) {
259 conn = cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000260 break;
261 }
adamdunkelsa38da252003-08-20 20:56:54 +0000262 if(cconn->tcpstateflags == TIME_WAIT) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000263 if(conn == 0 ||
adamdunkels75b9d002004-09-17 20:48:39 +0000264 cconn->timer > conn->timer) {
adamdunkelsa38da252003-08-20 20:56:54 +0000265 conn = cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000266 }
267 }
268 }
269
270 if(conn == 0) {
271 return 0;
272 }
273
274 conn->tcpstateflags = SYN_SENT;
275
276 conn->snd_nxt[0] = iss[0];
277 conn->snd_nxt[1] = iss[1];
278 conn->snd_nxt[2] = iss[2];
279 conn->snd_nxt[3] = iss[3];
280
adamdunkels0170b082003-10-01 11:25:37 +0000281 conn->initialmss = conn->mss = UIP_TCP_MSS;
adamdunkelsd962db42003-08-21 18:10:21 +0000282
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000283 conn->len = 1; /* TCP length of the SYN is one. */
284 conn->nrtx = 0;
285 conn->timer = 1; /* Send the SYN next time around. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000286 conn->rto = UIP_RTO;
287 conn->sa = 0;
adamdunkels049a9122005-02-07 06:59:39 +0000288 conn->sv = 16; /* Initial value of the RTT variance. */
adamdunkels1e45c6d2003-09-02 21:47:27 +0000289 conn->lport = htons(lastport);
290 conn->rport = rport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000291 conn->ripaddr[0] = ripaddr[0];
292 conn->ripaddr[1] = ripaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000293
294 return conn;
295}
296#endif /* UIP_ACTIVE_OPEN */
297/*-----------------------------------------------------------------------------------*/
298#if UIP_UDP
299struct uip_udp_conn *
300uip_udp_new(u16_t *ripaddr, u16_t rport)
301{
adamdunkels23664022003-08-05 13:51:50 +0000302 register struct uip_udp_conn *conn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000303
304 /* Find an unused local port. */
305 again:
306 ++lastport;
307
308 if(lastport >= 32000) {
309 lastport = 4096;
310 }
311
312 for(c = 0; c < UIP_UDP_CONNS; ++c) {
adamdunkels049a9122005-02-07 06:59:39 +0000313 if(uip_udp_conns[c].lport == htons(lastport)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000314 goto again;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000315 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000316 }
317
318
319 conn = 0;
320 for(c = 0; c < UIP_UDP_CONNS; ++c) {
321 if(uip_udp_conns[c].lport == 0) {
322 conn = &uip_udp_conns[c];
323 break;
324 }
325 }
326
327 if(conn == 0) {
328 return 0;
329 }
330
adamdunkels47ec7fa2003-03-28 12:11:17 +0000331 conn->lport = HTONS(lastport);
adamdunkels75b9d002004-09-17 20:48:39 +0000332 conn->rport = rport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000333 conn->ripaddr[0] = ripaddr[0];
334 conn->ripaddr[1] = ripaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000335
336 return conn;
337}
338#endif /* UIP_UDP */
339/*-----------------------------------------------------------------------------------*/
340void
adamdunkelscd8c3a22003-08-13 22:52:48 +0000341uip_unlisten(u16_t port)
342{
343 for(c = 0; c < UIP_LISTENPORTS; ++c) {
344 if(uip_listenports[c] == port) {
345 uip_listenports[c] = 0;
346 return;
347 }
348 }
349}
350/*-----------------------------------------------------------------------------------*/
351void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000352uip_listen(u16_t port)
353{
354 for(c = 0; c < UIP_LISTENPORTS; ++c) {
355 if(uip_listenports[c] == 0) {
adamdunkels1e45c6d2003-09-02 21:47:27 +0000356 uip_listenports[c] = port;
adamdunkelscd8c3a22003-08-13 22:52:48 +0000357 return;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000358 }
359 }
360}
361/*-----------------------------------------------------------------------------------*/
adamdunkelsb489e7a2003-10-14 11:12:50 +0000362/* XXX: IP fragment reassembly: not well-tested. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000363
364#if UIP_REASSEMBLY
365#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)
366static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];
367static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];
368static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f,
369 0x0f, 0x07, 0x03, 0x01};
370static u16_t uip_reasslen;
371static u8_t uip_reassflags;
372#define UIP_REASS_FLAG_LASTFRAG 0x01
373static u8_t uip_reasstmr;
374
adamdunkelsb489e7a2003-10-14 11:12:50 +0000375#define IP_MF 0x20
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000376
377static u8_t
378uip_reass(void)
379{
380 u16_t offset, len;
381 u16_t i;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000382
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000383 /* If ip_reasstmr is zero, no packet is present in the buffer, so we
384 write the IP header of the fragment into the reassembly
385 buffer. The timer is updated with the maximum age. */
386 if(uip_reasstmr == 0) {
adamdunkels31a50262005-02-22 22:33:56 +0000387 memcpy(uip_reassbuf, &BUF->vhl, UIP_IPH_LEN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000388 uip_reasstmr = UIP_REASS_MAXAGE;
389 uip_reassflags = 0;
390 /* Clear the bitmap. */
adamdunkels31a50262005-02-22 22:33:56 +0000391 memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap));
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000392 }
393
394 /* Check if the incoming fragment matches the one currently present
395 in the reasembly buffer. If so, we proceed with copying the
396 fragment into the buffer. */
397 if(BUF->srcipaddr[0] == FBUF->srcipaddr[0] &&
adamdunkelsb489e7a2003-10-14 11:12:50 +0000398 BUF->srcipaddr[1] == FBUF->srcipaddr[1] &&
399 BUF->destipaddr[0] == FBUF->destipaddr[0] &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000400 BUF->destipaddr[1] == FBUF->destipaddr[1] &&
adamdunkelsb489e7a2003-10-14 11:12:50 +0000401 BUF->ipid[0] == FBUF->ipid[0] &&
402 BUF->ipid[1] == FBUF->ipid[1]) {
403
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000404 len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4;
405 offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8;
406
407 /* If the offset or the offset + fragment length overflows the
408 reassembly buffer, we discard the entire packet. */
409 if(offset > UIP_REASS_BUFSIZE ||
410 offset + len > UIP_REASS_BUFSIZE) {
411 uip_reasstmr = 0;
412 goto nullreturn;
413 }
414
415 /* Copy the fragment into the reassembly buffer, at the right
416 offset. */
adamdunkels31a50262005-02-22 22:33:56 +0000417 memcpy(&uip_reassbuf[UIP_IPH_LEN + offset],
adamdunkelsb489e7a2003-10-14 11:12:50 +0000418 (char *)BUF + (int)((BUF->vhl & 0x0f) * 4),
419 len);
420
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000421 /* Update the bitmap. */
422 if(offset / (8 * 8) == (offset + len) / (8 * 8)) {
423 /* If the two endpoints are in the same byte, we only update
424 that byte. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000425
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000426 uip_reassbitmap[offset / (8 * 8)] |=
adamdunkelsb489e7a2003-10-14 11:12:50 +0000427 bitmap_bits[(offset / 8 ) & 7] &
428 ~bitmap_bits[((offset + len) / 8 ) & 7];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000429 } else {
430 /* If the two endpoints are in different bytes, we update the
431 bytes in the endpoints and fill the stuff inbetween with
432 0xff. */
433 uip_reassbitmap[offset / (8 * 8)] |=
434 bitmap_bits[(offset / 8 ) & 7];
435 for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
436 uip_reassbitmap[i] = 0xff;
437 }
438 uip_reassbitmap[(offset + len) / (8 * 8)] |=
439 ~bitmap_bits[((offset + len) / 8 ) & 7];
440 }
441
442 /* If this fragment has the More Fragments flag set to zero, we
443 know that this is the last fragment, so we can calculate the
444 size of the entire packet. We also set the
445 IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
446 the final fragment. */
447
448 if((BUF->ipoffset[0] & IP_MF) == 0) {
449 uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
450 uip_reasslen = offset + len;
451 }
452
453 /* Finally, we check if we have a full packet in the buffer. We do
454 this by checking if we have the last fragment and if all bits
455 in the bitmap are set. */
456 if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) {
457 /* Check all bytes up to and including all but the last byte in
458 the bitmap. */
459 for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) {
460 if(uip_reassbitmap[i] != 0xff) {
461 goto nullreturn;
462 }
463 }
464 /* Check the last byte in the bitmap. It should contain just the
465 right amount of bits. */
466 if(uip_reassbitmap[uip_reasslen / (8 * 8)] !=
467 (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) {
468 goto nullreturn;
469 }
470
471 /* If we have come this far, we have a full packet in the
472 buffer, so we allocate a pbuf and copy the packet into it. We
473 also reset the timer. */
474 uip_reasstmr = 0;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000475 memcpy(BUF, FBUF, uip_reasslen);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000476
477 /* Pretend to be a "normal" (i.e., not fragmented) IP packet
478 from now on. */
479 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000480 BUF->len[0] = uip_reasslen >> 8;
481 BUF->len[1] = uip_reasslen & 0xff;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000482 BUF->ipchksum = 0;
483 BUF->ipchksum = ~(uip_ipchksum());
484
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000485 return uip_reasslen;
486 }
487 }
488
489 nullreturn:
490 return 0;
491}
adamdunkels049a9122005-02-07 06:59:39 +0000492#endif /* UIP_REASSEMBLY */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000493/*-----------------------------------------------------------------------------------*/
494static void
495uip_add_rcv_nxt(u16_t n)
496{
497 uip_add32(uip_conn->rcv_nxt, n);
498 uip_conn->rcv_nxt[0] = uip_acc32[0];
499 uip_conn->rcv_nxt[1] = uip_acc32[1];
500 uip_conn->rcv_nxt[2] = uip_acc32[2];
501 uip_conn->rcv_nxt[3] = uip_acc32[3];
502}
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000503/*-----------------------------------------------------------------------------------*/
504void
505uip_process(u8_t flag)
506{
507 register struct uip_conn *uip_connr = uip_conn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000508
adamdunkels049a9122005-02-07 06:59:39 +0000509 uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN];
adamdunkels3335cd92005-02-27 09:44:33 +0000510
511 /* Check if we were invoked because of a poll request for a
512 particular connection. */
513 if(flag == UIP_POLL_REQUEST) {
514 if((uip_connr->tcpstateflags & TS_MASK) == ESTABLISHED &&
515 !uip_outstanding(uip_connr)) {
516 uip_flags = UIP_POLL;
517 UIP_APPCALL();
518 goto appsend;
519 }
adamdunkelsa7713622005-03-14 07:18:15 +0000520 goto drop;
521
adamdunkels3335cd92005-02-27 09:44:33 +0000522 /* Check if we were invoked because of the perodic timer fireing. */
523 } else if(flag == UIP_TIMER) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000524#if UIP_REASSEMBLY
525 if(uip_reasstmr != 0) {
526 --uip_reasstmr;
527 }
528#endif /* UIP_REASSEMBLY */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000529 /* Increase the initial sequence number. */
530 if(++iss[3] == 0) {
531 if(++iss[2] == 0) {
532 if(++iss[1] == 0) {
533 ++iss[0];
534 }
535 }
536 }
537 uip_len = 0;
adamdunkels3335cd92005-02-27 09:44:33 +0000538 uip_slen = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000539 if(uip_connr->tcpstateflags == TIME_WAIT ||
540 uip_connr->tcpstateflags == FIN_WAIT_2) {
541 ++(uip_connr->timer);
542 if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) {
543 uip_connr->tcpstateflags = CLOSED;
544 }
545 } else if(uip_connr->tcpstateflags != CLOSED) {
546 /* If the connection has outstanding data, we increase the
547 connection's timer and see if it has reached the RTO value
548 in which case we retransmit. */
549 if(uip_outstanding(uip_connr)) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000550 if(uip_connr->timer-- == 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000551 if(uip_connr->nrtx == UIP_MAXRTX ||
552 ((uip_connr->tcpstateflags == SYN_SENT ||
553 uip_connr->tcpstateflags == SYN_RCVD) &&
554 uip_connr->nrtx == UIP_MAXSYNRTX)) {
555 uip_connr->tcpstateflags = CLOSED;
556
557 /* We call UIP_APPCALL() with uip_flags set to
558 UIP_TIMEDOUT to inform the application that the
559 connection has timed out. */
560 uip_flags = UIP_TIMEDOUT;
561 UIP_APPCALL();
562
563 /* We also send a reset packet to the remote host. */
564 BUF->flags = TCP_RST | TCP_ACK;
565 goto tcp_send_nodata;
566 }
567
568 /* Exponential backoff. */
adamdunkels47ec7fa2003-03-28 12:11:17 +0000569 uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4?
570 4:
571 uip_connr->nrtx);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000572 ++(uip_connr->nrtx);
573
574 /* Ok, so we need to retransmit. We do this differently
575 depending on which state we are in. In ESTABLISHED, we
576 call upon the application so that it may prepare the
577 data for the retransmit. In SYN_RCVD, we resend the
578 SYNACK that we sent earlier and in LAST_ACK we have to
579 retransmit our FINACK. */
580 UIP_STAT(++uip_stat.tcp.rexmit);
581 switch(uip_connr->tcpstateflags & TS_MASK) {
582 case SYN_RCVD:
583 /* In the SYN_RCVD state, we should retransmit our
584 SYNACK. */
585 goto tcp_send_synack;
586
587#if UIP_ACTIVE_OPEN
588 case SYN_SENT:
589 /* In the SYN_SENT state, we retransmit out SYN. */
590 BUF->flags = 0;
591 goto tcp_send_syn;
592#endif /* UIP_ACTIVE_OPEN */
593
594 case ESTABLISHED:
595 /* In the ESTABLISHED state, we call upon the application
596 to do the actual retransmit after which we jump into
597 the code for sending out the packet (the apprexmit
598 label). */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000599 uip_flags = UIP_REXMIT;
600 UIP_APPCALL();
601 goto apprexmit;
602
603 case FIN_WAIT_1:
604 case CLOSING:
605 case LAST_ACK:
606 /* In all these states we should retransmit a FINACK. */
607 goto tcp_send_finack;
608
609 }
610 }
611 } else if((uip_connr->tcpstateflags & TS_MASK) == ESTABLISHED) {
612 /* If there was no need for a retransmission, we poll the
613 application for new data. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000614 uip_flags = UIP_POLL;
615 UIP_APPCALL();
616 goto appsend;
617 }
618 }
619 goto drop;
620 }
621#if UIP_UDP
622 if(flag == UIP_UDP_TIMER) {
623 if(uip_udp_conn->lport != 0) {
adamdunkels399a0782004-02-16 20:52:07 +0000624 uip_conn = NULL;
adamdunkels049a9122005-02-07 06:59:39 +0000625 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000626 uip_len = uip_slen = 0;
627 uip_flags = UIP_POLL;
628 UIP_UDP_APPCALL();
629 goto udp_send;
630 } else {
631 goto drop;
632 }
633 }
634#endif
635
636 /* This is where the input processing starts. */
637 UIP_STAT(++uip_stat.ip.recv);
638
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000639
640 /* Start of IPv4 input header processing code. */
641
642 /* Check validity of the IP header. */
643 if(BUF->vhl != 0x45) { /* IP version and header length. */
644 UIP_STAT(++uip_stat.ip.drop);
645 UIP_STAT(++uip_stat.ip.vhlerr);
646 UIP_LOG("ip: invalid version or header length.");
647 goto drop;
648 }
649
650 /* Check the size of the packet. If the size reported to us in
adamdunkels049a9122005-02-07 06:59:39 +0000651 uip_len is smaller the size reported in the IP header, we assume
652 that the packet has been corrupted in transit. If the size of
653 uip_len is larger than the size reported in the IP packet header,
654 the packet has been padded and we set uip_len to the correct
655 value.. */
656
657 if((BUF->len[0] << 8) + BUF->len[1] <= uip_len) {
658 uip_len = (BUF->len[0] << 8) + BUF->len[1];
659 } else {
660 UIP_LOG("ip: packet shorter than reported in IP header.");
661 goto drop;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000662 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000663
adamdunkelsb489e7a2003-10-14 11:12:50 +0000664 /* Check the fragment flag. */
665 if((BUF->ipoffset[0] & 0x3f) != 0 ||
666 BUF->ipoffset[1] != 0) {
667#if UIP_REASSEMBLY
668 uip_len = uip_reass();
669 if(uip_len == 0) {
670 goto drop;
671 }
672#else
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000673 UIP_STAT(++uip_stat.ip.drop);
674 UIP_STAT(++uip_stat.ip.fragerr);
675 UIP_LOG("ip: fragment dropped.");
676 goto drop;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000677#endif /* UIP_REASSEMBLY */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000678 }
679
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000680 if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
adamdunkels75b9d002004-09-17 20:48:39 +0000681 /* If we are configured to use ping IP address configuration and
682 hasn't been assigned an IP address yet, we accept all ICMP
683 packets. */
684#if UIP_PINGADDRCONF
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000685 if(BUF->proto == UIP_PROTO_ICMP) {
686 UIP_LOG("ip: possible ping config packet received.");
687 goto icmp_input;
688 } else {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000689 UIP_LOG("ip: packet dropped since no address assigned.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000690 goto drop;
adamdunkels75b9d002004-09-17 20:48:39 +0000691 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000692#endif /* UIP_PINGADDRCONF */
adamdunkels9fad4132004-06-06 06:14:19 +0000693
adamdunkels75b9d002004-09-17 20:48:39 +0000694 } else {
695 /* If IP broadcast support is configured, we check for a broadcast
696 UDP packet, which may be destined to us. */
adamdunkels9fad4132004-06-06 06:14:19 +0000697#if UIP_BROADCAST
adamdunkels75b9d002004-09-17 20:48:39 +0000698 if(BUF->proto == UIP_PROTO_UDP &&
699 BUF->destipaddr[0] == 0xffff &&
adamdunkels9fad4132004-06-06 06:14:19 +0000700 BUF->destipaddr[1] == 0xffff &&
adamdunkels75b9d002004-09-17 20:48:39 +0000701 uip_ipchksum() == 0xffff) {
702 goto udp_input;
703 }
adamdunkels9fad4132004-06-06 06:14:19 +0000704#endif /* UIP_BROADCAST */
adamdunkels75b9d002004-09-17 20:48:39 +0000705
706 /* Check if the packet is destined for our IP address. */
707 if(BUF->destipaddr[0] != uip_hostaddr[0]) {
708 UIP_STAT(++uip_stat.ip.drop);
adamdunkels75b9d002004-09-17 20:48:39 +0000709 goto drop;
710 }
711 if(BUF->destipaddr[1] != uip_hostaddr[1]) {
712 UIP_STAT(++uip_stat.ip.drop);
adamdunkels75b9d002004-09-17 20:48:39 +0000713 goto drop;
714 }
715 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000716
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000717 if(uip_ipchksum() != 0xffff) { /* Compute and check the IP header
718 checksum. */
719 UIP_STAT(++uip_stat.ip.drop);
720 UIP_STAT(++uip_stat.ip.chkerr);
adamdunkels9fad4132004-06-06 06:14:19 +0000721 UIP_LOG("ip: bad checksum.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000722 goto drop;
723 }
724
adamdunkels049a9122005-02-07 06:59:39 +0000725 if(BUF->proto == UIP_PROTO_TCP) { /* Check for TCP packet. If so,
726 proceed with TCP input
727 processing. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000728 goto tcp_input;
adamdunkels049a9122005-02-07 06:59:39 +0000729 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000730
731#if UIP_UDP
adamdunkels049a9122005-02-07 06:59:39 +0000732 if(BUF->proto == UIP_PROTO_UDP) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000733 goto udp_input;
adamdunkels049a9122005-02-07 06:59:39 +0000734 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000735#endif /* UIP_UDP */
736
737 if(BUF->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from
738 here. */
739 UIP_STAT(++uip_stat.ip.drop);
740 UIP_STAT(++uip_stat.ip.protoerr);
741 UIP_LOG("ip: neither tcp nor icmp.");
742 goto drop;
743 }
adamdunkels82fcc772005-03-09 10:21:56 +0000744
745#if UIP_PINGADDRCONF
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000746 icmp_input:
adamdunkels82fcc772005-03-09 10:21:56 +0000747#endif /* UIP_PINGADDRCONF */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000748 UIP_STAT(++uip_stat.icmp.recv);
749
750 /* ICMP echo (i.e., ping) processing. This is simple, we only change
751 the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
752 checksum before we return the packet. */
753 if(ICMPBUF->type != ICMP_ECHO) {
754 UIP_STAT(++uip_stat.icmp.drop);
755 UIP_STAT(++uip_stat.icmp.typeerr);
756 UIP_LOG("icmp: not icmp echo.");
757 goto drop;
758 }
759
760 /* If we are configured to use ping IP address assignment, we use
761 the destination IP address of this ping packet and assign it to
762 ourself. */
763#if UIP_PINGADDRCONF
764 if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
765 uip_hostaddr[0] = BUF->destipaddr[0];
766 uip_hostaddr[1] = BUF->destipaddr[1];
767 }
768#endif /* UIP_PINGADDRCONF */
769
770 ICMPBUF->type = ICMP_ECHO_REPLY;
771
adamdunkels47ec7fa2003-03-28 12:11:17 +0000772 if(ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) {
773 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000774 } else {
adamdunkels47ec7fa2003-03-28 12:11:17 +0000775 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000776 }
777
778 /* Swap IP addresses. */
adamdunkels0170b082003-10-01 11:25:37 +0000779 tmp16 = BUF->destipaddr[0];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000780 BUF->destipaddr[0] = BUF->srcipaddr[0];
adamdunkels0170b082003-10-01 11:25:37 +0000781 BUF->srcipaddr[0] = tmp16;
782 tmp16 = BUF->destipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000783 BUF->destipaddr[1] = BUF->srcipaddr[1];
adamdunkels0170b082003-10-01 11:25:37 +0000784 BUF->srcipaddr[1] = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000785
786 UIP_STAT(++uip_stat.icmp.sent);
787 goto send;
788
789 /* End of IPv4 input header processing code. */
790
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000791
792#if UIP_UDP
793 /* UDP input processing. */
794 udp_input:
795 /* UDP processing is really just a hack. We don't do anything to the
796 UDP/IP headers, but let the UDP application do all the hard
797 work. If the application sets uip_slen, it has a packet to
798 send. */
799#if UIP_UDP_CHECKSUMS
adamdunkels049a9122005-02-07 06:59:39 +0000800 uip_len = uip_len - UIP_IPTCPH_LEN;
801 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];
802 if(uip_udpchksum() != 0xffff) {
803 printf("checksum 0x%04x\n", uip_udpchksum());
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000804 UIP_STAT(++uip_stat.udp.drop);
805 UIP_STAT(++uip_stat.udp.chkerr);
806 UIP_LOG("udp: bad checksum.");
807 goto drop;
adamdunkels049a9122005-02-07 06:59:39 +0000808 }
809 uip_len = uip_len + (UIP_IPTCPH_LEN - UIP_IPUDPH_LEN);
810#else /* UIP_UDP_CHECKSUMS */
811 uip_len = uip_len - UIP_IPUDPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000812#endif /* UIP_UDP_CHECKSUMS */
813
814 /* Demultiplex this UDP packet between the UDP "connections". */
815 for(uip_udp_conn = &uip_udp_conns[0];
816 uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS];
817 ++uip_udp_conn) {
adamdunkels9fad4132004-06-06 06:14:19 +0000818 /* If the local UDP port is non-zero, the connection is considered
819 to be used. If so, the local port number is checked against the
820 destination port number in the received packet. If the two port
821 numbers match, the remote port number is checked if the
822 connection is bound to a remote port. Finally, if the
823 connection is bound to a remote IP address, the source IP
824 address of the packet is checked. */
825 if(uip_udp_conn->lport != 0 &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000826 UDPBUF->destport == uip_udp_conn->lport &&
827 (uip_udp_conn->rport == 0 ||
828 UDPBUF->srcport == uip_udp_conn->rport) &&
adamdunkels9fad4132004-06-06 06:14:19 +0000829 ((uip_udp_conn->ripaddr[0] | uip_udp_conn->ripaddr[1]) == 0 ||
830 (uip_udp_conn->ripaddr[0] == 0xffff &&
831 uip_udp_conn->ripaddr[1] == 0xffff) ||
832 uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000833 goto udp_found;
834 }
835 }
adamdunkels9fad4132004-06-06 06:14:19 +0000836 UIP_LOG("udp: no matching connection found");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000837 goto drop;
838
839 udp_found:
adamdunkels399a0782004-02-16 20:52:07 +0000840 uip_conn = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000841 uip_flags = UIP_NEWDATA;
adamdunkels049a9122005-02-07 06:59:39 +0000842 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000843 uip_slen = 0;
844 UIP_UDP_APPCALL();
845 udp_send:
846 if(uip_slen == 0) {
847 goto drop;
848 }
adamdunkels049a9122005-02-07 06:59:39 +0000849 uip_len = uip_slen + UIP_IPUDPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000850
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000851 BUF->len[0] = (uip_len >> 8);
852 BUF->len[1] = (uip_len & 0xff);
adamdunkelsb489e7a2003-10-14 11:12:50 +0000853
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000854 BUF->proto = UIP_PROTO_UDP;
855
adamdunkels049a9122005-02-07 06:59:39 +0000856 UDPBUF->udplen = HTONS(uip_slen + UIP_UDPH_LEN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000857 UDPBUF->udpchksum = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000858
859 BUF->srcport = uip_udp_conn->lport;
860 BUF->destport = uip_udp_conn->rport;
861
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000862 BUF->srcipaddr[0] = uip_hostaddr[0];
863 BUF->srcipaddr[1] = uip_hostaddr[1];
864 BUF->destipaddr[0] = uip_udp_conn->ripaddr[0];
865 BUF->destipaddr[1] = uip_udp_conn->ripaddr[1];
866
adamdunkels049a9122005-02-07 06:59:39 +0000867 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];
adamdunkelsc4b80c52004-09-18 20:17:01 +0000868
869#if UIP_UDP_CHECKSUMS
870 /* Calculate UDP checksum. */
871 UDPBUF->udpchksum = ~(uip_udpchksum());
872 if(UDPBUF->udpchksum == 0) {
873 UDPBUF->udpchksum = 0xffff;
874 }
875#endif /* UIP_UDP_CHECKSUMS */
876
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000877 goto ip_send_nolen;
878#endif /* UIP_UDP */
879
880 /* TCP input processing. */
881 tcp_input:
882 UIP_STAT(++uip_stat.tcp.recv);
883
884 /* Start of TCP input header processing code. */
885
886 if(uip_tcpchksum() != 0xffff) { /* Compute and check the TCP
887 checksum. */
888 UIP_STAT(++uip_stat.tcp.drop);
889 UIP_STAT(++uip_stat.tcp.chkerr);
adamdunkels9fad4132004-06-06 06:14:19 +0000890 UIP_LOG("tcp: bad checksum.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000891 goto drop;
892 }
893
adamdunkels9fad4132004-06-06 06:14:19 +0000894
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000895 /* Demultiplex this segment. */
896 /* First check any active connections. */
adamdunkels049a9122005-02-07 06:59:39 +0000897 for(uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1];
898 ++uip_connr) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000899 if(uip_connr->tcpstateflags != CLOSED &&
900 BUF->destport == uip_connr->lport &&
901 BUF->srcport == uip_connr->rport &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000902 BUF->srcipaddr[0] == uip_connr->ripaddr[0] &&
903 BUF->srcipaddr[1] == uip_connr->ripaddr[1]) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000904 goto found;
905 }
906 }
907
908 /* If we didn't find and active connection that expected the packet,
909 either this packet is an old duplicate, or this is a SYN packet
910 destined for a connection in LISTEN. If the SYN flag isn't set,
911 it is an old packet and we send a RST. */
adamdunkels049a9122005-02-07 06:59:39 +0000912 if((BUF->flags & TCP_CTL) != TCP_SYN) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000913 goto reset;
adamdunkels049a9122005-02-07 06:59:39 +0000914 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000915
adamdunkels0170b082003-10-01 11:25:37 +0000916 tmp16 = BUF->destport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000917 /* Next, check listening connections. */
adamdunkelscd8c3a22003-08-13 22:52:48 +0000918 for(c = 0; c < UIP_LISTENPORTS; ++c) {
adamdunkels0170b082003-10-01 11:25:37 +0000919 if(tmp16 == uip_listenports[c])
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000920 goto found_listen;
921 }
922
923 /* No matching connection found, so we send a RST packet. */
924 UIP_STAT(++uip_stat.tcp.synrst);
925 reset:
926
927 /* We do not send resets in response to resets. */
adamdunkels049a9122005-02-07 06:59:39 +0000928 if(BUF->flags & TCP_RST) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000929 goto drop;
adamdunkels049a9122005-02-07 06:59:39 +0000930 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000931
932 UIP_STAT(++uip_stat.tcp.rst);
933
934 BUF->flags = TCP_RST | TCP_ACK;
adamdunkels049a9122005-02-07 06:59:39 +0000935 uip_len = UIP_IPTCPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000936 BUF->tcpoffset = 5 << 4;
937
938 /* Flip the seqno and ackno fields in the TCP header. */
939 c = BUF->seqno[3];
940 BUF->seqno[3] = BUF->ackno[3];
941 BUF->ackno[3] = c;
942
943 c = BUF->seqno[2];
944 BUF->seqno[2] = BUF->ackno[2];
945 BUF->ackno[2] = c;
946
947 c = BUF->seqno[1];
948 BUF->seqno[1] = BUF->ackno[1];
949 BUF->ackno[1] = c;
950
951 c = BUF->seqno[0];
952 BUF->seqno[0] = BUF->ackno[0];
953 BUF->ackno[0] = c;
954
955 /* We also have to increase the sequence number we are
956 acknowledging. If the least significant byte overflowed, we need
957 to propagate the carry to the other bytes as well. */
958 if(++BUF->ackno[3] == 0) {
959 if(++BUF->ackno[2] == 0) {
960 if(++BUF->ackno[1] == 0) {
961 ++BUF->ackno[0];
962 }
963 }
964 }
965
966 /* Swap port numbers. */
adamdunkels0170b082003-10-01 11:25:37 +0000967 tmp16 = BUF->srcport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000968 BUF->srcport = BUF->destport;
adamdunkels0170b082003-10-01 11:25:37 +0000969 BUF->destport = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000970
971 /* Swap IP addresses. */
adamdunkels0170b082003-10-01 11:25:37 +0000972 tmp16 = BUF->destipaddr[0];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000973 BUF->destipaddr[0] = BUF->srcipaddr[0];
adamdunkels0170b082003-10-01 11:25:37 +0000974 BUF->srcipaddr[0] = tmp16;
975 tmp16 = BUF->destipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000976 BUF->destipaddr[1] = BUF->srcipaddr[1];
adamdunkels0170b082003-10-01 11:25:37 +0000977 BUF->srcipaddr[1] = tmp16;
adamdunkelsa38da252003-08-20 20:56:54 +0000978
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000979
980 /* And send out the RST packet! */
981 goto tcp_send_noconn;
982
983 /* This label will be jumped to if we matched the incoming packet
984 with a connection in LISTEN. In that case, we should create a new
985 connection and send a SYNACK in return. */
986 found_listen:
987 /* First we check if there are any connections avaliable. Unused
988 connections are kept in the same table as used connections, but
989 unused ones have the tcpstate set to CLOSED. Also, connections in
990 TIME_WAIT are kept track of and we'll use the oldest one if no
991 CLOSED connections are found. Thanks to Eddie C. Dost for a very
992 nice algorithm for the TIME_WAIT search. */
993 uip_connr = 0;
994 for(c = 0; c < UIP_CONNS; ++c) {
995 if(uip_conns[c].tcpstateflags == CLOSED) {
996 uip_connr = &uip_conns[c];
997 break;
998 }
999 if(uip_conns[c].tcpstateflags == TIME_WAIT) {
1000 if(uip_connr == 0 ||
1001 uip_conns[c].timer > uip_connr->timer) {
1002 uip_connr = &uip_conns[c];
1003 }
1004 }
1005 }
1006
1007 if(uip_connr == 0) {
1008 /* All connections are used already, we drop packet and hope that
1009 the remote end will retransmit the packet at a time when we
1010 have more spare connections. */
1011 UIP_STAT(++uip_stat.tcp.syndrop);
1012 UIP_LOG("tcp: found no unused connections.");
1013 goto drop;
1014 }
1015 uip_conn = uip_connr;
1016
1017 /* Fill in the necessary fields for the new connection. */
adamdunkelsb489e7a2003-10-14 11:12:50 +00001018 uip_connr->rto = uip_connr->timer = UIP_RTO;
1019 uip_connr->sa = 0;
1020 uip_connr->sv = 4;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001021 uip_connr->nrtx = 0;
1022 uip_connr->lport = BUF->destport;
1023 uip_connr->rport = BUF->srcport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001024 uip_connr->ripaddr[0] = BUF->srcipaddr[0];
1025 uip_connr->ripaddr[1] = BUF->srcipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001026 uip_connr->tcpstateflags = SYN_RCVD;
1027
1028 uip_connr->snd_nxt[0] = iss[0];
1029 uip_connr->snd_nxt[1] = iss[1];
1030 uip_connr->snd_nxt[2] = iss[2];
1031 uip_connr->snd_nxt[3] = iss[3];
1032 uip_connr->len = 1;
1033
1034 /* rcv_nxt should be the seqno from the incoming packet + 1. */
1035 uip_connr->rcv_nxt[3] = BUF->seqno[3];
1036 uip_connr->rcv_nxt[2] = BUF->seqno[2];
1037 uip_connr->rcv_nxt[1] = BUF->seqno[1];
1038 uip_connr->rcv_nxt[0] = BUF->seqno[0];
1039 uip_add_rcv_nxt(1);
1040
1041 /* Parse the TCP MSS option, if present. */
1042 if((BUF->tcpoffset & 0xf0) > 0x50) {
1043 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
1044 opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c];
adamdunkels049a9122005-02-07 06:59:39 +00001045 if(opt == TCP_OPT_END) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001046 /* End of options. */
1047 break;
adamdunkels049a9122005-02-07 06:59:39 +00001048 } else if(opt == TCP_OPT_NOOP) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001049 ++c;
1050 /* NOP option. */
adamdunkels049a9122005-02-07 06:59:39 +00001051 } else if(opt == TCP_OPT_MSS &&
1052 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001053 /* An MSS option with the right option length. */
adamdunkels0170b082003-10-01 11:25:37 +00001054 tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
adamdunkels049a9122005-02-07 06:59:39 +00001055 (u16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c];
adamdunkels0170b082003-10-01 11:25:37 +00001056 uip_connr->initialmss = uip_connr->mss =
1057 tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001058
1059 /* And we are done processing options. */
1060 break;
1061 } else {
1062 /* All other options have a length field, so that we easily
1063 can skip past them. */
1064 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
1065 /* If the length field is zero, the options are malformed
1066 and we don't process them further. */
1067 break;
1068 }
1069 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
1070 }
1071 }
1072 }
1073
1074 /* Our response will be a SYNACK. */
1075#if UIP_ACTIVE_OPEN
1076 tcp_send_synack:
1077 BUF->flags = TCP_ACK;
1078
1079 tcp_send_syn:
1080 BUF->flags |= TCP_SYN;
1081#else /* UIP_ACTIVE_OPEN */
1082 tcp_send_synack:
1083 BUF->flags = TCP_SYN | TCP_ACK;
1084#endif /* UIP_ACTIVE_OPEN */
1085
1086 /* We send out the TCP Maximum Segment Size option with our
1087 SYNACK. */
adamdunkels049a9122005-02-07 06:59:39 +00001088 BUF->optdata[0] = TCP_OPT_MSS;
1089 BUF->optdata[1] = TCP_OPT_MSS_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001090 BUF->optdata[2] = (UIP_TCP_MSS) / 256;
1091 BUF->optdata[3] = (UIP_TCP_MSS) & 255;
adamdunkels049a9122005-02-07 06:59:39 +00001092 uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN;
1093 BUF->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001094 goto tcp_send;
1095
1096 /* This label will be jumped to if we found an active connection. */
1097 found:
1098 uip_conn = uip_connr;
1099 uip_flags = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001100 /* We do a very naive form of TCP reset processing; we just accept
1101 any RST and kill our connection. We should in fact check if the
1102 sequence number of this reset is wihtin our advertised window
1103 before we accept the reset. */
1104 if(BUF->flags & TCP_RST) {
1105 uip_connr->tcpstateflags = CLOSED;
1106 UIP_LOG("tcp: got reset, aborting connection.");
1107 uip_flags = UIP_ABORT;
1108 UIP_APPCALL();
1109 goto drop;
adamdunkels47ec7fa2003-03-28 12:11:17 +00001110 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001111 /* Calculated the length of the data, if the application has sent
1112 any data to us. */
1113 c = (BUF->tcpoffset >> 4) << 2;
1114 /* uip_len will contain the length of the actual TCP data. This is
1115 calculated by subtracing the length of the TCP header (in
1116 c) and the length of the IP header (20 bytes). */
adamdunkels049a9122005-02-07 06:59:39 +00001117 uip_len = uip_len - c - UIP_IPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001118
1119 /* First, check if the sequence number of the incoming packet is
1120 what we're expecting next. If not, we send out an ACK with the
1121 correct numbers in. */
adamdunkels049a9122005-02-07 06:59:39 +00001122 if(!(((uip_connr->tcpstateflags & TS_MASK) == SYN_SENT) &&
1123 ((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) {
1124 if((uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 0)) &&
1125 (BUF->seqno[0] != uip_connr->rcv_nxt[0] ||
1126 BUF->seqno[1] != uip_connr->rcv_nxt[1] ||
1127 BUF->seqno[2] != uip_connr->rcv_nxt[2] ||
1128 BUF->seqno[3] != uip_connr->rcv_nxt[3])) {
1129 goto tcp_send_ack;
1130 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001131 }
1132
1133 /* Next, check if the incoming segment acknowledges any outstanding
1134 data. If so, we update the sequence number, reset the length of
1135 the outstanding data, calculate RTT estimations, and reset the
1136 retransmission timer. */
adamdunkels47ec7fa2003-03-28 12:11:17 +00001137 if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001138 uip_add32(uip_connr->snd_nxt, uip_connr->len);
adamdunkels08eac9e2004-09-12 07:17:37 +00001139
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001140 if(BUF->ackno[0] == uip_acc32[0] &&
1141 BUF->ackno[1] == uip_acc32[1] &&
1142 BUF->ackno[2] == uip_acc32[2] &&
1143 BUF->ackno[3] == uip_acc32[3]) {
1144 /* Update sequence number. */
1145 uip_connr->snd_nxt[0] = uip_acc32[0];
1146 uip_connr->snd_nxt[1] = uip_acc32[1];
1147 uip_connr->snd_nxt[2] = uip_acc32[2];
1148 uip_connr->snd_nxt[3] = uip_acc32[3];
adamdunkelsa38da252003-08-20 20:56:54 +00001149
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001150
1151 /* Do RTT estimation, unless we have done retransmissions. */
1152 if(uip_connr->nrtx == 0) {
1153 signed char m;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001154 m = uip_connr->rto - uip_connr->timer;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001155 /* This is taken directly from VJs original code in his paper */
1156 m = m - (uip_connr->sa >> 3);
1157 uip_connr->sa += m;
1158 if(m < 0) {
1159 m = -m;
1160 }
1161 m = m - (uip_connr->sv >> 2);
1162 uip_connr->sv += m;
1163 uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv;
1164
1165 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001166 /* Set the acknowledged flag. */
1167 uip_flags = UIP_ACKDATA;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001168 /* Reset the retransmission timer. */
adamdunkelsb489e7a2003-10-14 11:12:50 +00001169 uip_connr->timer = uip_connr->rto;
adamdunkels08eac9e2004-09-12 07:17:37 +00001170
1171 /* Reset length of outstanding data. */
1172 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001173 }
adamdunkelsab4b0822003-07-30 23:31:40 +00001174
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001175 }
1176
1177 /* Do different things depending on in what state the connection is. */
1178 switch(uip_connr->tcpstateflags & TS_MASK) {
1179 /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
1180 implemented, since we force the application to close when the
1181 peer sends a FIN (hence the application goes directly from
1182 ESTABLISHED to LAST_ACK). */
1183 case SYN_RCVD:
1184 /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and
1185 we are waiting for an ACK that acknowledges the data we sent
1186 out the last time. Therefore, we want to have the UIP_ACKDATA
1187 flag set. If so, we enter the ESTABLISHED state. */
1188 if(uip_flags & UIP_ACKDATA) {
1189 uip_connr->tcpstateflags = ESTABLISHED;
1190 uip_flags = UIP_CONNECTED;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001191 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001192 if(uip_len > 0) {
1193 uip_flags |= UIP_NEWDATA;
1194 uip_add_rcv_nxt(uip_len);
1195 }
1196 uip_slen = 0;
1197 UIP_APPCALL();
1198 goto appsend;
1199 }
1200 goto drop;
1201#if UIP_ACTIVE_OPEN
1202 case SYN_SENT:
1203 /* In SYN_SENT, we wait for a SYNACK that is sent in response to
1204 our SYN. The rcv_nxt is set to sequence number in the SYNACK
1205 plus one, and we send an ACK. We move into the ESTABLISHED
1206 state. */
1207 if((uip_flags & UIP_ACKDATA) &&
adamdunkels049a9122005-02-07 06:59:39 +00001208 (BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001209
1210 /* Parse the TCP MSS option, if present. */
1211 if((BUF->tcpoffset & 0xf0) > 0x50) {
1212 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
adamdunkels049a9122005-02-07 06:59:39 +00001213 opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c];
1214 if(opt == TCP_OPT_END) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001215 /* End of options. */
1216 break;
adamdunkels049a9122005-02-07 06:59:39 +00001217 } else if(opt == TCP_OPT_NOOP) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001218 ++c;
1219 /* NOP option. */
adamdunkels049a9122005-02-07 06:59:39 +00001220 } else if(opt == TCP_OPT_MSS &&
1221 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001222 /* An MSS option with the right option length. */
adamdunkels0170b082003-10-01 11:25:37 +00001223 tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001224 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];
adamdunkels0170b082003-10-01 11:25:37 +00001225 uip_connr->initialmss =
1226 uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001227
1228 /* And we are done processing options. */
1229 break;
1230 } else {
1231 /* All other options have a length field, so that we easily
1232 can skip past them. */
1233 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
1234 /* If the length field is zero, the options are malformed
1235 and we don't process them further. */
1236 break;
1237 }
1238 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
1239 }
1240 }
1241 }
1242 uip_connr->tcpstateflags = ESTABLISHED;
1243 uip_connr->rcv_nxt[0] = BUF->seqno[0];
1244 uip_connr->rcv_nxt[1] = BUF->seqno[1];
1245 uip_connr->rcv_nxt[2] = BUF->seqno[2];
1246 uip_connr->rcv_nxt[3] = BUF->seqno[3];
1247 uip_add_rcv_nxt(1);
1248 uip_flags = UIP_CONNECTED | UIP_NEWDATA;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001249 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001250 uip_len = 0;
1251 uip_slen = 0;
1252 UIP_APPCALL();
1253 goto appsend;
1254 }
adamdunkels049a9122005-02-07 06:59:39 +00001255 /* Inform the application that the connection failed */
1256 uip_flags = UIP_ABORT;
1257 UIP_APPCALL();
1258 /* The connection is closed after we send the RST */
1259 uip_conn->tcpstateflags = CLOSED;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001260 goto reset;
1261#endif /* UIP_ACTIVE_OPEN */
1262
1263 case ESTABLISHED:
1264 /* In the ESTABLISHED state, we call upon the application to feed
1265 data into the uip_buf. If the UIP_ACKDATA flag is set, the
1266 application should put new data into the buffer, otherwise we are
1267 retransmitting an old segment, and the application should put that
1268 data into the buffer.
1269
1270 If the incoming packet is a FIN, we should close the connection on
1271 this side as well, and we send out a FIN and enter the LAST_ACK
1272 state. We require that there is no outstanding data; otherwise the
1273 sequence numbers will be screwed up. */
1274
adamdunkels31a50262005-02-22 22:33:56 +00001275 if(BUF->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001276 if(uip_outstanding(uip_connr)) {
1277 goto drop;
1278 }
1279 uip_add_rcv_nxt(1 + uip_len);
1280 uip_flags = UIP_CLOSE;
1281 if(uip_len > 0) {
1282 uip_flags |= UIP_NEWDATA;
1283 }
1284 UIP_APPCALL();
1285 uip_connr->len = 1;
1286 uip_connr->tcpstateflags = LAST_ACK;
1287 uip_connr->nrtx = 0;
1288 tcp_send_finack:
1289 BUF->flags = TCP_FIN | TCP_ACK;
1290 goto tcp_send_nodata;
1291 }
1292
1293 /* Check the URG flag. If this is set, the segment carries urgent
1294 data that we must pass to the application. */
adamdunkels9fad4132004-06-06 06:14:19 +00001295 if((BUF->flags & TCP_URG) != 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001296#if UIP_URGDATA > 0
1297 uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1];
1298 if(uip_urglen > uip_len) {
1299 /* There is more urgent data in the next segment to come. */
1300 uip_urglen = uip_len;
1301 }
1302 uip_add_rcv_nxt(uip_urglen);
1303 uip_len -= uip_urglen;
1304 uip_urgdata = uip_appdata;
1305 uip_appdata += uip_urglen;
1306 } else {
1307 uip_urglen = 0;
adamdunkels9fad4132004-06-06 06:14:19 +00001308#else /* UIP_URGDATA > 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001309 uip_appdata += (BUF->urgp[0] << 8) | BUF->urgp[1];
1310 uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1];
adamdunkels9fad4132004-06-06 06:14:19 +00001311#endif /* UIP_URGDATA > 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001312 }
adamdunkels9fad4132004-06-06 06:14:19 +00001313
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001314 /* If uip_len > 0 we have TCP data in the packet, and we flag this
1315 by setting the UIP_NEWDATA flag and update the sequence number
1316 we acknowledge. If the application has stopped the dataflow
1317 using uip_stop(), we must not accept any data packets from the
1318 remote host. */
1319 if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
1320 uip_flags |= UIP_NEWDATA;
1321 uip_add_rcv_nxt(uip_len);
1322 }
adamdunkels0170b082003-10-01 11:25:37 +00001323
1324 /* Check if the available buffer space advertised by the other end
1325 is smaller than the initial MSS for this connection. If so, we
1326 set the current MSS to the window size to ensure that the
1327 application does not send more data than the other end can
1328 handle.
1329
1330 If the remote host advertises a zero window, we set the MSS to
1331 the initial MSS so that the application will send an entire MSS
1332 of data. This data will not be acknowledged by the receiver,
1333 and the application will retransmit it. This is called the
1334 "persistent timer" and uses the retransmission mechanim.
1335 */
1336 tmp16 = ((u16_t)BUF->wnd[0] << 8) + (u16_t)BUF->wnd[1];
1337 if(tmp16 > uip_connr->initialmss ||
1338 tmp16 == 0) {
1339 tmp16 = uip_connr->initialmss;
1340 }
1341 uip_connr->mss = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001342
1343 /* If this packet constitutes an ACK for outstanding data (flagged
1344 by the UIP_ACKDATA flag, we should call the application since it
1345 might want to send more data. If the incoming packet had data
1346 from the peer (as flagged by the UIP_NEWDATA flag), the
1347 application must also be notified.
1348
1349 When the application is called, the global variable uip_len
1350 contains the length of the incoming data. The application can
1351 access the incoming data through the global pointer
adamdunkels049a9122005-02-07 06:59:39 +00001352 uip_appdata, which usually points UIP_IPTCPH_LEN + UIP_LLH_LEN
1353 bytes into the uip_buf array.
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001354
1355 If the application wishes to send any data, this data should be
1356 put into the uip_appdata and the length of the data should be
1357 put into uip_len. If the application don't have any data to
1358 send, uip_len must be set to 0. */
1359 if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) {
1360 uip_slen = 0;
1361 UIP_APPCALL();
1362
1363 appsend:
adamdunkels0170b082003-10-01 11:25:37 +00001364
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001365 if(uip_flags & UIP_ABORT) {
1366 uip_slen = 0;
1367 uip_connr->tcpstateflags = CLOSED;
1368 BUF->flags = TCP_RST | TCP_ACK;
1369 goto tcp_send_nodata;
1370 }
1371
1372 if(uip_flags & UIP_CLOSE) {
1373 uip_slen = 0;
1374 uip_connr->len = 1;
1375 uip_connr->tcpstateflags = FIN_WAIT_1;
1376 uip_connr->nrtx = 0;
1377 BUF->flags = TCP_FIN | TCP_ACK;
1378 goto tcp_send_nodata;
1379 }
1380
adamdunkelsb489e7a2003-10-14 11:12:50 +00001381 /* If uip_slen > 0, the application has data to be sent. */
1382 if(uip_slen > 0) {
1383
1384 /* If the connection has acknowledged data, the contents of
1385 the ->len variable should be discarded. */
1386 if((uip_flags & UIP_ACKDATA) != 0) {
1387 uip_connr->len = 0;
1388 }
1389
1390 /* If the ->len variable is non-zero the connection has
1391 already data in transit and cannot send anymore right
1392 now. */
1393 if(uip_connr->len == 0) {
1394
1395 /* The application cannot send more than what is allowed by
1396 the mss (the minumum of the MSS and the available
1397 window). */
1398 if(uip_slen > uip_connr->mss) {
1399 uip_slen = uip_connr->mss;
1400 }
1401
1402 /* Remember how much data we send out now so that we know
1403 when everything has been acknowledged. */
1404 uip_connr->len = uip_slen;
1405 } else {
1406
1407 /* If the application already had unacknowledged data, we
1408 make sure that the application does not send (i.e.,
1409 retransmit) out more than it previously sent out. */
1410 uip_slen = uip_connr->len;
1411 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001412 }
adamdunkelsb489e7a2003-10-14 11:12:50 +00001413 uip_connr->nrtx = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001414 apprexmit:
adamdunkels0170b082003-10-01 11:25:37 +00001415 uip_appdata = uip_sappdata;
1416
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001417 /* If the application has data to be sent, or if the incoming
1418 packet had new data in it, we must send out a packet. */
adamdunkels759185d2003-06-30 20:35:41 +00001419 if(uip_slen > 0 && uip_connr->len > 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001420 /* Add the length of the IP and TCP headers. */
1421 uip_len = uip_connr->len + UIP_TCPIP_HLEN;
1422 /* We always set the ACK flag in response packets. */
adamdunkels759185d2003-06-30 20:35:41 +00001423 BUF->flags = TCP_ACK | TCP_PSH;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001424 /* Send the packet. */
1425 goto tcp_send_noopts;
1426 }
adamdunkels759185d2003-06-30 20:35:41 +00001427 /* If there is no data to send, just send out a pure ACK if
1428 there is newdata. */
1429 if(uip_flags & UIP_NEWDATA) {
1430 uip_len = UIP_TCPIP_HLEN;
1431 BUF->flags = TCP_ACK;
1432 goto tcp_send_noopts;
1433 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001434 }
1435 goto drop;
1436 case LAST_ACK:
1437 /* We can close this connection if the peer has acknowledged our
1438 FIN. This is indicated by the UIP_ACKDATA flag. */
1439 if(uip_flags & UIP_ACKDATA) {
1440 uip_connr->tcpstateflags = CLOSED;
1441 uip_flags = UIP_CLOSE;
1442 UIP_APPCALL();
1443 }
1444 break;
1445
1446 case FIN_WAIT_1:
1447 /* The application has closed the connection, but the remote host
1448 hasn't closed its end yet. Thus we do nothing but wait for a
1449 FIN from the other side. */
1450 if(uip_len > 0) {
1451 uip_add_rcv_nxt(uip_len);
1452 }
1453 if(BUF->flags & TCP_FIN) {
1454 if(uip_flags & UIP_ACKDATA) {
1455 uip_connr->tcpstateflags = TIME_WAIT;
1456 uip_connr->timer = 0;
1457 uip_connr->len = 0;
1458 } else {
1459 uip_connr->tcpstateflags = CLOSING;
1460 }
1461 uip_add_rcv_nxt(1);
1462 uip_flags = UIP_CLOSE;
1463 UIP_APPCALL();
1464 goto tcp_send_ack;
1465 } else if(uip_flags & UIP_ACKDATA) {
1466 uip_connr->tcpstateflags = FIN_WAIT_2;
1467 uip_connr->len = 0;
1468 goto drop;
1469 }
1470 if(uip_len > 0) {
1471 goto tcp_send_ack;
1472 }
1473 goto drop;
1474
1475 case FIN_WAIT_2:
1476 if(uip_len > 0) {
1477 uip_add_rcv_nxt(uip_len);
1478 }
1479 if(BUF->flags & TCP_FIN) {
1480 uip_connr->tcpstateflags = TIME_WAIT;
1481 uip_connr->timer = 0;
1482 uip_add_rcv_nxt(1);
1483 uip_flags = UIP_CLOSE;
1484 UIP_APPCALL();
1485 goto tcp_send_ack;
1486 }
1487 if(uip_len > 0) {
1488 goto tcp_send_ack;
1489 }
1490 goto drop;
1491
1492 case TIME_WAIT:
1493 goto tcp_send_ack;
1494
1495 case CLOSING:
1496 if(uip_flags & UIP_ACKDATA) {
1497 uip_connr->tcpstateflags = TIME_WAIT;
1498 uip_connr->timer = 0;
1499 }
1500 }
1501 goto drop;
1502
1503
1504 /* We jump here when we are ready to send the packet, and just want
1505 to set the appropriate TCP sequence numbers in the TCP header. */
1506 tcp_send_ack:
1507 BUF->flags = TCP_ACK;
1508 tcp_send_nodata:
adamdunkels049a9122005-02-07 06:59:39 +00001509 uip_len = UIP_IPTCPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001510 tcp_send_noopts:
adamdunkels049a9122005-02-07 06:59:39 +00001511 BUF->tcpoffset = (UIP_TCPH_LEN / 4) << 4;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001512 tcp_send:
1513 /* We're done with the input processing. We are now ready to send a
1514 reply. Our job is to fill in all the fields of the TCP and IP
1515 headers before calculating the checksum and finally send the
1516 packet. */
1517 BUF->ackno[0] = uip_connr->rcv_nxt[0];
1518 BUF->ackno[1] = uip_connr->rcv_nxt[1];
1519 BUF->ackno[2] = uip_connr->rcv_nxt[2];
1520 BUF->ackno[3] = uip_connr->rcv_nxt[3];
1521
1522 BUF->seqno[0] = uip_connr->snd_nxt[0];
1523 BUF->seqno[1] = uip_connr->snd_nxt[1];
1524 BUF->seqno[2] = uip_connr->snd_nxt[2];
1525 BUF->seqno[3] = uip_connr->snd_nxt[3];
1526
1527 BUF->proto = UIP_PROTO_TCP;
1528
1529 BUF->srcport = uip_connr->lport;
1530 BUF->destport = uip_connr->rport;
1531
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001532 BUF->srcipaddr[0] = uip_hostaddr[0];
1533 BUF->srcipaddr[1] = uip_hostaddr[1];
1534 BUF->destipaddr[0] = uip_connr->ripaddr[0];
1535 BUF->destipaddr[1] = uip_connr->ripaddr[1];
1536
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001537
1538 if(uip_connr->tcpstateflags & UIP_STOPPED) {
1539 /* If the connection has issued uip_stop(), we advertise a zero
1540 window so that the remote host will stop sending data. */
1541 BUF->wnd[0] = BUF->wnd[1] = 0;
1542 } else {
adamdunkelsb489e7a2003-10-14 11:12:50 +00001543 BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8);
1544 BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001545 }
1546
1547 tcp_send_noconn:
1548
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001549 BUF->len[0] = (uip_len >> 8);
1550 BUF->len[1] = (uip_len & 0xff);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001551
adamdunkels9fad4132004-06-06 06:14:19 +00001552 BUF->urgp[0] = BUF->urgp[1] = 0;
1553
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001554 /* Calculate TCP checksum. */
1555 BUF->tcpchksum = 0;
1556 BUF->tcpchksum = ~(uip_tcpchksum());
1557
1558 ip_send_nolen:
1559
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001560 BUF->vhl = 0x45;
1561 BUF->tos = 0;
1562 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
1563 BUF->ttl = UIP_TTL;
1564 ++ipid;
1565 BUF->ipid[0] = ipid >> 8;
1566 BUF->ipid[1] = ipid & 0xff;
1567
1568 /* Calculate IP checksum. */
1569 BUF->ipchksum = 0;
1570 BUF->ipchksum = ~(uip_ipchksum());
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001571
1572 UIP_STAT(++uip_stat.tcp.sent);
1573 send:
adamdunkels9fad4132004-06-06 06:14:19 +00001574
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001575 UIP_STAT(++uip_stat.ip.sent);
1576 /* Return and let the caller do the actual transmission. */
1577 return;
1578 drop:
1579 uip_len = 0;
1580 return;
1581}
1582/*-----------------------------------------------------------------------------------*/
adamdunkels47ec7fa2003-03-28 12:11:17 +00001583u16_t
1584htons(u16_t val)
1585{
1586 return HTONS(val);
1587}
1588/*-----------------------------------------------------------------------------------*/
adamdunkels0170b082003-10-01 11:25:37 +00001589/** @} */