blob: 18fc4ed5ae539a5ce5ace465c2083f85a3a1603c [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 *
adamdunkelsc4b80c52004-09-18 20:17:01 +000042 * $Id: uip.c,v 1.18 2004/09/18 20:17:01 adamdunkels Exp $
adamdunkelsca9ddcb2003-03-19 14:13:31 +000043 *
44 */
45
46/*
47This is a small implementation of the IP and TCP protocols (as well as
48some basic ICMP stuff). The implementation couples the IP, TCP and the
49application layers very tightly. To keep the size of the compiled code
50down, this code also features heavy usage of the goto statement.
51
52The principle is that we have a small buffer, called the uip_buf, in
53which the device driver puts an incoming packet. The TCP/IP stack
54parses the headers in the packet, and calls upon the application. If
55the remote host has sent data to the application, this data is present
56in the uip_buf and the application read the data from there. It is up
57to the application to put this data into a byte stream if needed. The
58application will not be fed with data that is out of sequence.
59
60If the application whishes to send data to the peer, it should put its
61data into the uip_buf, 40 bytes from the start of the buffer. The
62TCP/IP stack will calculate the checksums, and fill in the necessary
63header fields and finally send the packet back to the peer.
64*/
65
66#include "uip.h"
67#include "uipopt.h"
68#include "uip_arch.h"
69
70/*-----------------------------------------------------------------------------------*/
71/* Variable definitions. */
72
73
74/* The IP address of this host. If it is defined to be fixed (by setting UIP_FIXEDADDR to 1 in uipopt.h), the address is set here. Otherwise, the address */
75#if UIP_FIXEDADDR > 0
adamdunkelsca9ddcb2003-03-19 14:13:31 +000076const u16_t uip_hostaddr[2] =
adamdunkels47ec7fa2003-03-28 12:11:17 +000077 {HTONS((UIP_IPADDR0 << 8) | UIP_IPADDR1),
78 HTONS((UIP_IPADDR2 << 8) | UIP_IPADDR3)};
adamdunkels9fad4132004-06-06 06:14:19 +000079const u16_t uip_draddr[2] =
adamdunkelsb489e7a2003-10-14 11:12:50 +000080 {HTONS((UIP_DRIPADDR0 << 8) | UIP_DRIPADDR1),
81 HTONS((UIP_DRIPADDR2 << 8) | UIP_DRIPADDR3)};
adamdunkels9fad4132004-06-06 06:14:19 +000082const u16_t uip_netmask[2] =
adamdunkelsb489e7a2003-10-14 11:12:50 +000083 {HTONS((UIP_NETMASK0 << 8) | UIP_NETMASK1),
84 HTONS((UIP_NETMASK2 << 8) | UIP_NETMASK3)};
adamdunkelsca9ddcb2003-03-19 14:13:31 +000085#else
adamdunkelsca9ddcb2003-03-19 14:13:31 +000086u16_t uip_hostaddr[2];
adamdunkels9fad4132004-06-06 06:14:19 +000087u16_t uip_draddr[2], uip_netmask[2];
adamdunkelsca9ddcb2003-03-19 14:13:31 +000088#endif /* UIP_FIXEDADDR */
89
adamdunkelsb380a3e2004-09-17 20:59:23 +000090#if UIP_FIXEDETHADDR
91const struct uip_eth_addr uip_ethaddr = {{UIP_ETHADDR0,
92 UIP_ETHADDR1,
93 UIP_ETHADDR2,
94 UIP_ETHADDR3,
95 UIP_ETHADDR4,
96 UIP_ETHADDR5}};
97#else
98struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}};
99#endif
100
101
adamdunkelsa49d1dc2003-08-21 22:26:57 +0000102u8_t uip_buf[UIP_BUFSIZE+2]; /* The packet buffer that contains
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000103 incoming packets. */
adamdunkels9fad4132004-06-06 06:14:19 +0000104u8_t *uip_appdata; /* The uip_appdata pointer points to
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000105 application data. */
adamdunkels9fad4132004-06-06 06:14:19 +0000106u8_t *uip_sappdata; /* The uip_appdata pointer points to the
adamdunkels0170b082003-10-01 11:25:37 +0000107 application data which is to be sent. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000108#if UIP_URGDATA > 0
adamdunkels9fad4132004-06-06 06:14:19 +0000109u8_t *uip_urgdata; /* The uip_urgdata pointer points to
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000110 urgent data (out-of-band data), if
111 present. */
adamdunkels9fad4132004-06-06 06:14:19 +0000112u8_t uip_urglen, uip_surglen;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000113#endif /* UIP_URGDATA > 0 */
114
adamdunkels9fad4132004-06-06 06:14:19 +0000115u16_t uip_len, uip_slen;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000116 /* The uip_len is either 8 or 16 bits,
117 depending on the maximum packet
118 size. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000119
adamdunkels9fad4132004-06-06 06:14:19 +0000120u8_t uip_flags; /* The uip_flags variable is used for
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000121 communication between the TCP/IP stack
122 and the application program. */
123struct uip_conn *uip_conn; /* uip_conn always points to the current
124 connection. */
125
126struct uip_conn uip_conns[UIP_CONNS];
127 /* The uip_conns array holds all TCP
128 connections. */
129u16_t uip_listenports[UIP_LISTENPORTS];
130 /* The uip_listenports list all currently
131 listning ports. */
132#if UIP_UDP
133struct uip_udp_conn *uip_udp_conn;
134struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
135#endif /* UIP_UDP */
136
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000137static u16_t ipid; /* Ths ipid variable is an increasing
138 number that is used for the IP ID
139 field. */
140
141static u8_t iss[4]; /* The iss variable is used for the TCP
142 initial sequence number. */
143
144#if UIP_ACTIVE_OPEN
adamdunkelsb489e7a2003-10-14 11:12:50 +0000145static u16_t lastport; /* Keeps track of the last port used for
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000146 a new connection. */
147#endif /* UIP_ACTIVE_OPEN */
148
149/* Temporary variables. */
adamdunkels9fad4132004-06-06 06:14:19 +0000150u8_t uip_acc32[4];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000151static u8_t c, opt;
adamdunkels0170b082003-10-01 11:25:37 +0000152static u16_t tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000153
154/* Structures and definitions. */
155#define TCP_FIN 0x01
156#define TCP_SYN 0x02
157#define TCP_RST 0x04
158#define TCP_PSH 0x08
159#define TCP_ACK 0x10
160#define TCP_URG 0x20
161#define TCP_CTL 0x3f
162
163#define ICMP_ECHO_REPLY 0
164#define ICMP_ECHO 8
165
166/* Macros. */
167#define BUF ((uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
168#define FBUF ((uip_tcpip_hdr *)&uip_reassbuf[0])
169#define ICMPBUF ((uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
170#define UDPBUF ((uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])
171
172#if UIP_STATISTICS == 1
173struct uip_stats uip_stat;
174#define UIP_STAT(s) s
175#else
176#define UIP_STAT(s)
177#endif /* UIP_STATISTICS == 1 */
178
179#if UIP_LOGGING == 1
180#include <stdio.h>
181void uip_log(char *msg);
182#define UIP_LOG(m) uip_log(m)
183#else
184#define UIP_LOG(m)
185#endif /* UIP_LOGGING == 1 */
186
187/*-----------------------------------------------------------------------------------*/
188void
189uip_init(void)
190{
191 for(c = 0; c < UIP_LISTENPORTS; ++c) {
192 uip_listenports[c] = 0;
193 }
194 for(c = 0; c < UIP_CONNS; ++c) {
195 uip_conns[c].tcpstateflags = CLOSED;
196 }
197#if UIP_ACTIVE_OPEN
198 lastport = 1024;
199#endif /* UIP_ACTIVE_OPEN */
200
201#if UIP_UDP
202 for(c = 0; c < UIP_UDP_CONNS; ++c) {
203 uip_udp_conns[c].lport = 0;
204 }
205#endif /* UIP_UDP */
206
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000207
208 /* IPv4 initialization. */
209#if UIP_FIXEDADDR == 0
210 uip_hostaddr[0] = uip_hostaddr[1] = 0;
211#endif /* UIP_FIXEDADDR */
adamdunkelsa38da252003-08-20 20:56:54 +0000212
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000213}
214/*-----------------------------------------------------------------------------------*/
215#if UIP_ACTIVE_OPEN
216struct uip_conn *
217uip_connect(u16_t *ripaddr, u16_t rport)
218{
adamdunkelsa38da252003-08-20 20:56:54 +0000219 register struct uip_conn *conn, *cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000220
221 /* Find an unused local port. */
222 again:
223 ++lastport;
224
225 if(lastport >= 32000) {
226 lastport = 4096;
227 }
adamdunkels1e45c6d2003-09-02 21:47:27 +0000228
229 /* Check if this port is already in use, and if so try to find
230 another one. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000231 for(c = 0; c < UIP_CONNS; ++c) {
adamdunkels23664022003-08-05 13:51:50 +0000232 conn = &uip_conns[c];
233 if(conn->tcpstateflags != CLOSED &&
adamdunkels1e45c6d2003-09-02 21:47:27 +0000234 conn->lport == htons(lastport)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000235 goto again;
adamdunkelsa38da252003-08-20 20:56:54 +0000236 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000237 }
238
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000239 conn = 0;
240 for(c = 0; c < UIP_CONNS; ++c) {
adamdunkelsa38da252003-08-20 20:56:54 +0000241 cconn = &uip_conns[c];
242 if(cconn->tcpstateflags == CLOSED) {
243 conn = cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000244 break;
245 }
adamdunkelsa38da252003-08-20 20:56:54 +0000246 if(cconn->tcpstateflags == TIME_WAIT) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000247 if(conn == 0 ||
adamdunkels75b9d002004-09-17 20:48:39 +0000248 cconn->timer > conn->timer) {
adamdunkelsa38da252003-08-20 20:56:54 +0000249 conn = cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000250 }
251 }
252 }
253
254 if(conn == 0) {
255 return 0;
256 }
257
258 conn->tcpstateflags = SYN_SENT;
259
260 conn->snd_nxt[0] = iss[0];
261 conn->snd_nxt[1] = iss[1];
262 conn->snd_nxt[2] = iss[2];
263 conn->snd_nxt[3] = iss[3];
264
adamdunkels0170b082003-10-01 11:25:37 +0000265 conn->initialmss = conn->mss = UIP_TCP_MSS;
adamdunkelsd962db42003-08-21 18:10:21 +0000266
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000267 conn->len = 1; /* TCP length of the SYN is one. */
268 conn->nrtx = 0;
269 conn->timer = 1; /* Send the SYN next time around. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000270 conn->rto = UIP_RTO;
271 conn->sa = 0;
272 conn->sv = 16;
adamdunkels1e45c6d2003-09-02 21:47:27 +0000273 conn->lport = htons(lastport);
274 conn->rport = rport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000275 conn->ripaddr[0] = ripaddr[0];
276 conn->ripaddr[1] = ripaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000277
278 return conn;
279}
280#endif /* UIP_ACTIVE_OPEN */
281/*-----------------------------------------------------------------------------------*/
282#if UIP_UDP
283struct uip_udp_conn *
284uip_udp_new(u16_t *ripaddr, u16_t rport)
285{
adamdunkels23664022003-08-05 13:51:50 +0000286 register struct uip_udp_conn *conn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000287
288 /* Find an unused local port. */
289 again:
290 ++lastport;
291
292 if(lastport >= 32000) {
293 lastport = 4096;
294 }
295
296 for(c = 0; c < UIP_UDP_CONNS; ++c) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000297 if(uip_udp_conns[c].lport == lastport) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000298 goto again;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000299 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000300 }
301
302
303 conn = 0;
304 for(c = 0; c < UIP_UDP_CONNS; ++c) {
305 if(uip_udp_conns[c].lport == 0) {
306 conn = &uip_udp_conns[c];
307 break;
308 }
309 }
310
311 if(conn == 0) {
312 return 0;
313 }
314
adamdunkels47ec7fa2003-03-28 12:11:17 +0000315 conn->lport = HTONS(lastport);
adamdunkels75b9d002004-09-17 20:48:39 +0000316 conn->rport = rport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000317 conn->ripaddr[0] = ripaddr[0];
318 conn->ripaddr[1] = ripaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000319
320 return conn;
321}
322#endif /* UIP_UDP */
323/*-----------------------------------------------------------------------------------*/
324void
adamdunkelscd8c3a22003-08-13 22:52:48 +0000325uip_unlisten(u16_t port)
326{
327 for(c = 0; c < UIP_LISTENPORTS; ++c) {
328 if(uip_listenports[c] == port) {
329 uip_listenports[c] = 0;
330 return;
331 }
332 }
333}
334/*-----------------------------------------------------------------------------------*/
335void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000336uip_listen(u16_t port)
337{
338 for(c = 0; c < UIP_LISTENPORTS; ++c) {
339 if(uip_listenports[c] == 0) {
adamdunkels1e45c6d2003-09-02 21:47:27 +0000340 uip_listenports[c] = port;
adamdunkelscd8c3a22003-08-13 22:52:48 +0000341 return;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000342 }
343 }
344}
345/*-----------------------------------------------------------------------------------*/
adamdunkelsb489e7a2003-10-14 11:12:50 +0000346/* XXX: IP fragment reassembly: not well-tested. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000347
348#if UIP_REASSEMBLY
349#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)
350static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];
351static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];
352static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f,
353 0x0f, 0x07, 0x03, 0x01};
354static u16_t uip_reasslen;
355static u8_t uip_reassflags;
356#define UIP_REASS_FLAG_LASTFRAG 0x01
357static u8_t uip_reasstmr;
358
359#define IP_HLEN 20
adamdunkelsb489e7a2003-10-14 11:12:50 +0000360#define IP_MF 0x20
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000361
362static u8_t
363uip_reass(void)
364{
365 u16_t offset, len;
366 u16_t i;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000367
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000368 /* If ip_reasstmr is zero, no packet is present in the buffer, so we
369 write the IP header of the fragment into the reassembly
370 buffer. The timer is updated with the maximum age. */
371 if(uip_reasstmr == 0) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000372 memcpy(uip_reassbuf, &BUF->vhl, IP_HLEN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000373 uip_reasstmr = UIP_REASS_MAXAGE;
374 uip_reassflags = 0;
375 /* Clear the bitmap. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000376 memset(uip_reassbitmap, sizeof(uip_reassbitmap), 0);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000377 }
378
379 /* Check if the incoming fragment matches the one currently present
380 in the reasembly buffer. If so, we proceed with copying the
381 fragment into the buffer. */
382 if(BUF->srcipaddr[0] == FBUF->srcipaddr[0] &&
adamdunkelsb489e7a2003-10-14 11:12:50 +0000383 BUF->srcipaddr[1] == FBUF->srcipaddr[1] &&
384 BUF->destipaddr[0] == FBUF->destipaddr[0] &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000385 BUF->destipaddr[1] == FBUF->destipaddr[1] &&
adamdunkelsb489e7a2003-10-14 11:12:50 +0000386 BUF->ipid[0] == FBUF->ipid[0] &&
387 BUF->ipid[1] == FBUF->ipid[1]) {
388
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000389 len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4;
390 offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8;
391
392 /* If the offset or the offset + fragment length overflows the
393 reassembly buffer, we discard the entire packet. */
394 if(offset > UIP_REASS_BUFSIZE ||
395 offset + len > UIP_REASS_BUFSIZE) {
396 uip_reasstmr = 0;
397 goto nullreturn;
398 }
399
400 /* Copy the fragment into the reassembly buffer, at the right
401 offset. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000402 memcpy(&uip_reassbuf[IP_HLEN + offset],
403 (char *)BUF + (int)((BUF->vhl & 0x0f) * 4),
404 len);
405
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000406 /* Update the bitmap. */
407 if(offset / (8 * 8) == (offset + len) / (8 * 8)) {
408 /* If the two endpoints are in the same byte, we only update
409 that byte. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000410
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000411 uip_reassbitmap[offset / (8 * 8)] |=
adamdunkelsb489e7a2003-10-14 11:12:50 +0000412 bitmap_bits[(offset / 8 ) & 7] &
413 ~bitmap_bits[((offset + len) / 8 ) & 7];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000414 } else {
415 /* If the two endpoints are in different bytes, we update the
416 bytes in the endpoints and fill the stuff inbetween with
417 0xff. */
418 uip_reassbitmap[offset / (8 * 8)] |=
419 bitmap_bits[(offset / 8 ) & 7];
420 for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
421 uip_reassbitmap[i] = 0xff;
422 }
423 uip_reassbitmap[(offset + len) / (8 * 8)] |=
424 ~bitmap_bits[((offset + len) / 8 ) & 7];
425 }
426
427 /* If this fragment has the More Fragments flag set to zero, we
428 know that this is the last fragment, so we can calculate the
429 size of the entire packet. We also set the
430 IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
431 the final fragment. */
432
433 if((BUF->ipoffset[0] & IP_MF) == 0) {
434 uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
435 uip_reasslen = offset + len;
436 }
437
438 /* Finally, we check if we have a full packet in the buffer. We do
439 this by checking if we have the last fragment and if all bits
440 in the bitmap are set. */
441 if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) {
442 /* Check all bytes up to and including all but the last byte in
443 the bitmap. */
444 for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) {
445 if(uip_reassbitmap[i] != 0xff) {
446 goto nullreturn;
447 }
448 }
449 /* Check the last byte in the bitmap. It should contain just the
450 right amount of bits. */
451 if(uip_reassbitmap[uip_reasslen / (8 * 8)] !=
452 (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) {
453 goto nullreturn;
454 }
455
456 /* If we have come this far, we have a full packet in the
457 buffer, so we allocate a pbuf and copy the packet into it. We
458 also reset the timer. */
459 uip_reasstmr = 0;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000460 memcpy(BUF, FBUF, uip_reasslen);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000461
462 /* Pretend to be a "normal" (i.e., not fragmented) IP packet
463 from now on. */
464 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000465 BUF->len[0] = uip_reasslen >> 8;
466 BUF->len[1] = uip_reasslen & 0xff;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000467 BUF->ipchksum = 0;
468 BUF->ipchksum = ~(uip_ipchksum());
469
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000470 return uip_reasslen;
471 }
472 }
473
474 nullreturn:
475 return 0;
476}
adamdunkelsb489e7a2003-10-14 11:12:50 +0000477#endif /* UIP_REASSEMBL */
478/*-----------------------------------------------------------------------------------*/
479static void
480uip_add_rcv_nxt(u16_t n)
481{
482 uip_add32(uip_conn->rcv_nxt, n);
483 uip_conn->rcv_nxt[0] = uip_acc32[0];
484 uip_conn->rcv_nxt[1] = uip_acc32[1];
485 uip_conn->rcv_nxt[2] = uip_acc32[2];
486 uip_conn->rcv_nxt[3] = uip_acc32[3];
487}
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000488/*-----------------------------------------------------------------------------------*/
489void
490uip_process(u8_t flag)
491{
492 register struct uip_conn *uip_connr = uip_conn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000493
494 uip_appdata = &uip_buf[40 + UIP_LLH_LEN];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000495
496 /* Check if we were invoked because of the perodic timer fireing. */
497 if(flag == UIP_TIMER) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000498#if UIP_REASSEMBLY
499 if(uip_reasstmr != 0) {
500 --uip_reasstmr;
501 }
502#endif /* UIP_REASSEMBLY */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000503 /* Increase the initial sequence number. */
504 if(++iss[3] == 0) {
505 if(++iss[2] == 0) {
506 if(++iss[1] == 0) {
507 ++iss[0];
508 }
509 }
510 }
511 uip_len = 0;
512 if(uip_connr->tcpstateflags == TIME_WAIT ||
513 uip_connr->tcpstateflags == FIN_WAIT_2) {
514 ++(uip_connr->timer);
515 if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) {
516 uip_connr->tcpstateflags = CLOSED;
517 }
518 } else if(uip_connr->tcpstateflags != CLOSED) {
519 /* If the connection has outstanding data, we increase the
520 connection's timer and see if it has reached the RTO value
521 in which case we retransmit. */
522 if(uip_outstanding(uip_connr)) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000523 if(uip_connr->timer-- == 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000524 if(uip_connr->nrtx == UIP_MAXRTX ||
525 ((uip_connr->tcpstateflags == SYN_SENT ||
526 uip_connr->tcpstateflags == SYN_RCVD) &&
527 uip_connr->nrtx == UIP_MAXSYNRTX)) {
528 uip_connr->tcpstateflags = CLOSED;
529
530 /* We call UIP_APPCALL() with uip_flags set to
531 UIP_TIMEDOUT to inform the application that the
532 connection has timed out. */
533 uip_flags = UIP_TIMEDOUT;
534 UIP_APPCALL();
535
536 /* We also send a reset packet to the remote host. */
537 BUF->flags = TCP_RST | TCP_ACK;
538 goto tcp_send_nodata;
539 }
540
541 /* Exponential backoff. */
adamdunkels47ec7fa2003-03-28 12:11:17 +0000542 uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4?
543 4:
544 uip_connr->nrtx);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000545 ++(uip_connr->nrtx);
546
547 /* Ok, so we need to retransmit. We do this differently
548 depending on which state we are in. In ESTABLISHED, we
549 call upon the application so that it may prepare the
550 data for the retransmit. In SYN_RCVD, we resend the
551 SYNACK that we sent earlier and in LAST_ACK we have to
552 retransmit our FINACK. */
553 UIP_STAT(++uip_stat.tcp.rexmit);
554 switch(uip_connr->tcpstateflags & TS_MASK) {
555 case SYN_RCVD:
556 /* In the SYN_RCVD state, we should retransmit our
557 SYNACK. */
558 goto tcp_send_synack;
559
560#if UIP_ACTIVE_OPEN
561 case SYN_SENT:
562 /* In the SYN_SENT state, we retransmit out SYN. */
563 BUF->flags = 0;
564 goto tcp_send_syn;
565#endif /* UIP_ACTIVE_OPEN */
566
567 case ESTABLISHED:
568 /* In the ESTABLISHED state, we call upon the application
569 to do the actual retransmit after which we jump into
570 the code for sending out the packet (the apprexmit
571 label). */
572 uip_len = 0;
573 uip_slen = 0;
574 uip_flags = UIP_REXMIT;
575 UIP_APPCALL();
576 goto apprexmit;
577
578 case FIN_WAIT_1:
579 case CLOSING:
580 case LAST_ACK:
581 /* In all these states we should retransmit a FINACK. */
582 goto tcp_send_finack;
583
584 }
585 }
586 } else if((uip_connr->tcpstateflags & TS_MASK) == ESTABLISHED) {
587 /* If there was no need for a retransmission, we poll the
588 application for new data. */
589 uip_len = 0;
590 uip_slen = 0;
591 uip_flags = UIP_POLL;
592 UIP_APPCALL();
593 goto appsend;
594 }
595 }
596 goto drop;
597 }
598#if UIP_UDP
599 if(flag == UIP_UDP_TIMER) {
600 if(uip_udp_conn->lport != 0) {
adamdunkels399a0782004-02-16 20:52:07 +0000601 uip_conn = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000602 uip_appdata = &uip_buf[UIP_LLH_LEN + 28];
603 uip_len = uip_slen = 0;
604 uip_flags = UIP_POLL;
605 UIP_UDP_APPCALL();
606 goto udp_send;
607 } else {
608 goto drop;
609 }
610 }
611#endif
612
613 /* This is where the input processing starts. */
614 UIP_STAT(++uip_stat.ip.recv);
615
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000616
617 /* Start of IPv4 input header processing code. */
618
619 /* Check validity of the IP header. */
620 if(BUF->vhl != 0x45) { /* IP version and header length. */
621 UIP_STAT(++uip_stat.ip.drop);
622 UIP_STAT(++uip_stat.ip.vhlerr);
623 UIP_LOG("ip: invalid version or header length.");
624 goto drop;
625 }
626
627 /* Check the size of the packet. If the size reported to us in
adamdunkels9fad4132004-06-06 06:14:19 +0000628 uip_len doesn't match the size reported in the IP header, the
629 packet has been padded by the network device. We correct the
630 uip_len variable based on the reported length in the IP
631 header. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000632
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000633 if(BUF->len[0] != (uip_len >> 8)) { /* IP length, high byte. */
634 uip_len = (uip_len & 0xff) | (BUF->len[0] << 8);
635 }
636 if(BUF->len[1] != (uip_len & 0xff)) { /* IP length, low byte. */
637 uip_len = (uip_len & 0xff00) | BUF->len[1];
638 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000639
adamdunkelsb489e7a2003-10-14 11:12:50 +0000640 /* Check the fragment flag. */
641 if((BUF->ipoffset[0] & 0x3f) != 0 ||
642 BUF->ipoffset[1] != 0) {
643#if UIP_REASSEMBLY
644 uip_len = uip_reass();
645 if(uip_len == 0) {
646 goto drop;
647 }
648#else
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000649 UIP_STAT(++uip_stat.ip.drop);
650 UIP_STAT(++uip_stat.ip.fragerr);
651 UIP_LOG("ip: fragment dropped.");
652 goto drop;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000653#endif /* UIP_REASSEMBLY */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000654 }
655
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000656 if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
adamdunkels75b9d002004-09-17 20:48:39 +0000657 /* If we are configured to use ping IP address configuration and
658 hasn't been assigned an IP address yet, we accept all ICMP
659 packets. */
660#if UIP_PINGADDRCONF
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000661 if(BUF->proto == UIP_PROTO_ICMP) {
662 UIP_LOG("ip: possible ping config packet received.");
663 goto icmp_input;
664 } else {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000665 UIP_LOG("ip: packet dropped since no address assigned.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000666 goto drop;
adamdunkels75b9d002004-09-17 20:48:39 +0000667 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000668#endif /* UIP_PINGADDRCONF */
adamdunkels9fad4132004-06-06 06:14:19 +0000669
adamdunkels75b9d002004-09-17 20:48:39 +0000670 } else {
671 /* If IP broadcast support is configured, we check for a broadcast
672 UDP packet, which may be destined to us. */
adamdunkels9fad4132004-06-06 06:14:19 +0000673#if UIP_BROADCAST
adamdunkels75b9d002004-09-17 20:48:39 +0000674 if(BUF->proto == UIP_PROTO_UDP &&
675 BUF->destipaddr[0] == 0xffff &&
adamdunkels9fad4132004-06-06 06:14:19 +0000676 BUF->destipaddr[1] == 0xffff &&
adamdunkels75b9d002004-09-17 20:48:39 +0000677 uip_ipchksum() == 0xffff) {
678 goto udp_input;
679 }
adamdunkels9fad4132004-06-06 06:14:19 +0000680#endif /* UIP_BROADCAST */
adamdunkels75b9d002004-09-17 20:48:39 +0000681
682 /* Check if the packet is destined for our IP address. */
683 if(BUF->destipaddr[0] != uip_hostaddr[0]) {
684 UIP_STAT(++uip_stat.ip.drop);
685 /* UIP_LOG("ip: packet not for us."); */
686 goto drop;
687 }
688 if(BUF->destipaddr[1] != uip_hostaddr[1]) {
689 UIP_STAT(++uip_stat.ip.drop);
690 /* UIP_LOG("ip: packet not for us."); */
691 goto drop;
692 }
693 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000694
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000695 if(uip_ipchksum() != 0xffff) { /* Compute and check the IP header
696 checksum. */
697 UIP_STAT(++uip_stat.ip.drop);
698 UIP_STAT(++uip_stat.ip.chkerr);
adamdunkels9fad4132004-06-06 06:14:19 +0000699 UIP_LOG("ip: bad checksum.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000700 goto drop;
701 }
702
703 if(BUF->proto == UIP_PROTO_TCP) /* Check for TCP packet. If so, jump
704 to the tcp_input label. */
705 goto tcp_input;
706
707#if UIP_UDP
708 if(BUF->proto == UIP_PROTO_UDP)
709 goto udp_input;
710#endif /* UIP_UDP */
711
712 if(BUF->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from
713 here. */
714 UIP_STAT(++uip_stat.ip.drop);
715 UIP_STAT(++uip_stat.ip.protoerr);
716 UIP_LOG("ip: neither tcp nor icmp.");
717 goto drop;
718 }
719
720 icmp_input:
721 UIP_STAT(++uip_stat.icmp.recv);
722
723 /* ICMP echo (i.e., ping) processing. This is simple, we only change
724 the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
725 checksum before we return the packet. */
726 if(ICMPBUF->type != ICMP_ECHO) {
727 UIP_STAT(++uip_stat.icmp.drop);
728 UIP_STAT(++uip_stat.icmp.typeerr);
729 UIP_LOG("icmp: not icmp echo.");
730 goto drop;
731 }
732
733 /* If we are configured to use ping IP address assignment, we use
734 the destination IP address of this ping packet and assign it to
735 ourself. */
736#if UIP_PINGADDRCONF
737 if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
738 uip_hostaddr[0] = BUF->destipaddr[0];
739 uip_hostaddr[1] = BUF->destipaddr[1];
740 }
741#endif /* UIP_PINGADDRCONF */
742
743 ICMPBUF->type = ICMP_ECHO_REPLY;
744
adamdunkels47ec7fa2003-03-28 12:11:17 +0000745 if(ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) {
746 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000747 } else {
adamdunkels47ec7fa2003-03-28 12:11:17 +0000748 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000749 }
750
751 /* Swap IP addresses. */
adamdunkels0170b082003-10-01 11:25:37 +0000752 tmp16 = BUF->destipaddr[0];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000753 BUF->destipaddr[0] = BUF->srcipaddr[0];
adamdunkels0170b082003-10-01 11:25:37 +0000754 BUF->srcipaddr[0] = tmp16;
755 tmp16 = BUF->destipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000756 BUF->destipaddr[1] = BUF->srcipaddr[1];
adamdunkels0170b082003-10-01 11:25:37 +0000757 BUF->srcipaddr[1] = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000758
759 UIP_STAT(++uip_stat.icmp.sent);
760 goto send;
761
762 /* End of IPv4 input header processing code. */
763
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000764
765#if UIP_UDP
766 /* UDP input processing. */
767 udp_input:
768 /* UDP processing is really just a hack. We don't do anything to the
769 UDP/IP headers, but let the UDP application do all the hard
770 work. If the application sets uip_slen, it has a packet to
771 send. */
772#if UIP_UDP_CHECKSUMS
773 if(uip_udpchksum() != 0xffff) {
774 UIP_STAT(++uip_stat.udp.drop);
775 UIP_STAT(++uip_stat.udp.chkerr);
776 UIP_LOG("udp: bad checksum.");
777 goto drop;
778 }
779#endif /* UIP_UDP_CHECKSUMS */
780
781 /* Demultiplex this UDP packet between the UDP "connections". */
782 for(uip_udp_conn = &uip_udp_conns[0];
783 uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS];
784 ++uip_udp_conn) {
adamdunkels9fad4132004-06-06 06:14:19 +0000785 /* If the local UDP port is non-zero, the connection is considered
786 to be used. If so, the local port number is checked against the
787 destination port number in the received packet. If the two port
788 numbers match, the remote port number is checked if the
789 connection is bound to a remote port. Finally, if the
790 connection is bound to a remote IP address, the source IP
791 address of the packet is checked. */
792 if(uip_udp_conn->lport != 0 &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000793 UDPBUF->destport == uip_udp_conn->lport &&
794 (uip_udp_conn->rport == 0 ||
795 UDPBUF->srcport == uip_udp_conn->rport) &&
adamdunkels9fad4132004-06-06 06:14:19 +0000796 ((uip_udp_conn->ripaddr[0] | uip_udp_conn->ripaddr[1]) == 0 ||
797 (uip_udp_conn->ripaddr[0] == 0xffff &&
798 uip_udp_conn->ripaddr[1] == 0xffff) ||
799 uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000800 goto udp_found;
801 }
802 }
adamdunkels9fad4132004-06-06 06:14:19 +0000803 UIP_LOG("udp: no matching connection found");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000804 goto drop;
805
806 udp_found:
adamdunkels399a0782004-02-16 20:52:07 +0000807 uip_conn = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000808 uip_len = uip_len - 28;
809 uip_appdata = &uip_buf[UIP_LLH_LEN + 28];
810 uip_flags = UIP_NEWDATA;
811 uip_slen = 0;
812 UIP_UDP_APPCALL();
813 udp_send:
814 if(uip_slen == 0) {
815 goto drop;
816 }
817 uip_len = uip_slen + 28;
818
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000819 BUF->len[0] = (uip_len >> 8);
820 BUF->len[1] = (uip_len & 0xff);
adamdunkelsb489e7a2003-10-14 11:12:50 +0000821
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000822 BUF->proto = UIP_PROTO_UDP;
823
adamdunkels47ec7fa2003-03-28 12:11:17 +0000824 UDPBUF->udplen = HTONS(uip_slen + 8);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000825 UDPBUF->udpchksum = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000826
827 BUF->srcport = uip_udp_conn->lport;
828 BUF->destport = uip_udp_conn->rport;
829
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000830 BUF->srcipaddr[0] = uip_hostaddr[0];
831 BUF->srcipaddr[1] = uip_hostaddr[1];
832 BUF->destipaddr[0] = uip_udp_conn->ripaddr[0];
833 BUF->destipaddr[1] = uip_udp_conn->ripaddr[1];
834
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000835 uip_appdata = &uip_buf[UIP_LLH_LEN + 40];
adamdunkelsc4b80c52004-09-18 20:17:01 +0000836
837#if UIP_UDP_CHECKSUMS
838 /* Calculate UDP checksum. */
839 UDPBUF->udpchksum = ~(uip_udpchksum());
840 if(UDPBUF->udpchksum == 0) {
841 UDPBUF->udpchksum = 0xffff;
842 }
843#endif /* UIP_UDP_CHECKSUMS */
844
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000845 goto ip_send_nolen;
846#endif /* UIP_UDP */
847
848 /* TCP input processing. */
849 tcp_input:
850 UIP_STAT(++uip_stat.tcp.recv);
851
852 /* Start of TCP input header processing code. */
853
854 if(uip_tcpchksum() != 0xffff) { /* Compute and check the TCP
855 checksum. */
856 UIP_STAT(++uip_stat.tcp.drop);
857 UIP_STAT(++uip_stat.tcp.chkerr);
adamdunkels9fad4132004-06-06 06:14:19 +0000858 UIP_LOG("tcp: bad checksum.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000859 goto drop;
860 }
861
adamdunkels9fad4132004-06-06 06:14:19 +0000862
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000863 /* Demultiplex this segment. */
864 /* First check any active connections. */
865 for(uip_connr = &uip_conns[0]; uip_connr < &uip_conns[UIP_CONNS]; ++uip_connr) {
866 if(uip_connr->tcpstateflags != CLOSED &&
867 BUF->destport == uip_connr->lport &&
868 BUF->srcport == uip_connr->rport &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000869 BUF->srcipaddr[0] == uip_connr->ripaddr[0] &&
870 BUF->srcipaddr[1] == uip_connr->ripaddr[1]) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000871 goto found;
872 }
873 }
874
875 /* If we didn't find and active connection that expected the packet,
876 either this packet is an old duplicate, or this is a SYN packet
877 destined for a connection in LISTEN. If the SYN flag isn't set,
878 it is an old packet and we send a RST. */
879 if((BUF->flags & TCP_CTL) != TCP_SYN)
880 goto reset;
881
adamdunkels0170b082003-10-01 11:25:37 +0000882 tmp16 = BUF->destport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000883 /* Next, check listening connections. */
adamdunkelscd8c3a22003-08-13 22:52:48 +0000884 for(c = 0; c < UIP_LISTENPORTS; ++c) {
adamdunkels0170b082003-10-01 11:25:37 +0000885 if(tmp16 == uip_listenports[c])
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000886 goto found_listen;
887 }
888
889 /* No matching connection found, so we send a RST packet. */
890 UIP_STAT(++uip_stat.tcp.synrst);
891 reset:
892
893 /* We do not send resets in response to resets. */
894 if(BUF->flags & TCP_RST)
895 goto drop;
896
897 UIP_STAT(++uip_stat.tcp.rst);
898
899 BUF->flags = TCP_RST | TCP_ACK;
900 uip_len = 40;
901 BUF->tcpoffset = 5 << 4;
902
903 /* Flip the seqno and ackno fields in the TCP header. */
904 c = BUF->seqno[3];
905 BUF->seqno[3] = BUF->ackno[3];
906 BUF->ackno[3] = c;
907
908 c = BUF->seqno[2];
909 BUF->seqno[2] = BUF->ackno[2];
910 BUF->ackno[2] = c;
911
912 c = BUF->seqno[1];
913 BUF->seqno[1] = BUF->ackno[1];
914 BUF->ackno[1] = c;
915
916 c = BUF->seqno[0];
917 BUF->seqno[0] = BUF->ackno[0];
918 BUF->ackno[0] = c;
919
920 /* We also have to increase the sequence number we are
921 acknowledging. If the least significant byte overflowed, we need
922 to propagate the carry to the other bytes as well. */
923 if(++BUF->ackno[3] == 0) {
924 if(++BUF->ackno[2] == 0) {
925 if(++BUF->ackno[1] == 0) {
926 ++BUF->ackno[0];
927 }
928 }
929 }
930
931 /* Swap port numbers. */
adamdunkels0170b082003-10-01 11:25:37 +0000932 tmp16 = BUF->srcport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000933 BUF->srcport = BUF->destport;
adamdunkels0170b082003-10-01 11:25:37 +0000934 BUF->destport = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000935
936 /* Swap IP addresses. */
adamdunkels0170b082003-10-01 11:25:37 +0000937 tmp16 = BUF->destipaddr[0];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000938 BUF->destipaddr[0] = BUF->srcipaddr[0];
adamdunkels0170b082003-10-01 11:25:37 +0000939 BUF->srcipaddr[0] = tmp16;
940 tmp16 = BUF->destipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000941 BUF->destipaddr[1] = BUF->srcipaddr[1];
adamdunkels0170b082003-10-01 11:25:37 +0000942 BUF->srcipaddr[1] = tmp16;
adamdunkelsa38da252003-08-20 20:56:54 +0000943
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000944
945 /* And send out the RST packet! */
946 goto tcp_send_noconn;
947
948 /* This label will be jumped to if we matched the incoming packet
949 with a connection in LISTEN. In that case, we should create a new
950 connection and send a SYNACK in return. */
951 found_listen:
952 /* First we check if there are any connections avaliable. Unused
953 connections are kept in the same table as used connections, but
954 unused ones have the tcpstate set to CLOSED. Also, connections in
955 TIME_WAIT are kept track of and we'll use the oldest one if no
956 CLOSED connections are found. Thanks to Eddie C. Dost for a very
957 nice algorithm for the TIME_WAIT search. */
958 uip_connr = 0;
959 for(c = 0; c < UIP_CONNS; ++c) {
960 if(uip_conns[c].tcpstateflags == CLOSED) {
961 uip_connr = &uip_conns[c];
962 break;
963 }
964 if(uip_conns[c].tcpstateflags == TIME_WAIT) {
965 if(uip_connr == 0 ||
966 uip_conns[c].timer > uip_connr->timer) {
967 uip_connr = &uip_conns[c];
968 }
969 }
970 }
971
972 if(uip_connr == 0) {
973 /* All connections are used already, we drop packet and hope that
974 the remote end will retransmit the packet at a time when we
975 have more spare connections. */
976 UIP_STAT(++uip_stat.tcp.syndrop);
977 UIP_LOG("tcp: found no unused connections.");
978 goto drop;
979 }
980 uip_conn = uip_connr;
981
982 /* Fill in the necessary fields for the new connection. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000983 uip_connr->rto = uip_connr->timer = UIP_RTO;
984 uip_connr->sa = 0;
985 uip_connr->sv = 4;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000986 uip_connr->nrtx = 0;
987 uip_connr->lport = BUF->destport;
988 uip_connr->rport = BUF->srcport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000989 uip_connr->ripaddr[0] = BUF->srcipaddr[0];
990 uip_connr->ripaddr[1] = BUF->srcipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000991 uip_connr->tcpstateflags = SYN_RCVD;
992
993 uip_connr->snd_nxt[0] = iss[0];
994 uip_connr->snd_nxt[1] = iss[1];
995 uip_connr->snd_nxt[2] = iss[2];
996 uip_connr->snd_nxt[3] = iss[3];
997 uip_connr->len = 1;
998
999 /* rcv_nxt should be the seqno from the incoming packet + 1. */
1000 uip_connr->rcv_nxt[3] = BUF->seqno[3];
1001 uip_connr->rcv_nxt[2] = BUF->seqno[2];
1002 uip_connr->rcv_nxt[1] = BUF->seqno[1];
1003 uip_connr->rcv_nxt[0] = BUF->seqno[0];
1004 uip_add_rcv_nxt(1);
1005
1006 /* Parse the TCP MSS option, if present. */
1007 if((BUF->tcpoffset & 0xf0) > 0x50) {
1008 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
1009 opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c];
1010 if(opt == 0x00) {
1011 /* End of options. */
1012 break;
1013 } else if(opt == 0x01) {
1014 ++c;
1015 /* NOP option. */
1016 } else if(opt == 0x02 &&
1017 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0x04) {
1018 /* An MSS option with the right option length. */
adamdunkels0170b082003-10-01 11:25:37 +00001019 tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
1020 (u16_t)uip_buf[40 + UIP_LLH_LEN + 3 + c];
1021 uip_connr->initialmss = uip_connr->mss =
1022 tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001023
1024 /* And we are done processing options. */
1025 break;
1026 } else {
1027 /* All other options have a length field, so that we easily
1028 can skip past them. */
1029 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
1030 /* If the length field is zero, the options are malformed
1031 and we don't process them further. */
1032 break;
1033 }
1034 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
1035 }
1036 }
1037 }
1038
1039 /* Our response will be a SYNACK. */
1040#if UIP_ACTIVE_OPEN
1041 tcp_send_synack:
1042 BUF->flags = TCP_ACK;
1043
1044 tcp_send_syn:
1045 BUF->flags |= TCP_SYN;
1046#else /* UIP_ACTIVE_OPEN */
1047 tcp_send_synack:
1048 BUF->flags = TCP_SYN | TCP_ACK;
1049#endif /* UIP_ACTIVE_OPEN */
1050
1051 /* We send out the TCP Maximum Segment Size option with our
1052 SYNACK. */
1053 BUF->optdata[0] = 2;
1054 BUF->optdata[1] = 4;
1055 BUF->optdata[2] = (UIP_TCP_MSS) / 256;
1056 BUF->optdata[3] = (UIP_TCP_MSS) & 255;
1057 uip_len = 44;
1058 BUF->tcpoffset = 6 << 4;
1059 goto tcp_send;
1060
1061 /* This label will be jumped to if we found an active connection. */
1062 found:
1063 uip_conn = uip_connr;
1064 uip_flags = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001065 /* We do a very naive form of TCP reset processing; we just accept
1066 any RST and kill our connection. We should in fact check if the
1067 sequence number of this reset is wihtin our advertised window
1068 before we accept the reset. */
1069 if(BUF->flags & TCP_RST) {
1070 uip_connr->tcpstateflags = CLOSED;
1071 UIP_LOG("tcp: got reset, aborting connection.");
1072 uip_flags = UIP_ABORT;
1073 UIP_APPCALL();
1074 goto drop;
adamdunkels47ec7fa2003-03-28 12:11:17 +00001075 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001076 /* Calculated the length of the data, if the application has sent
1077 any data to us. */
1078 c = (BUF->tcpoffset >> 4) << 2;
1079 /* uip_len will contain the length of the actual TCP data. This is
1080 calculated by subtracing the length of the TCP header (in
1081 c) and the length of the IP header (20 bytes). */
1082 uip_len = uip_len - c - 20;
1083
1084 /* First, check if the sequence number of the incoming packet is
1085 what we're expecting next. If not, we send out an ACK with the
1086 correct numbers in. */
1087 if(uip_len > 0 &&
1088 (BUF->seqno[0] != uip_connr->rcv_nxt[0] ||
1089 BUF->seqno[1] != uip_connr->rcv_nxt[1] ||
1090 BUF->seqno[2] != uip_connr->rcv_nxt[2] ||
1091 BUF->seqno[3] != uip_connr->rcv_nxt[3])) {
1092 goto tcp_send_ack;
1093 }
1094
1095 /* Next, check if the incoming segment acknowledges any outstanding
1096 data. If so, we update the sequence number, reset the length of
1097 the outstanding data, calculate RTT estimations, and reset the
1098 retransmission timer. */
adamdunkels47ec7fa2003-03-28 12:11:17 +00001099 if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001100 uip_add32(uip_connr->snd_nxt, uip_connr->len);
adamdunkels08eac9e2004-09-12 07:17:37 +00001101
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001102 if(BUF->ackno[0] == uip_acc32[0] &&
1103 BUF->ackno[1] == uip_acc32[1] &&
1104 BUF->ackno[2] == uip_acc32[2] &&
1105 BUF->ackno[3] == uip_acc32[3]) {
1106 /* Update sequence number. */
1107 uip_connr->snd_nxt[0] = uip_acc32[0];
1108 uip_connr->snd_nxt[1] = uip_acc32[1];
1109 uip_connr->snd_nxt[2] = uip_acc32[2];
1110 uip_connr->snd_nxt[3] = uip_acc32[3];
adamdunkelsa38da252003-08-20 20:56:54 +00001111
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001112
1113 /* Do RTT estimation, unless we have done retransmissions. */
1114 if(uip_connr->nrtx == 0) {
1115 signed char m;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001116 m = uip_connr->rto - uip_connr->timer;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001117 /* This is taken directly from VJs original code in his paper */
1118 m = m - (uip_connr->sa >> 3);
1119 uip_connr->sa += m;
1120 if(m < 0) {
1121 m = -m;
1122 }
1123 m = m - (uip_connr->sv >> 2);
1124 uip_connr->sv += m;
1125 uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv;
1126
1127 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001128 /* Set the acknowledged flag. */
1129 uip_flags = UIP_ACKDATA;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001130 /* Reset the retransmission timer. */
adamdunkelsb489e7a2003-10-14 11:12:50 +00001131 uip_connr->timer = uip_connr->rto;
adamdunkels08eac9e2004-09-12 07:17:37 +00001132
1133 /* Reset length of outstanding data. */
1134 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001135 }
adamdunkelsab4b0822003-07-30 23:31:40 +00001136
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001137 }
1138
1139 /* Do different things depending on in what state the connection is. */
1140 switch(uip_connr->tcpstateflags & TS_MASK) {
1141 /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
1142 implemented, since we force the application to close when the
1143 peer sends a FIN (hence the application goes directly from
1144 ESTABLISHED to LAST_ACK). */
1145 case SYN_RCVD:
1146 /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and
1147 we are waiting for an ACK that acknowledges the data we sent
1148 out the last time. Therefore, we want to have the UIP_ACKDATA
1149 flag set. If so, we enter the ESTABLISHED state. */
1150 if(uip_flags & UIP_ACKDATA) {
1151 uip_connr->tcpstateflags = ESTABLISHED;
1152 uip_flags = UIP_CONNECTED;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001153 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001154 if(uip_len > 0) {
1155 uip_flags |= UIP_NEWDATA;
1156 uip_add_rcv_nxt(uip_len);
1157 }
1158 uip_slen = 0;
1159 UIP_APPCALL();
1160 goto appsend;
1161 }
1162 goto drop;
1163#if UIP_ACTIVE_OPEN
1164 case SYN_SENT:
1165 /* In SYN_SENT, we wait for a SYNACK that is sent in response to
1166 our SYN. The rcv_nxt is set to sequence number in the SYNACK
1167 plus one, and we send an ACK. We move into the ESTABLISHED
1168 state. */
1169 if((uip_flags & UIP_ACKDATA) &&
1170 BUF->flags == (TCP_SYN | TCP_ACK)) {
1171
1172 /* Parse the TCP MSS option, if present. */
1173 if((BUF->tcpoffset & 0xf0) > 0x50) {
1174 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
1175 opt = uip_buf[40 + UIP_LLH_LEN + c];
1176 if(opt == 0x00) {
1177 /* End of options. */
1178 break;
1179 } else if(opt == 0x01) {
1180 ++c;
1181 /* NOP option. */
1182 } else if(opt == 0x02 &&
1183 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0x04) {
1184 /* An MSS option with the right option length. */
adamdunkels0170b082003-10-01 11:25:37 +00001185 tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001186 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];
adamdunkels0170b082003-10-01 11:25:37 +00001187 uip_connr->initialmss =
1188 uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001189
1190 /* And we are done processing options. */
1191 break;
1192 } else {
1193 /* All other options have a length field, so that we easily
1194 can skip past them. */
1195 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
1196 /* If the length field is zero, the options are malformed
1197 and we don't process them further. */
1198 break;
1199 }
1200 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
1201 }
1202 }
1203 }
1204 uip_connr->tcpstateflags = ESTABLISHED;
1205 uip_connr->rcv_nxt[0] = BUF->seqno[0];
1206 uip_connr->rcv_nxt[1] = BUF->seqno[1];
1207 uip_connr->rcv_nxt[2] = BUF->seqno[2];
1208 uip_connr->rcv_nxt[3] = BUF->seqno[3];
1209 uip_add_rcv_nxt(1);
1210 uip_flags = UIP_CONNECTED | UIP_NEWDATA;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001211 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001212 uip_len = 0;
1213 uip_slen = 0;
1214 UIP_APPCALL();
1215 goto appsend;
1216 }
1217 goto reset;
1218#endif /* UIP_ACTIVE_OPEN */
1219
1220 case ESTABLISHED:
1221 /* In the ESTABLISHED state, we call upon the application to feed
1222 data into the uip_buf. If the UIP_ACKDATA flag is set, the
1223 application should put new data into the buffer, otherwise we are
1224 retransmitting an old segment, and the application should put that
1225 data into the buffer.
1226
1227 If the incoming packet is a FIN, we should close the connection on
1228 this side as well, and we send out a FIN and enter the LAST_ACK
1229 state. We require that there is no outstanding data; otherwise the
1230 sequence numbers will be screwed up. */
1231
1232 if(BUF->flags & TCP_FIN) {
1233 if(uip_outstanding(uip_connr)) {
1234 goto drop;
1235 }
1236 uip_add_rcv_nxt(1 + uip_len);
1237 uip_flags = UIP_CLOSE;
1238 if(uip_len > 0) {
1239 uip_flags |= UIP_NEWDATA;
1240 }
1241 UIP_APPCALL();
1242 uip_connr->len = 1;
1243 uip_connr->tcpstateflags = LAST_ACK;
1244 uip_connr->nrtx = 0;
1245 tcp_send_finack:
1246 BUF->flags = TCP_FIN | TCP_ACK;
1247 goto tcp_send_nodata;
1248 }
1249
1250 /* Check the URG flag. If this is set, the segment carries urgent
1251 data that we must pass to the application. */
adamdunkels9fad4132004-06-06 06:14:19 +00001252 if((BUF->flags & TCP_URG) != 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001253#if UIP_URGDATA > 0
1254 uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1];
1255 if(uip_urglen > uip_len) {
1256 /* There is more urgent data in the next segment to come. */
1257 uip_urglen = uip_len;
1258 }
1259 uip_add_rcv_nxt(uip_urglen);
1260 uip_len -= uip_urglen;
1261 uip_urgdata = uip_appdata;
1262 uip_appdata += uip_urglen;
1263 } else {
1264 uip_urglen = 0;
adamdunkels9fad4132004-06-06 06:14:19 +00001265#else /* UIP_URGDATA > 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001266 uip_appdata += (BUF->urgp[0] << 8) | BUF->urgp[1];
1267 uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1];
adamdunkels9fad4132004-06-06 06:14:19 +00001268#endif /* UIP_URGDATA > 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001269 }
adamdunkels9fad4132004-06-06 06:14:19 +00001270
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001271 /* If uip_len > 0 we have TCP data in the packet, and we flag this
1272 by setting the UIP_NEWDATA flag and update the sequence number
1273 we acknowledge. If the application has stopped the dataflow
1274 using uip_stop(), we must not accept any data packets from the
1275 remote host. */
1276 if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
1277 uip_flags |= UIP_NEWDATA;
1278 uip_add_rcv_nxt(uip_len);
1279 }
adamdunkels0170b082003-10-01 11:25:37 +00001280
1281 /* Check if the available buffer space advertised by the other end
1282 is smaller than the initial MSS for this connection. If so, we
1283 set the current MSS to the window size to ensure that the
1284 application does not send more data than the other end can
1285 handle.
1286
1287 If the remote host advertises a zero window, we set the MSS to
1288 the initial MSS so that the application will send an entire MSS
1289 of data. This data will not be acknowledged by the receiver,
1290 and the application will retransmit it. This is called the
1291 "persistent timer" and uses the retransmission mechanim.
1292 */
1293 tmp16 = ((u16_t)BUF->wnd[0] << 8) + (u16_t)BUF->wnd[1];
1294 if(tmp16 > uip_connr->initialmss ||
1295 tmp16 == 0) {
1296 tmp16 = uip_connr->initialmss;
1297 }
1298 uip_connr->mss = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001299
1300 /* If this packet constitutes an ACK for outstanding data (flagged
1301 by the UIP_ACKDATA flag, we should call the application since it
1302 might want to send more data. If the incoming packet had data
1303 from the peer (as flagged by the UIP_NEWDATA flag), the
1304 application must also be notified.
1305
1306 When the application is called, the global variable uip_len
1307 contains the length of the incoming data. The application can
1308 access the incoming data through the global pointer
1309 uip_appdata, which usually points 40 bytes into the uip_buf
1310 array.
1311
1312 If the application wishes to send any data, this data should be
1313 put into the uip_appdata and the length of the data should be
1314 put into uip_len. If the application don't have any data to
1315 send, uip_len must be set to 0. */
1316 if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) {
1317 uip_slen = 0;
1318 UIP_APPCALL();
1319
1320 appsend:
adamdunkels0170b082003-10-01 11:25:37 +00001321
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001322 if(uip_flags & UIP_ABORT) {
1323 uip_slen = 0;
1324 uip_connr->tcpstateflags = CLOSED;
1325 BUF->flags = TCP_RST | TCP_ACK;
1326 goto tcp_send_nodata;
1327 }
1328
1329 if(uip_flags & UIP_CLOSE) {
1330 uip_slen = 0;
1331 uip_connr->len = 1;
1332 uip_connr->tcpstateflags = FIN_WAIT_1;
1333 uip_connr->nrtx = 0;
1334 BUF->flags = TCP_FIN | TCP_ACK;
1335 goto tcp_send_nodata;
1336 }
1337
adamdunkelsb489e7a2003-10-14 11:12:50 +00001338 /* If uip_slen > 0, the application has data to be sent. */
1339 if(uip_slen > 0) {
1340
1341 /* If the connection has acknowledged data, the contents of
1342 the ->len variable should be discarded. */
1343 if((uip_flags & UIP_ACKDATA) != 0) {
1344 uip_connr->len = 0;
1345 }
1346
1347 /* If the ->len variable is non-zero the connection has
1348 already data in transit and cannot send anymore right
1349 now. */
1350 if(uip_connr->len == 0) {
1351
1352 /* The application cannot send more than what is allowed by
1353 the mss (the minumum of the MSS and the available
1354 window). */
1355 if(uip_slen > uip_connr->mss) {
1356 uip_slen = uip_connr->mss;
1357 }
1358
1359 /* Remember how much data we send out now so that we know
1360 when everything has been acknowledged. */
1361 uip_connr->len = uip_slen;
1362 } else {
1363
1364 /* If the application already had unacknowledged data, we
1365 make sure that the application does not send (i.e.,
1366 retransmit) out more than it previously sent out. */
1367 uip_slen = uip_connr->len;
1368 }
adamdunkelsab4b0822003-07-30 23:31:40 +00001369 } else {
adamdunkels08eac9e2004-09-12 07:17:37 +00001370 /* uip_connr->len = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001371 }
adamdunkelsb489e7a2003-10-14 11:12:50 +00001372 uip_connr->nrtx = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001373 apprexmit:
adamdunkels0170b082003-10-01 11:25:37 +00001374 uip_appdata = uip_sappdata;
1375
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001376 /* If the application has data to be sent, or if the incoming
1377 packet had new data in it, we must send out a packet. */
adamdunkels759185d2003-06-30 20:35:41 +00001378 if(uip_slen > 0 && uip_connr->len > 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001379 /* Add the length of the IP and TCP headers. */
1380 uip_len = uip_connr->len + UIP_TCPIP_HLEN;
1381 /* We always set the ACK flag in response packets. */
adamdunkels759185d2003-06-30 20:35:41 +00001382 BUF->flags = TCP_ACK | TCP_PSH;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001383 /* Send the packet. */
1384 goto tcp_send_noopts;
1385 }
adamdunkels759185d2003-06-30 20:35:41 +00001386 /* If there is no data to send, just send out a pure ACK if
1387 there is newdata. */
1388 if(uip_flags & UIP_NEWDATA) {
1389 uip_len = UIP_TCPIP_HLEN;
1390 BUF->flags = TCP_ACK;
1391 goto tcp_send_noopts;
1392 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001393 }
1394 goto drop;
1395 case LAST_ACK:
1396 /* We can close this connection if the peer has acknowledged our
1397 FIN. This is indicated by the UIP_ACKDATA flag. */
1398 if(uip_flags & UIP_ACKDATA) {
1399 uip_connr->tcpstateflags = CLOSED;
1400 uip_flags = UIP_CLOSE;
1401 UIP_APPCALL();
1402 }
1403 break;
1404
1405 case FIN_WAIT_1:
1406 /* The application has closed the connection, but the remote host
1407 hasn't closed its end yet. Thus we do nothing but wait for a
1408 FIN from the other side. */
1409 if(uip_len > 0) {
1410 uip_add_rcv_nxt(uip_len);
1411 }
1412 if(BUF->flags & TCP_FIN) {
1413 if(uip_flags & UIP_ACKDATA) {
1414 uip_connr->tcpstateflags = TIME_WAIT;
1415 uip_connr->timer = 0;
1416 uip_connr->len = 0;
1417 } else {
1418 uip_connr->tcpstateflags = CLOSING;
1419 }
1420 uip_add_rcv_nxt(1);
1421 uip_flags = UIP_CLOSE;
1422 UIP_APPCALL();
1423 goto tcp_send_ack;
1424 } else if(uip_flags & UIP_ACKDATA) {
1425 uip_connr->tcpstateflags = FIN_WAIT_2;
1426 uip_connr->len = 0;
1427 goto drop;
1428 }
1429 if(uip_len > 0) {
1430 goto tcp_send_ack;
1431 }
1432 goto drop;
1433
1434 case FIN_WAIT_2:
1435 if(uip_len > 0) {
1436 uip_add_rcv_nxt(uip_len);
1437 }
1438 if(BUF->flags & TCP_FIN) {
1439 uip_connr->tcpstateflags = TIME_WAIT;
1440 uip_connr->timer = 0;
1441 uip_add_rcv_nxt(1);
1442 uip_flags = UIP_CLOSE;
1443 UIP_APPCALL();
1444 goto tcp_send_ack;
1445 }
1446 if(uip_len > 0) {
1447 goto tcp_send_ack;
1448 }
1449 goto drop;
1450
1451 case TIME_WAIT:
1452 goto tcp_send_ack;
1453
1454 case CLOSING:
1455 if(uip_flags & UIP_ACKDATA) {
1456 uip_connr->tcpstateflags = TIME_WAIT;
1457 uip_connr->timer = 0;
1458 }
1459 }
1460 goto drop;
1461
1462
1463 /* We jump here when we are ready to send the packet, and just want
1464 to set the appropriate TCP sequence numbers in the TCP header. */
1465 tcp_send_ack:
1466 BUF->flags = TCP_ACK;
1467 tcp_send_nodata:
1468 uip_len = 40;
1469 tcp_send_noopts:
1470 BUF->tcpoffset = 5 << 4;
1471 tcp_send:
1472 /* We're done with the input processing. We are now ready to send a
1473 reply. Our job is to fill in all the fields of the TCP and IP
1474 headers before calculating the checksum and finally send the
1475 packet. */
1476 BUF->ackno[0] = uip_connr->rcv_nxt[0];
1477 BUF->ackno[1] = uip_connr->rcv_nxt[1];
1478 BUF->ackno[2] = uip_connr->rcv_nxt[2];
1479 BUF->ackno[3] = uip_connr->rcv_nxt[3];
1480
1481 BUF->seqno[0] = uip_connr->snd_nxt[0];
1482 BUF->seqno[1] = uip_connr->snd_nxt[1];
1483 BUF->seqno[2] = uip_connr->snd_nxt[2];
1484 BUF->seqno[3] = uip_connr->snd_nxt[3];
1485
1486 BUF->proto = UIP_PROTO_TCP;
1487
1488 BUF->srcport = uip_connr->lport;
1489 BUF->destport = uip_connr->rport;
1490
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001491 BUF->srcipaddr[0] = uip_hostaddr[0];
1492 BUF->srcipaddr[1] = uip_hostaddr[1];
1493 BUF->destipaddr[0] = uip_connr->ripaddr[0];
1494 BUF->destipaddr[1] = uip_connr->ripaddr[1];
1495
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001496
1497 if(uip_connr->tcpstateflags & UIP_STOPPED) {
1498 /* If the connection has issued uip_stop(), we advertise a zero
1499 window so that the remote host will stop sending data. */
1500 BUF->wnd[0] = BUF->wnd[1] = 0;
1501 } else {
adamdunkelsb489e7a2003-10-14 11:12:50 +00001502 BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8);
1503 BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001504 }
1505
1506 tcp_send_noconn:
1507
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001508 BUF->len[0] = (uip_len >> 8);
1509 BUF->len[1] = (uip_len & 0xff);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001510
adamdunkels9fad4132004-06-06 06:14:19 +00001511 BUF->urgp[0] = BUF->urgp[1] = 0;
1512
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001513 /* Calculate TCP checksum. */
1514 BUF->tcpchksum = 0;
1515 BUF->tcpchksum = ~(uip_tcpchksum());
1516
1517 ip_send_nolen:
1518
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001519 BUF->vhl = 0x45;
1520 BUF->tos = 0;
1521 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
1522 BUF->ttl = UIP_TTL;
1523 ++ipid;
1524 BUF->ipid[0] = ipid >> 8;
1525 BUF->ipid[1] = ipid & 0xff;
1526
1527 /* Calculate IP checksum. */
1528 BUF->ipchksum = 0;
1529 BUF->ipchksum = ~(uip_ipchksum());
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001530
1531 UIP_STAT(++uip_stat.tcp.sent);
1532 send:
adamdunkels9fad4132004-06-06 06:14:19 +00001533
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001534 UIP_STAT(++uip_stat.ip.sent);
1535 /* Return and let the caller do the actual transmission. */
1536 return;
1537 drop:
1538 uip_len = 0;
1539 return;
1540}
1541/*-----------------------------------------------------------------------------------*/
adamdunkels47ec7fa2003-03-28 12:11:17 +00001542u16_t
1543htons(u16_t val)
1544{
1545 return HTONS(val);
1546}
1547/*-----------------------------------------------------------------------------------*/
adamdunkels0170b082003-10-01 11:25:37 +00001548/** @} */