blob: 5912782949c5a2103e102d63aa8818530bdde717 [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 *
adamdunkels08eac9e2004-09-12 07:17:37 +000042 * $Id: uip.c,v 1.15 2004/09/12 07:17:37 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
adamdunkelsa49d1dc2003-08-21 22:26:57 +000090u8_t uip_buf[UIP_BUFSIZE+2]; /* The packet buffer that contains
adamdunkelsca9ddcb2003-03-19 14:13:31 +000091 incoming packets. */
adamdunkels9fad4132004-06-06 06:14:19 +000092u8_t *uip_appdata; /* The uip_appdata pointer points to
adamdunkelsca9ddcb2003-03-19 14:13:31 +000093 application data. */
adamdunkels9fad4132004-06-06 06:14:19 +000094u8_t *uip_sappdata; /* The uip_appdata pointer points to the
adamdunkels0170b082003-10-01 11:25:37 +000095 application data which is to be sent. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +000096#if UIP_URGDATA > 0
adamdunkels9fad4132004-06-06 06:14:19 +000097u8_t *uip_urgdata; /* The uip_urgdata pointer points to
adamdunkelsca9ddcb2003-03-19 14:13:31 +000098 urgent data (out-of-band data), if
99 present. */
adamdunkels9fad4132004-06-06 06:14:19 +0000100u8_t uip_urglen, uip_surglen;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000101#endif /* UIP_URGDATA > 0 */
102
adamdunkels9fad4132004-06-06 06:14:19 +0000103u16_t uip_len, uip_slen;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000104 /* The uip_len is either 8 or 16 bits,
105 depending on the maximum packet
106 size. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000107
adamdunkels9fad4132004-06-06 06:14:19 +0000108u8_t uip_flags; /* The uip_flags variable is used for
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000109 communication between the TCP/IP stack
110 and the application program. */
111struct uip_conn *uip_conn; /* uip_conn always points to the current
112 connection. */
113
114struct uip_conn uip_conns[UIP_CONNS];
115 /* The uip_conns array holds all TCP
116 connections. */
117u16_t uip_listenports[UIP_LISTENPORTS];
118 /* The uip_listenports list all currently
119 listning ports. */
120#if UIP_UDP
121struct uip_udp_conn *uip_udp_conn;
122struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
123#endif /* UIP_UDP */
124
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000125static u16_t ipid; /* Ths ipid variable is an increasing
126 number that is used for the IP ID
127 field. */
128
129static u8_t iss[4]; /* The iss variable is used for the TCP
130 initial sequence number. */
131
132#if UIP_ACTIVE_OPEN
adamdunkelsb489e7a2003-10-14 11:12:50 +0000133static u16_t lastport; /* Keeps track of the last port used for
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000134 a new connection. */
135#endif /* UIP_ACTIVE_OPEN */
136
137/* Temporary variables. */
adamdunkels9fad4132004-06-06 06:14:19 +0000138u8_t uip_acc32[4];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000139static u8_t c, opt;
adamdunkels0170b082003-10-01 11:25:37 +0000140static u16_t tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000141
142/* Structures and definitions. */
143#define TCP_FIN 0x01
144#define TCP_SYN 0x02
145#define TCP_RST 0x04
146#define TCP_PSH 0x08
147#define TCP_ACK 0x10
148#define TCP_URG 0x20
149#define TCP_CTL 0x3f
150
151#define ICMP_ECHO_REPLY 0
152#define ICMP_ECHO 8
153
154/* Macros. */
155#define BUF ((uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
156#define FBUF ((uip_tcpip_hdr *)&uip_reassbuf[0])
157#define ICMPBUF ((uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
158#define UDPBUF ((uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])
159
160#if UIP_STATISTICS == 1
161struct uip_stats uip_stat;
162#define UIP_STAT(s) s
163#else
164#define UIP_STAT(s)
165#endif /* UIP_STATISTICS == 1 */
166
167#if UIP_LOGGING == 1
168#include <stdio.h>
169void uip_log(char *msg);
170#define UIP_LOG(m) uip_log(m)
171#else
172#define UIP_LOG(m)
173#endif /* UIP_LOGGING == 1 */
174
175/*-----------------------------------------------------------------------------------*/
176void
177uip_init(void)
178{
179 for(c = 0; c < UIP_LISTENPORTS; ++c) {
180 uip_listenports[c] = 0;
181 }
182 for(c = 0; c < UIP_CONNS; ++c) {
183 uip_conns[c].tcpstateflags = CLOSED;
184 }
185#if UIP_ACTIVE_OPEN
186 lastport = 1024;
187#endif /* UIP_ACTIVE_OPEN */
188
189#if UIP_UDP
190 for(c = 0; c < UIP_UDP_CONNS; ++c) {
191 uip_udp_conns[c].lport = 0;
192 }
193#endif /* UIP_UDP */
194
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000195
196 /* IPv4 initialization. */
197#if UIP_FIXEDADDR == 0
198 uip_hostaddr[0] = uip_hostaddr[1] = 0;
199#endif /* UIP_FIXEDADDR */
adamdunkelsa38da252003-08-20 20:56:54 +0000200
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000201}
202/*-----------------------------------------------------------------------------------*/
203#if UIP_ACTIVE_OPEN
204struct uip_conn *
205uip_connect(u16_t *ripaddr, u16_t rport)
206{
adamdunkelsa38da252003-08-20 20:56:54 +0000207 register struct uip_conn *conn, *cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000208
209 /* Find an unused local port. */
210 again:
211 ++lastport;
212
213 if(lastport >= 32000) {
214 lastport = 4096;
215 }
adamdunkels1e45c6d2003-09-02 21:47:27 +0000216
217 /* Check if this port is already in use, and if so try to find
218 another one. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000219 for(c = 0; c < UIP_CONNS; ++c) {
adamdunkels23664022003-08-05 13:51:50 +0000220 conn = &uip_conns[c];
221 if(conn->tcpstateflags != CLOSED &&
adamdunkels1e45c6d2003-09-02 21:47:27 +0000222 conn->lport == htons(lastport)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000223 goto again;
adamdunkelsa38da252003-08-20 20:56:54 +0000224 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000225 }
226
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000227 conn = 0;
228 for(c = 0; c < UIP_CONNS; ++c) {
adamdunkelsa38da252003-08-20 20:56:54 +0000229 cconn = &uip_conns[c];
230 if(cconn->tcpstateflags == CLOSED) {
231 conn = cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000232 break;
233 }
adamdunkelsa38da252003-08-20 20:56:54 +0000234 if(cconn->tcpstateflags == TIME_WAIT) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000235 if(conn == 0 ||
adamdunkelsa38da252003-08-20 20:56:54 +0000236 cconn->timer > uip_conn->timer) {
237 conn = cconn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000238 }
239 }
240 }
241
242 if(conn == 0) {
243 return 0;
244 }
245
246 conn->tcpstateflags = SYN_SENT;
247
248 conn->snd_nxt[0] = iss[0];
249 conn->snd_nxt[1] = iss[1];
250 conn->snd_nxt[2] = iss[2];
251 conn->snd_nxt[3] = iss[3];
252
adamdunkels0170b082003-10-01 11:25:37 +0000253 conn->initialmss = conn->mss = UIP_TCP_MSS;
adamdunkelsd962db42003-08-21 18:10:21 +0000254
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000255 conn->len = 1; /* TCP length of the SYN is one. */
256 conn->nrtx = 0;
257 conn->timer = 1; /* Send the SYN next time around. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000258 conn->rto = UIP_RTO;
259 conn->sa = 0;
260 conn->sv = 16;
adamdunkels1e45c6d2003-09-02 21:47:27 +0000261 conn->lport = htons(lastport);
262 conn->rport = rport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000263 conn->ripaddr[0] = ripaddr[0];
264 conn->ripaddr[1] = ripaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000265
266 return conn;
267}
268#endif /* UIP_ACTIVE_OPEN */
269/*-----------------------------------------------------------------------------------*/
270#if UIP_UDP
271struct uip_udp_conn *
272uip_udp_new(u16_t *ripaddr, u16_t rport)
273{
adamdunkels23664022003-08-05 13:51:50 +0000274 register struct uip_udp_conn *conn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000275
276 /* Find an unused local port. */
277 again:
278 ++lastport;
279
280 if(lastport >= 32000) {
281 lastport = 4096;
282 }
283
284 for(c = 0; c < UIP_UDP_CONNS; ++c) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000285 if(uip_udp_conns[c].lport == lastport) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000286 goto again;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000287 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000288 }
289
290
291 conn = 0;
292 for(c = 0; c < UIP_UDP_CONNS; ++c) {
293 if(uip_udp_conns[c].lport == 0) {
294 conn = &uip_udp_conns[c];
295 break;
296 }
297 }
298
299 if(conn == 0) {
300 return 0;
301 }
302
adamdunkels47ec7fa2003-03-28 12:11:17 +0000303 conn->lport = HTONS(lastport);
304 conn->rport = HTONS(rport);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000305 conn->ripaddr[0] = ripaddr[0];
306 conn->ripaddr[1] = ripaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000307
308 return conn;
309}
310#endif /* UIP_UDP */
311/*-----------------------------------------------------------------------------------*/
312void
adamdunkelscd8c3a22003-08-13 22:52:48 +0000313uip_unlisten(u16_t port)
314{
315 for(c = 0; c < UIP_LISTENPORTS; ++c) {
316 if(uip_listenports[c] == port) {
317 uip_listenports[c] = 0;
318 return;
319 }
320 }
321}
322/*-----------------------------------------------------------------------------------*/
323void
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000324uip_listen(u16_t port)
325{
326 for(c = 0; c < UIP_LISTENPORTS; ++c) {
327 if(uip_listenports[c] == 0) {
adamdunkels1e45c6d2003-09-02 21:47:27 +0000328 uip_listenports[c] = port;
adamdunkelscd8c3a22003-08-13 22:52:48 +0000329 return;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000330 }
331 }
332}
333/*-----------------------------------------------------------------------------------*/
adamdunkelsb489e7a2003-10-14 11:12:50 +0000334/* XXX: IP fragment reassembly: not well-tested. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000335
336#if UIP_REASSEMBLY
337#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)
338static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];
339static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];
340static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f,
341 0x0f, 0x07, 0x03, 0x01};
342static u16_t uip_reasslen;
343static u8_t uip_reassflags;
344#define UIP_REASS_FLAG_LASTFRAG 0x01
345static u8_t uip_reasstmr;
346
347#define IP_HLEN 20
adamdunkelsb489e7a2003-10-14 11:12:50 +0000348#define IP_MF 0x20
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000349
350static u8_t
351uip_reass(void)
352{
353 u16_t offset, len;
354 u16_t i;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000355
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000356 /* If ip_reasstmr is zero, no packet is present in the buffer, so we
357 write the IP header of the fragment into the reassembly
358 buffer. The timer is updated with the maximum age. */
359 if(uip_reasstmr == 0) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000360 memcpy(uip_reassbuf, &BUF->vhl, IP_HLEN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000361 uip_reasstmr = UIP_REASS_MAXAGE;
362 uip_reassflags = 0;
363 /* Clear the bitmap. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000364 memset(uip_reassbitmap, sizeof(uip_reassbitmap), 0);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000365 }
366
367 /* Check if the incoming fragment matches the one currently present
368 in the reasembly buffer. If so, we proceed with copying the
369 fragment into the buffer. */
370 if(BUF->srcipaddr[0] == FBUF->srcipaddr[0] &&
adamdunkelsb489e7a2003-10-14 11:12:50 +0000371 BUF->srcipaddr[1] == FBUF->srcipaddr[1] &&
372 BUF->destipaddr[0] == FBUF->destipaddr[0] &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000373 BUF->destipaddr[1] == FBUF->destipaddr[1] &&
adamdunkelsb489e7a2003-10-14 11:12:50 +0000374 BUF->ipid[0] == FBUF->ipid[0] &&
375 BUF->ipid[1] == FBUF->ipid[1]) {
376
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000377 len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4;
378 offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8;
379
380 /* If the offset or the offset + fragment length overflows the
381 reassembly buffer, we discard the entire packet. */
382 if(offset > UIP_REASS_BUFSIZE ||
383 offset + len > UIP_REASS_BUFSIZE) {
384 uip_reasstmr = 0;
385 goto nullreturn;
386 }
387
388 /* Copy the fragment into the reassembly buffer, at the right
389 offset. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000390 memcpy(&uip_reassbuf[IP_HLEN + offset],
391 (char *)BUF + (int)((BUF->vhl & 0x0f) * 4),
392 len);
393
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000394 /* Update the bitmap. */
395 if(offset / (8 * 8) == (offset + len) / (8 * 8)) {
396 /* If the two endpoints are in the same byte, we only update
397 that byte. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000398
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000399 uip_reassbitmap[offset / (8 * 8)] |=
adamdunkelsb489e7a2003-10-14 11:12:50 +0000400 bitmap_bits[(offset / 8 ) & 7] &
401 ~bitmap_bits[((offset + len) / 8 ) & 7];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000402 } else {
403 /* If the two endpoints are in different bytes, we update the
404 bytes in the endpoints and fill the stuff inbetween with
405 0xff. */
406 uip_reassbitmap[offset / (8 * 8)] |=
407 bitmap_bits[(offset / 8 ) & 7];
408 for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
409 uip_reassbitmap[i] = 0xff;
410 }
411 uip_reassbitmap[(offset + len) / (8 * 8)] |=
412 ~bitmap_bits[((offset + len) / 8 ) & 7];
413 }
414
415 /* If this fragment has the More Fragments flag set to zero, we
416 know that this is the last fragment, so we can calculate the
417 size of the entire packet. We also set the
418 IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
419 the final fragment. */
420
421 if((BUF->ipoffset[0] & IP_MF) == 0) {
422 uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
423 uip_reasslen = offset + len;
424 }
425
426 /* Finally, we check if we have a full packet in the buffer. We do
427 this by checking if we have the last fragment and if all bits
428 in the bitmap are set. */
429 if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) {
430 /* Check all bytes up to and including all but the last byte in
431 the bitmap. */
432 for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) {
433 if(uip_reassbitmap[i] != 0xff) {
434 goto nullreturn;
435 }
436 }
437 /* Check the last byte in the bitmap. It should contain just the
438 right amount of bits. */
439 if(uip_reassbitmap[uip_reasslen / (8 * 8)] !=
440 (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) {
441 goto nullreturn;
442 }
443
444 /* If we have come this far, we have a full packet in the
445 buffer, so we allocate a pbuf and copy the packet into it. We
446 also reset the timer. */
447 uip_reasstmr = 0;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000448 memcpy(BUF, FBUF, uip_reasslen);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000449
450 /* Pretend to be a "normal" (i.e., not fragmented) IP packet
451 from now on. */
452 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000453 BUF->len[0] = uip_reasslen >> 8;
454 BUF->len[1] = uip_reasslen & 0xff;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000455 BUF->ipchksum = 0;
456 BUF->ipchksum = ~(uip_ipchksum());
457
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000458 return uip_reasslen;
459 }
460 }
461
462 nullreturn:
463 return 0;
464}
adamdunkelsb489e7a2003-10-14 11:12:50 +0000465#endif /* UIP_REASSEMBL */
466/*-----------------------------------------------------------------------------------*/
467static void
468uip_add_rcv_nxt(u16_t n)
469{
470 uip_add32(uip_conn->rcv_nxt, n);
471 uip_conn->rcv_nxt[0] = uip_acc32[0];
472 uip_conn->rcv_nxt[1] = uip_acc32[1];
473 uip_conn->rcv_nxt[2] = uip_acc32[2];
474 uip_conn->rcv_nxt[3] = uip_acc32[3];
475}
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000476/*-----------------------------------------------------------------------------------*/
477void
478uip_process(u8_t flag)
479{
480 register struct uip_conn *uip_connr = uip_conn;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000481
482 uip_appdata = &uip_buf[40 + UIP_LLH_LEN];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000483
484 /* Check if we were invoked because of the perodic timer fireing. */
485 if(flag == UIP_TIMER) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000486#if UIP_REASSEMBLY
487 if(uip_reasstmr != 0) {
488 --uip_reasstmr;
489 }
490#endif /* UIP_REASSEMBLY */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000491 /* Increase the initial sequence number. */
492 if(++iss[3] == 0) {
493 if(++iss[2] == 0) {
494 if(++iss[1] == 0) {
495 ++iss[0];
496 }
497 }
498 }
499 uip_len = 0;
500 if(uip_connr->tcpstateflags == TIME_WAIT ||
501 uip_connr->tcpstateflags == FIN_WAIT_2) {
502 ++(uip_connr->timer);
503 if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) {
504 uip_connr->tcpstateflags = CLOSED;
505 }
506 } else if(uip_connr->tcpstateflags != CLOSED) {
507 /* If the connection has outstanding data, we increase the
508 connection's timer and see if it has reached the RTO value
509 in which case we retransmit. */
510 if(uip_outstanding(uip_connr)) {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000511 if(uip_connr->timer-- == 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000512 if(uip_connr->nrtx == UIP_MAXRTX ||
513 ((uip_connr->tcpstateflags == SYN_SENT ||
514 uip_connr->tcpstateflags == SYN_RCVD) &&
515 uip_connr->nrtx == UIP_MAXSYNRTX)) {
516 uip_connr->tcpstateflags = CLOSED;
517
518 /* We call UIP_APPCALL() with uip_flags set to
519 UIP_TIMEDOUT to inform the application that the
520 connection has timed out. */
521 uip_flags = UIP_TIMEDOUT;
522 UIP_APPCALL();
523
524 /* We also send a reset packet to the remote host. */
525 BUF->flags = TCP_RST | TCP_ACK;
526 goto tcp_send_nodata;
527 }
528
529 /* Exponential backoff. */
adamdunkels47ec7fa2003-03-28 12:11:17 +0000530 uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4?
531 4:
532 uip_connr->nrtx);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000533 ++(uip_connr->nrtx);
534
535 /* Ok, so we need to retransmit. We do this differently
536 depending on which state we are in. In ESTABLISHED, we
537 call upon the application so that it may prepare the
538 data for the retransmit. In SYN_RCVD, we resend the
539 SYNACK that we sent earlier and in LAST_ACK we have to
540 retransmit our FINACK. */
541 UIP_STAT(++uip_stat.tcp.rexmit);
542 switch(uip_connr->tcpstateflags & TS_MASK) {
543 case SYN_RCVD:
544 /* In the SYN_RCVD state, we should retransmit our
545 SYNACK. */
546 goto tcp_send_synack;
547
548#if UIP_ACTIVE_OPEN
549 case SYN_SENT:
550 /* In the SYN_SENT state, we retransmit out SYN. */
551 BUF->flags = 0;
552 goto tcp_send_syn;
553#endif /* UIP_ACTIVE_OPEN */
554
555 case ESTABLISHED:
556 /* In the ESTABLISHED state, we call upon the application
557 to do the actual retransmit after which we jump into
558 the code for sending out the packet (the apprexmit
559 label). */
560 uip_len = 0;
561 uip_slen = 0;
562 uip_flags = UIP_REXMIT;
563 UIP_APPCALL();
564 goto apprexmit;
565
566 case FIN_WAIT_1:
567 case CLOSING:
568 case LAST_ACK:
569 /* In all these states we should retransmit a FINACK. */
570 goto tcp_send_finack;
571
572 }
573 }
574 } else if((uip_connr->tcpstateflags & TS_MASK) == ESTABLISHED) {
575 /* If there was no need for a retransmission, we poll the
576 application for new data. */
577 uip_len = 0;
578 uip_slen = 0;
579 uip_flags = UIP_POLL;
580 UIP_APPCALL();
581 goto appsend;
582 }
583 }
584 goto drop;
585 }
586#if UIP_UDP
587 if(flag == UIP_UDP_TIMER) {
588 if(uip_udp_conn->lport != 0) {
adamdunkels399a0782004-02-16 20:52:07 +0000589 uip_conn = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000590 uip_appdata = &uip_buf[UIP_LLH_LEN + 28];
591 uip_len = uip_slen = 0;
592 uip_flags = UIP_POLL;
593 UIP_UDP_APPCALL();
594 goto udp_send;
595 } else {
596 goto drop;
597 }
598 }
599#endif
600
601 /* This is where the input processing starts. */
602 UIP_STAT(++uip_stat.ip.recv);
603
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000604
605 /* Start of IPv4 input header processing code. */
606
607 /* Check validity of the IP header. */
608 if(BUF->vhl != 0x45) { /* IP version and header length. */
609 UIP_STAT(++uip_stat.ip.drop);
610 UIP_STAT(++uip_stat.ip.vhlerr);
611 UIP_LOG("ip: invalid version or header length.");
612 goto drop;
613 }
614
615 /* Check the size of the packet. If the size reported to us in
adamdunkels9fad4132004-06-06 06:14:19 +0000616 uip_len doesn't match the size reported in the IP header, the
617 packet has been padded by the network device. We correct the
618 uip_len variable based on the reported length in the IP
619 header. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000620
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000621 if(BUF->len[0] != (uip_len >> 8)) { /* IP length, high byte. */
622 uip_len = (uip_len & 0xff) | (BUF->len[0] << 8);
623 }
624 if(BUF->len[1] != (uip_len & 0xff)) { /* IP length, low byte. */
625 uip_len = (uip_len & 0xff00) | BUF->len[1];
626 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000627
adamdunkelsb489e7a2003-10-14 11:12:50 +0000628 /* Check the fragment flag. */
629 if((BUF->ipoffset[0] & 0x3f) != 0 ||
630 BUF->ipoffset[1] != 0) {
631#if UIP_REASSEMBLY
632 uip_len = uip_reass();
633 if(uip_len == 0) {
634 goto drop;
635 }
636#else
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000637 UIP_STAT(++uip_stat.ip.drop);
638 UIP_STAT(++uip_stat.ip.fragerr);
639 UIP_LOG("ip: fragment dropped.");
640 goto drop;
adamdunkelsb489e7a2003-10-14 11:12:50 +0000641#endif /* UIP_REASSEMBLY */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000642 }
643
644 /* If we are configured to use ping IP address configuration and
645 hasn't been assigned an IP address yet, we accept all ICMP
646 packets. */
647#if UIP_PINGADDRCONF
648 if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
649 if(BUF->proto == UIP_PROTO_ICMP) {
650 UIP_LOG("ip: possible ping config packet received.");
651 goto icmp_input;
652 } else {
adamdunkelsb489e7a2003-10-14 11:12:50 +0000653 UIP_LOG("ip: packet dropped since no address assigned.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000654 goto drop;
655 }
656 }
657#endif /* UIP_PINGADDRCONF */
adamdunkels9fad4132004-06-06 06:14:19 +0000658
659 /* If IP broadcast support is configured, we check for a broadcast
660 UDP packet, which may be destined to us. */
661#if UIP_BROADCAST
662 if(BUF->proto == UIP_PROTO_UDP &&
663 BUF->destipaddr[0] == 0xffff &&
664 BUF->destipaddr[1] == 0xffff &&
665 uip_ipchksum() == 0xffff) {
666 goto udp_input;
667 }
668#endif /* UIP_BROADCAST */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000669
670 /* Check if the packet is destined for our IP address. */
671 if(BUF->destipaddr[0] != uip_hostaddr[0]) {
672 UIP_STAT(++uip_stat.ip.drop);
adamdunkels9fad4132004-06-06 06:14:19 +0000673 /* UIP_LOG("ip: packet not for us."); */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000674 goto drop;
675 }
676 if(BUF->destipaddr[1] != uip_hostaddr[1]) {
677 UIP_STAT(++uip_stat.ip.drop);
adamdunkels9fad4132004-06-06 06:14:19 +0000678 /* UIP_LOG("ip: packet not for us."); */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000679 goto drop;
680 }
681
682 if(uip_ipchksum() != 0xffff) { /* Compute and check the IP header
683 checksum. */
684 UIP_STAT(++uip_stat.ip.drop);
685 UIP_STAT(++uip_stat.ip.chkerr);
adamdunkels9fad4132004-06-06 06:14:19 +0000686 UIP_LOG("ip: bad checksum.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000687 goto drop;
688 }
689
690 if(BUF->proto == UIP_PROTO_TCP) /* Check for TCP packet. If so, jump
691 to the tcp_input label. */
692 goto tcp_input;
693
694#if UIP_UDP
695 if(BUF->proto == UIP_PROTO_UDP)
696 goto udp_input;
697#endif /* UIP_UDP */
698
699 if(BUF->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from
700 here. */
701 UIP_STAT(++uip_stat.ip.drop);
702 UIP_STAT(++uip_stat.ip.protoerr);
703 UIP_LOG("ip: neither tcp nor icmp.");
704 goto drop;
705 }
706
707 icmp_input:
708 UIP_STAT(++uip_stat.icmp.recv);
709
710 /* ICMP echo (i.e., ping) processing. This is simple, we only change
711 the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
712 checksum before we return the packet. */
713 if(ICMPBUF->type != ICMP_ECHO) {
714 UIP_STAT(++uip_stat.icmp.drop);
715 UIP_STAT(++uip_stat.icmp.typeerr);
716 UIP_LOG("icmp: not icmp echo.");
717 goto drop;
718 }
719
720 /* If we are configured to use ping IP address assignment, we use
721 the destination IP address of this ping packet and assign it to
722 ourself. */
723#if UIP_PINGADDRCONF
724 if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
725 uip_hostaddr[0] = BUF->destipaddr[0];
726 uip_hostaddr[1] = BUF->destipaddr[1];
727 }
728#endif /* UIP_PINGADDRCONF */
729
730 ICMPBUF->type = ICMP_ECHO_REPLY;
731
adamdunkels47ec7fa2003-03-28 12:11:17 +0000732 if(ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) {
733 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000734 } else {
adamdunkels47ec7fa2003-03-28 12:11:17 +0000735 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000736 }
737
738 /* Swap IP addresses. */
adamdunkels0170b082003-10-01 11:25:37 +0000739 tmp16 = BUF->destipaddr[0];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000740 BUF->destipaddr[0] = BUF->srcipaddr[0];
adamdunkels0170b082003-10-01 11:25:37 +0000741 BUF->srcipaddr[0] = tmp16;
742 tmp16 = BUF->destipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000743 BUF->destipaddr[1] = BUF->srcipaddr[1];
adamdunkels0170b082003-10-01 11:25:37 +0000744 BUF->srcipaddr[1] = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000745
746 UIP_STAT(++uip_stat.icmp.sent);
747 goto send;
748
749 /* End of IPv4 input header processing code. */
750
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000751
752#if UIP_UDP
753 /* UDP input processing. */
754 udp_input:
755 /* UDP processing is really just a hack. We don't do anything to the
756 UDP/IP headers, but let the UDP application do all the hard
757 work. If the application sets uip_slen, it has a packet to
758 send. */
759#if UIP_UDP_CHECKSUMS
760 if(uip_udpchksum() != 0xffff) {
761 UIP_STAT(++uip_stat.udp.drop);
762 UIP_STAT(++uip_stat.udp.chkerr);
763 UIP_LOG("udp: bad checksum.");
764 goto drop;
765 }
766#endif /* UIP_UDP_CHECKSUMS */
767
768 /* Demultiplex this UDP packet between the UDP "connections". */
769 for(uip_udp_conn = &uip_udp_conns[0];
770 uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS];
771 ++uip_udp_conn) {
adamdunkels9fad4132004-06-06 06:14:19 +0000772 /* If the local UDP port is non-zero, the connection is considered
773 to be used. If so, the local port number is checked against the
774 destination port number in the received packet. If the two port
775 numbers match, the remote port number is checked if the
776 connection is bound to a remote port. Finally, if the
777 connection is bound to a remote IP address, the source IP
778 address of the packet is checked. */
779 if(uip_udp_conn->lport != 0 &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000780 UDPBUF->destport == uip_udp_conn->lport &&
781 (uip_udp_conn->rport == 0 ||
782 UDPBUF->srcport == uip_udp_conn->rport) &&
adamdunkels9fad4132004-06-06 06:14:19 +0000783 ((uip_udp_conn->ripaddr[0] | uip_udp_conn->ripaddr[1]) == 0 ||
784 (uip_udp_conn->ripaddr[0] == 0xffff &&
785 uip_udp_conn->ripaddr[1] == 0xffff) ||
786 uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000787 goto udp_found;
788 }
789 }
adamdunkels9fad4132004-06-06 06:14:19 +0000790 UIP_LOG("udp: no matching connection found");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000791 goto drop;
792
793 udp_found:
adamdunkels399a0782004-02-16 20:52:07 +0000794 uip_conn = NULL;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000795 uip_len = uip_len - 28;
796 uip_appdata = &uip_buf[UIP_LLH_LEN + 28];
797 uip_flags = UIP_NEWDATA;
798 uip_slen = 0;
799 UIP_UDP_APPCALL();
800 udp_send:
801 if(uip_slen == 0) {
802 goto drop;
803 }
804 uip_len = uip_slen + 28;
805
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000806 BUF->len[0] = (uip_len >> 8);
807 BUF->len[1] = (uip_len & 0xff);
adamdunkelsb489e7a2003-10-14 11:12:50 +0000808
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000809 BUF->proto = UIP_PROTO_UDP;
810
adamdunkels47ec7fa2003-03-28 12:11:17 +0000811 UDPBUF->udplen = HTONS(uip_slen + 8);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000812 UDPBUF->udpchksum = 0;
813#if UIP_UDP_CHECKSUMS
814 /* Calculate UDP checksum. */
815 UDPBUF->udpchksum = ~(uip_udpchksum());
816 if(UDPBUF->udpchksum == 0) {
817 UDPBUF->udpchksum = 0xffff;
818 }
819#endif /* UIP_UDP_CHECKSUMS */
820
821 BUF->srcport = uip_udp_conn->lport;
822 BUF->destport = uip_udp_conn->rport;
823
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000824 BUF->srcipaddr[0] = uip_hostaddr[0];
825 BUF->srcipaddr[1] = uip_hostaddr[1];
826 BUF->destipaddr[0] = uip_udp_conn->ripaddr[0];
827 BUF->destipaddr[1] = uip_udp_conn->ripaddr[1];
828
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000829 uip_appdata = &uip_buf[UIP_LLH_LEN + 40];
830 goto ip_send_nolen;
831#endif /* UIP_UDP */
832
833 /* TCP input processing. */
834 tcp_input:
835 UIP_STAT(++uip_stat.tcp.recv);
836
837 /* Start of TCP input header processing code. */
838
839 if(uip_tcpchksum() != 0xffff) { /* Compute and check the TCP
840 checksum. */
841 UIP_STAT(++uip_stat.tcp.drop);
842 UIP_STAT(++uip_stat.tcp.chkerr);
adamdunkels9fad4132004-06-06 06:14:19 +0000843 UIP_LOG("tcp: bad checksum.");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000844 goto drop;
845 }
846
adamdunkels9fad4132004-06-06 06:14:19 +0000847
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000848 /* Demultiplex this segment. */
849 /* First check any active connections. */
850 for(uip_connr = &uip_conns[0]; uip_connr < &uip_conns[UIP_CONNS]; ++uip_connr) {
851 if(uip_connr->tcpstateflags != CLOSED &&
852 BUF->destport == uip_connr->lport &&
853 BUF->srcport == uip_connr->rport &&
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000854 BUF->srcipaddr[0] == uip_connr->ripaddr[0] &&
855 BUF->srcipaddr[1] == uip_connr->ripaddr[1]) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000856 goto found;
857 }
858 }
859
860 /* If we didn't find and active connection that expected the packet,
861 either this packet is an old duplicate, or this is a SYN packet
862 destined for a connection in LISTEN. If the SYN flag isn't set,
863 it is an old packet and we send a RST. */
864 if((BUF->flags & TCP_CTL) != TCP_SYN)
865 goto reset;
866
adamdunkels0170b082003-10-01 11:25:37 +0000867 tmp16 = BUF->destport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000868 /* Next, check listening connections. */
adamdunkelscd8c3a22003-08-13 22:52:48 +0000869 for(c = 0; c < UIP_LISTENPORTS; ++c) {
adamdunkels0170b082003-10-01 11:25:37 +0000870 if(tmp16 == uip_listenports[c])
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000871 goto found_listen;
872 }
873
874 /* No matching connection found, so we send a RST packet. */
875 UIP_STAT(++uip_stat.tcp.synrst);
876 reset:
877
878 /* We do not send resets in response to resets. */
879 if(BUF->flags & TCP_RST)
880 goto drop;
881
882 UIP_STAT(++uip_stat.tcp.rst);
883
884 BUF->flags = TCP_RST | TCP_ACK;
885 uip_len = 40;
886 BUF->tcpoffset = 5 << 4;
887
888 /* Flip the seqno and ackno fields in the TCP header. */
889 c = BUF->seqno[3];
890 BUF->seqno[3] = BUF->ackno[3];
891 BUF->ackno[3] = c;
892
893 c = BUF->seqno[2];
894 BUF->seqno[2] = BUF->ackno[2];
895 BUF->ackno[2] = c;
896
897 c = BUF->seqno[1];
898 BUF->seqno[1] = BUF->ackno[1];
899 BUF->ackno[1] = c;
900
901 c = BUF->seqno[0];
902 BUF->seqno[0] = BUF->ackno[0];
903 BUF->ackno[0] = c;
904
905 /* We also have to increase the sequence number we are
906 acknowledging. If the least significant byte overflowed, we need
907 to propagate the carry to the other bytes as well. */
908 if(++BUF->ackno[3] == 0) {
909 if(++BUF->ackno[2] == 0) {
910 if(++BUF->ackno[1] == 0) {
911 ++BUF->ackno[0];
912 }
913 }
914 }
915
916 /* Swap port numbers. */
adamdunkels0170b082003-10-01 11:25:37 +0000917 tmp16 = BUF->srcport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000918 BUF->srcport = BUF->destport;
adamdunkels0170b082003-10-01 11:25:37 +0000919 BUF->destport = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000920
921 /* Swap IP addresses. */
adamdunkels0170b082003-10-01 11:25:37 +0000922 tmp16 = BUF->destipaddr[0];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000923 BUF->destipaddr[0] = BUF->srcipaddr[0];
adamdunkels0170b082003-10-01 11:25:37 +0000924 BUF->srcipaddr[0] = tmp16;
925 tmp16 = BUF->destipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000926 BUF->destipaddr[1] = BUF->srcipaddr[1];
adamdunkels0170b082003-10-01 11:25:37 +0000927 BUF->srcipaddr[1] = tmp16;
adamdunkelsa38da252003-08-20 20:56:54 +0000928
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000929
930 /* And send out the RST packet! */
931 goto tcp_send_noconn;
932
933 /* This label will be jumped to if we matched the incoming packet
934 with a connection in LISTEN. In that case, we should create a new
935 connection and send a SYNACK in return. */
936 found_listen:
937 /* First we check if there are any connections avaliable. Unused
938 connections are kept in the same table as used connections, but
939 unused ones have the tcpstate set to CLOSED. Also, connections in
940 TIME_WAIT are kept track of and we'll use the oldest one if no
941 CLOSED connections are found. Thanks to Eddie C. Dost for a very
942 nice algorithm for the TIME_WAIT search. */
943 uip_connr = 0;
944 for(c = 0; c < UIP_CONNS; ++c) {
945 if(uip_conns[c].tcpstateflags == CLOSED) {
946 uip_connr = &uip_conns[c];
947 break;
948 }
949 if(uip_conns[c].tcpstateflags == TIME_WAIT) {
950 if(uip_connr == 0 ||
951 uip_conns[c].timer > uip_connr->timer) {
952 uip_connr = &uip_conns[c];
953 }
954 }
955 }
956
957 if(uip_connr == 0) {
958 /* All connections are used already, we drop packet and hope that
959 the remote end will retransmit the packet at a time when we
960 have more spare connections. */
961 UIP_STAT(++uip_stat.tcp.syndrop);
962 UIP_LOG("tcp: found no unused connections.");
963 goto drop;
964 }
965 uip_conn = uip_connr;
966
967 /* Fill in the necessary fields for the new connection. */
adamdunkelsb489e7a2003-10-14 11:12:50 +0000968 uip_connr->rto = uip_connr->timer = UIP_RTO;
969 uip_connr->sa = 0;
970 uip_connr->sv = 4;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000971 uip_connr->nrtx = 0;
972 uip_connr->lport = BUF->destport;
973 uip_connr->rport = BUF->srcport;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000974 uip_connr->ripaddr[0] = BUF->srcipaddr[0];
975 uip_connr->ripaddr[1] = BUF->srcipaddr[1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000976 uip_connr->tcpstateflags = SYN_RCVD;
977
978 uip_connr->snd_nxt[0] = iss[0];
979 uip_connr->snd_nxt[1] = iss[1];
980 uip_connr->snd_nxt[2] = iss[2];
981 uip_connr->snd_nxt[3] = iss[3];
982 uip_connr->len = 1;
983
984 /* rcv_nxt should be the seqno from the incoming packet + 1. */
985 uip_connr->rcv_nxt[3] = BUF->seqno[3];
986 uip_connr->rcv_nxt[2] = BUF->seqno[2];
987 uip_connr->rcv_nxt[1] = BUF->seqno[1];
988 uip_connr->rcv_nxt[0] = BUF->seqno[0];
989 uip_add_rcv_nxt(1);
990
991 /* Parse the TCP MSS option, if present. */
992 if((BUF->tcpoffset & 0xf0) > 0x50) {
993 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
994 opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c];
995 if(opt == 0x00) {
996 /* End of options. */
997 break;
998 } else if(opt == 0x01) {
999 ++c;
1000 /* NOP option. */
1001 } else if(opt == 0x02 &&
1002 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0x04) {
1003 /* An MSS option with the right option length. */
adamdunkels0170b082003-10-01 11:25:37 +00001004 tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
1005 (u16_t)uip_buf[40 + UIP_LLH_LEN + 3 + c];
1006 uip_connr->initialmss = uip_connr->mss =
1007 tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001008
1009 /* And we are done processing options. */
1010 break;
1011 } else {
1012 /* All other options have a length field, so that we easily
1013 can skip past them. */
1014 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
1015 /* If the length field is zero, the options are malformed
1016 and we don't process them further. */
1017 break;
1018 }
1019 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
1020 }
1021 }
1022 }
1023
1024 /* Our response will be a SYNACK. */
1025#if UIP_ACTIVE_OPEN
1026 tcp_send_synack:
1027 BUF->flags = TCP_ACK;
1028
1029 tcp_send_syn:
1030 BUF->flags |= TCP_SYN;
1031#else /* UIP_ACTIVE_OPEN */
1032 tcp_send_synack:
1033 BUF->flags = TCP_SYN | TCP_ACK;
1034#endif /* UIP_ACTIVE_OPEN */
1035
1036 /* We send out the TCP Maximum Segment Size option with our
1037 SYNACK. */
1038 BUF->optdata[0] = 2;
1039 BUF->optdata[1] = 4;
1040 BUF->optdata[2] = (UIP_TCP_MSS) / 256;
1041 BUF->optdata[3] = (UIP_TCP_MSS) & 255;
1042 uip_len = 44;
1043 BUF->tcpoffset = 6 << 4;
1044 goto tcp_send;
1045
1046 /* This label will be jumped to if we found an active connection. */
1047 found:
1048 uip_conn = uip_connr;
1049 uip_flags = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001050 /* We do a very naive form of TCP reset processing; we just accept
1051 any RST and kill our connection. We should in fact check if the
1052 sequence number of this reset is wihtin our advertised window
1053 before we accept the reset. */
1054 if(BUF->flags & TCP_RST) {
1055 uip_connr->tcpstateflags = CLOSED;
1056 UIP_LOG("tcp: got reset, aborting connection.");
1057 uip_flags = UIP_ABORT;
1058 UIP_APPCALL();
1059 goto drop;
adamdunkels47ec7fa2003-03-28 12:11:17 +00001060 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001061 /* Calculated the length of the data, if the application has sent
1062 any data to us. */
1063 c = (BUF->tcpoffset >> 4) << 2;
1064 /* uip_len will contain the length of the actual TCP data. This is
1065 calculated by subtracing the length of the TCP header (in
1066 c) and the length of the IP header (20 bytes). */
1067 uip_len = uip_len - c - 20;
1068
1069 /* First, check if the sequence number of the incoming packet is
1070 what we're expecting next. If not, we send out an ACK with the
1071 correct numbers in. */
1072 if(uip_len > 0 &&
1073 (BUF->seqno[0] != uip_connr->rcv_nxt[0] ||
1074 BUF->seqno[1] != uip_connr->rcv_nxt[1] ||
1075 BUF->seqno[2] != uip_connr->rcv_nxt[2] ||
1076 BUF->seqno[3] != uip_connr->rcv_nxt[3])) {
1077 goto tcp_send_ack;
1078 }
1079
1080 /* Next, check if the incoming segment acknowledges any outstanding
1081 data. If so, we update the sequence number, reset the length of
1082 the outstanding data, calculate RTT estimations, and reset the
1083 retransmission timer. */
adamdunkels47ec7fa2003-03-28 12:11:17 +00001084 if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001085 uip_add32(uip_connr->snd_nxt, uip_connr->len);
adamdunkels08eac9e2004-09-12 07:17:37 +00001086
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001087 if(BUF->ackno[0] == uip_acc32[0] &&
1088 BUF->ackno[1] == uip_acc32[1] &&
1089 BUF->ackno[2] == uip_acc32[2] &&
1090 BUF->ackno[3] == uip_acc32[3]) {
1091 /* Update sequence number. */
1092 uip_connr->snd_nxt[0] = uip_acc32[0];
1093 uip_connr->snd_nxt[1] = uip_acc32[1];
1094 uip_connr->snd_nxt[2] = uip_acc32[2];
1095 uip_connr->snd_nxt[3] = uip_acc32[3];
adamdunkelsa38da252003-08-20 20:56:54 +00001096
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001097
1098 /* Do RTT estimation, unless we have done retransmissions. */
1099 if(uip_connr->nrtx == 0) {
1100 signed char m;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001101 m = uip_connr->rto - uip_connr->timer;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001102 /* This is taken directly from VJs original code in his paper */
1103 m = m - (uip_connr->sa >> 3);
1104 uip_connr->sa += m;
1105 if(m < 0) {
1106 m = -m;
1107 }
1108 m = m - (uip_connr->sv >> 2);
1109 uip_connr->sv += m;
1110 uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv;
1111
1112 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001113 /* Set the acknowledged flag. */
1114 uip_flags = UIP_ACKDATA;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001115 /* Reset the retransmission timer. */
adamdunkelsb489e7a2003-10-14 11:12:50 +00001116 uip_connr->timer = uip_connr->rto;
adamdunkels08eac9e2004-09-12 07:17:37 +00001117
1118 /* Reset length of outstanding data. */
1119 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001120 }
adamdunkelsab4b0822003-07-30 23:31:40 +00001121
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001122 }
1123
1124 /* Do different things depending on in what state the connection is. */
1125 switch(uip_connr->tcpstateflags & TS_MASK) {
1126 /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
1127 implemented, since we force the application to close when the
1128 peer sends a FIN (hence the application goes directly from
1129 ESTABLISHED to LAST_ACK). */
1130 case SYN_RCVD:
1131 /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and
1132 we are waiting for an ACK that acknowledges the data we sent
1133 out the last time. Therefore, we want to have the UIP_ACKDATA
1134 flag set. If so, we enter the ESTABLISHED state. */
1135 if(uip_flags & UIP_ACKDATA) {
1136 uip_connr->tcpstateflags = ESTABLISHED;
1137 uip_flags = UIP_CONNECTED;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001138 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001139 if(uip_len > 0) {
1140 uip_flags |= UIP_NEWDATA;
1141 uip_add_rcv_nxt(uip_len);
1142 }
1143 uip_slen = 0;
1144 UIP_APPCALL();
1145 goto appsend;
1146 }
1147 goto drop;
1148#if UIP_ACTIVE_OPEN
1149 case SYN_SENT:
1150 /* In SYN_SENT, we wait for a SYNACK that is sent in response to
1151 our SYN. The rcv_nxt is set to sequence number in the SYNACK
1152 plus one, and we send an ACK. We move into the ESTABLISHED
1153 state. */
1154 if((uip_flags & UIP_ACKDATA) &&
1155 BUF->flags == (TCP_SYN | TCP_ACK)) {
1156
1157 /* Parse the TCP MSS option, if present. */
1158 if((BUF->tcpoffset & 0xf0) > 0x50) {
1159 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
1160 opt = uip_buf[40 + UIP_LLH_LEN + c];
1161 if(opt == 0x00) {
1162 /* End of options. */
1163 break;
1164 } else if(opt == 0x01) {
1165 ++c;
1166 /* NOP option. */
1167 } else if(opt == 0x02 &&
1168 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0x04) {
1169 /* An MSS option with the right option length. */
adamdunkels0170b082003-10-01 11:25:37 +00001170 tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001171 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];
adamdunkels0170b082003-10-01 11:25:37 +00001172 uip_connr->initialmss =
1173 uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001174
1175 /* And we are done processing options. */
1176 break;
1177 } else {
1178 /* All other options have a length field, so that we easily
1179 can skip past them. */
1180 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
1181 /* If the length field is zero, the options are malformed
1182 and we don't process them further. */
1183 break;
1184 }
1185 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
1186 }
1187 }
1188 }
1189 uip_connr->tcpstateflags = ESTABLISHED;
1190 uip_connr->rcv_nxt[0] = BUF->seqno[0];
1191 uip_connr->rcv_nxt[1] = BUF->seqno[1];
1192 uip_connr->rcv_nxt[2] = BUF->seqno[2];
1193 uip_connr->rcv_nxt[3] = BUF->seqno[3];
1194 uip_add_rcv_nxt(1);
1195 uip_flags = UIP_CONNECTED | UIP_NEWDATA;
adamdunkelsb489e7a2003-10-14 11:12:50 +00001196 uip_connr->len = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001197 uip_len = 0;
1198 uip_slen = 0;
1199 UIP_APPCALL();
1200 goto appsend;
1201 }
1202 goto reset;
1203#endif /* UIP_ACTIVE_OPEN */
1204
1205 case ESTABLISHED:
1206 /* In the ESTABLISHED state, we call upon the application to feed
1207 data into the uip_buf. If the UIP_ACKDATA flag is set, the
1208 application should put new data into the buffer, otherwise we are
1209 retransmitting an old segment, and the application should put that
1210 data into the buffer.
1211
1212 If the incoming packet is a FIN, we should close the connection on
1213 this side as well, and we send out a FIN and enter the LAST_ACK
1214 state. We require that there is no outstanding data; otherwise the
1215 sequence numbers will be screwed up. */
1216
1217 if(BUF->flags & TCP_FIN) {
1218 if(uip_outstanding(uip_connr)) {
1219 goto drop;
1220 }
1221 uip_add_rcv_nxt(1 + uip_len);
1222 uip_flags = UIP_CLOSE;
1223 if(uip_len > 0) {
1224 uip_flags |= UIP_NEWDATA;
1225 }
1226 UIP_APPCALL();
1227 uip_connr->len = 1;
1228 uip_connr->tcpstateflags = LAST_ACK;
1229 uip_connr->nrtx = 0;
1230 tcp_send_finack:
1231 BUF->flags = TCP_FIN | TCP_ACK;
1232 goto tcp_send_nodata;
1233 }
1234
1235 /* Check the URG flag. If this is set, the segment carries urgent
1236 data that we must pass to the application. */
adamdunkels9fad4132004-06-06 06:14:19 +00001237 if((BUF->flags & TCP_URG) != 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001238#if UIP_URGDATA > 0
1239 uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1];
1240 if(uip_urglen > uip_len) {
1241 /* There is more urgent data in the next segment to come. */
1242 uip_urglen = uip_len;
1243 }
1244 uip_add_rcv_nxt(uip_urglen);
1245 uip_len -= uip_urglen;
1246 uip_urgdata = uip_appdata;
1247 uip_appdata += uip_urglen;
1248 } else {
1249 uip_urglen = 0;
adamdunkels9fad4132004-06-06 06:14:19 +00001250#else /* UIP_URGDATA > 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001251 uip_appdata += (BUF->urgp[0] << 8) | BUF->urgp[1];
1252 uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1];
adamdunkels9fad4132004-06-06 06:14:19 +00001253#endif /* UIP_URGDATA > 0 */
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001254 }
adamdunkels9fad4132004-06-06 06:14:19 +00001255
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001256 /* If uip_len > 0 we have TCP data in the packet, and we flag this
1257 by setting the UIP_NEWDATA flag and update the sequence number
1258 we acknowledge. If the application has stopped the dataflow
1259 using uip_stop(), we must not accept any data packets from the
1260 remote host. */
1261 if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
1262 uip_flags |= UIP_NEWDATA;
1263 uip_add_rcv_nxt(uip_len);
1264 }
adamdunkels0170b082003-10-01 11:25:37 +00001265
1266 /* Check if the available buffer space advertised by the other end
1267 is smaller than the initial MSS for this connection. If so, we
1268 set the current MSS to the window size to ensure that the
1269 application does not send more data than the other end can
1270 handle.
1271
1272 If the remote host advertises a zero window, we set the MSS to
1273 the initial MSS so that the application will send an entire MSS
1274 of data. This data will not be acknowledged by the receiver,
1275 and the application will retransmit it. This is called the
1276 "persistent timer" and uses the retransmission mechanim.
1277 */
1278 tmp16 = ((u16_t)BUF->wnd[0] << 8) + (u16_t)BUF->wnd[1];
1279 if(tmp16 > uip_connr->initialmss ||
1280 tmp16 == 0) {
1281 tmp16 = uip_connr->initialmss;
1282 }
1283 uip_connr->mss = tmp16;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001284
1285 /* If this packet constitutes an ACK for outstanding data (flagged
1286 by the UIP_ACKDATA flag, we should call the application since it
1287 might want to send more data. If the incoming packet had data
1288 from the peer (as flagged by the UIP_NEWDATA flag), the
1289 application must also be notified.
1290
1291 When the application is called, the global variable uip_len
1292 contains the length of the incoming data. The application can
1293 access the incoming data through the global pointer
1294 uip_appdata, which usually points 40 bytes into the uip_buf
1295 array.
1296
1297 If the application wishes to send any data, this data should be
1298 put into the uip_appdata and the length of the data should be
1299 put into uip_len. If the application don't have any data to
1300 send, uip_len must be set to 0. */
1301 if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) {
1302 uip_slen = 0;
1303 UIP_APPCALL();
1304
1305 appsend:
adamdunkels0170b082003-10-01 11:25:37 +00001306
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001307 if(uip_flags & UIP_ABORT) {
1308 uip_slen = 0;
1309 uip_connr->tcpstateflags = CLOSED;
1310 BUF->flags = TCP_RST | TCP_ACK;
1311 goto tcp_send_nodata;
1312 }
1313
1314 if(uip_flags & UIP_CLOSE) {
1315 uip_slen = 0;
1316 uip_connr->len = 1;
1317 uip_connr->tcpstateflags = FIN_WAIT_1;
1318 uip_connr->nrtx = 0;
1319 BUF->flags = TCP_FIN | TCP_ACK;
1320 goto tcp_send_nodata;
1321 }
1322
adamdunkelsb489e7a2003-10-14 11:12:50 +00001323 /* If uip_slen > 0, the application has data to be sent. */
1324 if(uip_slen > 0) {
1325
1326 /* If the connection has acknowledged data, the contents of
1327 the ->len variable should be discarded. */
1328 if((uip_flags & UIP_ACKDATA) != 0) {
1329 uip_connr->len = 0;
1330 }
1331
1332 /* If the ->len variable is non-zero the connection has
1333 already data in transit and cannot send anymore right
1334 now. */
1335 if(uip_connr->len == 0) {
1336
1337 /* The application cannot send more than what is allowed by
1338 the mss (the minumum of the MSS and the available
1339 window). */
1340 if(uip_slen > uip_connr->mss) {
1341 uip_slen = uip_connr->mss;
1342 }
1343
1344 /* Remember how much data we send out now so that we know
1345 when everything has been acknowledged. */
1346 uip_connr->len = uip_slen;
1347 } else {
1348
1349 /* If the application already had unacknowledged data, we
1350 make sure that the application does not send (i.e.,
1351 retransmit) out more than it previously sent out. */
1352 uip_slen = uip_connr->len;
1353 }
adamdunkelsab4b0822003-07-30 23:31:40 +00001354 } else {
adamdunkels08eac9e2004-09-12 07:17:37 +00001355 /* uip_connr->len = 0;*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001356 }
adamdunkelsb489e7a2003-10-14 11:12:50 +00001357 uip_connr->nrtx = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001358 apprexmit:
adamdunkels0170b082003-10-01 11:25:37 +00001359 uip_appdata = uip_sappdata;
1360
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001361 /* If the application has data to be sent, or if the incoming
1362 packet had new data in it, we must send out a packet. */
adamdunkels759185d2003-06-30 20:35:41 +00001363 if(uip_slen > 0 && uip_connr->len > 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001364 /* Add the length of the IP and TCP headers. */
1365 uip_len = uip_connr->len + UIP_TCPIP_HLEN;
1366 /* We always set the ACK flag in response packets. */
adamdunkels759185d2003-06-30 20:35:41 +00001367 BUF->flags = TCP_ACK | TCP_PSH;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001368 /* Send the packet. */
1369 goto tcp_send_noopts;
1370 }
adamdunkels759185d2003-06-30 20:35:41 +00001371 /* If there is no data to send, just send out a pure ACK if
1372 there is newdata. */
1373 if(uip_flags & UIP_NEWDATA) {
1374 uip_len = UIP_TCPIP_HLEN;
1375 BUF->flags = TCP_ACK;
1376 goto tcp_send_noopts;
1377 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001378 }
1379 goto drop;
1380 case LAST_ACK:
1381 /* We can close this connection if the peer has acknowledged our
1382 FIN. This is indicated by the UIP_ACKDATA flag. */
1383 if(uip_flags & UIP_ACKDATA) {
1384 uip_connr->tcpstateflags = CLOSED;
1385 uip_flags = UIP_CLOSE;
1386 UIP_APPCALL();
1387 }
1388 break;
1389
1390 case FIN_WAIT_1:
1391 /* The application has closed the connection, but the remote host
1392 hasn't closed its end yet. Thus we do nothing but wait for a
1393 FIN from the other side. */
1394 if(uip_len > 0) {
1395 uip_add_rcv_nxt(uip_len);
1396 }
1397 if(BUF->flags & TCP_FIN) {
1398 if(uip_flags & UIP_ACKDATA) {
1399 uip_connr->tcpstateflags = TIME_WAIT;
1400 uip_connr->timer = 0;
1401 uip_connr->len = 0;
1402 } else {
1403 uip_connr->tcpstateflags = CLOSING;
1404 }
1405 uip_add_rcv_nxt(1);
1406 uip_flags = UIP_CLOSE;
1407 UIP_APPCALL();
1408 goto tcp_send_ack;
1409 } else if(uip_flags & UIP_ACKDATA) {
1410 uip_connr->tcpstateflags = FIN_WAIT_2;
1411 uip_connr->len = 0;
1412 goto drop;
1413 }
1414 if(uip_len > 0) {
1415 goto tcp_send_ack;
1416 }
1417 goto drop;
1418
1419 case FIN_WAIT_2:
1420 if(uip_len > 0) {
1421 uip_add_rcv_nxt(uip_len);
1422 }
1423 if(BUF->flags & TCP_FIN) {
1424 uip_connr->tcpstateflags = TIME_WAIT;
1425 uip_connr->timer = 0;
1426 uip_add_rcv_nxt(1);
1427 uip_flags = UIP_CLOSE;
1428 UIP_APPCALL();
1429 goto tcp_send_ack;
1430 }
1431 if(uip_len > 0) {
1432 goto tcp_send_ack;
1433 }
1434 goto drop;
1435
1436 case TIME_WAIT:
1437 goto tcp_send_ack;
1438
1439 case CLOSING:
1440 if(uip_flags & UIP_ACKDATA) {
1441 uip_connr->tcpstateflags = TIME_WAIT;
1442 uip_connr->timer = 0;
1443 }
1444 }
1445 goto drop;
1446
1447
1448 /* We jump here when we are ready to send the packet, and just want
1449 to set the appropriate TCP sequence numbers in the TCP header. */
1450 tcp_send_ack:
1451 BUF->flags = TCP_ACK;
1452 tcp_send_nodata:
1453 uip_len = 40;
1454 tcp_send_noopts:
1455 BUF->tcpoffset = 5 << 4;
1456 tcp_send:
1457 /* We're done with the input processing. We are now ready to send a
1458 reply. Our job is to fill in all the fields of the TCP and IP
1459 headers before calculating the checksum and finally send the
1460 packet. */
1461 BUF->ackno[0] = uip_connr->rcv_nxt[0];
1462 BUF->ackno[1] = uip_connr->rcv_nxt[1];
1463 BUF->ackno[2] = uip_connr->rcv_nxt[2];
1464 BUF->ackno[3] = uip_connr->rcv_nxt[3];
1465
1466 BUF->seqno[0] = uip_connr->snd_nxt[0];
1467 BUF->seqno[1] = uip_connr->snd_nxt[1];
1468 BUF->seqno[2] = uip_connr->snd_nxt[2];
1469 BUF->seqno[3] = uip_connr->snd_nxt[3];
1470
1471 BUF->proto = UIP_PROTO_TCP;
1472
1473 BUF->srcport = uip_connr->lport;
1474 BUF->destport = uip_connr->rport;
1475
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001476 BUF->srcipaddr[0] = uip_hostaddr[0];
1477 BUF->srcipaddr[1] = uip_hostaddr[1];
1478 BUF->destipaddr[0] = uip_connr->ripaddr[0];
1479 BUF->destipaddr[1] = uip_connr->ripaddr[1];
1480
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001481
1482 if(uip_connr->tcpstateflags & UIP_STOPPED) {
1483 /* If the connection has issued uip_stop(), we advertise a zero
1484 window so that the remote host will stop sending data. */
1485 BUF->wnd[0] = BUF->wnd[1] = 0;
1486 } else {
adamdunkelsb489e7a2003-10-14 11:12:50 +00001487 BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8);
1488 BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001489 }
1490
1491 tcp_send_noconn:
1492
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001493 BUF->len[0] = (uip_len >> 8);
1494 BUF->len[1] = (uip_len & 0xff);
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001495
adamdunkels9fad4132004-06-06 06:14:19 +00001496 BUF->urgp[0] = BUF->urgp[1] = 0;
1497
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001498 /* Calculate TCP checksum. */
1499 BUF->tcpchksum = 0;
1500 BUF->tcpchksum = ~(uip_tcpchksum());
1501
1502 ip_send_nolen:
1503
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001504 BUF->vhl = 0x45;
1505 BUF->tos = 0;
1506 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
1507 BUF->ttl = UIP_TTL;
1508 ++ipid;
1509 BUF->ipid[0] = ipid >> 8;
1510 BUF->ipid[1] = ipid & 0xff;
1511
1512 /* Calculate IP checksum. */
1513 BUF->ipchksum = 0;
1514 BUF->ipchksum = ~(uip_ipchksum());
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001515
1516 UIP_STAT(++uip_stat.tcp.sent);
1517 send:
adamdunkels9fad4132004-06-06 06:14:19 +00001518
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001519 UIP_STAT(++uip_stat.ip.sent);
1520 /* Return and let the caller do the actual transmission. */
1521 return;
1522 drop:
1523 uip_len = 0;
1524 return;
1525}
1526/*-----------------------------------------------------------------------------------*/
adamdunkels47ec7fa2003-03-28 12:11:17 +00001527u16_t
1528htons(u16_t val)
1529{
1530 return HTONS(val);
1531}
1532/*-----------------------------------------------------------------------------------*/
adamdunkels0170b082003-10-01 11:25:37 +00001533/** @} */