blob: 0664f716bfcfbba0bc60ea498ec3396adf409727 [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 *
oliverschmidt7cd06bb2005-02-23 17:30:27 +000042 * $Id: uip.c,v 1.21 2005/02/23 17:30:27 oliverschmidt 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 */
adamdunkels049a9122005-02-07 06:59:39 +0000110u8_t *uip_appdata; /* The uip_appdata pointer points to
111 application data. */
oliverschmidt7cd06bb2005-02-23 17:30:27 +0000112
adamdunkels049a9122005-02-07 06:59:39 +0000113u8_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
oliverschmidt7cd06bb2005-02-23 17:30:27 +0000123u16_t uip_len, uip_slen; /* The uip_len is either 8 or 16 bits,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000124 depending on the maximum packet
125 size. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000126
oliverschmidt7cd06bb2005-02-23 17:30:27 +0000127u8_t uip_flags; /* The uip_flags variable is used for
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000128 communication between the TCP/IP stack
129 and the application program. */
oliverschmidt7cd06bb2005-02-23 17:30:27 +0000130
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000131struct 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. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000151#if UIP_ACTIVE_OPEN
adamdunkelsb489e7a2003-10-14 11:12:50 +0000152static u16_t lastport; /* Keeps track of the last port used for
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000153 a new connection. */
154#endif /* UIP_ACTIVE_OPEN */
155
156/* Temporary variables. */
adamdunkels9fad4132004-06-06 06:14:19 +0000157u8_t uip_acc32[4];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000158static u8_t c, opt;
adamdunkels0170b082003-10-01 11:25:37 +0000159static u16_t tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000160
161/* Structures and definitions. */
162#define TCP_FIN 0x01
163#define TCP_SYN 0x02
164#define TCP_RST 0x04
165#define TCP_PSH 0x08
166#define TCP_ACK 0x10
167#define TCP_URG 0x20
168#define TCP_CTL 0x3f
169
adamdunkels049a9122005-02-07 06:59:39 +0000170#define TCP_OPT_END 0 /* End of TCP options list */
171#define TCP_OPT_NOOP 1 /* "No-operation" TCP option */
172#define TCP_OPT_MSS 2 /* Maximum segment size TCP option */
173
174#define TCP_OPT_MSS_LEN 4 /* Length of TCP MSS option. */
175
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000176#define ICMP_ECHO_REPLY 0
177#define ICMP_ECHO 8
178
179/* Macros. */
180#define BUF ((uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
181#define FBUF ((uip_tcpip_hdr *)&uip_reassbuf[0])
182#define ICMPBUF ((uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
183#define UDPBUF ((uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])
184
185#if UIP_STATISTICS == 1
186struct uip_stats uip_stat;
187#define UIP_STAT(s) s
188#else
189#define UIP_STAT(s)
190#endif /* UIP_STATISTICS == 1 */
191
192#if UIP_LOGGING == 1
193#include <stdio.h>
194void uip_log(char *msg);
195#define UIP_LOG(m) uip_log(m)
196#else
197#define UIP_LOG(m)
198#endif /* UIP_LOGGING == 1 */
199
200/*-----------------------------------------------------------------------------------*/
201void
202uip_init(void)
203{
204 for(c = 0; c < UIP_LISTENPORTS; ++c) {
205 uip_listenports[c] = 0;
206 }
207 for(c = 0; c < UIP_CONNS; ++c) {
208 uip_conns[c].tcpstateflags = CLOSED;
209 }
210#if UIP_ACTIVE_OPEN
211 lastport = 1024;
212#endif /* UIP_ACTIVE_OPEN */
213
214#if UIP_UDP
215 for(c = 0; c < UIP_UDP_CONNS; ++c) {
216 uip_udp_conns[c].lport = 0;
217 }
218#endif /* UIP_UDP */
219
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000220
221 /* IPv4 initialization. */
222#if UIP_FIXEDADDR == 0
adamdunkels049a9122005-02-07 06:59:39 +0000223 /* uip_hostaddr[0] = uip_hostaddr[1] = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000224#endif /* UIP_FIXEDADDR */
adamdunkelsa38da252003-08-20 20:56:54 +0000225
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000226}
227/*-----------------------------------------------------------------------------------*/
228#if UIP_ACTIVE_OPEN
229struct uip_conn *
230uip_connect(u16_t *ripaddr, u16_t rport)
231{
adamdunkelsa38da252003-08-20 20:56:54 +0000232 register struct uip_conn *conn, *cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000233
234 /* Find an unused local port. */
235 again:
236 ++lastport;
237
238 if(lastport >= 32000) {
239 lastport = 4096;
240 }
adamdunkels1e45c6d2003-09-02 21:47:27 +0000241
242 /* Check if this port is already in use, and if so try to find
243 another one. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000244 for(c = 0; c < UIP_CONNS; ++c) {
adamdunkels23664022003-08-05 13:51:50 +0000245 conn = &uip_conns[c];
246 if(conn->tcpstateflags != CLOSED &&
adamdunkels1e45c6d2003-09-02 21:47:27 +0000247 conn->lport == htons(lastport)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000248 goto again;
adamdunkelsa38da252003-08-20 20:56:54 +0000249 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000250 }
251
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000252 conn = 0;
253 for(c = 0; c < UIP_CONNS; ++c) {
adamdunkelsa38da252003-08-20 20:56:54 +0000254 cconn = &uip_conns[c];
255 if(cconn->tcpstateflags == CLOSED) {
256 conn = cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000257 break;
258 }
adamdunkelsa38da252003-08-20 20:56:54 +0000259 if(cconn->tcpstateflags == TIME_WAIT) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000260 if(conn == 0 ||
adamdunkels75b9d002004-09-17 20:48:39 +0000261 cconn->timer > conn->timer) {
adamdunkelsa38da252003-08-20 20:56:54 +0000262 conn = cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000263 }
264 }
265 }
266
267 if(conn == 0) {
268 return 0;
269 }
270
271 conn->tcpstateflags = SYN_SENT;
272
273 conn->snd_nxt[0] = iss[0];
274 conn->snd_nxt[1] = iss[1];
275 conn->snd_nxt[2] = iss[2];
276 conn->snd_nxt[3] = iss[3];
277
adamdunkels0170b082003-10-01 11:25:37 +0000278 conn->initialmss = conn->mss = UIP_TCP_MSS;
adamdunkelsd962db42003-08-21 18:10:21 +0000279
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000280 conn->len = 1; /* TCP length of the SYN is one. */
281 conn->nrtx = 0;
282 conn->timer = 1; /* Send the SYN next time around. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000283 conn->rto = UIP_RTO;
284 conn->sa = 0;
adamdunkels049a9122005-02-07 06:59:39 +0000285 conn->sv = 16; /* Initial value of the RTT variance. */
adamdunkels1e45c6d2003-09-02 21:47:27 +0000286 conn->lport = htons(lastport);
287 conn->rport = rport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000288 conn->ripaddr[0] = ripaddr[0];
289 conn->ripaddr[1] = ripaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000290
291 return conn;
292}
293#endif /* UIP_ACTIVE_OPEN */
294/*-----------------------------------------------------------------------------------*/
295#if UIP_UDP
296struct uip_udp_conn *
297uip_udp_new(u16_t *ripaddr, u16_t rport)
298{
adamdunkels23664022003-08-05 13:51:50 +0000299 register struct uip_udp_conn *conn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000300
301 /* Find an unused local port. */
302 again:
303 ++lastport;
304
305 if(lastport >= 32000) {
306 lastport = 4096;
307 }
308
309 for(c = 0; c < UIP_UDP_CONNS; ++c) {
adamdunkels049a9122005-02-07 06:59:39 +0000310 if(uip_udp_conns[c].lport == htons(lastport)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000311 goto again;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000312 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000313 }
314
315
316 conn = 0;
317 for(c = 0; c < UIP_UDP_CONNS; ++c) {
318 if(uip_udp_conns[c].lport == 0) {
319 conn = &uip_udp_conns[c];
320 break;
321 }
322 }
323
324 if(conn == 0) {
325 return 0;
326 }
327
adamdunkels47ec7fa2003-03-28 12:11:17 +0000328 conn->lport = HTONS(lastport);
adamdunkels75b9d002004-09-17 20:48:39 +0000329 conn->rport = rport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000330 conn->ripaddr[0] = ripaddr[0];
331 conn->ripaddr[1] = ripaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000332
333 return conn;
334}
335#endif /* UIP_UDP */
336/*-----------------------------------------------------------------------------------*/
337void
adamdunkelscd8c3a22003-08-13 22:52:48 +0000338uip_unlisten(u16_t port)
339{
340 for(c = 0; c < UIP_LISTENPORTS; ++c) {
341 if(uip_listenports[c] == port) {
342 uip_listenports[c] = 0;
343 return;
344 }
345 }
346}
347/*-----------------------------------------------------------------------------------*/
348void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000349uip_listen(u16_t port)
350{
351 for(c = 0; c < UIP_LISTENPORTS; ++c) {
352 if(uip_listenports[c] == 0) {
adamdunkels1e45c6d2003-09-02 21:47:27 +0000353 uip_listenports[c] = port;
adamdunkelscd8c3a22003-08-13 22:52:48 +0000354 return;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000355 }
356 }
357}
358/*-----------------------------------------------------------------------------------*/
adamdunkelsb489e7a2003-10-14 11:12:50 +0000359/* XXX: IP fragment reassembly: not well-tested. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000360
361#if UIP_REASSEMBLY
362#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)
363static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];
364static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];
365static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f,
366 0x0f, 0x07, 0x03, 0x01};
367static u16_t uip_reasslen;
368static u8_t uip_reassflags;
369#define UIP_REASS_FLAG_LASTFRAG 0x01
370static u8_t uip_reasstmr;
371
adamdunkelsb489e7a2003-10-14 11:12:50 +0000372#define IP_MF 0x20
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000373
374static u8_t
375uip_reass(void)
376{
377 u16_t offset, len;
378 u16_t i;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000379
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000380 /* If ip_reasstmr is zero, no packet is present in the buffer, so we
381 write the IP header of the fragment into the reassembly
382 buffer. The timer is updated with the maximum age. */
383 if(uip_reasstmr == 0) {
adamdunkels31a50262005-02-22 22:33:56 +0000384 memcpy(uip_reassbuf, &BUF->vhl, UIP_IPH_LEN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000385 uip_reasstmr = UIP_REASS_MAXAGE;
386 uip_reassflags = 0;
387 /* Clear the bitmap. */
adamdunkels31a50262005-02-22 22:33:56 +0000388 memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap));
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000389 }
390
391 /* Check if the incoming fragment matches the one currently present
392 in the reasembly buffer. If so, we proceed with copying the
393 fragment into the buffer. */
394 if(BUF->srcipaddr[0] == FBUF->srcipaddr[0] &&
adamdunkelsb489e7a2003-10-14 11:12:50 +0000395 BUF->srcipaddr[1] == FBUF->srcipaddr[1] &&
396 BUF->destipaddr[0] == FBUF->destipaddr[0] &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000397 BUF->destipaddr[1] == FBUF->destipaddr[1] &&
adamdunkelsb489e7a2003-10-14 11:12:50 +0000398 BUF->ipid[0] == FBUF->ipid[0] &&
399 BUF->ipid[1] == FBUF->ipid[1]) {
400
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000401 len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4;
402 offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8;
403
404 /* If the offset or the offset + fragment length overflows the
405 reassembly buffer, we discard the entire packet. */
406 if(offset > UIP_REASS_BUFSIZE ||
407 offset + len > UIP_REASS_BUFSIZE) {
408 uip_reasstmr = 0;
409 goto nullreturn;
410 }
411
412 /* Copy the fragment into the reassembly buffer, at the right
413 offset. */
adamdunkels31a50262005-02-22 22:33:56 +0000414 memcpy(&uip_reassbuf[UIP_IPH_LEN + offset],
adamdunkelsb489e7a2003-10-14 11:12:50 +0000415 (char *)BUF + (int)((BUF->vhl & 0x0f) * 4),
416 len);
417
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000418 /* Update the bitmap. */
419 if(offset / (8 * 8) == (offset + len) / (8 * 8)) {
420 /* If the two endpoints are in the same byte, we only update
421 that byte. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000422
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000423 uip_reassbitmap[offset / (8 * 8)] |=
adamdunkelsb489e7a2003-10-14 11:12:50 +0000424 bitmap_bits[(offset / 8 ) & 7] &
425 ~bitmap_bits[((offset + len) / 8 ) & 7];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000426 } else {
427 /* If the two endpoints are in different bytes, we update the
428 bytes in the endpoints and fill the stuff inbetween with
429 0xff. */
430 uip_reassbitmap[offset / (8 * 8)] |=
431 bitmap_bits[(offset / 8 ) & 7];
432 for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
433 uip_reassbitmap[i] = 0xff;
434 }
435 uip_reassbitmap[(offset + len) / (8 * 8)] |=
436 ~bitmap_bits[((offset + len) / 8 ) & 7];
437 }
438
439 /* If this fragment has the More Fragments flag set to zero, we
440 know that this is the last fragment, so we can calculate the
441 size of the entire packet. We also set the
442 IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
443 the final fragment. */
444
445 if((BUF->ipoffset[0] & IP_MF) == 0) {
446 uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
447 uip_reasslen = offset + len;
448 }
449
450 /* Finally, we check if we have a full packet in the buffer. We do
451 this by checking if we have the last fragment and if all bits
452 in the bitmap are set. */
453 if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) {
454 /* Check all bytes up to and including all but the last byte in
455 the bitmap. */
456 for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) {
457 if(uip_reassbitmap[i] != 0xff) {
458 goto nullreturn;
459 }
460 }
461 /* Check the last byte in the bitmap. It should contain just the
462 right amount of bits. */
463 if(uip_reassbitmap[uip_reasslen / (8 * 8)] !=
464 (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) {
465 goto nullreturn;
466 }
467
468 /* If we have come this far, we have a full packet in the
469 buffer, so we allocate a pbuf and copy the packet into it. We
470 also reset the timer. */
471 uip_reasstmr = 0;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000472 memcpy(BUF, FBUF, uip_reasslen);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000473
474 /* Pretend to be a "normal" (i.e., not fragmented) IP packet
475 from now on. */
476 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000477 BUF->len[0] = uip_reasslen >> 8;
478 BUF->len[1] = uip_reasslen & 0xff;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000479 BUF->ipchksum = 0;
480 BUF->ipchksum = ~(uip_ipchksum());
481
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000482 return uip_reasslen;
483 }
484 }
485
486 nullreturn:
487 return 0;
488}
adamdunkels049a9122005-02-07 06:59:39 +0000489#endif /* UIP_REASSEMBLY */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000490/*-----------------------------------------------------------------------------------*/
491static void
492uip_add_rcv_nxt(u16_t n)
493{
494 uip_add32(uip_conn->rcv_nxt, n);
495 uip_conn->rcv_nxt[0] = uip_acc32[0];
496 uip_conn->rcv_nxt[1] = uip_acc32[1];
497 uip_conn->rcv_nxt[2] = uip_acc32[2];
498 uip_conn->rcv_nxt[3] = uip_acc32[3];
499}
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000500/*-----------------------------------------------------------------------------------*/
501void
502uip_process(u8_t flag)
503{
504 register struct uip_conn *uip_connr = uip_conn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000505
adamdunkels049a9122005-02-07 06:59:39 +0000506 uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000507
508 /* Check if we were invoked because of the perodic timer fireing. */
509 if(flag == UIP_TIMER) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000510#if UIP_REASSEMBLY
511 if(uip_reasstmr != 0) {
512 --uip_reasstmr;
513 }
514#endif /* UIP_REASSEMBLY */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000515 /* Increase the initial sequence number. */
516 if(++iss[3] == 0) {
517 if(++iss[2] == 0) {
518 if(++iss[1] == 0) {
519 ++iss[0];
520 }
521 }
522 }
523 uip_len = 0;
524 if(uip_connr->tcpstateflags == TIME_WAIT ||
525 uip_connr->tcpstateflags == FIN_WAIT_2) {
526 ++(uip_connr->timer);
527 if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) {
528 uip_connr->tcpstateflags = CLOSED;
529 }
530 } else if(uip_connr->tcpstateflags != CLOSED) {
531 /* If the connection has outstanding data, we increase the
532 connection's timer and see if it has reached the RTO value
533 in which case we retransmit. */
534 if(uip_outstanding(uip_connr)) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000535 if(uip_connr->timer-- == 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000536 if(uip_connr->nrtx == UIP_MAXRTX ||
537 ((uip_connr->tcpstateflags == SYN_SENT ||
538 uip_connr->tcpstateflags == SYN_RCVD) &&
539 uip_connr->nrtx == UIP_MAXSYNRTX)) {
540 uip_connr->tcpstateflags = CLOSED;
541
542 /* We call UIP_APPCALL() with uip_flags set to
543 UIP_TIMEDOUT to inform the application that the
544 connection has timed out. */
545 uip_flags = UIP_TIMEDOUT;
546 UIP_APPCALL();
547
548 /* We also send a reset packet to the remote host. */
549 BUF->flags = TCP_RST | TCP_ACK;
550 goto tcp_send_nodata;
551 }
552
553 /* Exponential backoff. */
adamdunkels47ec7fa2003-03-28 12:11:17 +0000554 uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4?
555 4:
556 uip_connr->nrtx);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000557 ++(uip_connr->nrtx);
558
559 /* Ok, so we need to retransmit. We do this differently
560 depending on which state we are in. In ESTABLISHED, we
561 call upon the application so that it may prepare the
562 data for the retransmit. In SYN_RCVD, we resend the
563 SYNACK that we sent earlier and in LAST_ACK we have to
564 retransmit our FINACK. */
565 UIP_STAT(++uip_stat.tcp.rexmit);
566 switch(uip_connr->tcpstateflags & TS_MASK) {
567 case SYN_RCVD:
568 /* In the SYN_RCVD state, we should retransmit our
569 SYNACK. */
570 goto tcp_send_synack;
571
572#if UIP_ACTIVE_OPEN
573 case SYN_SENT:
574 /* In the SYN_SENT state, we retransmit out SYN. */
575 BUF->flags = 0;
576 goto tcp_send_syn;
577#endif /* UIP_ACTIVE_OPEN */
578
579 case ESTABLISHED:
580 /* In the ESTABLISHED state, we call upon the application
581 to do the actual retransmit after which we jump into
582 the code for sending out the packet (the apprexmit
583 label). */
584 uip_len = 0;
585 uip_slen = 0;
586 uip_flags = UIP_REXMIT;
587 UIP_APPCALL();
588 goto apprexmit;
589
590 case FIN_WAIT_1:
591 case CLOSING:
592 case LAST_ACK:
593 /* In all these states we should retransmit a FINACK. */
594 goto tcp_send_finack;
595
596 }
597 }
598 } else if((uip_connr->tcpstateflags & TS_MASK) == ESTABLISHED) {
599 /* If there was no need for a retransmission, we poll the
600 application for new data. */
601 uip_len = 0;
602 uip_slen = 0;
603 uip_flags = UIP_POLL;
604 UIP_APPCALL();
605 goto appsend;
606 }
607 }
608 goto drop;
609 }
610#if UIP_UDP
611 if(flag == UIP_UDP_TIMER) {
612 if(uip_udp_conn->lport != 0) {
adamdunkels399a0782004-02-16 20:52:07 +0000613 uip_conn = NULL;
adamdunkels049a9122005-02-07 06:59:39 +0000614 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000615 uip_len = uip_slen = 0;
616 uip_flags = UIP_POLL;
617 UIP_UDP_APPCALL();
618 goto udp_send;
619 } else {
620 goto drop;
621 }
622 }
623#endif
624
625 /* This is where the input processing starts. */
626 UIP_STAT(++uip_stat.ip.recv);
627
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000628
629 /* Start of IPv4 input header processing code. */
630
631 /* Check validity of the IP header. */
632 if(BUF->vhl != 0x45) { /* IP version and header length. */
633 UIP_STAT(++uip_stat.ip.drop);
634 UIP_STAT(++uip_stat.ip.vhlerr);
635 UIP_LOG("ip: invalid version or header length.");
636 goto drop;
637 }
638
639 /* Check the size of the packet. If the size reported to us in
adamdunkels049a9122005-02-07 06:59:39 +0000640 uip_len is smaller the size reported in the IP header, we assume
641 that the packet has been corrupted in transit. If the size of
642 uip_len is larger than the size reported in the IP packet header,
643 the packet has been padded and we set uip_len to the correct
644 value.. */
645
646 if((BUF->len[0] << 8) + BUF->len[1] <= uip_len) {
647 uip_len = (BUF->len[0] << 8) + BUF->len[1];
648 } else {
649 UIP_LOG("ip: packet shorter than reported in IP header.");
650 goto drop;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000651 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000652
adamdunkelsb489e7a2003-10-14 11:12:50 +0000653 /* Check the fragment flag. */
654 if((BUF->ipoffset[0] & 0x3f) != 0 ||
655 BUF->ipoffset[1] != 0) {
656#if UIP_REASSEMBLY
657 uip_len = uip_reass();
658 if(uip_len == 0) {
659 goto drop;
660 }
661#else
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000662 UIP_STAT(++uip_stat.ip.drop);
663 UIP_STAT(++uip_stat.ip.fragerr);
664 UIP_LOG("ip: fragment dropped.");
665 goto drop;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000666#endif /* UIP_REASSEMBLY */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000667 }
668
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000669 if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
adamdunkels75b9d002004-09-17 20:48:39 +0000670 /* If we are configured to use ping IP address configuration and
671 hasn't been assigned an IP address yet, we accept all ICMP
672 packets. */
673#if UIP_PINGADDRCONF
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000674 if(BUF->proto == UIP_PROTO_ICMP) {
675 UIP_LOG("ip: possible ping config packet received.");
676 goto icmp_input;
677 } else {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000678 UIP_LOG("ip: packet dropped since no address assigned.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000679 goto drop;
adamdunkels75b9d002004-09-17 20:48:39 +0000680 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000681#endif /* UIP_PINGADDRCONF */
adamdunkels9fad4132004-06-06 06:14:19 +0000682
adamdunkels75b9d002004-09-17 20:48:39 +0000683 } else {
684 /* If IP broadcast support is configured, we check for a broadcast
685 UDP packet, which may be destined to us. */
adamdunkels9fad4132004-06-06 06:14:19 +0000686#if UIP_BROADCAST
adamdunkels75b9d002004-09-17 20:48:39 +0000687 if(BUF->proto == UIP_PROTO_UDP &&
688 BUF->destipaddr[0] == 0xffff &&
adamdunkels9fad4132004-06-06 06:14:19 +0000689 BUF->destipaddr[1] == 0xffff &&
adamdunkels75b9d002004-09-17 20:48:39 +0000690 uip_ipchksum() == 0xffff) {
691 goto udp_input;
692 }
adamdunkels9fad4132004-06-06 06:14:19 +0000693#endif /* UIP_BROADCAST */
adamdunkels75b9d002004-09-17 20:48:39 +0000694
695 /* Check if the packet is destined for our IP address. */
696 if(BUF->destipaddr[0] != uip_hostaddr[0]) {
697 UIP_STAT(++uip_stat.ip.drop);
adamdunkels75b9d002004-09-17 20:48:39 +0000698 goto drop;
699 }
700 if(BUF->destipaddr[1] != uip_hostaddr[1]) {
701 UIP_STAT(++uip_stat.ip.drop);
adamdunkels75b9d002004-09-17 20:48:39 +0000702 goto drop;
703 }
704 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000705
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000706 if(uip_ipchksum() != 0xffff) { /* Compute and check the IP header
707 checksum. */
708 UIP_STAT(++uip_stat.ip.drop);
709 UIP_STAT(++uip_stat.ip.chkerr);
adamdunkels9fad4132004-06-06 06:14:19 +0000710 UIP_LOG("ip: bad checksum.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000711 goto drop;
712 }
713
adamdunkels049a9122005-02-07 06:59:39 +0000714 if(BUF->proto == UIP_PROTO_TCP) { /* Check for TCP packet. If so,
715 proceed with TCP input
716 processing. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000717 goto tcp_input;
adamdunkels049a9122005-02-07 06:59:39 +0000718 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000719
720#if UIP_UDP
adamdunkels049a9122005-02-07 06:59:39 +0000721 if(BUF->proto == UIP_PROTO_UDP) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000722 goto udp_input;
adamdunkels049a9122005-02-07 06:59:39 +0000723 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000724#endif /* UIP_UDP */
725
726 if(BUF->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from
727 here. */
728 UIP_STAT(++uip_stat.ip.drop);
729 UIP_STAT(++uip_stat.ip.protoerr);
730 UIP_LOG("ip: neither tcp nor icmp.");
731 goto drop;
732 }
733
734 icmp_input:
735 UIP_STAT(++uip_stat.icmp.recv);
736
737 /* ICMP echo (i.e., ping) processing. This is simple, we only change
738 the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
739 checksum before we return the packet. */
740 if(ICMPBUF->type != ICMP_ECHO) {
741 UIP_STAT(++uip_stat.icmp.drop);
742 UIP_STAT(++uip_stat.icmp.typeerr);
743 UIP_LOG("icmp: not icmp echo.");
744 goto drop;
745 }
746
747 /* If we are configured to use ping IP address assignment, we use
748 the destination IP address of this ping packet and assign it to
749 ourself. */
750#if UIP_PINGADDRCONF
751 if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
752 uip_hostaddr[0] = BUF->destipaddr[0];
753 uip_hostaddr[1] = BUF->destipaddr[1];
754 }
755#endif /* UIP_PINGADDRCONF */
756
757 ICMPBUF->type = ICMP_ECHO_REPLY;
758
adamdunkels47ec7fa2003-03-28 12:11:17 +0000759 if(ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) {
760 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000761 } else {
adamdunkels47ec7fa2003-03-28 12:11:17 +0000762 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000763 }
764
765 /* Swap IP addresses. */
adamdunkels0170b082003-10-01 11:25:37 +0000766 tmp16 = BUF->destipaddr[0];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000767 BUF->destipaddr[0] = BUF->srcipaddr[0];
adamdunkels0170b082003-10-01 11:25:37 +0000768 BUF->srcipaddr[0] = tmp16;
769 tmp16 = BUF->destipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000770 BUF->destipaddr[1] = BUF->srcipaddr[1];
adamdunkels0170b082003-10-01 11:25:37 +0000771 BUF->srcipaddr[1] = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000772
773 UIP_STAT(++uip_stat.icmp.sent);
774 goto send;
775
776 /* End of IPv4 input header processing code. */
777
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000778
779#if UIP_UDP
780 /* UDP input processing. */
781 udp_input:
782 /* UDP processing is really just a hack. We don't do anything to the
783 UDP/IP headers, but let the UDP application do all the hard
784 work. If the application sets uip_slen, it has a packet to
785 send. */
786#if UIP_UDP_CHECKSUMS
adamdunkels049a9122005-02-07 06:59:39 +0000787 uip_len = uip_len - UIP_IPTCPH_LEN;
788 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];
789 if(uip_udpchksum() != 0xffff) {
790 printf("checksum 0x%04x\n", uip_udpchksum());
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000791 UIP_STAT(++uip_stat.udp.drop);
792 UIP_STAT(++uip_stat.udp.chkerr);
793 UIP_LOG("udp: bad checksum.");
794 goto drop;
adamdunkels049a9122005-02-07 06:59:39 +0000795 }
796 uip_len = uip_len + (UIP_IPTCPH_LEN - UIP_IPUDPH_LEN);
797#else /* UIP_UDP_CHECKSUMS */
798 uip_len = uip_len - UIP_IPUDPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000799#endif /* UIP_UDP_CHECKSUMS */
800
801 /* Demultiplex this UDP packet between the UDP "connections". */
802 for(uip_udp_conn = &uip_udp_conns[0];
803 uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS];
804 ++uip_udp_conn) {
adamdunkels9fad4132004-06-06 06:14:19 +0000805 /* If the local UDP port is non-zero, the connection is considered
806 to be used. If so, the local port number is checked against the
807 destination port number in the received packet. If the two port
808 numbers match, the remote port number is checked if the
809 connection is bound to a remote port. Finally, if the
810 connection is bound to a remote IP address, the source IP
811 address of the packet is checked. */
812 if(uip_udp_conn->lport != 0 &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000813 UDPBUF->destport == uip_udp_conn->lport &&
814 (uip_udp_conn->rport == 0 ||
815 UDPBUF->srcport == uip_udp_conn->rport) &&
adamdunkels9fad4132004-06-06 06:14:19 +0000816 ((uip_udp_conn->ripaddr[0] | uip_udp_conn->ripaddr[1]) == 0 ||
817 (uip_udp_conn->ripaddr[0] == 0xffff &&
818 uip_udp_conn->ripaddr[1] == 0xffff) ||
819 uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000820 goto udp_found;
821 }
822 }
adamdunkels9fad4132004-06-06 06:14:19 +0000823 UIP_LOG("udp: no matching connection found");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000824 goto drop;
825
826 udp_found:
adamdunkels399a0782004-02-16 20:52:07 +0000827 uip_conn = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000828 uip_flags = UIP_NEWDATA;
adamdunkels049a9122005-02-07 06:59:39 +0000829 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000830 uip_slen = 0;
831 UIP_UDP_APPCALL();
832 udp_send:
833 if(uip_slen == 0) {
834 goto drop;
835 }
adamdunkels049a9122005-02-07 06:59:39 +0000836 uip_len = uip_slen + UIP_IPUDPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000837
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000838 BUF->len[0] = (uip_len >> 8);
839 BUF->len[1] = (uip_len & 0xff);
adamdunkelsb489e7a2003-10-14 11:12:50 +0000840
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000841 BUF->proto = UIP_PROTO_UDP;
842
adamdunkels049a9122005-02-07 06:59:39 +0000843 UDPBUF->udplen = HTONS(uip_slen + UIP_UDPH_LEN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000844 UDPBUF->udpchksum = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000845
846 BUF->srcport = uip_udp_conn->lport;
847 BUF->destport = uip_udp_conn->rport;
848
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000849 BUF->srcipaddr[0] = uip_hostaddr[0];
850 BUF->srcipaddr[1] = uip_hostaddr[1];
851 BUF->destipaddr[0] = uip_udp_conn->ripaddr[0];
852 BUF->destipaddr[1] = uip_udp_conn->ripaddr[1];
853
adamdunkels049a9122005-02-07 06:59:39 +0000854 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];
adamdunkelsc4b80c52004-09-18 20:17:01 +0000855
856#if UIP_UDP_CHECKSUMS
857 /* Calculate UDP checksum. */
858 UDPBUF->udpchksum = ~(uip_udpchksum());
859 if(UDPBUF->udpchksum == 0) {
860 UDPBUF->udpchksum = 0xffff;
861 }
862#endif /* UIP_UDP_CHECKSUMS */
863
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000864 goto ip_send_nolen;
865#endif /* UIP_UDP */
866
867 /* TCP input processing. */
868 tcp_input:
869 UIP_STAT(++uip_stat.tcp.recv);
870
871 /* Start of TCP input header processing code. */
872
873 if(uip_tcpchksum() != 0xffff) { /* Compute and check the TCP
874 checksum. */
875 UIP_STAT(++uip_stat.tcp.drop);
876 UIP_STAT(++uip_stat.tcp.chkerr);
adamdunkels9fad4132004-06-06 06:14:19 +0000877 UIP_LOG("tcp: bad checksum.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000878 goto drop;
879 }
880
adamdunkels9fad4132004-06-06 06:14:19 +0000881
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000882 /* Demultiplex this segment. */
883 /* First check any active connections. */
adamdunkels049a9122005-02-07 06:59:39 +0000884 for(uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1];
885 ++uip_connr) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000886 if(uip_connr->tcpstateflags != CLOSED &&
887 BUF->destport == uip_connr->lport &&
888 BUF->srcport == uip_connr->rport &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000889 BUF->srcipaddr[0] == uip_connr->ripaddr[0] &&
890 BUF->srcipaddr[1] == uip_connr->ripaddr[1]) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000891 goto found;
892 }
893 }
894
895 /* If we didn't find and active connection that expected the packet,
896 either this packet is an old duplicate, or this is a SYN packet
897 destined for a connection in LISTEN. If the SYN flag isn't set,
898 it is an old packet and we send a RST. */
adamdunkels049a9122005-02-07 06:59:39 +0000899 if((BUF->flags & TCP_CTL) != TCP_SYN) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000900 goto reset;
adamdunkels049a9122005-02-07 06:59:39 +0000901 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000902
adamdunkels0170b082003-10-01 11:25:37 +0000903 tmp16 = BUF->destport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000904 /* Next, check listening connections. */
adamdunkelscd8c3a22003-08-13 22:52:48 +0000905 for(c = 0; c < UIP_LISTENPORTS; ++c) {
adamdunkels0170b082003-10-01 11:25:37 +0000906 if(tmp16 == uip_listenports[c])
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000907 goto found_listen;
908 }
909
910 /* No matching connection found, so we send a RST packet. */
911 UIP_STAT(++uip_stat.tcp.synrst);
912 reset:
913
914 /* We do not send resets in response to resets. */
adamdunkels049a9122005-02-07 06:59:39 +0000915 if(BUF->flags & TCP_RST) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000916 goto drop;
adamdunkels049a9122005-02-07 06:59:39 +0000917 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000918
919 UIP_STAT(++uip_stat.tcp.rst);
920
921 BUF->flags = TCP_RST | TCP_ACK;
adamdunkels049a9122005-02-07 06:59:39 +0000922 uip_len = UIP_IPTCPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000923 BUF->tcpoffset = 5 << 4;
924
925 /* Flip the seqno and ackno fields in the TCP header. */
926 c = BUF->seqno[3];
927 BUF->seqno[3] = BUF->ackno[3];
928 BUF->ackno[3] = c;
929
930 c = BUF->seqno[2];
931 BUF->seqno[2] = BUF->ackno[2];
932 BUF->ackno[2] = c;
933
934 c = BUF->seqno[1];
935 BUF->seqno[1] = BUF->ackno[1];
936 BUF->ackno[1] = c;
937
938 c = BUF->seqno[0];
939 BUF->seqno[0] = BUF->ackno[0];
940 BUF->ackno[0] = c;
941
942 /* We also have to increase the sequence number we are
943 acknowledging. If the least significant byte overflowed, we need
944 to propagate the carry to the other bytes as well. */
945 if(++BUF->ackno[3] == 0) {
946 if(++BUF->ackno[2] == 0) {
947 if(++BUF->ackno[1] == 0) {
948 ++BUF->ackno[0];
949 }
950 }
951 }
952
953 /* Swap port numbers. */
adamdunkels0170b082003-10-01 11:25:37 +0000954 tmp16 = BUF->srcport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000955 BUF->srcport = BUF->destport;
adamdunkels0170b082003-10-01 11:25:37 +0000956 BUF->destport = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000957
958 /* Swap IP addresses. */
adamdunkels0170b082003-10-01 11:25:37 +0000959 tmp16 = BUF->destipaddr[0];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000960 BUF->destipaddr[0] = BUF->srcipaddr[0];
adamdunkels0170b082003-10-01 11:25:37 +0000961 BUF->srcipaddr[0] = tmp16;
962 tmp16 = BUF->destipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000963 BUF->destipaddr[1] = BUF->srcipaddr[1];
adamdunkels0170b082003-10-01 11:25:37 +0000964 BUF->srcipaddr[1] = tmp16;
adamdunkelsa38da252003-08-20 20:56:54 +0000965
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000966
967 /* And send out the RST packet! */
968 goto tcp_send_noconn;
969
970 /* This label will be jumped to if we matched the incoming packet
971 with a connection in LISTEN. In that case, we should create a new
972 connection and send a SYNACK in return. */
973 found_listen:
974 /* First we check if there are any connections avaliable. Unused
975 connections are kept in the same table as used connections, but
976 unused ones have the tcpstate set to CLOSED. Also, connections in
977 TIME_WAIT are kept track of and we'll use the oldest one if no
978 CLOSED connections are found. Thanks to Eddie C. Dost for a very
979 nice algorithm for the TIME_WAIT search. */
980 uip_connr = 0;
981 for(c = 0; c < UIP_CONNS; ++c) {
982 if(uip_conns[c].tcpstateflags == CLOSED) {
983 uip_connr = &uip_conns[c];
984 break;
985 }
986 if(uip_conns[c].tcpstateflags == TIME_WAIT) {
987 if(uip_connr == 0 ||
988 uip_conns[c].timer > uip_connr->timer) {
989 uip_connr = &uip_conns[c];
990 }
991 }
992 }
993
994 if(uip_connr == 0) {
995 /* All connections are used already, we drop packet and hope that
996 the remote end will retransmit the packet at a time when we
997 have more spare connections. */
998 UIP_STAT(++uip_stat.tcp.syndrop);
999 UIP_LOG("tcp: found no unused connections.");
1000 goto drop;
1001 }
1002 uip_conn = uip_connr;
1003
1004 /* Fill in the necessary fields for the new connection. */
adamdunkelsb489e7a2003-10-14 11:12:50 +00001005 uip_connr->rto = uip_connr->timer = UIP_RTO;
1006 uip_connr->sa = 0;
1007 uip_connr->sv = 4;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001008 uip_connr->nrtx = 0;
1009 uip_connr->lport = BUF->destport;
1010 uip_connr->rport = BUF->srcport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001011 uip_connr->ripaddr[0] = BUF->srcipaddr[0];
1012 uip_connr->ripaddr[1] = BUF->srcipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001013 uip_connr->tcpstateflags = SYN_RCVD;
1014
1015 uip_connr->snd_nxt[0] = iss[0];
1016 uip_connr->snd_nxt[1] = iss[1];
1017 uip_connr->snd_nxt[2] = iss[2];
1018 uip_connr->snd_nxt[3] = iss[3];
1019 uip_connr->len = 1;
1020
1021 /* rcv_nxt should be the seqno from the incoming packet + 1. */
1022 uip_connr->rcv_nxt[3] = BUF->seqno[3];
1023 uip_connr->rcv_nxt[2] = BUF->seqno[2];
1024 uip_connr->rcv_nxt[1] = BUF->seqno[1];
1025 uip_connr->rcv_nxt[0] = BUF->seqno[0];
1026 uip_add_rcv_nxt(1);
1027
1028 /* Parse the TCP MSS option, if present. */
1029 if((BUF->tcpoffset & 0xf0) > 0x50) {
1030 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
1031 opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c];
adamdunkels049a9122005-02-07 06:59:39 +00001032 if(opt == TCP_OPT_END) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001033 /* End of options. */
1034 break;
adamdunkels049a9122005-02-07 06:59:39 +00001035 } else if(opt == TCP_OPT_NOOP) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001036 ++c;
1037 /* NOP option. */
adamdunkels049a9122005-02-07 06:59:39 +00001038 } else if(opt == TCP_OPT_MSS &&
1039 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001040 /* An MSS option with the right option length. */
adamdunkels0170b082003-10-01 11:25:37 +00001041 tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
adamdunkels049a9122005-02-07 06:59:39 +00001042 (u16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c];
adamdunkels0170b082003-10-01 11:25:37 +00001043 uip_connr->initialmss = uip_connr->mss =
1044 tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001045
1046 /* And we are done processing options. */
1047 break;
1048 } else {
1049 /* All other options have a length field, so that we easily
1050 can skip past them. */
1051 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
1052 /* If the length field is zero, the options are malformed
1053 and we don't process them further. */
1054 break;
1055 }
1056 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
1057 }
1058 }
1059 }
1060
1061 /* Our response will be a SYNACK. */
1062#if UIP_ACTIVE_OPEN
1063 tcp_send_synack:
1064 BUF->flags = TCP_ACK;
1065
1066 tcp_send_syn:
1067 BUF->flags |= TCP_SYN;
1068#else /* UIP_ACTIVE_OPEN */
1069 tcp_send_synack:
1070 BUF->flags = TCP_SYN | TCP_ACK;
1071#endif /* UIP_ACTIVE_OPEN */
1072
1073 /* We send out the TCP Maximum Segment Size option with our
1074 SYNACK. */
adamdunkels049a9122005-02-07 06:59:39 +00001075 BUF->optdata[0] = TCP_OPT_MSS;
1076 BUF->optdata[1] = TCP_OPT_MSS_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001077 BUF->optdata[2] = (UIP_TCP_MSS) / 256;
1078 BUF->optdata[3] = (UIP_TCP_MSS) & 255;
adamdunkels049a9122005-02-07 06:59:39 +00001079 uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN;
1080 BUF->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001081 goto tcp_send;
1082
1083 /* This label will be jumped to if we found an active connection. */
1084 found:
1085 uip_conn = uip_connr;
1086 uip_flags = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001087 /* We do a very naive form of TCP reset processing; we just accept
1088 any RST and kill our connection. We should in fact check if the
1089 sequence number of this reset is wihtin our advertised window
1090 before we accept the reset. */
1091 if(BUF->flags & TCP_RST) {
1092 uip_connr->tcpstateflags = CLOSED;
1093 UIP_LOG("tcp: got reset, aborting connection.");
1094 uip_flags = UIP_ABORT;
1095 UIP_APPCALL();
1096 goto drop;
adamdunkels47ec7fa2003-03-28 12:11:17 +00001097 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001098 /* Calculated the length of the data, if the application has sent
1099 any data to us. */
1100 c = (BUF->tcpoffset >> 4) << 2;
1101 /* uip_len will contain the length of the actual TCP data. This is
1102 calculated by subtracing the length of the TCP header (in
1103 c) and the length of the IP header (20 bytes). */
adamdunkels049a9122005-02-07 06:59:39 +00001104 uip_len = uip_len - c - UIP_IPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001105
1106 /* First, check if the sequence number of the incoming packet is
1107 what we're expecting next. If not, we send out an ACK with the
1108 correct numbers in. */
adamdunkels049a9122005-02-07 06:59:39 +00001109 if(!(((uip_connr->tcpstateflags & TS_MASK) == SYN_SENT) &&
1110 ((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) {
1111 if((uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 0)) &&
1112 (BUF->seqno[0] != uip_connr->rcv_nxt[0] ||
1113 BUF->seqno[1] != uip_connr->rcv_nxt[1] ||
1114 BUF->seqno[2] != uip_connr->rcv_nxt[2] ||
1115 BUF->seqno[3] != uip_connr->rcv_nxt[3])) {
1116 goto tcp_send_ack;
1117 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001118 }
1119
1120 /* Next, check if the incoming segment acknowledges any outstanding
1121 data. If so, we update the sequence number, reset the length of
1122 the outstanding data, calculate RTT estimations, and reset the
1123 retransmission timer. */
adamdunkels47ec7fa2003-03-28 12:11:17 +00001124 if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001125 uip_add32(uip_connr->snd_nxt, uip_connr->len);
adamdunkels08eac9e2004-09-12 07:17:37 +00001126
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001127 if(BUF->ackno[0] == uip_acc32[0] &&
1128 BUF->ackno[1] == uip_acc32[1] &&
1129 BUF->ackno[2] == uip_acc32[2] &&
1130 BUF->ackno[3] == uip_acc32[3]) {
1131 /* Update sequence number. */
1132 uip_connr->snd_nxt[0] = uip_acc32[0];
1133 uip_connr->snd_nxt[1] = uip_acc32[1];
1134 uip_connr->snd_nxt[2] = uip_acc32[2];
1135 uip_connr->snd_nxt[3] = uip_acc32[3];
adamdunkelsa38da252003-08-20 20:56:54 +00001136
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001137
1138 /* Do RTT estimation, unless we have done retransmissions. */
1139 if(uip_connr->nrtx == 0) {
1140 signed char m;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001141 m = uip_connr->rto - uip_connr->timer;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001142 /* This is taken directly from VJs original code in his paper */
1143 m = m - (uip_connr->sa >> 3);
1144 uip_connr->sa += m;
1145 if(m < 0) {
1146 m = -m;
1147 }
1148 m = m - (uip_connr->sv >> 2);
1149 uip_connr->sv += m;
1150 uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv;
1151
1152 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001153 /* Set the acknowledged flag. */
1154 uip_flags = UIP_ACKDATA;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001155 /* Reset the retransmission timer. */
adamdunkelsb489e7a2003-10-14 11:12:50 +00001156 uip_connr->timer = uip_connr->rto;
adamdunkels08eac9e2004-09-12 07:17:37 +00001157
1158 /* Reset length of outstanding data. */
1159 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001160 }
adamdunkelsab4b0822003-07-30 23:31:40 +00001161
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001162 }
1163
1164 /* Do different things depending on in what state the connection is. */
1165 switch(uip_connr->tcpstateflags & TS_MASK) {
1166 /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
1167 implemented, since we force the application to close when the
1168 peer sends a FIN (hence the application goes directly from
1169 ESTABLISHED to LAST_ACK). */
1170 case SYN_RCVD:
1171 /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and
1172 we are waiting for an ACK that acknowledges the data we sent
1173 out the last time. Therefore, we want to have the UIP_ACKDATA
1174 flag set. If so, we enter the ESTABLISHED state. */
1175 if(uip_flags & UIP_ACKDATA) {
1176 uip_connr->tcpstateflags = ESTABLISHED;
1177 uip_flags = UIP_CONNECTED;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001178 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001179 if(uip_len > 0) {
1180 uip_flags |= UIP_NEWDATA;
1181 uip_add_rcv_nxt(uip_len);
1182 }
1183 uip_slen = 0;
1184 UIP_APPCALL();
1185 goto appsend;
1186 }
1187 goto drop;
1188#if UIP_ACTIVE_OPEN
1189 case SYN_SENT:
1190 /* In SYN_SENT, we wait for a SYNACK that is sent in response to
1191 our SYN. The rcv_nxt is set to sequence number in the SYNACK
1192 plus one, and we send an ACK. We move into the ESTABLISHED
1193 state. */
1194 if((uip_flags & UIP_ACKDATA) &&
adamdunkels049a9122005-02-07 06:59:39 +00001195 (BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001196
1197 /* Parse the TCP MSS option, if present. */
1198 if((BUF->tcpoffset & 0xf0) > 0x50) {
1199 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
adamdunkels049a9122005-02-07 06:59:39 +00001200 opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c];
1201 if(opt == TCP_OPT_END) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001202 /* End of options. */
1203 break;
adamdunkels049a9122005-02-07 06:59:39 +00001204 } else if(opt == TCP_OPT_NOOP) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001205 ++c;
1206 /* NOP option. */
adamdunkels049a9122005-02-07 06:59:39 +00001207 } else if(opt == TCP_OPT_MSS &&
1208 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001209 /* An MSS option with the right option length. */
adamdunkels0170b082003-10-01 11:25:37 +00001210 tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001211 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];
adamdunkels0170b082003-10-01 11:25:37 +00001212 uip_connr->initialmss =
1213 uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001214
1215 /* And we are done processing options. */
1216 break;
1217 } else {
1218 /* All other options have a length field, so that we easily
1219 can skip past them. */
1220 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
1221 /* If the length field is zero, the options are malformed
1222 and we don't process them further. */
1223 break;
1224 }
1225 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
1226 }
1227 }
1228 }
1229 uip_connr->tcpstateflags = ESTABLISHED;
1230 uip_connr->rcv_nxt[0] = BUF->seqno[0];
1231 uip_connr->rcv_nxt[1] = BUF->seqno[1];
1232 uip_connr->rcv_nxt[2] = BUF->seqno[2];
1233 uip_connr->rcv_nxt[3] = BUF->seqno[3];
1234 uip_add_rcv_nxt(1);
1235 uip_flags = UIP_CONNECTED | UIP_NEWDATA;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001236 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001237 uip_len = 0;
1238 uip_slen = 0;
1239 UIP_APPCALL();
1240 goto appsend;
1241 }
adamdunkels049a9122005-02-07 06:59:39 +00001242 /* Inform the application that the connection failed */
1243 uip_flags = UIP_ABORT;
1244 UIP_APPCALL();
1245 /* The connection is closed after we send the RST */
1246 uip_conn->tcpstateflags = CLOSED;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001247 goto reset;
1248#endif /* UIP_ACTIVE_OPEN */
1249
1250 case ESTABLISHED:
1251 /* In the ESTABLISHED state, we call upon the application to feed
1252 data into the uip_buf. If the UIP_ACKDATA flag is set, the
1253 application should put new data into the buffer, otherwise we are
1254 retransmitting an old segment, and the application should put that
1255 data into the buffer.
1256
1257 If the incoming packet is a FIN, we should close the connection on
1258 this side as well, and we send out a FIN and enter the LAST_ACK
1259 state. We require that there is no outstanding data; otherwise the
1260 sequence numbers will be screwed up. */
1261
adamdunkels31a50262005-02-22 22:33:56 +00001262 if(BUF->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001263 if(uip_outstanding(uip_connr)) {
1264 goto drop;
1265 }
1266 uip_add_rcv_nxt(1 + uip_len);
1267 uip_flags = UIP_CLOSE;
1268 if(uip_len > 0) {
1269 uip_flags |= UIP_NEWDATA;
1270 }
1271 UIP_APPCALL();
1272 uip_connr->len = 1;
1273 uip_connr->tcpstateflags = LAST_ACK;
1274 uip_connr->nrtx = 0;
1275 tcp_send_finack:
1276 BUF->flags = TCP_FIN | TCP_ACK;
1277 goto tcp_send_nodata;
1278 }
1279
1280 /* Check the URG flag. If this is set, the segment carries urgent
1281 data that we must pass to the application. */
adamdunkels9fad4132004-06-06 06:14:19 +00001282 if((BUF->flags & TCP_URG) != 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001283#if UIP_URGDATA > 0
1284 uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1];
1285 if(uip_urglen > uip_len) {
1286 /* There is more urgent data in the next segment to come. */
1287 uip_urglen = uip_len;
1288 }
1289 uip_add_rcv_nxt(uip_urglen);
1290 uip_len -= uip_urglen;
1291 uip_urgdata = uip_appdata;
1292 uip_appdata += uip_urglen;
1293 } else {
1294 uip_urglen = 0;
adamdunkels9fad4132004-06-06 06:14:19 +00001295#else /* UIP_URGDATA > 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001296 uip_appdata += (BUF->urgp[0] << 8) | BUF->urgp[1];
1297 uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1];
adamdunkels9fad4132004-06-06 06:14:19 +00001298#endif /* UIP_URGDATA > 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001299 }
adamdunkels9fad4132004-06-06 06:14:19 +00001300
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001301 /* If uip_len > 0 we have TCP data in the packet, and we flag this
1302 by setting the UIP_NEWDATA flag and update the sequence number
1303 we acknowledge. If the application has stopped the dataflow
1304 using uip_stop(), we must not accept any data packets from the
1305 remote host. */
1306 if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
1307 uip_flags |= UIP_NEWDATA;
1308 uip_add_rcv_nxt(uip_len);
1309 }
adamdunkels0170b082003-10-01 11:25:37 +00001310
1311 /* Check if the available buffer space advertised by the other end
1312 is smaller than the initial MSS for this connection. If so, we
1313 set the current MSS to the window size to ensure that the
1314 application does not send more data than the other end can
1315 handle.
1316
1317 If the remote host advertises a zero window, we set the MSS to
1318 the initial MSS so that the application will send an entire MSS
1319 of data. This data will not be acknowledged by the receiver,
1320 and the application will retransmit it. This is called the
1321 "persistent timer" and uses the retransmission mechanim.
1322 */
1323 tmp16 = ((u16_t)BUF->wnd[0] << 8) + (u16_t)BUF->wnd[1];
1324 if(tmp16 > uip_connr->initialmss ||
1325 tmp16 == 0) {
1326 tmp16 = uip_connr->initialmss;
1327 }
1328 uip_connr->mss = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001329
1330 /* If this packet constitutes an ACK for outstanding data (flagged
1331 by the UIP_ACKDATA flag, we should call the application since it
1332 might want to send more data. If the incoming packet had data
1333 from the peer (as flagged by the UIP_NEWDATA flag), the
1334 application must also be notified.
1335
1336 When the application is called, the global variable uip_len
1337 contains the length of the incoming data. The application can
1338 access the incoming data through the global pointer
adamdunkels049a9122005-02-07 06:59:39 +00001339 uip_appdata, which usually points UIP_IPTCPH_LEN + UIP_LLH_LEN
1340 bytes into the uip_buf array.
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001341
1342 If the application wishes to send any data, this data should be
1343 put into the uip_appdata and the length of the data should be
1344 put into uip_len. If the application don't have any data to
1345 send, uip_len must be set to 0. */
1346 if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) {
1347 uip_slen = 0;
1348 UIP_APPCALL();
1349
1350 appsend:
adamdunkels0170b082003-10-01 11:25:37 +00001351
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001352 if(uip_flags & UIP_ABORT) {
1353 uip_slen = 0;
1354 uip_connr->tcpstateflags = CLOSED;
1355 BUF->flags = TCP_RST | TCP_ACK;
1356 goto tcp_send_nodata;
1357 }
1358
1359 if(uip_flags & UIP_CLOSE) {
1360 uip_slen = 0;
1361 uip_connr->len = 1;
1362 uip_connr->tcpstateflags = FIN_WAIT_1;
1363 uip_connr->nrtx = 0;
1364 BUF->flags = TCP_FIN | TCP_ACK;
1365 goto tcp_send_nodata;
1366 }
1367
adamdunkelsb489e7a2003-10-14 11:12:50 +00001368 /* If uip_slen > 0, the application has data to be sent. */
1369 if(uip_slen > 0) {
1370
1371 /* If the connection has acknowledged data, the contents of
1372 the ->len variable should be discarded. */
1373 if((uip_flags & UIP_ACKDATA) != 0) {
1374 uip_connr->len = 0;
1375 }
1376
1377 /* If the ->len variable is non-zero the connection has
1378 already data in transit and cannot send anymore right
1379 now. */
1380 if(uip_connr->len == 0) {
1381
1382 /* The application cannot send more than what is allowed by
1383 the mss (the minumum of the MSS and the available
1384 window). */
1385 if(uip_slen > uip_connr->mss) {
1386 uip_slen = uip_connr->mss;
1387 }
1388
1389 /* Remember how much data we send out now so that we know
1390 when everything has been acknowledged. */
1391 uip_connr->len = uip_slen;
1392 } else {
1393
1394 /* If the application already had unacknowledged data, we
1395 make sure that the application does not send (i.e.,
1396 retransmit) out more than it previously sent out. */
1397 uip_slen = uip_connr->len;
1398 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001399 }
adamdunkelsb489e7a2003-10-14 11:12:50 +00001400 uip_connr->nrtx = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001401 apprexmit:
adamdunkels0170b082003-10-01 11:25:37 +00001402 uip_appdata = uip_sappdata;
1403
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001404 /* If the application has data to be sent, or if the incoming
1405 packet had new data in it, we must send out a packet. */
adamdunkels759185d2003-06-30 20:35:41 +00001406 if(uip_slen > 0 && uip_connr->len > 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001407 /* Add the length of the IP and TCP headers. */
1408 uip_len = uip_connr->len + UIP_TCPIP_HLEN;
1409 /* We always set the ACK flag in response packets. */
adamdunkels759185d2003-06-30 20:35:41 +00001410 BUF->flags = TCP_ACK | TCP_PSH;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001411 /* Send the packet. */
1412 goto tcp_send_noopts;
1413 }
adamdunkels759185d2003-06-30 20:35:41 +00001414 /* If there is no data to send, just send out a pure ACK if
1415 there is newdata. */
1416 if(uip_flags & UIP_NEWDATA) {
1417 uip_len = UIP_TCPIP_HLEN;
1418 BUF->flags = TCP_ACK;
1419 goto tcp_send_noopts;
1420 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001421 }
1422 goto drop;
1423 case LAST_ACK:
1424 /* We can close this connection if the peer has acknowledged our
1425 FIN. This is indicated by the UIP_ACKDATA flag. */
1426 if(uip_flags & UIP_ACKDATA) {
1427 uip_connr->tcpstateflags = CLOSED;
1428 uip_flags = UIP_CLOSE;
1429 UIP_APPCALL();
1430 }
1431 break;
1432
1433 case FIN_WAIT_1:
1434 /* The application has closed the connection, but the remote host
1435 hasn't closed its end yet. Thus we do nothing but wait for a
1436 FIN from the other side. */
1437 if(uip_len > 0) {
1438 uip_add_rcv_nxt(uip_len);
1439 }
1440 if(BUF->flags & TCP_FIN) {
1441 if(uip_flags & UIP_ACKDATA) {
1442 uip_connr->tcpstateflags = TIME_WAIT;
1443 uip_connr->timer = 0;
1444 uip_connr->len = 0;
1445 } else {
1446 uip_connr->tcpstateflags = CLOSING;
1447 }
1448 uip_add_rcv_nxt(1);
1449 uip_flags = UIP_CLOSE;
1450 UIP_APPCALL();
1451 goto tcp_send_ack;
1452 } else if(uip_flags & UIP_ACKDATA) {
1453 uip_connr->tcpstateflags = FIN_WAIT_2;
1454 uip_connr->len = 0;
1455 goto drop;
1456 }
1457 if(uip_len > 0) {
1458 goto tcp_send_ack;
1459 }
1460 goto drop;
1461
1462 case FIN_WAIT_2:
1463 if(uip_len > 0) {
1464 uip_add_rcv_nxt(uip_len);
1465 }
1466 if(BUF->flags & TCP_FIN) {
1467 uip_connr->tcpstateflags = TIME_WAIT;
1468 uip_connr->timer = 0;
1469 uip_add_rcv_nxt(1);
1470 uip_flags = UIP_CLOSE;
1471 UIP_APPCALL();
1472 goto tcp_send_ack;
1473 }
1474 if(uip_len > 0) {
1475 goto tcp_send_ack;
1476 }
1477 goto drop;
1478
1479 case TIME_WAIT:
1480 goto tcp_send_ack;
1481
1482 case CLOSING:
1483 if(uip_flags & UIP_ACKDATA) {
1484 uip_connr->tcpstateflags = TIME_WAIT;
1485 uip_connr->timer = 0;
1486 }
1487 }
1488 goto drop;
1489
1490
1491 /* We jump here when we are ready to send the packet, and just want
1492 to set the appropriate TCP sequence numbers in the TCP header. */
1493 tcp_send_ack:
1494 BUF->flags = TCP_ACK;
1495 tcp_send_nodata:
adamdunkels049a9122005-02-07 06:59:39 +00001496 uip_len = UIP_IPTCPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001497 tcp_send_noopts:
adamdunkels049a9122005-02-07 06:59:39 +00001498 BUF->tcpoffset = (UIP_TCPH_LEN / 4) << 4;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001499 tcp_send:
1500 /* We're done with the input processing. We are now ready to send a
1501 reply. Our job is to fill in all the fields of the TCP and IP
1502 headers before calculating the checksum and finally send the
1503 packet. */
1504 BUF->ackno[0] = uip_connr->rcv_nxt[0];
1505 BUF->ackno[1] = uip_connr->rcv_nxt[1];
1506 BUF->ackno[2] = uip_connr->rcv_nxt[2];
1507 BUF->ackno[3] = uip_connr->rcv_nxt[3];
1508
1509 BUF->seqno[0] = uip_connr->snd_nxt[0];
1510 BUF->seqno[1] = uip_connr->snd_nxt[1];
1511 BUF->seqno[2] = uip_connr->snd_nxt[2];
1512 BUF->seqno[3] = uip_connr->snd_nxt[3];
1513
1514 BUF->proto = UIP_PROTO_TCP;
1515
1516 BUF->srcport = uip_connr->lport;
1517 BUF->destport = uip_connr->rport;
1518
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001519 BUF->srcipaddr[0] = uip_hostaddr[0];
1520 BUF->srcipaddr[1] = uip_hostaddr[1];
1521 BUF->destipaddr[0] = uip_connr->ripaddr[0];
1522 BUF->destipaddr[1] = uip_connr->ripaddr[1];
1523
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001524
1525 if(uip_connr->tcpstateflags & UIP_STOPPED) {
1526 /* If the connection has issued uip_stop(), we advertise a zero
1527 window so that the remote host will stop sending data. */
1528 BUF->wnd[0] = BUF->wnd[1] = 0;
1529 } else {
adamdunkelsb489e7a2003-10-14 11:12:50 +00001530 BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8);
1531 BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001532 }
1533
1534 tcp_send_noconn:
1535
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001536 BUF->len[0] = (uip_len >> 8);
1537 BUF->len[1] = (uip_len & 0xff);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001538
adamdunkels9fad4132004-06-06 06:14:19 +00001539 BUF->urgp[0] = BUF->urgp[1] = 0;
1540
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001541 /* Calculate TCP checksum. */
1542 BUF->tcpchksum = 0;
1543 BUF->tcpchksum = ~(uip_tcpchksum());
1544
1545 ip_send_nolen:
1546
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001547 BUF->vhl = 0x45;
1548 BUF->tos = 0;
1549 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
1550 BUF->ttl = UIP_TTL;
1551 ++ipid;
1552 BUF->ipid[0] = ipid >> 8;
1553 BUF->ipid[1] = ipid & 0xff;
1554
1555 /* Calculate IP checksum. */
1556 BUF->ipchksum = 0;
1557 BUF->ipchksum = ~(uip_ipchksum());
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001558
1559 UIP_STAT(++uip_stat.tcp.sent);
1560 send:
adamdunkels9fad4132004-06-06 06:14:19 +00001561
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001562 UIP_STAT(++uip_stat.ip.sent);
1563 /* Return and let the caller do the actual transmission. */
1564 return;
1565 drop:
1566 uip_len = 0;
1567 return;
1568}
1569/*-----------------------------------------------------------------------------------*/
adamdunkels47ec7fa2003-03-28 12:11:17 +00001570u16_t
1571htons(u16_t val)
1572{
1573 return HTONS(val);
1574}
1575/*-----------------------------------------------------------------------------------*/
adamdunkels0170b082003-10-01 11:25:37 +00001576/** @} */