blob: 0417e80d946ac61985ba063f4d39bc2b2eb68fd6 [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 *
adamdunkels31a50262005-02-22 22:33:56 +000042 * $Id: uip.c,v 1.20 2005/02/22 22:33:56 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
106
adamdunkels049a9122005-02-07 06:59:39 +0000107u8_t uip_buf[UIP_BUFSIZE + 2]; /* The packet buffer that contains
108 incoming packets. */
109u8_t *uip_appdata; /* The uip_appdata pointer points to
110 application data. */
111u8_t *uip_sappdata; /* The uip_appdata pointer points to
112 the application data which is to
113 be sent. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000114#if UIP_URGDATA > 0
adamdunkels049a9122005-02-07 06:59:39 +0000115u8_t *uip_urgdata; /* The uip_urgdata pointer points to
116 urgent data (out-of-band data), if
117 present. */
118u16_t uip_urglen, uip_surglen;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000119#endif /* UIP_URGDATA > 0 */
120
adamdunkels9fad4132004-06-06 06:14:19 +0000121u16_t uip_len, uip_slen;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000122 /* The uip_len is either 8 or 16 bits,
123 depending on the maximum packet
124 size. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000125
adamdunkels9fad4132004-06-06 06:14:19 +0000126u8_t uip_flags; /* The uip_flags variable is used for
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000127 communication between the TCP/IP stack
128 and the application program. */
129struct uip_conn *uip_conn; /* uip_conn always points to the current
130 connection. */
131
132struct uip_conn uip_conns[UIP_CONNS];
133 /* The uip_conns array holds all TCP
134 connections. */
135u16_t uip_listenports[UIP_LISTENPORTS];
136 /* The uip_listenports list all currently
137 listning ports. */
138#if UIP_UDP
139struct uip_udp_conn *uip_udp_conn;
140struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
141#endif /* UIP_UDP */
142
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000143static u16_t ipid; /* Ths ipid variable is an increasing
144 number that is used for the IP ID
145 field. */
146
147static u8_t iss[4]; /* The iss variable is used for the TCP
148 initial sequence number. */
149
150#if UIP_ACTIVE_OPEN
adamdunkelsb489e7a2003-10-14 11:12:50 +0000151static u16_t lastport; /* Keeps track of the last port used for
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000152 a new connection. */
153#endif /* UIP_ACTIVE_OPEN */
154
155/* Temporary variables. */
adamdunkels9fad4132004-06-06 06:14:19 +0000156u8_t uip_acc32[4];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000157static u8_t c, opt;
adamdunkels0170b082003-10-01 11:25:37 +0000158static u16_t tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000159
160/* Structures and definitions. */
161#define TCP_FIN 0x01
162#define TCP_SYN 0x02
163#define TCP_RST 0x04
164#define TCP_PSH 0x08
165#define TCP_ACK 0x10
166#define TCP_URG 0x20
167#define TCP_CTL 0x3f
168
adamdunkels049a9122005-02-07 06:59:39 +0000169#define TCP_OPT_END 0 /* End of TCP options list */
170#define TCP_OPT_NOOP 1 /* "No-operation" TCP option */
171#define TCP_OPT_MSS 2 /* Maximum segment size TCP option */
172
173#define TCP_OPT_MSS_LEN 4 /* Length of TCP MSS option. */
174
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000175#define ICMP_ECHO_REPLY 0
176#define ICMP_ECHO 8
177
adamdunkels049a9122005-02-07 06:59:39 +0000178
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000179/* 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
adamdunkels049a9122005-02-07 06:59:39 +0000185
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000186#if UIP_STATISTICS == 1
187struct uip_stats uip_stat;
188#define UIP_STAT(s) s
189#else
190#define UIP_STAT(s)
191#endif /* UIP_STATISTICS == 1 */
192
193#if UIP_LOGGING == 1
194#include <stdio.h>
195void uip_log(char *msg);
196#define UIP_LOG(m) uip_log(m)
197#else
198#define UIP_LOG(m)
199#endif /* UIP_LOGGING == 1 */
200
201/*-----------------------------------------------------------------------------------*/
202void
203uip_init(void)
204{
205 for(c = 0; c < UIP_LISTENPORTS; ++c) {
206 uip_listenports[c] = 0;
207 }
208 for(c = 0; c < UIP_CONNS; ++c) {
209 uip_conns[c].tcpstateflags = CLOSED;
210 }
211#if UIP_ACTIVE_OPEN
212 lastport = 1024;
213#endif /* UIP_ACTIVE_OPEN */
214
215#if UIP_UDP
216 for(c = 0; c < UIP_UDP_CONNS; ++c) {
217 uip_udp_conns[c].lport = 0;
218 }
219#endif /* UIP_UDP */
220
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000221
222 /* IPv4 initialization. */
223#if UIP_FIXEDADDR == 0
adamdunkels049a9122005-02-07 06:59:39 +0000224 /* uip_hostaddr[0] = uip_hostaddr[1] = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000225#endif /* UIP_FIXEDADDR */
adamdunkelsa38da252003-08-20 20:56:54 +0000226
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000227}
228/*-----------------------------------------------------------------------------------*/
229#if UIP_ACTIVE_OPEN
230struct uip_conn *
231uip_connect(u16_t *ripaddr, u16_t rport)
232{
adamdunkelsa38da252003-08-20 20:56:54 +0000233 register struct uip_conn *conn, *cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000234
235 /* Find an unused local port. */
236 again:
237 ++lastport;
238
239 if(lastport >= 32000) {
240 lastport = 4096;
241 }
adamdunkels1e45c6d2003-09-02 21:47:27 +0000242
243 /* Check if this port is already in use, and if so try to find
244 another one. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000245 for(c = 0; c < UIP_CONNS; ++c) {
adamdunkels23664022003-08-05 13:51:50 +0000246 conn = &uip_conns[c];
247 if(conn->tcpstateflags != CLOSED &&
adamdunkels1e45c6d2003-09-02 21:47:27 +0000248 conn->lport == htons(lastport)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000249 goto again;
adamdunkelsa38da252003-08-20 20:56:54 +0000250 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000251 }
252
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000253 conn = 0;
254 for(c = 0; c < UIP_CONNS; ++c) {
adamdunkelsa38da252003-08-20 20:56:54 +0000255 cconn = &uip_conns[c];
256 if(cconn->tcpstateflags == CLOSED) {
257 conn = cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000258 break;
259 }
adamdunkelsa38da252003-08-20 20:56:54 +0000260 if(cconn->tcpstateflags == TIME_WAIT) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000261 if(conn == 0 ||
adamdunkels75b9d002004-09-17 20:48:39 +0000262 cconn->timer > conn->timer) {
adamdunkelsa38da252003-08-20 20:56:54 +0000263 conn = cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000264 }
265 }
266 }
267
268 if(conn == 0) {
269 return 0;
270 }
271
272 conn->tcpstateflags = SYN_SENT;
273
274 conn->snd_nxt[0] = iss[0];
275 conn->snd_nxt[1] = iss[1];
276 conn->snd_nxt[2] = iss[2];
277 conn->snd_nxt[3] = iss[3];
278
adamdunkels0170b082003-10-01 11:25:37 +0000279 conn->initialmss = conn->mss = UIP_TCP_MSS;
adamdunkelsd962db42003-08-21 18:10:21 +0000280
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000281 conn->len = 1; /* TCP length of the SYN is one. */
282 conn->nrtx = 0;
283 conn->timer = 1; /* Send the SYN next time around. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000284 conn->rto = UIP_RTO;
285 conn->sa = 0;
adamdunkels049a9122005-02-07 06:59:39 +0000286 conn->sv = 16; /* Initial value of the RTT variance. */
adamdunkels1e45c6d2003-09-02 21:47:27 +0000287 conn->lport = htons(lastport);
288 conn->rport = rport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000289 conn->ripaddr[0] = ripaddr[0];
290 conn->ripaddr[1] = ripaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000291
292 return conn;
293}
294#endif /* UIP_ACTIVE_OPEN */
295/*-----------------------------------------------------------------------------------*/
296#if UIP_UDP
297struct uip_udp_conn *
298uip_udp_new(u16_t *ripaddr, u16_t rport)
299{
adamdunkels23664022003-08-05 13:51:50 +0000300 register struct uip_udp_conn *conn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000301
302 /* Find an unused local port. */
303 again:
304 ++lastport;
305
306 if(lastport >= 32000) {
307 lastport = 4096;
308 }
309
310 for(c = 0; c < UIP_UDP_CONNS; ++c) {
adamdunkels049a9122005-02-07 06:59:39 +0000311 if(uip_udp_conns[c].lport == htons(lastport)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000312 goto again;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000313 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000314 }
315
316
317 conn = 0;
318 for(c = 0; c < UIP_UDP_CONNS; ++c) {
319 if(uip_udp_conns[c].lport == 0) {
320 conn = &uip_udp_conns[c];
321 break;
322 }
323 }
324
325 if(conn == 0) {
326 return 0;
327 }
328
adamdunkels47ec7fa2003-03-28 12:11:17 +0000329 conn->lport = HTONS(lastport);
adamdunkels75b9d002004-09-17 20:48:39 +0000330 conn->rport = rport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000331 conn->ripaddr[0] = ripaddr[0];
332 conn->ripaddr[1] = ripaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000333
334 return conn;
335}
336#endif /* UIP_UDP */
337/*-----------------------------------------------------------------------------------*/
338void
adamdunkelscd8c3a22003-08-13 22:52:48 +0000339uip_unlisten(u16_t port)
340{
341 for(c = 0; c < UIP_LISTENPORTS; ++c) {
342 if(uip_listenports[c] == port) {
343 uip_listenports[c] = 0;
344 return;
345 }
346 }
347}
348/*-----------------------------------------------------------------------------------*/
349void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000350uip_listen(u16_t port)
351{
352 for(c = 0; c < UIP_LISTENPORTS; ++c) {
353 if(uip_listenports[c] == 0) {
adamdunkels1e45c6d2003-09-02 21:47:27 +0000354 uip_listenports[c] = port;
adamdunkelscd8c3a22003-08-13 22:52:48 +0000355 return;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000356 }
357 }
358}
359/*-----------------------------------------------------------------------------------*/
adamdunkelsb489e7a2003-10-14 11:12:50 +0000360/* XXX: IP fragment reassembly: not well-tested. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000361
362#if UIP_REASSEMBLY
363#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)
364static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];
365static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];
366static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f,
367 0x0f, 0x07, 0x03, 0x01};
368static u16_t uip_reasslen;
369static u8_t uip_reassflags;
370#define UIP_REASS_FLAG_LASTFRAG 0x01
371static u8_t uip_reasstmr;
372
adamdunkelsb489e7a2003-10-14 11:12:50 +0000373#define IP_MF 0x20
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000374
375static u8_t
376uip_reass(void)
377{
378 u16_t offset, len;
379 u16_t i;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000380
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000381 /* If ip_reasstmr is zero, no packet is present in the buffer, so we
382 write the IP header of the fragment into the reassembly
383 buffer. The timer is updated with the maximum age. */
384 if(uip_reasstmr == 0) {
adamdunkels31a50262005-02-22 22:33:56 +0000385 memcpy(uip_reassbuf, &BUF->vhl, UIP_IPH_LEN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000386 uip_reasstmr = UIP_REASS_MAXAGE;
387 uip_reassflags = 0;
388 /* Clear the bitmap. */
adamdunkels31a50262005-02-22 22:33:56 +0000389 memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap));
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000390 }
391
392 /* Check if the incoming fragment matches the one currently present
393 in the reasembly buffer. If so, we proceed with copying the
394 fragment into the buffer. */
395 if(BUF->srcipaddr[0] == FBUF->srcipaddr[0] &&
adamdunkelsb489e7a2003-10-14 11:12:50 +0000396 BUF->srcipaddr[1] == FBUF->srcipaddr[1] &&
397 BUF->destipaddr[0] == FBUF->destipaddr[0] &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000398 BUF->destipaddr[1] == FBUF->destipaddr[1] &&
adamdunkelsb489e7a2003-10-14 11:12:50 +0000399 BUF->ipid[0] == FBUF->ipid[0] &&
400 BUF->ipid[1] == FBUF->ipid[1]) {
401
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000402 len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4;
403 offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8;
404
405 /* If the offset or the offset + fragment length overflows the
406 reassembly buffer, we discard the entire packet. */
407 if(offset > UIP_REASS_BUFSIZE ||
408 offset + len > UIP_REASS_BUFSIZE) {
409 uip_reasstmr = 0;
410 goto nullreturn;
411 }
412
413 /* Copy the fragment into the reassembly buffer, at the right
414 offset. */
adamdunkels31a50262005-02-22 22:33:56 +0000415 memcpy(&uip_reassbuf[UIP_IPH_LEN + offset],
adamdunkelsb489e7a2003-10-14 11:12:50 +0000416 (char *)BUF + (int)((BUF->vhl & 0x0f) * 4),
417 len);
418
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000419 /* Update the bitmap. */
420 if(offset / (8 * 8) == (offset + len) / (8 * 8)) {
421 /* If the two endpoints are in the same byte, we only update
422 that byte. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000423
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000424 uip_reassbitmap[offset / (8 * 8)] |=
adamdunkelsb489e7a2003-10-14 11:12:50 +0000425 bitmap_bits[(offset / 8 ) & 7] &
426 ~bitmap_bits[((offset + len) / 8 ) & 7];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000427 } else {
428 /* If the two endpoints are in different bytes, we update the
429 bytes in the endpoints and fill the stuff inbetween with
430 0xff. */
431 uip_reassbitmap[offset / (8 * 8)] |=
432 bitmap_bits[(offset / 8 ) & 7];
433 for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
434 uip_reassbitmap[i] = 0xff;
435 }
436 uip_reassbitmap[(offset + len) / (8 * 8)] |=
437 ~bitmap_bits[((offset + len) / 8 ) & 7];
438 }
439
440 /* If this fragment has the More Fragments flag set to zero, we
441 know that this is the last fragment, so we can calculate the
442 size of the entire packet. We also set the
443 IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
444 the final fragment. */
445
446 if((BUF->ipoffset[0] & IP_MF) == 0) {
447 uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
448 uip_reasslen = offset + len;
449 }
450
451 /* Finally, we check if we have a full packet in the buffer. We do
452 this by checking if we have the last fragment and if all bits
453 in the bitmap are set. */
454 if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) {
455 /* Check all bytes up to and including all but the last byte in
456 the bitmap. */
457 for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) {
458 if(uip_reassbitmap[i] != 0xff) {
459 goto nullreturn;
460 }
461 }
462 /* Check the last byte in the bitmap. It should contain just the
463 right amount of bits. */
464 if(uip_reassbitmap[uip_reasslen / (8 * 8)] !=
465 (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) {
466 goto nullreturn;
467 }
468
469 /* If we have come this far, we have a full packet in the
470 buffer, so we allocate a pbuf and copy the packet into it. We
471 also reset the timer. */
472 uip_reasstmr = 0;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000473 memcpy(BUF, FBUF, uip_reasslen);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000474
475 /* Pretend to be a "normal" (i.e., not fragmented) IP packet
476 from now on. */
477 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000478 BUF->len[0] = uip_reasslen >> 8;
479 BUF->len[1] = uip_reasslen & 0xff;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000480 BUF->ipchksum = 0;
481 BUF->ipchksum = ~(uip_ipchksum());
482
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000483 return uip_reasslen;
484 }
485 }
486
487 nullreturn:
488 return 0;
489}
adamdunkels049a9122005-02-07 06:59:39 +0000490#endif /* UIP_REASSEMBLY */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000491/*-----------------------------------------------------------------------------------*/
492static void
493uip_add_rcv_nxt(u16_t n)
494{
495 uip_add32(uip_conn->rcv_nxt, n);
496 uip_conn->rcv_nxt[0] = uip_acc32[0];
497 uip_conn->rcv_nxt[1] = uip_acc32[1];
498 uip_conn->rcv_nxt[2] = uip_acc32[2];
499 uip_conn->rcv_nxt[3] = uip_acc32[3];
500}
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000501/*-----------------------------------------------------------------------------------*/
502void
503uip_process(u8_t flag)
504{
505 register struct uip_conn *uip_connr = uip_conn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000506
adamdunkels049a9122005-02-07 06:59:39 +0000507 uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000508
509 /* Check if we were invoked because of the perodic timer fireing. */
510 if(flag == UIP_TIMER) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000511#if UIP_REASSEMBLY
512 if(uip_reasstmr != 0) {
513 --uip_reasstmr;
514 }
515#endif /* UIP_REASSEMBLY */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000516 /* Increase the initial sequence number. */
517 if(++iss[3] == 0) {
518 if(++iss[2] == 0) {
519 if(++iss[1] == 0) {
520 ++iss[0];
521 }
522 }
523 }
524 uip_len = 0;
525 if(uip_connr->tcpstateflags == TIME_WAIT ||
526 uip_connr->tcpstateflags == FIN_WAIT_2) {
527 ++(uip_connr->timer);
528 if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) {
529 uip_connr->tcpstateflags = CLOSED;
530 }
531 } else if(uip_connr->tcpstateflags != CLOSED) {
532 /* If the connection has outstanding data, we increase the
533 connection's timer and see if it has reached the RTO value
534 in which case we retransmit. */
535 if(uip_outstanding(uip_connr)) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000536 if(uip_connr->timer-- == 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000537 if(uip_connr->nrtx == UIP_MAXRTX ||
538 ((uip_connr->tcpstateflags == SYN_SENT ||
539 uip_connr->tcpstateflags == SYN_RCVD) &&
540 uip_connr->nrtx == UIP_MAXSYNRTX)) {
541 uip_connr->tcpstateflags = CLOSED;
542
543 /* We call UIP_APPCALL() with uip_flags set to
544 UIP_TIMEDOUT to inform the application that the
545 connection has timed out. */
546 uip_flags = UIP_TIMEDOUT;
547 UIP_APPCALL();
548
549 /* We also send a reset packet to the remote host. */
550 BUF->flags = TCP_RST | TCP_ACK;
551 goto tcp_send_nodata;
552 }
553
554 /* Exponential backoff. */
adamdunkels47ec7fa2003-03-28 12:11:17 +0000555 uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4?
556 4:
557 uip_connr->nrtx);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000558 ++(uip_connr->nrtx);
559
560 /* Ok, so we need to retransmit. We do this differently
561 depending on which state we are in. In ESTABLISHED, we
562 call upon the application so that it may prepare the
563 data for the retransmit. In SYN_RCVD, we resend the
564 SYNACK that we sent earlier and in LAST_ACK we have to
565 retransmit our FINACK. */
566 UIP_STAT(++uip_stat.tcp.rexmit);
567 switch(uip_connr->tcpstateflags & TS_MASK) {
568 case SYN_RCVD:
569 /* In the SYN_RCVD state, we should retransmit our
570 SYNACK. */
571 goto tcp_send_synack;
572
573#if UIP_ACTIVE_OPEN
574 case SYN_SENT:
575 /* In the SYN_SENT state, we retransmit out SYN. */
576 BUF->flags = 0;
577 goto tcp_send_syn;
578#endif /* UIP_ACTIVE_OPEN */
579
580 case ESTABLISHED:
581 /* In the ESTABLISHED state, we call upon the application
582 to do the actual retransmit after which we jump into
583 the code for sending out the packet (the apprexmit
584 label). */
585 uip_len = 0;
586 uip_slen = 0;
587 uip_flags = UIP_REXMIT;
588 UIP_APPCALL();
589 goto apprexmit;
590
591 case FIN_WAIT_1:
592 case CLOSING:
593 case LAST_ACK:
594 /* In all these states we should retransmit a FINACK. */
595 goto tcp_send_finack;
596
597 }
598 }
599 } else if((uip_connr->tcpstateflags & TS_MASK) == ESTABLISHED) {
600 /* If there was no need for a retransmission, we poll the
601 application for new data. */
602 uip_len = 0;
603 uip_slen = 0;
604 uip_flags = UIP_POLL;
605 UIP_APPCALL();
606 goto appsend;
607 }
608 }
609 goto drop;
610 }
611#if UIP_UDP
612 if(flag == UIP_UDP_TIMER) {
613 if(uip_udp_conn->lport != 0) {
adamdunkels399a0782004-02-16 20:52:07 +0000614 uip_conn = NULL;
adamdunkels049a9122005-02-07 06:59:39 +0000615 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000616 uip_len = uip_slen = 0;
617 uip_flags = UIP_POLL;
618 UIP_UDP_APPCALL();
619 goto udp_send;
620 } else {
621 goto drop;
622 }
623 }
624#endif
625
626 /* This is where the input processing starts. */
627 UIP_STAT(++uip_stat.ip.recv);
628
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000629
630 /* Start of IPv4 input header processing code. */
631
632 /* Check validity of the IP header. */
633 if(BUF->vhl != 0x45) { /* IP version and header length. */
634 UIP_STAT(++uip_stat.ip.drop);
635 UIP_STAT(++uip_stat.ip.vhlerr);
636 UIP_LOG("ip: invalid version or header length.");
637 goto drop;
638 }
639
640 /* Check the size of the packet. If the size reported to us in
adamdunkels049a9122005-02-07 06:59:39 +0000641 uip_len is smaller the size reported in the IP header, we assume
642 that the packet has been corrupted in transit. If the size of
643 uip_len is larger than the size reported in the IP packet header,
644 the packet has been padded and we set uip_len to the correct
645 value.. */
646
647 if((BUF->len[0] << 8) + BUF->len[1] <= uip_len) {
648 uip_len = (BUF->len[0] << 8) + BUF->len[1];
649 } else {
650 UIP_LOG("ip: packet shorter than reported in IP header.");
651 goto drop;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000652 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000653
adamdunkelsb489e7a2003-10-14 11:12:50 +0000654 /* Check the fragment flag. */
655 if((BUF->ipoffset[0] & 0x3f) != 0 ||
656 BUF->ipoffset[1] != 0) {
657#if UIP_REASSEMBLY
658 uip_len = uip_reass();
659 if(uip_len == 0) {
660 goto drop;
661 }
662#else
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000663 UIP_STAT(++uip_stat.ip.drop);
664 UIP_STAT(++uip_stat.ip.fragerr);
665 UIP_LOG("ip: fragment dropped.");
666 goto drop;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000667#endif /* UIP_REASSEMBLY */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000668 }
669
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000670 if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
adamdunkels75b9d002004-09-17 20:48:39 +0000671 /* If we are configured to use ping IP address configuration and
672 hasn't been assigned an IP address yet, we accept all ICMP
673 packets. */
674#if UIP_PINGADDRCONF
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000675 if(BUF->proto == UIP_PROTO_ICMP) {
676 UIP_LOG("ip: possible ping config packet received.");
677 goto icmp_input;
678 } else {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000679 UIP_LOG("ip: packet dropped since no address assigned.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000680 goto drop;
adamdunkels75b9d002004-09-17 20:48:39 +0000681 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000682#endif /* UIP_PINGADDRCONF */
adamdunkels9fad4132004-06-06 06:14:19 +0000683
adamdunkels75b9d002004-09-17 20:48:39 +0000684 } else {
685 /* If IP broadcast support is configured, we check for a broadcast
686 UDP packet, which may be destined to us. */
adamdunkels9fad4132004-06-06 06:14:19 +0000687#if UIP_BROADCAST
adamdunkels75b9d002004-09-17 20:48:39 +0000688 if(BUF->proto == UIP_PROTO_UDP &&
689 BUF->destipaddr[0] == 0xffff &&
adamdunkels9fad4132004-06-06 06:14:19 +0000690 BUF->destipaddr[1] == 0xffff &&
adamdunkels75b9d002004-09-17 20:48:39 +0000691 uip_ipchksum() == 0xffff) {
692 goto udp_input;
693 }
adamdunkels9fad4132004-06-06 06:14:19 +0000694#endif /* UIP_BROADCAST */
adamdunkels75b9d002004-09-17 20:48:39 +0000695
696 /* Check if the packet is destined for our IP address. */
697 if(BUF->destipaddr[0] != uip_hostaddr[0]) {
698 UIP_STAT(++uip_stat.ip.drop);
adamdunkels75b9d002004-09-17 20:48:39 +0000699 goto drop;
700 }
701 if(BUF->destipaddr[1] != uip_hostaddr[1]) {
702 UIP_STAT(++uip_stat.ip.drop);
adamdunkels75b9d002004-09-17 20:48:39 +0000703 goto drop;
704 }
705 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000706
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000707 if(uip_ipchksum() != 0xffff) { /* Compute and check the IP header
708 checksum. */
709 UIP_STAT(++uip_stat.ip.drop);
710 UIP_STAT(++uip_stat.ip.chkerr);
adamdunkels9fad4132004-06-06 06:14:19 +0000711 UIP_LOG("ip: bad checksum.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000712 goto drop;
713 }
714
adamdunkels049a9122005-02-07 06:59:39 +0000715 if(BUF->proto == UIP_PROTO_TCP) { /* Check for TCP packet. If so,
716 proceed with TCP input
717 processing. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000718 goto tcp_input;
adamdunkels049a9122005-02-07 06:59:39 +0000719 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000720
721#if UIP_UDP
adamdunkels049a9122005-02-07 06:59:39 +0000722 if(BUF->proto == UIP_PROTO_UDP) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000723 goto udp_input;
adamdunkels049a9122005-02-07 06:59:39 +0000724 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000725#endif /* UIP_UDP */
726
727 if(BUF->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from
728 here. */
729 UIP_STAT(++uip_stat.ip.drop);
730 UIP_STAT(++uip_stat.ip.protoerr);
731 UIP_LOG("ip: neither tcp nor icmp.");
732 goto drop;
733 }
734
735 icmp_input:
736 UIP_STAT(++uip_stat.icmp.recv);
737
738 /* ICMP echo (i.e., ping) processing. This is simple, we only change
739 the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
740 checksum before we return the packet. */
741 if(ICMPBUF->type != ICMP_ECHO) {
742 UIP_STAT(++uip_stat.icmp.drop);
743 UIP_STAT(++uip_stat.icmp.typeerr);
744 UIP_LOG("icmp: not icmp echo.");
745 goto drop;
746 }
747
748 /* If we are configured to use ping IP address assignment, we use
749 the destination IP address of this ping packet and assign it to
750 ourself. */
751#if UIP_PINGADDRCONF
752 if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
753 uip_hostaddr[0] = BUF->destipaddr[0];
754 uip_hostaddr[1] = BUF->destipaddr[1];
755 }
756#endif /* UIP_PINGADDRCONF */
757
758 ICMPBUF->type = ICMP_ECHO_REPLY;
759
adamdunkels47ec7fa2003-03-28 12:11:17 +0000760 if(ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) {
761 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000762 } else {
adamdunkels47ec7fa2003-03-28 12:11:17 +0000763 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000764 }
765
766 /* Swap IP addresses. */
adamdunkels0170b082003-10-01 11:25:37 +0000767 tmp16 = BUF->destipaddr[0];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000768 BUF->destipaddr[0] = BUF->srcipaddr[0];
adamdunkels0170b082003-10-01 11:25:37 +0000769 BUF->srcipaddr[0] = tmp16;
770 tmp16 = BUF->destipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000771 BUF->destipaddr[1] = BUF->srcipaddr[1];
adamdunkels0170b082003-10-01 11:25:37 +0000772 BUF->srcipaddr[1] = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000773
774 UIP_STAT(++uip_stat.icmp.sent);
775 goto send;
776
777 /* End of IPv4 input header processing code. */
778
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000779
780#if UIP_UDP
781 /* UDP input processing. */
782 udp_input:
783 /* UDP processing is really just a hack. We don't do anything to the
784 UDP/IP headers, but let the UDP application do all the hard
785 work. If the application sets uip_slen, it has a packet to
786 send. */
787#if UIP_UDP_CHECKSUMS
adamdunkels049a9122005-02-07 06:59:39 +0000788 uip_len = uip_len - UIP_IPTCPH_LEN;
789 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];
790 if(uip_udpchksum() != 0xffff) {
791 printf("checksum 0x%04x\n", uip_udpchksum());
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000792 UIP_STAT(++uip_stat.udp.drop);
793 UIP_STAT(++uip_stat.udp.chkerr);
794 UIP_LOG("udp: bad checksum.");
795 goto drop;
adamdunkels049a9122005-02-07 06:59:39 +0000796 }
797 uip_len = uip_len + (UIP_IPTCPH_LEN - UIP_IPUDPH_LEN);
798#else /* UIP_UDP_CHECKSUMS */
799 uip_len = uip_len - UIP_IPUDPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000800#endif /* UIP_UDP_CHECKSUMS */
801
802 /* Demultiplex this UDP packet between the UDP "connections". */
803 for(uip_udp_conn = &uip_udp_conns[0];
804 uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS];
805 ++uip_udp_conn) {
adamdunkels9fad4132004-06-06 06:14:19 +0000806 /* If the local UDP port is non-zero, the connection is considered
807 to be used. If so, the local port number is checked against the
808 destination port number in the received packet. If the two port
809 numbers match, the remote port number is checked if the
810 connection is bound to a remote port. Finally, if the
811 connection is bound to a remote IP address, the source IP
812 address of the packet is checked. */
813 if(uip_udp_conn->lport != 0 &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000814 UDPBUF->destport == uip_udp_conn->lport &&
815 (uip_udp_conn->rport == 0 ||
816 UDPBUF->srcport == uip_udp_conn->rport) &&
adamdunkels9fad4132004-06-06 06:14:19 +0000817 ((uip_udp_conn->ripaddr[0] | uip_udp_conn->ripaddr[1]) == 0 ||
818 (uip_udp_conn->ripaddr[0] == 0xffff &&
819 uip_udp_conn->ripaddr[1] == 0xffff) ||
820 uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000821 goto udp_found;
822 }
823 }
adamdunkels9fad4132004-06-06 06:14:19 +0000824 UIP_LOG("udp: no matching connection found");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000825 goto drop;
826
827 udp_found:
adamdunkels399a0782004-02-16 20:52:07 +0000828 uip_conn = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000829 uip_flags = UIP_NEWDATA;
adamdunkels049a9122005-02-07 06:59:39 +0000830 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000831 uip_slen = 0;
832 UIP_UDP_APPCALL();
833 udp_send:
834 if(uip_slen == 0) {
835 goto drop;
836 }
adamdunkels049a9122005-02-07 06:59:39 +0000837 uip_len = uip_slen + UIP_IPUDPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000838
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000839 BUF->len[0] = (uip_len >> 8);
840 BUF->len[1] = (uip_len & 0xff);
adamdunkelsb489e7a2003-10-14 11:12:50 +0000841
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000842 BUF->proto = UIP_PROTO_UDP;
843
adamdunkels049a9122005-02-07 06:59:39 +0000844 UDPBUF->udplen = HTONS(uip_slen + UIP_UDPH_LEN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000845 UDPBUF->udpchksum = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000846
847 BUF->srcport = uip_udp_conn->lport;
848 BUF->destport = uip_udp_conn->rport;
849
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000850 BUF->srcipaddr[0] = uip_hostaddr[0];
851 BUF->srcipaddr[1] = uip_hostaddr[1];
852 BUF->destipaddr[0] = uip_udp_conn->ripaddr[0];
853 BUF->destipaddr[1] = uip_udp_conn->ripaddr[1];
854
adamdunkels049a9122005-02-07 06:59:39 +0000855 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];
adamdunkelsc4b80c52004-09-18 20:17:01 +0000856
857#if UIP_UDP_CHECKSUMS
858 /* Calculate UDP checksum. */
859 UDPBUF->udpchksum = ~(uip_udpchksum());
860 if(UDPBUF->udpchksum == 0) {
861 UDPBUF->udpchksum = 0xffff;
862 }
863#endif /* UIP_UDP_CHECKSUMS */
864
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000865 goto ip_send_nolen;
866#endif /* UIP_UDP */
867
868 /* TCP input processing. */
869 tcp_input:
870 UIP_STAT(++uip_stat.tcp.recv);
871
872 /* Start of TCP input header processing code. */
873
874 if(uip_tcpchksum() != 0xffff) { /* Compute and check the TCP
875 checksum. */
876 UIP_STAT(++uip_stat.tcp.drop);
877 UIP_STAT(++uip_stat.tcp.chkerr);
adamdunkels9fad4132004-06-06 06:14:19 +0000878 UIP_LOG("tcp: bad checksum.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000879 goto drop;
880 }
881
adamdunkels9fad4132004-06-06 06:14:19 +0000882
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000883 /* Demultiplex this segment. */
884 /* First check any active connections. */
adamdunkels049a9122005-02-07 06:59:39 +0000885 for(uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1];
886 ++uip_connr) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000887 if(uip_connr->tcpstateflags != CLOSED &&
888 BUF->destport == uip_connr->lport &&
889 BUF->srcport == uip_connr->rport &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000890 BUF->srcipaddr[0] == uip_connr->ripaddr[0] &&
891 BUF->srcipaddr[1] == uip_connr->ripaddr[1]) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000892 goto found;
893 }
894 }
895
896 /* If we didn't find and active connection that expected the packet,
897 either this packet is an old duplicate, or this is a SYN packet
898 destined for a connection in LISTEN. If the SYN flag isn't set,
899 it is an old packet and we send a RST. */
adamdunkels049a9122005-02-07 06:59:39 +0000900 if((BUF->flags & TCP_CTL) != TCP_SYN) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000901 goto reset;
adamdunkels049a9122005-02-07 06:59:39 +0000902 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000903
adamdunkels0170b082003-10-01 11:25:37 +0000904 tmp16 = BUF->destport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000905 /* Next, check listening connections. */
adamdunkelscd8c3a22003-08-13 22:52:48 +0000906 for(c = 0; c < UIP_LISTENPORTS; ++c) {
adamdunkels0170b082003-10-01 11:25:37 +0000907 if(tmp16 == uip_listenports[c])
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000908 goto found_listen;
909 }
910
911 /* No matching connection found, so we send a RST packet. */
912 UIP_STAT(++uip_stat.tcp.synrst);
913 reset:
914
915 /* We do not send resets in response to resets. */
adamdunkels049a9122005-02-07 06:59:39 +0000916 if(BUF->flags & TCP_RST) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000917 goto drop;
adamdunkels049a9122005-02-07 06:59:39 +0000918 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000919
920 UIP_STAT(++uip_stat.tcp.rst);
921
922 BUF->flags = TCP_RST | TCP_ACK;
adamdunkels049a9122005-02-07 06:59:39 +0000923 uip_len = UIP_IPTCPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000924 BUF->tcpoffset = 5 << 4;
925
926 /* Flip the seqno and ackno fields in the TCP header. */
927 c = BUF->seqno[3];
928 BUF->seqno[3] = BUF->ackno[3];
929 BUF->ackno[3] = c;
930
931 c = BUF->seqno[2];
932 BUF->seqno[2] = BUF->ackno[2];
933 BUF->ackno[2] = c;
934
935 c = BUF->seqno[1];
936 BUF->seqno[1] = BUF->ackno[1];
937 BUF->ackno[1] = c;
938
939 c = BUF->seqno[0];
940 BUF->seqno[0] = BUF->ackno[0];
941 BUF->ackno[0] = c;
942
943 /* We also have to increase the sequence number we are
944 acknowledging. If the least significant byte overflowed, we need
945 to propagate the carry to the other bytes as well. */
946 if(++BUF->ackno[3] == 0) {
947 if(++BUF->ackno[2] == 0) {
948 if(++BUF->ackno[1] == 0) {
949 ++BUF->ackno[0];
950 }
951 }
952 }
953
954 /* Swap port numbers. */
adamdunkels0170b082003-10-01 11:25:37 +0000955 tmp16 = BUF->srcport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000956 BUF->srcport = BUF->destport;
adamdunkels0170b082003-10-01 11:25:37 +0000957 BUF->destport = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000958
959 /* Swap IP addresses. */
adamdunkels0170b082003-10-01 11:25:37 +0000960 tmp16 = BUF->destipaddr[0];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000961 BUF->destipaddr[0] = BUF->srcipaddr[0];
adamdunkels0170b082003-10-01 11:25:37 +0000962 BUF->srcipaddr[0] = tmp16;
963 tmp16 = BUF->destipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000964 BUF->destipaddr[1] = BUF->srcipaddr[1];
adamdunkels0170b082003-10-01 11:25:37 +0000965 BUF->srcipaddr[1] = tmp16;
adamdunkelsa38da252003-08-20 20:56:54 +0000966
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000967
968 /* And send out the RST packet! */
969 goto tcp_send_noconn;
970
971 /* This label will be jumped to if we matched the incoming packet
972 with a connection in LISTEN. In that case, we should create a new
973 connection and send a SYNACK in return. */
974 found_listen:
975 /* First we check if there are any connections avaliable. Unused
976 connections are kept in the same table as used connections, but
977 unused ones have the tcpstate set to CLOSED. Also, connections in
978 TIME_WAIT are kept track of and we'll use the oldest one if no
979 CLOSED connections are found. Thanks to Eddie C. Dost for a very
980 nice algorithm for the TIME_WAIT search. */
981 uip_connr = 0;
982 for(c = 0; c < UIP_CONNS; ++c) {
983 if(uip_conns[c].tcpstateflags == CLOSED) {
984 uip_connr = &uip_conns[c];
985 break;
986 }
987 if(uip_conns[c].tcpstateflags == TIME_WAIT) {
988 if(uip_connr == 0 ||
989 uip_conns[c].timer > uip_connr->timer) {
990 uip_connr = &uip_conns[c];
991 }
992 }
993 }
994
995 if(uip_connr == 0) {
996 /* All connections are used already, we drop packet and hope that
997 the remote end will retransmit the packet at a time when we
998 have more spare connections. */
999 UIP_STAT(++uip_stat.tcp.syndrop);
1000 UIP_LOG("tcp: found no unused connections.");
1001 goto drop;
1002 }
1003 uip_conn = uip_connr;
1004
1005 /* Fill in the necessary fields for the new connection. */
adamdunkelsb489e7a2003-10-14 11:12:50 +00001006 uip_connr->rto = uip_connr->timer = UIP_RTO;
1007 uip_connr->sa = 0;
1008 uip_connr->sv = 4;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001009 uip_connr->nrtx = 0;
1010 uip_connr->lport = BUF->destport;
1011 uip_connr->rport = BUF->srcport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001012 uip_connr->ripaddr[0] = BUF->srcipaddr[0];
1013 uip_connr->ripaddr[1] = BUF->srcipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001014 uip_connr->tcpstateflags = SYN_RCVD;
1015
1016 uip_connr->snd_nxt[0] = iss[0];
1017 uip_connr->snd_nxt[1] = iss[1];
1018 uip_connr->snd_nxt[2] = iss[2];
1019 uip_connr->snd_nxt[3] = iss[3];
1020 uip_connr->len = 1;
1021
1022 /* rcv_nxt should be the seqno from the incoming packet + 1. */
1023 uip_connr->rcv_nxt[3] = BUF->seqno[3];
1024 uip_connr->rcv_nxt[2] = BUF->seqno[2];
1025 uip_connr->rcv_nxt[1] = BUF->seqno[1];
1026 uip_connr->rcv_nxt[0] = BUF->seqno[0];
1027 uip_add_rcv_nxt(1);
1028
1029 /* Parse the TCP MSS option, if present. */
1030 if((BUF->tcpoffset & 0xf0) > 0x50) {
1031 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
1032 opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c];
adamdunkels049a9122005-02-07 06:59:39 +00001033 if(opt == TCP_OPT_END) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001034 /* End of options. */
1035 break;
adamdunkels049a9122005-02-07 06:59:39 +00001036 } else if(opt == TCP_OPT_NOOP) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001037 ++c;
1038 /* NOP option. */
adamdunkels049a9122005-02-07 06:59:39 +00001039 } else if(opt == TCP_OPT_MSS &&
1040 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001041 /* An MSS option with the right option length. */
adamdunkels0170b082003-10-01 11:25:37 +00001042 tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
adamdunkels049a9122005-02-07 06:59:39 +00001043 (u16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c];
adamdunkels0170b082003-10-01 11:25:37 +00001044 uip_connr->initialmss = uip_connr->mss =
1045 tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001046
1047 /* And we are done processing options. */
1048 break;
1049 } else {
1050 /* All other options have a length field, so that we easily
1051 can skip past them. */
1052 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
1053 /* If the length field is zero, the options are malformed
1054 and we don't process them further. */
1055 break;
1056 }
1057 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
1058 }
1059 }
1060 }
1061
1062 /* Our response will be a SYNACK. */
1063#if UIP_ACTIVE_OPEN
1064 tcp_send_synack:
1065 BUF->flags = TCP_ACK;
1066
1067 tcp_send_syn:
1068 BUF->flags |= TCP_SYN;
1069#else /* UIP_ACTIVE_OPEN */
1070 tcp_send_synack:
1071 BUF->flags = TCP_SYN | TCP_ACK;
1072#endif /* UIP_ACTIVE_OPEN */
1073
1074 /* We send out the TCP Maximum Segment Size option with our
1075 SYNACK. */
adamdunkels049a9122005-02-07 06:59:39 +00001076 BUF->optdata[0] = TCP_OPT_MSS;
1077 BUF->optdata[1] = TCP_OPT_MSS_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001078 BUF->optdata[2] = (UIP_TCP_MSS) / 256;
1079 BUF->optdata[3] = (UIP_TCP_MSS) & 255;
adamdunkels049a9122005-02-07 06:59:39 +00001080 uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN;
1081 BUF->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001082 goto tcp_send;
1083
1084 /* This label will be jumped to if we found an active connection. */
1085 found:
1086 uip_conn = uip_connr;
1087 uip_flags = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001088 /* We do a very naive form of TCP reset processing; we just accept
1089 any RST and kill our connection. We should in fact check if the
1090 sequence number of this reset is wihtin our advertised window
1091 before we accept the reset. */
1092 if(BUF->flags & TCP_RST) {
1093 uip_connr->tcpstateflags = CLOSED;
1094 UIP_LOG("tcp: got reset, aborting connection.");
1095 uip_flags = UIP_ABORT;
1096 UIP_APPCALL();
1097 goto drop;
adamdunkels47ec7fa2003-03-28 12:11:17 +00001098 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001099 /* Calculated the length of the data, if the application has sent
1100 any data to us. */
1101 c = (BUF->tcpoffset >> 4) << 2;
1102 /* uip_len will contain the length of the actual TCP data. This is
1103 calculated by subtracing the length of the TCP header (in
1104 c) and the length of the IP header (20 bytes). */
adamdunkels049a9122005-02-07 06:59:39 +00001105 uip_len = uip_len - c - UIP_IPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001106
1107 /* First, check if the sequence number of the incoming packet is
1108 what we're expecting next. If not, we send out an ACK with the
1109 correct numbers in. */
adamdunkels049a9122005-02-07 06:59:39 +00001110 if(!(((uip_connr->tcpstateflags & TS_MASK) == SYN_SENT) &&
1111 ((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) {
1112 if((uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 0)) &&
1113 (BUF->seqno[0] != uip_connr->rcv_nxt[0] ||
1114 BUF->seqno[1] != uip_connr->rcv_nxt[1] ||
1115 BUF->seqno[2] != uip_connr->rcv_nxt[2] ||
1116 BUF->seqno[3] != uip_connr->rcv_nxt[3])) {
1117 goto tcp_send_ack;
1118 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001119 }
1120
1121 /* Next, check if the incoming segment acknowledges any outstanding
1122 data. If so, we update the sequence number, reset the length of
1123 the outstanding data, calculate RTT estimations, and reset the
1124 retransmission timer. */
adamdunkels47ec7fa2003-03-28 12:11:17 +00001125 if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001126 uip_add32(uip_connr->snd_nxt, uip_connr->len);
adamdunkels08eac9e2004-09-12 07:17:37 +00001127
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001128 if(BUF->ackno[0] == uip_acc32[0] &&
1129 BUF->ackno[1] == uip_acc32[1] &&
1130 BUF->ackno[2] == uip_acc32[2] &&
1131 BUF->ackno[3] == uip_acc32[3]) {
1132 /* Update sequence number. */
1133 uip_connr->snd_nxt[0] = uip_acc32[0];
1134 uip_connr->snd_nxt[1] = uip_acc32[1];
1135 uip_connr->snd_nxt[2] = uip_acc32[2];
1136 uip_connr->snd_nxt[3] = uip_acc32[3];
adamdunkelsa38da252003-08-20 20:56:54 +00001137
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001138
1139 /* Do RTT estimation, unless we have done retransmissions. */
1140 if(uip_connr->nrtx == 0) {
1141 signed char m;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001142 m = uip_connr->rto - uip_connr->timer;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001143 /* This is taken directly from VJs original code in his paper */
1144 m = m - (uip_connr->sa >> 3);
1145 uip_connr->sa += m;
1146 if(m < 0) {
1147 m = -m;
1148 }
1149 m = m - (uip_connr->sv >> 2);
1150 uip_connr->sv += m;
1151 uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv;
1152
1153 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001154 /* Set the acknowledged flag. */
1155 uip_flags = UIP_ACKDATA;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001156 /* Reset the retransmission timer. */
adamdunkelsb489e7a2003-10-14 11:12:50 +00001157 uip_connr->timer = uip_connr->rto;
adamdunkels08eac9e2004-09-12 07:17:37 +00001158
1159 /* Reset length of outstanding data. */
1160 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001161 }
adamdunkelsab4b0822003-07-30 23:31:40 +00001162
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001163 }
1164
1165 /* Do different things depending on in what state the connection is. */
1166 switch(uip_connr->tcpstateflags & TS_MASK) {
1167 /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
1168 implemented, since we force the application to close when the
1169 peer sends a FIN (hence the application goes directly from
1170 ESTABLISHED to LAST_ACK). */
1171 case SYN_RCVD:
1172 /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and
1173 we are waiting for an ACK that acknowledges the data we sent
1174 out the last time. Therefore, we want to have the UIP_ACKDATA
1175 flag set. If so, we enter the ESTABLISHED state. */
1176 if(uip_flags & UIP_ACKDATA) {
1177 uip_connr->tcpstateflags = ESTABLISHED;
1178 uip_flags = UIP_CONNECTED;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001179 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001180 if(uip_len > 0) {
1181 uip_flags |= UIP_NEWDATA;
1182 uip_add_rcv_nxt(uip_len);
1183 }
1184 uip_slen = 0;
1185 UIP_APPCALL();
1186 goto appsend;
1187 }
1188 goto drop;
1189#if UIP_ACTIVE_OPEN
1190 case SYN_SENT:
1191 /* In SYN_SENT, we wait for a SYNACK that is sent in response to
1192 our SYN. The rcv_nxt is set to sequence number in the SYNACK
1193 plus one, and we send an ACK. We move into the ESTABLISHED
1194 state. */
1195 if((uip_flags & UIP_ACKDATA) &&
adamdunkels049a9122005-02-07 06:59:39 +00001196 (BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001197
1198 /* Parse the TCP MSS option, if present. */
1199 if((BUF->tcpoffset & 0xf0) > 0x50) {
1200 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
adamdunkels049a9122005-02-07 06:59:39 +00001201 opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c];
1202 if(opt == TCP_OPT_END) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001203 /* End of options. */
1204 break;
adamdunkels049a9122005-02-07 06:59:39 +00001205 } else if(opt == TCP_OPT_NOOP) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001206 ++c;
1207 /* NOP option. */
adamdunkels049a9122005-02-07 06:59:39 +00001208 } else if(opt == TCP_OPT_MSS &&
1209 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001210 /* An MSS option with the right option length. */
adamdunkels0170b082003-10-01 11:25:37 +00001211 tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001212 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];
adamdunkels0170b082003-10-01 11:25:37 +00001213 uip_connr->initialmss =
1214 uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001215
1216 /* And we are done processing options. */
1217 break;
1218 } else {
1219 /* All other options have a length field, so that we easily
1220 can skip past them. */
1221 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
1222 /* If the length field is zero, the options are malformed
1223 and we don't process them further. */
1224 break;
1225 }
1226 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
1227 }
1228 }
1229 }
1230 uip_connr->tcpstateflags = ESTABLISHED;
1231 uip_connr->rcv_nxt[0] = BUF->seqno[0];
1232 uip_connr->rcv_nxt[1] = BUF->seqno[1];
1233 uip_connr->rcv_nxt[2] = BUF->seqno[2];
1234 uip_connr->rcv_nxt[3] = BUF->seqno[3];
1235 uip_add_rcv_nxt(1);
1236 uip_flags = UIP_CONNECTED | UIP_NEWDATA;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001237 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001238 uip_len = 0;
1239 uip_slen = 0;
1240 UIP_APPCALL();
1241 goto appsend;
1242 }
adamdunkels049a9122005-02-07 06:59:39 +00001243 /* Inform the application that the connection failed */
1244 uip_flags = UIP_ABORT;
1245 UIP_APPCALL();
1246 /* The connection is closed after we send the RST */
1247 uip_conn->tcpstateflags = CLOSED;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001248 goto reset;
1249#endif /* UIP_ACTIVE_OPEN */
1250
1251 case ESTABLISHED:
1252 /* In the ESTABLISHED state, we call upon the application to feed
1253 data into the uip_buf. If the UIP_ACKDATA flag is set, the
1254 application should put new data into the buffer, otherwise we are
1255 retransmitting an old segment, and the application should put that
1256 data into the buffer.
1257
1258 If the incoming packet is a FIN, we should close the connection on
1259 this side as well, and we send out a FIN and enter the LAST_ACK
1260 state. We require that there is no outstanding data; otherwise the
1261 sequence numbers will be screwed up. */
1262
adamdunkels31a50262005-02-22 22:33:56 +00001263 if(BUF->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001264 if(uip_outstanding(uip_connr)) {
1265 goto drop;
1266 }
1267 uip_add_rcv_nxt(1 + uip_len);
1268 uip_flags = UIP_CLOSE;
1269 if(uip_len > 0) {
1270 uip_flags |= UIP_NEWDATA;
1271 }
1272 UIP_APPCALL();
1273 uip_connr->len = 1;
1274 uip_connr->tcpstateflags = LAST_ACK;
1275 uip_connr->nrtx = 0;
1276 tcp_send_finack:
1277 BUF->flags = TCP_FIN | TCP_ACK;
1278 goto tcp_send_nodata;
1279 }
1280
1281 /* Check the URG flag. If this is set, the segment carries urgent
1282 data that we must pass to the application. */
adamdunkels9fad4132004-06-06 06:14:19 +00001283 if((BUF->flags & TCP_URG) != 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001284#if UIP_URGDATA > 0
1285 uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1];
1286 if(uip_urglen > uip_len) {
1287 /* There is more urgent data in the next segment to come. */
1288 uip_urglen = uip_len;
1289 }
1290 uip_add_rcv_nxt(uip_urglen);
1291 uip_len -= uip_urglen;
1292 uip_urgdata = uip_appdata;
1293 uip_appdata += uip_urglen;
1294 } else {
1295 uip_urglen = 0;
adamdunkels9fad4132004-06-06 06:14:19 +00001296#else /* UIP_URGDATA > 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001297 uip_appdata += (BUF->urgp[0] << 8) | BUF->urgp[1];
1298 uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1];
adamdunkels9fad4132004-06-06 06:14:19 +00001299#endif /* UIP_URGDATA > 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001300 }
adamdunkels9fad4132004-06-06 06:14:19 +00001301
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001302 /* If uip_len > 0 we have TCP data in the packet, and we flag this
1303 by setting the UIP_NEWDATA flag and update the sequence number
1304 we acknowledge. If the application has stopped the dataflow
1305 using uip_stop(), we must not accept any data packets from the
1306 remote host. */
1307 if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
1308 uip_flags |= UIP_NEWDATA;
1309 uip_add_rcv_nxt(uip_len);
1310 }
adamdunkels0170b082003-10-01 11:25:37 +00001311
1312 /* Check if the available buffer space advertised by the other end
1313 is smaller than the initial MSS for this connection. If so, we
1314 set the current MSS to the window size to ensure that the
1315 application does not send more data than the other end can
1316 handle.
1317
1318 If the remote host advertises a zero window, we set the MSS to
1319 the initial MSS so that the application will send an entire MSS
1320 of data. This data will not be acknowledged by the receiver,
1321 and the application will retransmit it. This is called the
1322 "persistent timer" and uses the retransmission mechanim.
1323 */
1324 tmp16 = ((u16_t)BUF->wnd[0] << 8) + (u16_t)BUF->wnd[1];
1325 if(tmp16 > uip_connr->initialmss ||
1326 tmp16 == 0) {
1327 tmp16 = uip_connr->initialmss;
1328 }
1329 uip_connr->mss = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001330
1331 /* If this packet constitutes an ACK for outstanding data (flagged
1332 by the UIP_ACKDATA flag, we should call the application since it
1333 might want to send more data. If the incoming packet had data
1334 from the peer (as flagged by the UIP_NEWDATA flag), the
1335 application must also be notified.
1336
1337 When the application is called, the global variable uip_len
1338 contains the length of the incoming data. The application can
1339 access the incoming data through the global pointer
adamdunkels049a9122005-02-07 06:59:39 +00001340 uip_appdata, which usually points UIP_IPTCPH_LEN + UIP_LLH_LEN
1341 bytes into the uip_buf array.
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001342
1343 If the application wishes to send any data, this data should be
1344 put into the uip_appdata and the length of the data should be
1345 put into uip_len. If the application don't have any data to
1346 send, uip_len must be set to 0. */
1347 if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) {
1348 uip_slen = 0;
1349 UIP_APPCALL();
1350
1351 appsend:
adamdunkels0170b082003-10-01 11:25:37 +00001352
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001353 if(uip_flags & UIP_ABORT) {
1354 uip_slen = 0;
1355 uip_connr->tcpstateflags = CLOSED;
1356 BUF->flags = TCP_RST | TCP_ACK;
1357 goto tcp_send_nodata;
1358 }
1359
1360 if(uip_flags & UIP_CLOSE) {
1361 uip_slen = 0;
1362 uip_connr->len = 1;
1363 uip_connr->tcpstateflags = FIN_WAIT_1;
1364 uip_connr->nrtx = 0;
1365 BUF->flags = TCP_FIN | TCP_ACK;
1366 goto tcp_send_nodata;
1367 }
1368
adamdunkelsb489e7a2003-10-14 11:12:50 +00001369 /* If uip_slen > 0, the application has data to be sent. */
1370 if(uip_slen > 0) {
1371
1372 /* If the connection has acknowledged data, the contents of
1373 the ->len variable should be discarded. */
1374 if((uip_flags & UIP_ACKDATA) != 0) {
1375 uip_connr->len = 0;
1376 }
1377
1378 /* If the ->len variable is non-zero the connection has
1379 already data in transit and cannot send anymore right
1380 now. */
1381 if(uip_connr->len == 0) {
1382
1383 /* The application cannot send more than what is allowed by
1384 the mss (the minumum of the MSS and the available
1385 window). */
1386 if(uip_slen > uip_connr->mss) {
1387 uip_slen = uip_connr->mss;
1388 }
1389
1390 /* Remember how much data we send out now so that we know
1391 when everything has been acknowledged. */
1392 uip_connr->len = uip_slen;
1393 } else {
1394
1395 /* If the application already had unacknowledged data, we
1396 make sure that the application does not send (i.e.,
1397 retransmit) out more than it previously sent out. */
1398 uip_slen = uip_connr->len;
1399 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001400 }
adamdunkelsb489e7a2003-10-14 11:12:50 +00001401 uip_connr->nrtx = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001402 apprexmit:
adamdunkels0170b082003-10-01 11:25:37 +00001403 uip_appdata = uip_sappdata;
1404
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001405 /* If the application has data to be sent, or if the incoming
1406 packet had new data in it, we must send out a packet. */
adamdunkels759185d2003-06-30 20:35:41 +00001407 if(uip_slen > 0 && uip_connr->len > 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001408 /* Add the length of the IP and TCP headers. */
1409 uip_len = uip_connr->len + UIP_TCPIP_HLEN;
1410 /* We always set the ACK flag in response packets. */
adamdunkels759185d2003-06-30 20:35:41 +00001411 BUF->flags = TCP_ACK | TCP_PSH;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001412 /* Send the packet. */
1413 goto tcp_send_noopts;
1414 }
adamdunkels759185d2003-06-30 20:35:41 +00001415 /* If there is no data to send, just send out a pure ACK if
1416 there is newdata. */
1417 if(uip_flags & UIP_NEWDATA) {
1418 uip_len = UIP_TCPIP_HLEN;
1419 BUF->flags = TCP_ACK;
1420 goto tcp_send_noopts;
1421 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001422 }
1423 goto drop;
1424 case LAST_ACK:
1425 /* We can close this connection if the peer has acknowledged our
1426 FIN. This is indicated by the UIP_ACKDATA flag. */
1427 if(uip_flags & UIP_ACKDATA) {
1428 uip_connr->tcpstateflags = CLOSED;
1429 uip_flags = UIP_CLOSE;
1430 UIP_APPCALL();
1431 }
1432 break;
1433
1434 case FIN_WAIT_1:
1435 /* The application has closed the connection, but the remote host
1436 hasn't closed its end yet. Thus we do nothing but wait for a
1437 FIN from the other side. */
1438 if(uip_len > 0) {
1439 uip_add_rcv_nxt(uip_len);
1440 }
1441 if(BUF->flags & TCP_FIN) {
1442 if(uip_flags & UIP_ACKDATA) {
1443 uip_connr->tcpstateflags = TIME_WAIT;
1444 uip_connr->timer = 0;
1445 uip_connr->len = 0;
1446 } else {
1447 uip_connr->tcpstateflags = CLOSING;
1448 }
1449 uip_add_rcv_nxt(1);
1450 uip_flags = UIP_CLOSE;
1451 UIP_APPCALL();
1452 goto tcp_send_ack;
1453 } else if(uip_flags & UIP_ACKDATA) {
1454 uip_connr->tcpstateflags = FIN_WAIT_2;
1455 uip_connr->len = 0;
1456 goto drop;
1457 }
1458 if(uip_len > 0) {
1459 goto tcp_send_ack;
1460 }
1461 goto drop;
1462
1463 case FIN_WAIT_2:
1464 if(uip_len > 0) {
1465 uip_add_rcv_nxt(uip_len);
1466 }
1467 if(BUF->flags & TCP_FIN) {
1468 uip_connr->tcpstateflags = TIME_WAIT;
1469 uip_connr->timer = 0;
1470 uip_add_rcv_nxt(1);
1471 uip_flags = UIP_CLOSE;
1472 UIP_APPCALL();
1473 goto tcp_send_ack;
1474 }
1475 if(uip_len > 0) {
1476 goto tcp_send_ack;
1477 }
1478 goto drop;
1479
1480 case TIME_WAIT:
1481 goto tcp_send_ack;
1482
1483 case CLOSING:
1484 if(uip_flags & UIP_ACKDATA) {
1485 uip_connr->tcpstateflags = TIME_WAIT;
1486 uip_connr->timer = 0;
1487 }
1488 }
1489 goto drop;
1490
1491
1492 /* We jump here when we are ready to send the packet, and just want
1493 to set the appropriate TCP sequence numbers in the TCP header. */
1494 tcp_send_ack:
1495 BUF->flags = TCP_ACK;
1496 tcp_send_nodata:
adamdunkels049a9122005-02-07 06:59:39 +00001497 uip_len = UIP_IPTCPH_LEN;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001498 tcp_send_noopts:
adamdunkels049a9122005-02-07 06:59:39 +00001499 BUF->tcpoffset = (UIP_TCPH_LEN / 4) << 4;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001500 tcp_send:
1501 /* We're done with the input processing. We are now ready to send a
1502 reply. Our job is to fill in all the fields of the TCP and IP
1503 headers before calculating the checksum and finally send the
1504 packet. */
1505 BUF->ackno[0] = uip_connr->rcv_nxt[0];
1506 BUF->ackno[1] = uip_connr->rcv_nxt[1];
1507 BUF->ackno[2] = uip_connr->rcv_nxt[2];
1508 BUF->ackno[3] = uip_connr->rcv_nxt[3];
1509
1510 BUF->seqno[0] = uip_connr->snd_nxt[0];
1511 BUF->seqno[1] = uip_connr->snd_nxt[1];
1512 BUF->seqno[2] = uip_connr->snd_nxt[2];
1513 BUF->seqno[3] = uip_connr->snd_nxt[3];
1514
1515 BUF->proto = UIP_PROTO_TCP;
1516
1517 BUF->srcport = uip_connr->lport;
1518 BUF->destport = uip_connr->rport;
1519
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001520 BUF->srcipaddr[0] = uip_hostaddr[0];
1521 BUF->srcipaddr[1] = uip_hostaddr[1];
1522 BUF->destipaddr[0] = uip_connr->ripaddr[0];
1523 BUF->destipaddr[1] = uip_connr->ripaddr[1];
1524
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001525
1526 if(uip_connr->tcpstateflags & UIP_STOPPED) {
1527 /* If the connection has issued uip_stop(), we advertise a zero
1528 window so that the remote host will stop sending data. */
1529 BUF->wnd[0] = BUF->wnd[1] = 0;
1530 } else {
adamdunkelsb489e7a2003-10-14 11:12:50 +00001531 BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8);
1532 BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001533 }
1534
1535 tcp_send_noconn:
1536
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001537 BUF->len[0] = (uip_len >> 8);
1538 BUF->len[1] = (uip_len & 0xff);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001539
adamdunkels9fad4132004-06-06 06:14:19 +00001540 BUF->urgp[0] = BUF->urgp[1] = 0;
1541
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001542 /* Calculate TCP checksum. */
1543 BUF->tcpchksum = 0;
1544 BUF->tcpchksum = ~(uip_tcpchksum());
1545
1546 ip_send_nolen:
1547
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001548 BUF->vhl = 0x45;
1549 BUF->tos = 0;
1550 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
1551 BUF->ttl = UIP_TTL;
1552 ++ipid;
1553 BUF->ipid[0] = ipid >> 8;
1554 BUF->ipid[1] = ipid & 0xff;
1555
1556 /* Calculate IP checksum. */
1557 BUF->ipchksum = 0;
1558 BUF->ipchksum = ~(uip_ipchksum());
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001559
1560 UIP_STAT(++uip_stat.tcp.sent);
1561 send:
adamdunkels9fad4132004-06-06 06:14:19 +00001562
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001563 UIP_STAT(++uip_stat.ip.sent);
1564 /* Return and let the caller do the actual transmission. */
1565 return;
1566 drop:
1567 uip_len = 0;
1568 return;
1569}
1570/*-----------------------------------------------------------------------------------*/
adamdunkels47ec7fa2003-03-28 12:11:17 +00001571u16_t
1572htons(u16_t val)
1573{
1574 return HTONS(val);
1575}
1576/*-----------------------------------------------------------------------------------*/
adamdunkels0170b082003-10-01 11:25:37 +00001577/** @} */