blob: 1a8cbe51f613c237e66f35cb1fac976ebbfee5ee [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 *
adamdunkels3335cd92005-02-27 09:44:33 +000042 * $Id: uip.c,v 1.22 2005/02/27 09:44:33 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 }
520 /* Check if we were invoked because of the perodic timer fireing. */
521 } else if(flag == UIP_TIMER) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000522#if UIP_REASSEMBLY
523 if(uip_reasstmr != 0) {
524 --uip_reasstmr;
525 }
526#endif /* UIP_REASSEMBLY */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000527 /* Increase the initial sequence number. */
528 if(++iss[3] == 0) {
529 if(++iss[2] == 0) {
530 if(++iss[1] == 0) {
531 ++iss[0];
532 }
533 }
534 }
535 uip_len = 0;
adamdunkels3335cd92005-02-27 09:44:33 +0000536 uip_slen = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000537 if(uip_connr->tcpstateflags == TIME_WAIT ||
538 uip_connr->tcpstateflags == FIN_WAIT_2) {
539 ++(uip_connr->timer);
540 if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) {
541 uip_connr->tcpstateflags = CLOSED;
542 }
543 } else if(uip_connr->tcpstateflags != CLOSED) {
544 /* If the connection has outstanding data, we increase the
545 connection's timer and see if it has reached the RTO value
546 in which case we retransmit. */
547 if(uip_outstanding(uip_connr)) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000548 if(uip_connr->timer-- == 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000549 if(uip_connr->nrtx == UIP_MAXRTX ||
550 ((uip_connr->tcpstateflags == SYN_SENT ||
551 uip_connr->tcpstateflags == SYN_RCVD) &&
552 uip_connr->nrtx == UIP_MAXSYNRTX)) {
553 uip_connr->tcpstateflags = CLOSED;
554
555 /* We call UIP_APPCALL() with uip_flags set to
556 UIP_TIMEDOUT to inform the application that the
557 connection has timed out. */
558 uip_flags = UIP_TIMEDOUT;
559 UIP_APPCALL();
560
561 /* We also send a reset packet to the remote host. */
562 BUF->flags = TCP_RST | TCP_ACK;
563 goto tcp_send_nodata;
564 }
565
566 /* Exponential backoff. */
adamdunkels47ec7fa2003-03-28 12:11:17 +0000567 uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4?
568 4:
569 uip_connr->nrtx);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000570 ++(uip_connr->nrtx);
571
572 /* Ok, so we need to retransmit. We do this differently
573 depending on which state we are in. In ESTABLISHED, we
574 call upon the application so that it may prepare the
575 data for the retransmit. In SYN_RCVD, we resend the
576 SYNACK that we sent earlier and in LAST_ACK we have to
577 retransmit our FINACK. */
578 UIP_STAT(++uip_stat.tcp.rexmit);
579 switch(uip_connr->tcpstateflags & TS_MASK) {
580 case SYN_RCVD:
581 /* In the SYN_RCVD state, we should retransmit our
582 SYNACK. */
583 goto tcp_send_synack;
584
585#if UIP_ACTIVE_OPEN
586 case SYN_SENT:
587 /* In the SYN_SENT state, we retransmit out SYN. */
588 BUF->flags = 0;
589 goto tcp_send_syn;
590#endif /* UIP_ACTIVE_OPEN */
591
592 case ESTABLISHED:
593 /* In the ESTABLISHED state, we call upon the application
594 to do the actual retransmit after which we jump into
595 the code for sending out the packet (the apprexmit
596 label). */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000597 uip_flags = UIP_REXMIT;
598 UIP_APPCALL();
599 goto apprexmit;
600
601 case FIN_WAIT_1:
602 case CLOSING:
603 case LAST_ACK:
604 /* In all these states we should retransmit a FINACK. */
605 goto tcp_send_finack;
606
607 }
608 }
609 } else if((uip_connr->tcpstateflags & TS_MASK) == ESTABLISHED) {
610 /* If there was no need for a retransmission, we poll the
611 application for new data. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000612 uip_flags = UIP_POLL;
613 UIP_APPCALL();
614 goto appsend;
615 }
616 }
617 goto drop;
618 }
619#if UIP_UDP
620 if(flag == UIP_UDP_TIMER) {
621 if(uip_udp_conn->lport != 0) {
adamdunkels399a0782004-02-16 20:52:07 +0000622 uip_conn = NULL;
adamdunkels049a9122005-02-07 06:59:39 +0000623 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000624 uip_len = uip_slen = 0;
625 uip_flags = UIP_POLL;
626 UIP_UDP_APPCALL();
627 goto udp_send;
628 } else {
629 goto drop;
630 }
631 }
632#endif
633
634 /* This is where the input processing starts. */
635 UIP_STAT(++uip_stat.ip.recv);
636
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000637
638 /* Start of IPv4 input header processing code. */
639
640 /* Check validity of the IP header. */
641 if(BUF->vhl != 0x45) { /* IP version and header length. */
642 UIP_STAT(++uip_stat.ip.drop);
643 UIP_STAT(++uip_stat.ip.vhlerr);
644 UIP_LOG("ip: invalid version or header length.");
645 goto drop;
646 }
647
648 /* Check the size of the packet. If the size reported to us in
adamdunkels049a9122005-02-07 06:59:39 +0000649 uip_len is smaller the size reported in the IP header, we assume
650 that the packet has been corrupted in transit. If the size of
651 uip_len is larger than the size reported in the IP packet header,
652 the packet has been padded and we set uip_len to the correct
653 value.. */
654
655 if((BUF->len[0] << 8) + BUF->len[1] <= uip_len) {
656 uip_len = (BUF->len[0] << 8) + BUF->len[1];
657 } else {
658 UIP_LOG("ip: packet shorter than reported in IP header.");
659 goto drop;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000660 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000661
adamdunkelsb489e7a2003-10-14 11:12:50 +0000662 /* Check the fragment flag. */
663 if((BUF->ipoffset[0] & 0x3f) != 0 ||
664 BUF->ipoffset[1] != 0) {
665#if UIP_REASSEMBLY
666 uip_len = uip_reass();
667 if(uip_len == 0) {
668 goto drop;
669 }
670#else
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000671 UIP_STAT(++uip_stat.ip.drop);
672 UIP_STAT(++uip_stat.ip.fragerr);
673 UIP_LOG("ip: fragment dropped.");
674 goto drop;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000675#endif /* UIP_REASSEMBLY */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000676 }
677
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000678 if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
adamdunkels75b9d002004-09-17 20:48:39 +0000679 /* If we are configured to use ping IP address configuration and
680 hasn't been assigned an IP address yet, we accept all ICMP
681 packets. */
682#if UIP_PINGADDRCONF
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000683 if(BUF->proto == UIP_PROTO_ICMP) {
684 UIP_LOG("ip: possible ping config packet received.");
685 goto icmp_input;
686 } else {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000687 UIP_LOG("ip: packet dropped since no address assigned.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000688 goto drop;
adamdunkels75b9d002004-09-17 20:48:39 +0000689 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000690#endif /* UIP_PINGADDRCONF */
adamdunkels9fad4132004-06-06 06:14:19 +0000691
adamdunkels75b9d002004-09-17 20:48:39 +0000692 } else {
693 /* If IP broadcast support is configured, we check for a broadcast
694 UDP packet, which may be destined to us. */
adamdunkels9fad4132004-06-06 06:14:19 +0000695#if UIP_BROADCAST
adamdunkels75b9d002004-09-17 20:48:39 +0000696 if(BUF->proto == UIP_PROTO_UDP &&
697 BUF->destipaddr[0] == 0xffff &&
adamdunkels9fad4132004-06-06 06:14:19 +0000698 BUF->destipaddr[1] == 0xffff &&
adamdunkels75b9d002004-09-17 20:48:39 +0000699 uip_ipchksum() == 0xffff) {
700 goto udp_input;
701 }
adamdunkels9fad4132004-06-06 06:14:19 +0000702#endif /* UIP_BROADCAST */
adamdunkels75b9d002004-09-17 20:48:39 +0000703
704 /* Check if the packet is destined for our IP address. */
705 if(BUF->destipaddr[0] != uip_hostaddr[0]) {
706 UIP_STAT(++uip_stat.ip.drop);
adamdunkels75b9d002004-09-17 20:48:39 +0000707 goto drop;
708 }
709 if(BUF->destipaddr[1] != uip_hostaddr[1]) {
710 UIP_STAT(++uip_stat.ip.drop);
adamdunkels75b9d002004-09-17 20:48:39 +0000711 goto drop;
712 }
713 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000714
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000715 if(uip_ipchksum() != 0xffff) { /* Compute and check the IP header
716 checksum. */
717 UIP_STAT(++uip_stat.ip.drop);
718 UIP_STAT(++uip_stat.ip.chkerr);
adamdunkels9fad4132004-06-06 06:14:19 +0000719 UIP_LOG("ip: bad checksum.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000720 goto drop;
721 }
722
adamdunkels049a9122005-02-07 06:59:39 +0000723 if(BUF->proto == UIP_PROTO_TCP) { /* Check for TCP packet. If so,
724 proceed with TCP input
725 processing. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000726 goto tcp_input;
adamdunkels049a9122005-02-07 06:59:39 +0000727 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000728
729#if UIP_UDP
adamdunkels049a9122005-02-07 06:59:39 +0000730 if(BUF->proto == UIP_PROTO_UDP) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000731 goto udp_input;
adamdunkels049a9122005-02-07 06:59:39 +0000732 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000733#endif /* UIP_UDP */
734
735 if(BUF->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from
736 here. */
737 UIP_STAT(++uip_stat.ip.drop);
738 UIP_STAT(++uip_stat.ip.protoerr);
739 UIP_LOG("ip: neither tcp nor icmp.");
740 goto drop;
741 }
742
743 icmp_input:
744 UIP_STAT(++uip_stat.icmp.recv);
745
746 /* ICMP echo (i.e., ping) processing. This is simple, we only change
747 the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
748 checksum before we return the packet. */
749 if(ICMPBUF->type != ICMP_ECHO) {
750 UIP_STAT(++uip_stat.icmp.drop);
751 UIP_STAT(++uip_stat.icmp.typeerr);
752 UIP_LOG("icmp: not icmp echo.");
753 goto drop;
754 }
755
756 /* If we are configured to use ping IP address assignment, we use
757 the destination IP address of this ping packet and assign it to
758 ourself. */
759#if UIP_PINGADDRCONF
760 if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
761 uip_hostaddr[0] = BUF->destipaddr[0];
762 uip_hostaddr[1] = BUF->destipaddr[1];
763 }
764#endif /* UIP_PINGADDRCONF */
765
766 ICMPBUF->type = ICMP_ECHO_REPLY;
767
adamdunkels47ec7fa2003-03-28 12:11:17 +0000768 if(ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) {
769 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000770 } else {
adamdunkels47ec7fa2003-03-28 12:11:17 +0000771 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000772 }
773
774 /* Swap IP addresses. */
adamdunkels0170b082003-10-01 11:25:37 +0000775 tmp16 = BUF->destipaddr[0];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000776 BUF->destipaddr[0] = BUF->srcipaddr[0];
adamdunkels0170b082003-10-01 11:25:37 +0000777 BUF->srcipaddr[0] = tmp16;
778 tmp16 = BUF->destipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000779 BUF->destipaddr[1] = BUF->srcipaddr[1];
adamdunkels0170b082003-10-01 11:25:37 +0000780 BUF->srcipaddr[1] = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000781
782 UIP_STAT(++uip_stat.icmp.sent);
783 goto send;
784
785 /* End of IPv4 input header processing code. */
786
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000787
788#if UIP_UDP
789 /* UDP input processing. */
790 udp_input:
791 /* UDP processing is really just a hack. We don't do anything to the
792 UDP/IP headers, but let the UDP application do all the hard
793 work. If the application sets uip_slen, it has a packet to
794 send. */
795#if UIP_UDP_CHECKSUMS
adamdunkels049a9122005-02-07 06:59:39 +0000796 uip_len = uip_len - UIP_IPTCPH_LEN;
797 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];
798 if(uip_udpchksum() != 0xffff) {
799 printf("checksum 0x%04x\n", uip_udpchksum());
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000800 UIP_STAT(++uip_stat.udp.drop);
801 UIP_STAT(++uip_stat.udp.chkerr);
802 UIP_LOG("udp: bad checksum.");
803 goto drop;
adamdunkels049a9122005-02-07 06:59:39 +0000804 }
805 uip_len = uip_len + (UIP_IPTCPH_LEN - UIP_IPUDPH_LEN);
806#else /* UIP_UDP_CHECKSUMS */
807 uip_len = uip_len - UIP_IPUDPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000808#endif /* UIP_UDP_CHECKSUMS */
809
810 /* Demultiplex this UDP packet between the UDP "connections". */
811 for(uip_udp_conn = &uip_udp_conns[0];
812 uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS];
813 ++uip_udp_conn) {
adamdunkels9fad4132004-06-06 06:14:19 +0000814 /* If the local UDP port is non-zero, the connection is considered
815 to be used. If so, the local port number is checked against the
816 destination port number in the received packet. If the two port
817 numbers match, the remote port number is checked if the
818 connection is bound to a remote port. Finally, if the
819 connection is bound to a remote IP address, the source IP
820 address of the packet is checked. */
821 if(uip_udp_conn->lport != 0 &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000822 UDPBUF->destport == uip_udp_conn->lport &&
823 (uip_udp_conn->rport == 0 ||
824 UDPBUF->srcport == uip_udp_conn->rport) &&
adamdunkels9fad4132004-06-06 06:14:19 +0000825 ((uip_udp_conn->ripaddr[0] | uip_udp_conn->ripaddr[1]) == 0 ||
826 (uip_udp_conn->ripaddr[0] == 0xffff &&
827 uip_udp_conn->ripaddr[1] == 0xffff) ||
828 uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000829 goto udp_found;
830 }
831 }
adamdunkels9fad4132004-06-06 06:14:19 +0000832 UIP_LOG("udp: no matching connection found");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000833 goto drop;
834
835 udp_found:
adamdunkels399a0782004-02-16 20:52:07 +0000836 uip_conn = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000837 uip_flags = UIP_NEWDATA;
adamdunkels049a9122005-02-07 06:59:39 +0000838 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000839 uip_slen = 0;
840 UIP_UDP_APPCALL();
841 udp_send:
842 if(uip_slen == 0) {
843 goto drop;
844 }
adamdunkels049a9122005-02-07 06:59:39 +0000845 uip_len = uip_slen + UIP_IPUDPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000846
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000847 BUF->len[0] = (uip_len >> 8);
848 BUF->len[1] = (uip_len & 0xff);
adamdunkelsb489e7a2003-10-14 11:12:50 +0000849
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000850 BUF->proto = UIP_PROTO_UDP;
851
adamdunkels049a9122005-02-07 06:59:39 +0000852 UDPBUF->udplen = HTONS(uip_slen + UIP_UDPH_LEN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000853 UDPBUF->udpchksum = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000854
855 BUF->srcport = uip_udp_conn->lport;
856 BUF->destport = uip_udp_conn->rport;
857
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000858 BUF->srcipaddr[0] = uip_hostaddr[0];
859 BUF->srcipaddr[1] = uip_hostaddr[1];
860 BUF->destipaddr[0] = uip_udp_conn->ripaddr[0];
861 BUF->destipaddr[1] = uip_udp_conn->ripaddr[1];
862
adamdunkels049a9122005-02-07 06:59:39 +0000863 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];
adamdunkelsc4b80c52004-09-18 20:17:01 +0000864
865#if UIP_UDP_CHECKSUMS
866 /* Calculate UDP checksum. */
867 UDPBUF->udpchksum = ~(uip_udpchksum());
868 if(UDPBUF->udpchksum == 0) {
869 UDPBUF->udpchksum = 0xffff;
870 }
871#endif /* UIP_UDP_CHECKSUMS */
872
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000873 goto ip_send_nolen;
874#endif /* UIP_UDP */
875
876 /* TCP input processing. */
877 tcp_input:
878 UIP_STAT(++uip_stat.tcp.recv);
879
880 /* Start of TCP input header processing code. */
881
882 if(uip_tcpchksum() != 0xffff) { /* Compute and check the TCP
883 checksum. */
884 UIP_STAT(++uip_stat.tcp.drop);
885 UIP_STAT(++uip_stat.tcp.chkerr);
adamdunkels9fad4132004-06-06 06:14:19 +0000886 UIP_LOG("tcp: bad checksum.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000887 goto drop;
888 }
889
adamdunkels9fad4132004-06-06 06:14:19 +0000890
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000891 /* Demultiplex this segment. */
892 /* First check any active connections. */
adamdunkels049a9122005-02-07 06:59:39 +0000893 for(uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1];
894 ++uip_connr) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000895 if(uip_connr->tcpstateflags != CLOSED &&
896 BUF->destport == uip_connr->lport &&
897 BUF->srcport == uip_connr->rport &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000898 BUF->srcipaddr[0] == uip_connr->ripaddr[0] &&
899 BUF->srcipaddr[1] == uip_connr->ripaddr[1]) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000900 goto found;
901 }
902 }
903
904 /* If we didn't find and active connection that expected the packet,
905 either this packet is an old duplicate, or this is a SYN packet
906 destined for a connection in LISTEN. If the SYN flag isn't set,
907 it is an old packet and we send a RST. */
adamdunkels049a9122005-02-07 06:59:39 +0000908 if((BUF->flags & TCP_CTL) != TCP_SYN) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000909 goto reset;
adamdunkels049a9122005-02-07 06:59:39 +0000910 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000911
adamdunkels0170b082003-10-01 11:25:37 +0000912 tmp16 = BUF->destport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000913 /* Next, check listening connections. */
adamdunkelscd8c3a22003-08-13 22:52:48 +0000914 for(c = 0; c < UIP_LISTENPORTS; ++c) {
adamdunkels0170b082003-10-01 11:25:37 +0000915 if(tmp16 == uip_listenports[c])
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000916 goto found_listen;
917 }
918
919 /* No matching connection found, so we send a RST packet. */
920 UIP_STAT(++uip_stat.tcp.synrst);
921 reset:
922
923 /* We do not send resets in response to resets. */
adamdunkels049a9122005-02-07 06:59:39 +0000924 if(BUF->flags & TCP_RST) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000925 goto drop;
adamdunkels049a9122005-02-07 06:59:39 +0000926 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000927
928 UIP_STAT(++uip_stat.tcp.rst);
929
930 BUF->flags = TCP_RST | TCP_ACK;
adamdunkels049a9122005-02-07 06:59:39 +0000931 uip_len = UIP_IPTCPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000932 BUF->tcpoffset = 5 << 4;
933
934 /* Flip the seqno and ackno fields in the TCP header. */
935 c = BUF->seqno[3];
936 BUF->seqno[3] = BUF->ackno[3];
937 BUF->ackno[3] = c;
938
939 c = BUF->seqno[2];
940 BUF->seqno[2] = BUF->ackno[2];
941 BUF->ackno[2] = c;
942
943 c = BUF->seqno[1];
944 BUF->seqno[1] = BUF->ackno[1];
945 BUF->ackno[1] = c;
946
947 c = BUF->seqno[0];
948 BUF->seqno[0] = BUF->ackno[0];
949 BUF->ackno[0] = c;
950
951 /* We also have to increase the sequence number we are
952 acknowledging. If the least significant byte overflowed, we need
953 to propagate the carry to the other bytes as well. */
954 if(++BUF->ackno[3] == 0) {
955 if(++BUF->ackno[2] == 0) {
956 if(++BUF->ackno[1] == 0) {
957 ++BUF->ackno[0];
958 }
959 }
960 }
961
962 /* Swap port numbers. */
adamdunkels0170b082003-10-01 11:25:37 +0000963 tmp16 = BUF->srcport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000964 BUF->srcport = BUF->destport;
adamdunkels0170b082003-10-01 11:25:37 +0000965 BUF->destport = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000966
967 /* Swap IP addresses. */
adamdunkels0170b082003-10-01 11:25:37 +0000968 tmp16 = BUF->destipaddr[0];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000969 BUF->destipaddr[0] = BUF->srcipaddr[0];
adamdunkels0170b082003-10-01 11:25:37 +0000970 BUF->srcipaddr[0] = tmp16;
971 tmp16 = BUF->destipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000972 BUF->destipaddr[1] = BUF->srcipaddr[1];
adamdunkels0170b082003-10-01 11:25:37 +0000973 BUF->srcipaddr[1] = tmp16;
adamdunkelsa38da252003-08-20 20:56:54 +0000974
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000975
976 /* And send out the RST packet! */
977 goto tcp_send_noconn;
978
979 /* This label will be jumped to if we matched the incoming packet
980 with a connection in LISTEN. In that case, we should create a new
981 connection and send a SYNACK in return. */
982 found_listen:
983 /* First we check if there are any connections avaliable. Unused
984 connections are kept in the same table as used connections, but
985 unused ones have the tcpstate set to CLOSED. Also, connections in
986 TIME_WAIT are kept track of and we'll use the oldest one if no
987 CLOSED connections are found. Thanks to Eddie C. Dost for a very
988 nice algorithm for the TIME_WAIT search. */
989 uip_connr = 0;
990 for(c = 0; c < UIP_CONNS; ++c) {
991 if(uip_conns[c].tcpstateflags == CLOSED) {
992 uip_connr = &uip_conns[c];
993 break;
994 }
995 if(uip_conns[c].tcpstateflags == TIME_WAIT) {
996 if(uip_connr == 0 ||
997 uip_conns[c].timer > uip_connr->timer) {
998 uip_connr = &uip_conns[c];
999 }
1000 }
1001 }
1002
1003 if(uip_connr == 0) {
1004 /* All connections are used already, we drop packet and hope that
1005 the remote end will retransmit the packet at a time when we
1006 have more spare connections. */
1007 UIP_STAT(++uip_stat.tcp.syndrop);
1008 UIP_LOG("tcp: found no unused connections.");
1009 goto drop;
1010 }
1011 uip_conn = uip_connr;
1012
1013 /* Fill in the necessary fields for the new connection. */
adamdunkelsb489e7a2003-10-14 11:12:50 +00001014 uip_connr->rto = uip_connr->timer = UIP_RTO;
1015 uip_connr->sa = 0;
1016 uip_connr->sv = 4;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001017 uip_connr->nrtx = 0;
1018 uip_connr->lport = BUF->destport;
1019 uip_connr->rport = BUF->srcport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001020 uip_connr->ripaddr[0] = BUF->srcipaddr[0];
1021 uip_connr->ripaddr[1] = BUF->srcipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001022 uip_connr->tcpstateflags = SYN_RCVD;
1023
1024 uip_connr->snd_nxt[0] = iss[0];
1025 uip_connr->snd_nxt[1] = iss[1];
1026 uip_connr->snd_nxt[2] = iss[2];
1027 uip_connr->snd_nxt[3] = iss[3];
1028 uip_connr->len = 1;
1029
1030 /* rcv_nxt should be the seqno from the incoming packet + 1. */
1031 uip_connr->rcv_nxt[3] = BUF->seqno[3];
1032 uip_connr->rcv_nxt[2] = BUF->seqno[2];
1033 uip_connr->rcv_nxt[1] = BUF->seqno[1];
1034 uip_connr->rcv_nxt[0] = BUF->seqno[0];
1035 uip_add_rcv_nxt(1);
1036
1037 /* Parse the TCP MSS option, if present. */
1038 if((BUF->tcpoffset & 0xf0) > 0x50) {
1039 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
1040 opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c];
adamdunkels049a9122005-02-07 06:59:39 +00001041 if(opt == TCP_OPT_END) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001042 /* End of options. */
1043 break;
adamdunkels049a9122005-02-07 06:59:39 +00001044 } else if(opt == TCP_OPT_NOOP) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001045 ++c;
1046 /* NOP option. */
adamdunkels049a9122005-02-07 06:59:39 +00001047 } else if(opt == TCP_OPT_MSS &&
1048 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001049 /* An MSS option with the right option length. */
adamdunkels0170b082003-10-01 11:25:37 +00001050 tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
adamdunkels049a9122005-02-07 06:59:39 +00001051 (u16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c];
adamdunkels0170b082003-10-01 11:25:37 +00001052 uip_connr->initialmss = uip_connr->mss =
1053 tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001054
1055 /* And we are done processing options. */
1056 break;
1057 } else {
1058 /* All other options have a length field, so that we easily
1059 can skip past them. */
1060 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
1061 /* If the length field is zero, the options are malformed
1062 and we don't process them further. */
1063 break;
1064 }
1065 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
1066 }
1067 }
1068 }
1069
1070 /* Our response will be a SYNACK. */
1071#if UIP_ACTIVE_OPEN
1072 tcp_send_synack:
1073 BUF->flags = TCP_ACK;
1074
1075 tcp_send_syn:
1076 BUF->flags |= TCP_SYN;
1077#else /* UIP_ACTIVE_OPEN */
1078 tcp_send_synack:
1079 BUF->flags = TCP_SYN | TCP_ACK;
1080#endif /* UIP_ACTIVE_OPEN */
1081
1082 /* We send out the TCP Maximum Segment Size option with our
1083 SYNACK. */
adamdunkels049a9122005-02-07 06:59:39 +00001084 BUF->optdata[0] = TCP_OPT_MSS;
1085 BUF->optdata[1] = TCP_OPT_MSS_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001086 BUF->optdata[2] = (UIP_TCP_MSS) / 256;
1087 BUF->optdata[3] = (UIP_TCP_MSS) & 255;
adamdunkels049a9122005-02-07 06:59:39 +00001088 uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN;
1089 BUF->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001090 goto tcp_send;
1091
1092 /* This label will be jumped to if we found an active connection. */
1093 found:
1094 uip_conn = uip_connr;
1095 uip_flags = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001096 /* We do a very naive form of TCP reset processing; we just accept
1097 any RST and kill our connection. We should in fact check if the
1098 sequence number of this reset is wihtin our advertised window
1099 before we accept the reset. */
1100 if(BUF->flags & TCP_RST) {
1101 uip_connr->tcpstateflags = CLOSED;
1102 UIP_LOG("tcp: got reset, aborting connection.");
1103 uip_flags = UIP_ABORT;
1104 UIP_APPCALL();
1105 goto drop;
adamdunkels47ec7fa2003-03-28 12:11:17 +00001106 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001107 /* Calculated the length of the data, if the application has sent
1108 any data to us. */
1109 c = (BUF->tcpoffset >> 4) << 2;
1110 /* uip_len will contain the length of the actual TCP data. This is
1111 calculated by subtracing the length of the TCP header (in
1112 c) and the length of the IP header (20 bytes). */
adamdunkels049a9122005-02-07 06:59:39 +00001113 uip_len = uip_len - c - UIP_IPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001114
1115 /* First, check if the sequence number of the incoming packet is
1116 what we're expecting next. If not, we send out an ACK with the
1117 correct numbers in. */
adamdunkels049a9122005-02-07 06:59:39 +00001118 if(!(((uip_connr->tcpstateflags & TS_MASK) == SYN_SENT) &&
1119 ((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) {
1120 if((uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 0)) &&
1121 (BUF->seqno[0] != uip_connr->rcv_nxt[0] ||
1122 BUF->seqno[1] != uip_connr->rcv_nxt[1] ||
1123 BUF->seqno[2] != uip_connr->rcv_nxt[2] ||
1124 BUF->seqno[3] != uip_connr->rcv_nxt[3])) {
1125 goto tcp_send_ack;
1126 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001127 }
1128
1129 /* Next, check if the incoming segment acknowledges any outstanding
1130 data. If so, we update the sequence number, reset the length of
1131 the outstanding data, calculate RTT estimations, and reset the
1132 retransmission timer. */
adamdunkels47ec7fa2003-03-28 12:11:17 +00001133 if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001134 uip_add32(uip_connr->snd_nxt, uip_connr->len);
adamdunkels08eac9e2004-09-12 07:17:37 +00001135
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001136 if(BUF->ackno[0] == uip_acc32[0] &&
1137 BUF->ackno[1] == uip_acc32[1] &&
1138 BUF->ackno[2] == uip_acc32[2] &&
1139 BUF->ackno[3] == uip_acc32[3]) {
1140 /* Update sequence number. */
1141 uip_connr->snd_nxt[0] = uip_acc32[0];
1142 uip_connr->snd_nxt[1] = uip_acc32[1];
1143 uip_connr->snd_nxt[2] = uip_acc32[2];
1144 uip_connr->snd_nxt[3] = uip_acc32[3];
adamdunkelsa38da252003-08-20 20:56:54 +00001145
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001146
1147 /* Do RTT estimation, unless we have done retransmissions. */
1148 if(uip_connr->nrtx == 0) {
1149 signed char m;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001150 m = uip_connr->rto - uip_connr->timer;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001151 /* This is taken directly from VJs original code in his paper */
1152 m = m - (uip_connr->sa >> 3);
1153 uip_connr->sa += m;
1154 if(m < 0) {
1155 m = -m;
1156 }
1157 m = m - (uip_connr->sv >> 2);
1158 uip_connr->sv += m;
1159 uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv;
1160
1161 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001162 /* Set the acknowledged flag. */
1163 uip_flags = UIP_ACKDATA;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001164 /* Reset the retransmission timer. */
adamdunkelsb489e7a2003-10-14 11:12:50 +00001165 uip_connr->timer = uip_connr->rto;
adamdunkels08eac9e2004-09-12 07:17:37 +00001166
1167 /* Reset length of outstanding data. */
1168 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001169 }
adamdunkelsab4b0822003-07-30 23:31:40 +00001170
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001171 }
1172
1173 /* Do different things depending on in what state the connection is. */
1174 switch(uip_connr->tcpstateflags & TS_MASK) {
1175 /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
1176 implemented, since we force the application to close when the
1177 peer sends a FIN (hence the application goes directly from
1178 ESTABLISHED to LAST_ACK). */
1179 case SYN_RCVD:
1180 /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and
1181 we are waiting for an ACK that acknowledges the data we sent
1182 out the last time. Therefore, we want to have the UIP_ACKDATA
1183 flag set. If so, we enter the ESTABLISHED state. */
1184 if(uip_flags & UIP_ACKDATA) {
1185 uip_connr->tcpstateflags = ESTABLISHED;
1186 uip_flags = UIP_CONNECTED;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001187 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001188 if(uip_len > 0) {
1189 uip_flags |= UIP_NEWDATA;
1190 uip_add_rcv_nxt(uip_len);
1191 }
1192 uip_slen = 0;
1193 UIP_APPCALL();
1194 goto appsend;
1195 }
1196 goto drop;
1197#if UIP_ACTIVE_OPEN
1198 case SYN_SENT:
1199 /* In SYN_SENT, we wait for a SYNACK that is sent in response to
1200 our SYN. The rcv_nxt is set to sequence number in the SYNACK
1201 plus one, and we send an ACK. We move into the ESTABLISHED
1202 state. */
1203 if((uip_flags & UIP_ACKDATA) &&
adamdunkels049a9122005-02-07 06:59:39 +00001204 (BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001205
1206 /* Parse the TCP MSS option, if present. */
1207 if((BUF->tcpoffset & 0xf0) > 0x50) {
1208 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
adamdunkels049a9122005-02-07 06:59:39 +00001209 opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c];
1210 if(opt == TCP_OPT_END) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001211 /* End of options. */
1212 break;
adamdunkels049a9122005-02-07 06:59:39 +00001213 } else if(opt == TCP_OPT_NOOP) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001214 ++c;
1215 /* NOP option. */
adamdunkels049a9122005-02-07 06:59:39 +00001216 } else if(opt == TCP_OPT_MSS &&
1217 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001218 /* An MSS option with the right option length. */
adamdunkels0170b082003-10-01 11:25:37 +00001219 tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001220 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];
adamdunkels0170b082003-10-01 11:25:37 +00001221 uip_connr->initialmss =
1222 uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001223
1224 /* And we are done processing options. */
1225 break;
1226 } else {
1227 /* All other options have a length field, so that we easily
1228 can skip past them. */
1229 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
1230 /* If the length field is zero, the options are malformed
1231 and we don't process them further. */
1232 break;
1233 }
1234 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
1235 }
1236 }
1237 }
1238 uip_connr->tcpstateflags = ESTABLISHED;
1239 uip_connr->rcv_nxt[0] = BUF->seqno[0];
1240 uip_connr->rcv_nxt[1] = BUF->seqno[1];
1241 uip_connr->rcv_nxt[2] = BUF->seqno[2];
1242 uip_connr->rcv_nxt[3] = BUF->seqno[3];
1243 uip_add_rcv_nxt(1);
1244 uip_flags = UIP_CONNECTED | UIP_NEWDATA;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001245 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001246 uip_len = 0;
1247 uip_slen = 0;
1248 UIP_APPCALL();
1249 goto appsend;
1250 }
adamdunkels049a9122005-02-07 06:59:39 +00001251 /* Inform the application that the connection failed */
1252 uip_flags = UIP_ABORT;
1253 UIP_APPCALL();
1254 /* The connection is closed after we send the RST */
1255 uip_conn->tcpstateflags = CLOSED;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001256 goto reset;
1257#endif /* UIP_ACTIVE_OPEN */
1258
1259 case ESTABLISHED:
1260 /* In the ESTABLISHED state, we call upon the application to feed
1261 data into the uip_buf. If the UIP_ACKDATA flag is set, the
1262 application should put new data into the buffer, otherwise we are
1263 retransmitting an old segment, and the application should put that
1264 data into the buffer.
1265
1266 If the incoming packet is a FIN, we should close the connection on
1267 this side as well, and we send out a FIN and enter the LAST_ACK
1268 state. We require that there is no outstanding data; otherwise the
1269 sequence numbers will be screwed up. */
1270
adamdunkels31a50262005-02-22 22:33:56 +00001271 if(BUF->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001272 if(uip_outstanding(uip_connr)) {
1273 goto drop;
1274 }
1275 uip_add_rcv_nxt(1 + uip_len);
1276 uip_flags = UIP_CLOSE;
1277 if(uip_len > 0) {
1278 uip_flags |= UIP_NEWDATA;
1279 }
1280 UIP_APPCALL();
1281 uip_connr->len = 1;
1282 uip_connr->tcpstateflags = LAST_ACK;
1283 uip_connr->nrtx = 0;
1284 tcp_send_finack:
1285 BUF->flags = TCP_FIN | TCP_ACK;
1286 goto tcp_send_nodata;
1287 }
1288
1289 /* Check the URG flag. If this is set, the segment carries urgent
1290 data that we must pass to the application. */
adamdunkels9fad4132004-06-06 06:14:19 +00001291 if((BUF->flags & TCP_URG) != 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001292#if UIP_URGDATA > 0
1293 uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1];
1294 if(uip_urglen > uip_len) {
1295 /* There is more urgent data in the next segment to come. */
1296 uip_urglen = uip_len;
1297 }
1298 uip_add_rcv_nxt(uip_urglen);
1299 uip_len -= uip_urglen;
1300 uip_urgdata = uip_appdata;
1301 uip_appdata += uip_urglen;
1302 } else {
1303 uip_urglen = 0;
adamdunkels9fad4132004-06-06 06:14:19 +00001304#else /* UIP_URGDATA > 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001305 uip_appdata += (BUF->urgp[0] << 8) | BUF->urgp[1];
1306 uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1];
adamdunkels9fad4132004-06-06 06:14:19 +00001307#endif /* UIP_URGDATA > 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001308 }
adamdunkels9fad4132004-06-06 06:14:19 +00001309
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001310 /* If uip_len > 0 we have TCP data in the packet, and we flag this
1311 by setting the UIP_NEWDATA flag and update the sequence number
1312 we acknowledge. If the application has stopped the dataflow
1313 using uip_stop(), we must not accept any data packets from the
1314 remote host. */
1315 if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
1316 uip_flags |= UIP_NEWDATA;
1317 uip_add_rcv_nxt(uip_len);
1318 }
adamdunkels0170b082003-10-01 11:25:37 +00001319
1320 /* Check if the available buffer space advertised by the other end
1321 is smaller than the initial MSS for this connection. If so, we
1322 set the current MSS to the window size to ensure that the
1323 application does not send more data than the other end can
1324 handle.
1325
1326 If the remote host advertises a zero window, we set the MSS to
1327 the initial MSS so that the application will send an entire MSS
1328 of data. This data will not be acknowledged by the receiver,
1329 and the application will retransmit it. This is called the
1330 "persistent timer" and uses the retransmission mechanim.
1331 */
1332 tmp16 = ((u16_t)BUF->wnd[0] << 8) + (u16_t)BUF->wnd[1];
1333 if(tmp16 > uip_connr->initialmss ||
1334 tmp16 == 0) {
1335 tmp16 = uip_connr->initialmss;
1336 }
1337 uip_connr->mss = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001338
1339 /* If this packet constitutes an ACK for outstanding data (flagged
1340 by the UIP_ACKDATA flag, we should call the application since it
1341 might want to send more data. If the incoming packet had data
1342 from the peer (as flagged by the UIP_NEWDATA flag), the
1343 application must also be notified.
1344
1345 When the application is called, the global variable uip_len
1346 contains the length of the incoming data. The application can
1347 access the incoming data through the global pointer
adamdunkels049a9122005-02-07 06:59:39 +00001348 uip_appdata, which usually points UIP_IPTCPH_LEN + UIP_LLH_LEN
1349 bytes into the uip_buf array.
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001350
1351 If the application wishes to send any data, this data should be
1352 put into the uip_appdata and the length of the data should be
1353 put into uip_len. If the application don't have any data to
1354 send, uip_len must be set to 0. */
1355 if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) {
1356 uip_slen = 0;
1357 UIP_APPCALL();
1358
1359 appsend:
adamdunkels0170b082003-10-01 11:25:37 +00001360
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001361 if(uip_flags & UIP_ABORT) {
1362 uip_slen = 0;
1363 uip_connr->tcpstateflags = CLOSED;
1364 BUF->flags = TCP_RST | TCP_ACK;
1365 goto tcp_send_nodata;
1366 }
1367
1368 if(uip_flags & UIP_CLOSE) {
1369 uip_slen = 0;
1370 uip_connr->len = 1;
1371 uip_connr->tcpstateflags = FIN_WAIT_1;
1372 uip_connr->nrtx = 0;
1373 BUF->flags = TCP_FIN | TCP_ACK;
1374 goto tcp_send_nodata;
1375 }
1376
adamdunkelsb489e7a2003-10-14 11:12:50 +00001377 /* If uip_slen > 0, the application has data to be sent. */
1378 if(uip_slen > 0) {
1379
1380 /* If the connection has acknowledged data, the contents of
1381 the ->len variable should be discarded. */
1382 if((uip_flags & UIP_ACKDATA) != 0) {
1383 uip_connr->len = 0;
1384 }
1385
1386 /* If the ->len variable is non-zero the connection has
1387 already data in transit and cannot send anymore right
1388 now. */
1389 if(uip_connr->len == 0) {
1390
1391 /* The application cannot send more than what is allowed by
1392 the mss (the minumum of the MSS and the available
1393 window). */
1394 if(uip_slen > uip_connr->mss) {
1395 uip_slen = uip_connr->mss;
1396 }
1397
1398 /* Remember how much data we send out now so that we know
1399 when everything has been acknowledged. */
1400 uip_connr->len = uip_slen;
1401 } else {
1402
1403 /* If the application already had unacknowledged data, we
1404 make sure that the application does not send (i.e.,
1405 retransmit) out more than it previously sent out. */
1406 uip_slen = uip_connr->len;
1407 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001408 }
adamdunkelsb489e7a2003-10-14 11:12:50 +00001409 uip_connr->nrtx = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001410 apprexmit:
adamdunkels0170b082003-10-01 11:25:37 +00001411 uip_appdata = uip_sappdata;
1412
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001413 /* If the application has data to be sent, or if the incoming
1414 packet had new data in it, we must send out a packet. */
adamdunkels759185d2003-06-30 20:35:41 +00001415 if(uip_slen > 0 && uip_connr->len > 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001416 /* Add the length of the IP and TCP headers. */
1417 uip_len = uip_connr->len + UIP_TCPIP_HLEN;
1418 /* We always set the ACK flag in response packets. */
adamdunkels759185d2003-06-30 20:35:41 +00001419 BUF->flags = TCP_ACK | TCP_PSH;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001420 /* Send the packet. */
1421 goto tcp_send_noopts;
1422 }
adamdunkels759185d2003-06-30 20:35:41 +00001423 /* If there is no data to send, just send out a pure ACK if
1424 there is newdata. */
1425 if(uip_flags & UIP_NEWDATA) {
1426 uip_len = UIP_TCPIP_HLEN;
1427 BUF->flags = TCP_ACK;
1428 goto tcp_send_noopts;
1429 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001430 }
1431 goto drop;
1432 case LAST_ACK:
1433 /* We can close this connection if the peer has acknowledged our
1434 FIN. This is indicated by the UIP_ACKDATA flag. */
1435 if(uip_flags & UIP_ACKDATA) {
1436 uip_connr->tcpstateflags = CLOSED;
1437 uip_flags = UIP_CLOSE;
1438 UIP_APPCALL();
1439 }
1440 break;
1441
1442 case FIN_WAIT_1:
1443 /* The application has closed the connection, but the remote host
1444 hasn't closed its end yet. Thus we do nothing but wait for a
1445 FIN from the other side. */
1446 if(uip_len > 0) {
1447 uip_add_rcv_nxt(uip_len);
1448 }
1449 if(BUF->flags & TCP_FIN) {
1450 if(uip_flags & UIP_ACKDATA) {
1451 uip_connr->tcpstateflags = TIME_WAIT;
1452 uip_connr->timer = 0;
1453 uip_connr->len = 0;
1454 } else {
1455 uip_connr->tcpstateflags = CLOSING;
1456 }
1457 uip_add_rcv_nxt(1);
1458 uip_flags = UIP_CLOSE;
1459 UIP_APPCALL();
1460 goto tcp_send_ack;
1461 } else if(uip_flags & UIP_ACKDATA) {
1462 uip_connr->tcpstateflags = FIN_WAIT_2;
1463 uip_connr->len = 0;
1464 goto drop;
1465 }
1466 if(uip_len > 0) {
1467 goto tcp_send_ack;
1468 }
1469 goto drop;
1470
1471 case FIN_WAIT_2:
1472 if(uip_len > 0) {
1473 uip_add_rcv_nxt(uip_len);
1474 }
1475 if(BUF->flags & TCP_FIN) {
1476 uip_connr->tcpstateflags = TIME_WAIT;
1477 uip_connr->timer = 0;
1478 uip_add_rcv_nxt(1);
1479 uip_flags = UIP_CLOSE;
1480 UIP_APPCALL();
1481 goto tcp_send_ack;
1482 }
1483 if(uip_len > 0) {
1484 goto tcp_send_ack;
1485 }
1486 goto drop;
1487
1488 case TIME_WAIT:
1489 goto tcp_send_ack;
1490
1491 case CLOSING:
1492 if(uip_flags & UIP_ACKDATA) {
1493 uip_connr->tcpstateflags = TIME_WAIT;
1494 uip_connr->timer = 0;
1495 }
1496 }
1497 goto drop;
1498
1499
1500 /* We jump here when we are ready to send the packet, and just want
1501 to set the appropriate TCP sequence numbers in the TCP header. */
1502 tcp_send_ack:
1503 BUF->flags = TCP_ACK;
1504 tcp_send_nodata:
adamdunkels049a9122005-02-07 06:59:39 +00001505 uip_len = UIP_IPTCPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001506 tcp_send_noopts:
adamdunkels049a9122005-02-07 06:59:39 +00001507 BUF->tcpoffset = (UIP_TCPH_LEN / 4) << 4;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001508 tcp_send:
1509 /* We're done with the input processing. We are now ready to send a
1510 reply. Our job is to fill in all the fields of the TCP and IP
1511 headers before calculating the checksum and finally send the
1512 packet. */
1513 BUF->ackno[0] = uip_connr->rcv_nxt[0];
1514 BUF->ackno[1] = uip_connr->rcv_nxt[1];
1515 BUF->ackno[2] = uip_connr->rcv_nxt[2];
1516 BUF->ackno[3] = uip_connr->rcv_nxt[3];
1517
1518 BUF->seqno[0] = uip_connr->snd_nxt[0];
1519 BUF->seqno[1] = uip_connr->snd_nxt[1];
1520 BUF->seqno[2] = uip_connr->snd_nxt[2];
1521 BUF->seqno[3] = uip_connr->snd_nxt[3];
1522
1523 BUF->proto = UIP_PROTO_TCP;
1524
1525 BUF->srcport = uip_connr->lport;
1526 BUF->destport = uip_connr->rport;
1527
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001528 BUF->srcipaddr[0] = uip_hostaddr[0];
1529 BUF->srcipaddr[1] = uip_hostaddr[1];
1530 BUF->destipaddr[0] = uip_connr->ripaddr[0];
1531 BUF->destipaddr[1] = uip_connr->ripaddr[1];
1532
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001533
1534 if(uip_connr->tcpstateflags & UIP_STOPPED) {
1535 /* If the connection has issued uip_stop(), we advertise a zero
1536 window so that the remote host will stop sending data. */
1537 BUF->wnd[0] = BUF->wnd[1] = 0;
1538 } else {
adamdunkelsb489e7a2003-10-14 11:12:50 +00001539 BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8);
1540 BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001541 }
1542
1543 tcp_send_noconn:
1544
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001545 BUF->len[0] = (uip_len >> 8);
1546 BUF->len[1] = (uip_len & 0xff);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001547
adamdunkels9fad4132004-06-06 06:14:19 +00001548 BUF->urgp[0] = BUF->urgp[1] = 0;
1549
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001550 /* Calculate TCP checksum. */
1551 BUF->tcpchksum = 0;
1552 BUF->tcpchksum = ~(uip_tcpchksum());
1553
1554 ip_send_nolen:
1555
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001556 BUF->vhl = 0x45;
1557 BUF->tos = 0;
1558 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
1559 BUF->ttl = UIP_TTL;
1560 ++ipid;
1561 BUF->ipid[0] = ipid >> 8;
1562 BUF->ipid[1] = ipid & 0xff;
1563
1564 /* Calculate IP checksum. */
1565 BUF->ipchksum = 0;
1566 BUF->ipchksum = ~(uip_ipchksum());
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001567
1568 UIP_STAT(++uip_stat.tcp.sent);
1569 send:
adamdunkels9fad4132004-06-06 06:14:19 +00001570
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001571 UIP_STAT(++uip_stat.ip.sent);
1572 /* Return and let the caller do the actual transmission. */
1573 return;
1574 drop:
1575 uip_len = 0;
1576 return;
1577}
1578/*-----------------------------------------------------------------------------------*/
adamdunkels47ec7fa2003-03-28 12:11:17 +00001579u16_t
1580htons(u16_t val)
1581{
1582 return HTONS(val);
1583}
1584/*-----------------------------------------------------------------------------------*/
adamdunkels0170b082003-10-01 11:25:37 +00001585/** @} */