]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/lwip/lib/contrib/src/core/tcp_in.c
update
[l4.git] / l4 / pkg / lwip / lib / contrib / src / core / tcp_in.c
1 /**
2  * @file
3  * Transmission Control Protocol, incoming traffic
4  *
5  * The input processing functions of the TCP layer.
6  *
7  * These functions are generally called in the order (ip_input() ->)
8  * tcp_input() -> * tcp_process() -> tcp_receive() (-> application).
9  * 
10  */
11
12 /*
13  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
14  * All rights reserved.
15  *
16  * Redistribution and use in source and binary forms, with or without modification,
17  * are permitted provided that the following conditions are met:
18  *
19  * 1. Redistributions of source code must retain the above copyright notice,
20  *    this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright notice,
22  *    this list of conditions and the following disclaimer in the documentation
23  *    and/or other materials provided with the distribution.
24  * 3. The name of the author may not be used to endorse or promote products
25  *    derived from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
28  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
29  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
30  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
32  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
35  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
36  * OF SUCH DAMAGE.
37  *
38  * This file is part of the lwIP TCP/IP stack.
39  *
40  * Author: Adam Dunkels <adam@sics.se>
41  *
42  */
43
44 #include "lwip/opt.h"
45
46 #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
47
48 #include "lwip/tcp_impl.h"
49 #include "lwip/def.h"
50 #include "lwip/ip_addr.h"
51 #include "lwip/netif.h"
52 #include "lwip/mem.h"
53 #include "lwip/memp.h"
54 #include "lwip/inet_chksum.h"
55 #include "lwip/stats.h"
56 #include "lwip/snmp.h"
57 #include "arch/perf.h"
58 #include "lwip/ip6.h"
59 #include "lwip/ip6_addr.h"
60 #include "lwip/inet_chksum.h"
61 #if LWIP_ND6_TCP_REACHABILITY_HINTS
62 #include "lwip/nd6.h"
63 #endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */
64
65 /* These variables are global to all functions involved in the input
66    processing of TCP segments. They are set by the tcp_input()
67    function. */
68 static struct tcp_seg inseg;
69 static struct tcp_hdr *tcphdr;
70 static u32_t seqno, ackno;
71 static u8_t flags;
72 static u16_t tcplen;
73
74 static u8_t recv_flags;
75 static struct pbuf *recv_data;
76
77 struct tcp_pcb *tcp_input_pcb;
78
79 /* Forward declarations. */
80 static err_t tcp_process(struct tcp_pcb *pcb);
81 static void tcp_receive(struct tcp_pcb *pcb);
82 static void tcp_parseopt(struct tcp_pcb *pcb);
83
84 static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);
85 static err_t tcp_timewait_input(struct tcp_pcb *pcb);
86
87 /**
88  * The initial input processing of TCP. It verifies the TCP header, demultiplexes
89  * the segment between the PCBs and passes it on to tcp_process(), which implements
90  * the TCP finite state machine. This function is called by the IP layer (in
91  * ip_input()).
92  *
93  * @param p received TCP segment to process (p->payload pointing to the TCP header)
94  * @param inp network interface on which this segment was received
95  */
96 void
97 tcp_input(struct pbuf *p, struct netif *inp)
98 {
99   struct tcp_pcb *pcb, *prev;
100   struct tcp_pcb_listen *lpcb;
101 #if SO_REUSE
102   struct tcp_pcb *lpcb_prev = NULL;
103   struct tcp_pcb_listen *lpcb_any = NULL;
104 #endif /* SO_REUSE */
105   u8_t hdrlen;
106   err_t err;
107 #if CHECKSUM_CHECK_TCP
108   u16_t chksum;
109 #endif /* CHECKSUM_CHECK_TCP */
110
111   PERF_START;
112
113   TCP_STATS_INC(tcp.recv);
114   snmp_inc_tcpinsegs();
115
116   tcphdr = (struct tcp_hdr *)p->payload;
117
118 #if TCP_INPUT_DEBUG
119   tcp_debug_print(tcphdr);
120 #endif
121
122   /* Check that TCP header fits in payload */
123   if (p->len < sizeof(struct tcp_hdr)) {
124     /* drop short packets */
125     LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));
126     TCP_STATS_INC(tcp.lenerr);
127     goto dropped;
128   }
129
130   /* Don't even process incoming broadcasts/multicasts. */
131   if ((!ip_current_is_v6() && ip_addr_isbroadcast(ip_current_dest_addr(), inp)) ||
132        ipX_addr_ismulticast(ip_current_is_v6(), ipX_current_dest_addr())) {
133     TCP_STATS_INC(tcp.proterr);
134     goto dropped;
135   }
136
137 #if CHECKSUM_CHECK_TCP
138   /* Verify TCP checksum. */
139   chksum = ipX_chksum_pseudo(ip_current_is_v6(), p, IP_PROTO_TCP, p->tot_len,
140                              ipX_current_src_addr(), ipX_current_dest_addr());
141   if (chksum != 0) {
142       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",
143         chksum));
144     tcp_debug_print(tcphdr);
145     TCP_STATS_INC(tcp.chkerr);
146     goto dropped;
147   }
148 #endif /* CHECKSUM_CHECK_TCP */
149
150   /* Move the payload pointer in the pbuf so that it points to the
151      TCP data instead of the TCP header. */
152   hdrlen = TCPH_HDRLEN(tcphdr);
153   if(pbuf_header(p, -(hdrlen * 4))){
154     /* drop short packets */
155     LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n"));
156     TCP_STATS_INC(tcp.lenerr);
157     goto dropped;
158   }
159
160   /* Convert fields in TCP header to host byte order. */
161   tcphdr->src = ntohs(tcphdr->src);
162   tcphdr->dest = ntohs(tcphdr->dest);
163   seqno = tcphdr->seqno = ntohl(tcphdr->seqno);
164   ackno = tcphdr->ackno = ntohl(tcphdr->ackno);
165   tcphdr->wnd = ntohs(tcphdr->wnd);
166
167   flags = TCPH_FLAGS(tcphdr);
168   tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0);
169
170   /* Demultiplex an incoming segment. First, we check if it is destined
171      for an active connection. */
172   prev = NULL;
173
174   
175   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
176     LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);
177     LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
178     LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
179     if (pcb->remote_port == tcphdr->src &&
180         pcb->local_port == tcphdr->dest &&
181         IP_PCB_IPVER_INPUT_MATCH(pcb) &&
182         ipX_addr_cmp(ip_current_is_v6(), &pcb->remote_ip, ipX_current_src_addr()) &&
183         ipX_addr_cmp(ip_current_is_v6(),&pcb->local_ip, ipX_current_dest_addr())) {
184       /* Move this PCB to the front of the list so that subsequent
185          lookups will be faster (we exploit locality in TCP segment
186          arrivals). */
187       LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);
188       if (prev != NULL) {
189         prev->next = pcb->next;
190         pcb->next = tcp_active_pcbs;
191         tcp_active_pcbs = pcb;
192       }
193       LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);
194       break;
195     }
196     prev = pcb;
197   }
198
199   if (pcb == NULL) {
200     /* If it did not go to an active connection, we check the connections
201        in the TIME-WAIT state. */
202     for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
203       LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
204       if (pcb->remote_port == tcphdr->src &&
205           pcb->local_port == tcphdr->dest &&
206           IP_PCB_IPVER_INPUT_MATCH(pcb) &&
207           ipX_addr_cmp(ip_current_is_v6(), &pcb->remote_ip, ipX_current_src_addr()) &&
208           ipX_addr_cmp(ip_current_is_v6(),&pcb->local_ip, ipX_current_dest_addr())) {
209         /* We don't really care enough to move this PCB to the front
210            of the list since we are not very likely to receive that
211            many segments for connections in TIME-WAIT. */
212         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n"));
213         tcp_timewait_input(pcb);
214         pbuf_free(p);
215         return;
216       }
217     }
218
219     /* Finally, if we still did not get a match, we check all PCBs that
220        are LISTENing for incoming connections. */
221     prev = NULL;
222     for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
223       if (lpcb->local_port == tcphdr->dest) {
224 #if LWIP_IPV6
225         if (lpcb->accept_any_ip_version) {
226           /* found an ANY-match */
227 #if SO_REUSE
228           lpcb_any = lpcb;
229           lpcb_prev = prev;
230 #else /* SO_REUSE */
231           break;
232 #endif /* SO_REUSE */
233         } else
234 #endif /* LWIP_IPV6 */
235         if (IP_PCB_IPVER_INPUT_MATCH(lpcb)) {
236           if (ipX_addr_cmp(ip_current_is_v6(), &lpcb->local_ip, ipX_current_dest_addr())) {
237             /* found an exact match */
238             break;
239           } else if (ipX_addr_isany(ip_current_is_v6(), &lpcb->local_ip)) {
240             /* found an ANY-match */
241 #if SO_REUSE
242             lpcb_any = lpcb;
243             lpcb_prev = prev;
244 #else /* SO_REUSE */
245             break;
246  #endif /* SO_REUSE */
247           }
248         }
249       }
250       prev = (struct tcp_pcb *)lpcb;
251     }
252 #if SO_REUSE
253     /* first try specific local IP */
254     if (lpcb == NULL) {
255       /* only pass to ANY if no specific local IP has been found */
256       lpcb = lpcb_any;
257       prev = lpcb_prev;
258     }
259 #endif /* SO_REUSE */
260     if (lpcb != NULL) {
261       /* Move this PCB to the front of the list so that subsequent
262          lookups will be faster (we exploit locality in TCP segment
263          arrivals). */
264       if (prev != NULL) {
265         ((struct tcp_pcb_listen *)prev)->next = lpcb->next;
266               /* our successor is the remainder of the listening list */
267         lpcb->next = tcp_listen_pcbs.listen_pcbs;
268               /* put this listening pcb at the head of the listening list */
269         tcp_listen_pcbs.listen_pcbs = lpcb;
270       }
271     
272       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));
273       tcp_listen_input(lpcb);
274       pbuf_free(p);
275       return;
276     }
277   }
278
279 #if TCP_INPUT_DEBUG
280   LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags "));
281   tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
282   LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"));
283 #endif /* TCP_INPUT_DEBUG */
284
285
286   if (pcb != NULL) {
287     /* The incoming segment belongs to a connection. */
288 #if TCP_INPUT_DEBUG
289 #if TCP_DEBUG
290     tcp_debug_print_state(pcb->state);
291 #endif /* TCP_DEBUG */
292 #endif /* TCP_INPUT_DEBUG */
293
294     /* Set up a tcp_seg structure. */
295     inseg.next = NULL;
296     inseg.len = p->tot_len;
297     inseg.p = p;
298     inseg.tcphdr = tcphdr;
299
300     recv_data = NULL;
301     recv_flags = 0;
302
303     /* If there is data which was previously "refused" by upper layer */
304     if (pcb->refused_data != NULL) {
305       /* Notify again application with data previously received. */
306       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
307       TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
308       if (err == ERR_OK) {
309         pcb->refused_data = NULL;
310       } else if ((err == ERR_ABRT) || (tcplen > 0)) {
311         /* if err == ERR_ABRT, 'pcb' is already deallocated */
312         /* Drop incoming packets because pcb is "full" (only if the incoming
313            segment contains data). */
314         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
315         goto dropped;
316       }
317     }
318     tcp_input_pcb = pcb;
319     err = tcp_process(pcb);
320     /* A return value of ERR_ABRT means that tcp_abort() was called
321        and that the pcb has been freed. If so, we don't do anything. */
322     if (err != ERR_ABRT) {
323       if (recv_flags & TF_RESET) {
324         /* TF_RESET means that the connection was reset by the other
325            end. We then call the error callback to inform the
326            application that the connection is dead before we
327            deallocate the PCB. */
328         TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);
329         tcp_pcb_remove(&tcp_active_pcbs, pcb);
330         memp_free(MEMP_TCP_PCB, pcb);
331       } else if (recv_flags & TF_CLOSED) {
332         /* The connection has been closed and we will deallocate the
333            PCB. */
334         tcp_pcb_remove(&tcp_active_pcbs, pcb);
335         memp_free(MEMP_TCP_PCB, pcb);
336       } else {
337         err = ERR_OK;
338         /* If the application has registered a "sent" function to be
339            called when new send buffer space is available, we call it
340            now. */
341         if (pcb->acked > 0) {
342           TCP_EVENT_SENT(pcb, pcb->acked, err);
343           if (err == ERR_ABRT) {
344             goto aborted;
345           }
346         }
347
348         if (recv_data != NULL) {
349           LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL);
350           if (pcb->flags & TF_RXCLOSED) {
351             /* received data although already closed -> abort (send RST) to
352                notify the remote host that not all data has been processed */
353             pbuf_free(recv_data);
354             tcp_abort(pcb);
355             goto aborted;
356           }
357           if (flags & TCP_PSH) {
358             recv_data->flags |= PBUF_FLAG_PUSH;
359           }
360
361           /* Notify application that data has been received. */
362           TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
363           if (err == ERR_ABRT) {
364             goto aborted;
365           }
366
367           /* If the upper layer can't receive this data, store it */
368           if (err != ERR_OK) {
369             pcb->refused_data = recv_data;
370             LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n"));
371           }
372         }
373
374         /* If a FIN segment was received, we call the callback
375            function with a NULL buffer to indicate EOF. */
376         if (recv_flags & TF_GOT_FIN) {
377           /* correct rcv_wnd as the application won't call tcp_recved()
378              for the FIN's seqno */
379           if (pcb->rcv_wnd != TCP_WND) {
380             pcb->rcv_wnd++;
381           }
382           TCP_EVENT_CLOSED(pcb, err);
383           if (err == ERR_ABRT) {
384             goto aborted;
385           }
386         }
387
388         tcp_input_pcb = NULL;
389         /* Try to send something out. */
390         tcp_output(pcb);
391 #if TCP_INPUT_DEBUG
392 #if TCP_DEBUG
393         tcp_debug_print_state(pcb->state);
394 #endif /* TCP_DEBUG */
395 #endif /* TCP_INPUT_DEBUG */
396       }
397     }
398     /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()).
399        Below this line, 'pcb' may not be dereferenced! */
400 aborted:
401     tcp_input_pcb = NULL;
402     recv_data = NULL;
403
404     /* give up our reference to inseg.p */
405     if (inseg.p != NULL)
406     {
407       pbuf_free(inseg.p);
408       inseg.p = NULL;
409     }
410   } else {
411
412     /* If no matching PCB was found, send a TCP RST (reset) to the
413        sender. */
414     LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));
415     if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {
416       TCP_STATS_INC(tcp.proterr);
417       TCP_STATS_INC(tcp.drop);
418       tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(),
419         ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6());
420     }
421     pbuf_free(p);
422   }
423
424   LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
425   PERF_STOP("tcp_input");
426   return;
427 dropped:
428   TCP_STATS_INC(tcp.drop);
429   snmp_inc_tcpinerrs();
430   pbuf_free(p);
431 }
432
433 /**
434  * Called by tcp_input() when a segment arrives for a listening
435  * connection (from tcp_input()).
436  *
437  * @param pcb the tcp_pcb_listen for which a segment arrived
438  * @return ERR_OK if the segment was processed
439  *         another err_t on error
440  *
441  * @note the return value is not (yet?) used in tcp_input()
442  * @note the segment which arrived is saved in global variables, therefore only the pcb
443  *       involved is passed as a parameter to this function
444  */
445 static err_t
446 tcp_listen_input(struct tcp_pcb_listen *pcb)
447 {
448   struct tcp_pcb *npcb;
449   err_t rc;
450
451   /* In the LISTEN state, we check for incoming SYN segments,
452      creates a new PCB, and responds with a SYN|ACK. */
453   if (flags & TCP_ACK) {
454     /* For incoming segments with the ACK flag set, respond with a
455        RST. */
456     LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
457     tcp_rst(ackno + 1, seqno + tcplen, ipX_current_dest_addr(),
458       ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6());
459   } else if (flags & TCP_SYN) {
460     LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
461 #if TCP_LISTEN_BACKLOG
462     if (pcb->accepts_pending >= pcb->backlog) {
463       LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest));
464       return ERR_ABRT;
465     }
466 #endif /* TCP_LISTEN_BACKLOG */
467     npcb = tcp_alloc(pcb->prio);
468     /* If a new PCB could not be created (probably due to lack of memory),
469        we don't do anything, but rely on the sender will retransmit the
470        SYN at a time when we have more memory available. */
471     if (npcb == NULL) {
472       LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));
473       TCP_STATS_INC(tcp.memerr);
474       return ERR_MEM;
475     }
476 #if TCP_LISTEN_BACKLOG
477     pcb->accepts_pending++;
478 #endif /* TCP_LISTEN_BACKLOG */
479     /* Set up the new PCB. */
480 #if LWIP_IPV6
481     PCB_ISIPV6(npcb) = ip_current_is_v6();
482 #endif /* LWIP_IPV6 */
483     ipX_addr_copy(ip_current_is_v6(), npcb->local_ip, *ipX_current_dest_addr());
484     ipX_addr_copy(ip_current_is_v6(), npcb->remote_ip, *ipX_current_src_addr());
485     npcb->local_port = pcb->local_port;
486     npcb->remote_port = tcphdr->src;
487     npcb->state = SYN_RCVD;
488     npcb->rcv_nxt = seqno + 1;
489     npcb->rcv_ann_right_edge = npcb->rcv_nxt;
490     npcb->snd_wnd = tcphdr->wnd;
491     npcb->ssthresh = npcb->snd_wnd;
492     npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
493     npcb->callback_arg = pcb->callback_arg;
494 #if LWIP_CALLBACK_API
495     npcb->accept = pcb->accept;
496 #endif /* LWIP_CALLBACK_API */
497     /* inherit socket options */
498     npcb->so_options = pcb->so_options & SOF_INHERITED;
499     /* Register the new PCB so that we can begin receiving segments
500        for it. */
501     TCP_REG(&tcp_active_pcbs, npcb);
502
503     /* Parse any options in the SYN. */
504     tcp_parseopt(npcb);
505 #if TCP_CALCULATE_EFF_SEND_MSS
506     npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip,
507       &npcb->remote_ip, PCB_ISIPV6(npcb));
508 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
509
510     snmp_inc_tcppassiveopens();
511
512     /* Send a SYN|ACK together with the MSS option. */
513     rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK);
514     if (rc != ERR_OK) {
515       tcp_abandon(npcb, 0);
516       return rc;
517     }
518     return tcp_output(npcb);
519   }
520   return ERR_OK;
521 }
522
523 /**
524  * Called by tcp_input() when a segment arrives for a connection in
525  * TIME_WAIT.
526  *
527  * @param pcb the tcp_pcb for which a segment arrived
528  *
529  * @note the segment which arrived is saved in global variables, therefore only the pcb
530  *       involved is passed as a parameter to this function
531  */
532 static err_t
533 tcp_timewait_input(struct tcp_pcb *pcb)
534 {
535   /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */
536   /* RFC 793 3.9 Event Processing - Segment Arrives:
537    * - first check sequence number - we skip that one in TIME_WAIT (always
538    *   acceptable since we only send ACKs)
539    * - second check the RST bit (... return) */
540   if (flags & TCP_RST)  {
541     return ERR_OK;
542   }
543   /* - fourth, check the SYN bit, */
544   if (flags & TCP_SYN) {
545     /* If an incoming segment is not acceptable, an acknowledgment
546        should be sent in reply */
547     if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
548       /* If the SYN is in the window it is an error, send a reset */
549       tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(),
550         ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6());
551       return ERR_OK;
552     }
553   } else if (flags & TCP_FIN) {
554     /* - eighth, check the FIN bit: Remain in the TIME-WAIT state.
555          Restart the 2 MSL time-wait timeout.*/
556     pcb->tmr = tcp_ticks;
557   }
558
559   if ((tcplen > 0))  {
560     /* Acknowledge data, FIN or out-of-window SYN */
561     pcb->flags |= TF_ACK_NOW;
562     return tcp_output(pcb);
563   }
564   return ERR_OK;
565 }
566
567 /**
568  * Implements the TCP state machine. Called by tcp_input. In some
569  * states tcp_receive() is called to receive data. The tcp_seg
570  * argument will be freed by the caller (tcp_input()) unless the
571  * recv_data pointer in the pcb is set.
572  *
573  * @param pcb the tcp_pcb for which a segment arrived
574  *
575  * @note the segment which arrived is saved in global variables, therefore only the pcb
576  *       involved is passed as a parameter to this function
577  */
578 static err_t
579 tcp_process(struct tcp_pcb *pcb)
580 {
581   struct tcp_seg *rseg;
582   u8_t acceptable = 0;
583   err_t err;
584
585   err = ERR_OK;
586
587   /* Process incoming RST segments. */
588   if (flags & TCP_RST) {
589     /* First, determine if the reset is acceptable. */
590     if (pcb->state == SYN_SENT) {
591       if (ackno == pcb->snd_nxt) {
592         acceptable = 1;
593       }
594     } else {
595       if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, 
596                           pcb->rcv_nxt+pcb->rcv_wnd)) {
597         acceptable = 1;
598       }
599     }
600
601     if (acceptable) {
602       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
603       LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
604       recv_flags |= TF_RESET;
605       pcb->flags &= ~TF_ACK_DELAY;
606       return ERR_RST;
607     } else {
608       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
609        seqno, pcb->rcv_nxt));
610       LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
611        seqno, pcb->rcv_nxt));
612       return ERR_OK;
613     }
614   }
615
616   if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { 
617     /* Cope with new connection attempt after remote end crashed */
618     tcp_ack_now(pcb);
619     return ERR_OK;
620   }
621   
622   if ((pcb->flags & TF_RXCLOSED) == 0) {
623     /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */
624     pcb->tmr = tcp_ticks;
625   }
626   pcb->keep_cnt_sent = 0;
627
628   tcp_parseopt(pcb);
629
630   /* Do different things depending on the TCP state. */
631   switch (pcb->state) {
632   case SYN_SENT:
633     LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,
634      pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
635     /* received SYN ACK with expected sequence number? */
636     if ((flags & TCP_ACK) && (flags & TCP_SYN)
637         && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
638       pcb->snd_buf++;
639       pcb->rcv_nxt = seqno + 1;
640       pcb->rcv_ann_right_edge = pcb->rcv_nxt;
641       pcb->lastack = ackno;
642       pcb->snd_wnd = tcphdr->wnd;
643       pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
644       pcb->state = ESTABLISHED;
645
646 #if TCP_CALCULATE_EFF_SEND_MSS
647       pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip,
648         PCB_ISIPV6(pcb));
649 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
650
651       /* Set ssthresh again after changing pcb->mss (already set in tcp_connect
652        * but for the default value of pcb->mss) */
653       pcb->ssthresh = pcb->mss * 10;
654
655       pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
656       LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0));
657       --pcb->snd_queuelen;
658       LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
659       rseg = pcb->unacked;
660       pcb->unacked = rseg->next;
661
662       /* If there's nothing left to acknowledge, stop the retransmit
663          timer, otherwise reset it to start again */
664       if(pcb->unacked == NULL)
665         pcb->rtime = -1;
666       else {
667         pcb->rtime = 0;
668         pcb->nrtx = 0;
669       }
670
671       tcp_seg_free(rseg);
672
673       /* Call the user specified function to call when sucessfully
674        * connected. */
675       TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
676       if (err == ERR_ABRT) {
677         return ERR_ABRT;
678       }
679       tcp_ack_now(pcb);
680     }
681     /* received ACK? possibly a half-open connection */
682     else if (flags & TCP_ACK) {
683       /* send a RST to bring the other side in a non-synchronized state. */
684       tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(),
685         ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6());
686     }
687     break;
688   case SYN_RCVD:
689     if (flags & TCP_ACK) {
690       /* expected ACK number? */
691       if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
692         u16_t old_cwnd;
693         pcb->state = ESTABLISHED;
694         LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
695 #if LWIP_CALLBACK_API
696         LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
697 #endif
698         /* Call the accept function. */
699         TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
700         if (err != ERR_OK) {
701           /* If the accept function returns with an error, we abort
702            * the connection. */
703           /* Already aborted? */
704           if (err != ERR_ABRT) {
705             tcp_abort(pcb);
706           }
707           return ERR_ABRT;
708         }
709         old_cwnd = pcb->cwnd;
710         /* If there was any data contained within this ACK,
711          * we'd better pass it on to the application as well. */
712         tcp_receive(pcb);
713
714         /* Prevent ACK for SYN to generate a sent event */
715         if (pcb->acked != 0) {
716           pcb->acked--;
717         }
718
719         pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
720
721         if (recv_flags & TF_GOT_FIN) {
722           tcp_ack_now(pcb);
723           pcb->state = CLOSE_WAIT;
724         }
725       } else {
726         /* incorrect ACK number, send RST */
727         tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(),
728           ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6());
729       }
730     } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
731       /* Looks like another copy of the SYN - retransmit our SYN-ACK */
732       tcp_rexmit(pcb);
733     }
734     break;
735   case CLOSE_WAIT:
736     /* FALLTHROUGH */
737   case ESTABLISHED:
738     tcp_receive(pcb);
739     if (recv_flags & TF_GOT_FIN) { /* passive close */
740       tcp_ack_now(pcb);
741       pcb->state = CLOSE_WAIT;
742     }
743     break;
744   case FIN_WAIT_1:
745     tcp_receive(pcb);
746     if (recv_flags & TF_GOT_FIN) {
747       if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
748         LWIP_DEBUGF(TCP_DEBUG,
749           ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
750         tcp_ack_now(pcb);
751         tcp_pcb_purge(pcb);
752         TCP_RMV(&tcp_active_pcbs, pcb);
753         pcb->state = TIME_WAIT;
754         TCP_REG(&tcp_tw_pcbs, pcb);
755       } else {
756         tcp_ack_now(pcb);
757         pcb->state = CLOSING;
758       }
759     } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
760       pcb->state = FIN_WAIT_2;
761     }
762     break;
763   case FIN_WAIT_2:
764     tcp_receive(pcb);
765     if (recv_flags & TF_GOT_FIN) {
766       LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
767       tcp_ack_now(pcb);
768       tcp_pcb_purge(pcb);
769       TCP_RMV(&tcp_active_pcbs, pcb);
770       pcb->state = TIME_WAIT;
771       TCP_REG(&tcp_tw_pcbs, pcb);
772     }
773     break;
774   case CLOSING:
775     tcp_receive(pcb);
776     if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
777       LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
778       tcp_pcb_purge(pcb);
779       TCP_RMV(&tcp_active_pcbs, pcb);
780       pcb->state = TIME_WAIT;
781       TCP_REG(&tcp_tw_pcbs, pcb);
782     }
783     break;
784   case LAST_ACK:
785     tcp_receive(pcb);
786     if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
787       LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
788       /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
789       recv_flags |= TF_CLOSED;
790     }
791     break;
792   default:
793     break;
794   }
795   return ERR_OK;
796 }
797
798 #if TCP_QUEUE_OOSEQ
799 /**
800  * Insert segment into the list (segments covered with new one will be deleted)
801  *
802  * Called from tcp_receive()
803  */
804 static void
805 tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
806 {
807   struct tcp_seg *old_seg;
808
809   if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
810     /* received segment overlaps all following segments */
811     tcp_segs_free(next);
812     next = NULL;
813   }
814   else {
815     /* delete some following segments
816        oos queue may have segments with FIN flag */
817     while (next &&
818            TCP_SEQ_GEQ((seqno + cseg->len),
819                       (next->tcphdr->seqno + next->len))) {
820       /* cseg with FIN already processed */
821       if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
822         TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN);
823       }
824       old_seg = next;
825       next = next->next;
826       tcp_seg_free(old_seg);
827     }
828     if (next &&
829         TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
830       /* We need to trim the incoming segment. */
831       cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
832       pbuf_realloc(cseg->p, cseg->len);
833     }
834   }
835   cseg->next = next;
836 }
837 #endif /* TCP_QUEUE_OOSEQ */
838
839 /**
840  * Called by tcp_process. Checks if the given segment is an ACK for outstanding
841  * data, and if so frees the memory of the buffered data. Next, is places the
842  * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment
843  * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until
844  * i it has been removed from the buffer.
845  *
846  * If the incoming segment constitutes an ACK for a segment that was used for RTT
847  * estimation, the RTT is estimated here as well.
848  *
849  * Called from tcp_process().
850  */
851 static void
852 tcp_receive(struct tcp_pcb *pcb)
853 {
854   struct tcp_seg *next;
855 #if TCP_QUEUE_OOSEQ
856   struct tcp_seg *prev, *cseg;
857 #endif /* TCP_QUEUE_OOSEQ */
858   struct pbuf *p;
859   s32_t off;
860   s16_t m;
861   u32_t right_wnd_edge;
862   u16_t new_tot_len;
863   int found_dupack = 0;
864
865   if (flags & TCP_ACK) {
866     right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;
867
868     /* Update window. */
869     if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||
870        (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||
871        (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {
872       pcb->snd_wnd = tcphdr->wnd;
873       pcb->snd_wl1 = seqno;
874       pcb->snd_wl2 = ackno;
875       if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) {
876           pcb->persist_backoff = 0;
877       }
878       LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd));
879 #if TCP_WND_DEBUG
880     } else {
881       if (pcb->snd_wnd != tcphdr->wnd) {
882         LWIP_DEBUGF(TCP_WND_DEBUG, 
883                     ("tcp_receive: no window update lastack %"U32_F" ackno %"
884                      U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",
885                      pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));
886       }
887 #endif /* TCP_WND_DEBUG */
888     }
889
890     /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a
891      * duplicate ack if:
892      * 1) It doesn't ACK new data 
893      * 2) length of received packet is zero (i.e. no payload) 
894      * 3) the advertised window hasn't changed 
895      * 4) There is outstanding unacknowledged data (retransmission timer running)
896      * 5) The ACK is == biggest ACK sequence number so far seen (snd_una)
897      * 
898      * If it passes all five, should process as a dupack: 
899      * a) dupacks < 3: do nothing 
900      * b) dupacks == 3: fast retransmit 
901      * c) dupacks > 3: increase cwnd 
902      * 
903      * If it only passes 1-3, should reset dupack counter (and add to
904      * stats, which we don't do in lwIP)
905      *
906      * If it only passes 1, should reset dupack counter
907      *
908      */
909
910     /* Clause 1 */
911     if (TCP_SEQ_LEQ(ackno, pcb->lastack)) {
912       pcb->acked = 0;
913       /* Clause 2 */
914       if (tcplen == 0) {
915         /* Clause 3 */
916         if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){
917           /* Clause 4 */
918           if (pcb->rtime >= 0) {
919             /* Clause 5 */
920             if (pcb->lastack == ackno) {
921               found_dupack = 1;
922               if (pcb->dupacks + 1 > pcb->dupacks)
923                 ++pcb->dupacks;
924               if (pcb->dupacks > 3) {
925                 /* Inflate the congestion window, but not if it means that
926                    the value overflows. */
927                 if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
928                   pcb->cwnd += pcb->mss;
929                 }
930               } else if (pcb->dupacks == 3) {
931                 /* Do fast retransmit */
932                 tcp_rexmit_fast(pcb);
933               }
934             }
935           }
936         }
937       }
938       /* If Clause (1) or more is true, but not a duplicate ack, reset
939        * count of consecutive duplicate acks */
940       if (!found_dupack) {
941         pcb->dupacks = 0;
942       }
943     } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){
944       /* We come here when the ACK acknowledges new data. */
945
946       /* Reset the "IN Fast Retransmit" flag, since we are no longer
947          in fast retransmit. Also reset the congestion window to the
948          slow start threshold. */
949       if (pcb->flags & TF_INFR) {
950         pcb->flags &= ~TF_INFR;
951         pcb->cwnd = pcb->ssthresh;
952       }
953
954       /* Reset the number of retransmissions. */
955       pcb->nrtx = 0;
956
957       /* Reset the retransmission time-out. */
958       pcb->rto = (pcb->sa >> 3) + pcb->sv;
959
960       /* Update the send buffer space. Diff between the two can never exceed 64K? */
961       pcb->acked = (u16_t)(ackno - pcb->lastack);
962
963       pcb->snd_buf += pcb->acked;
964
965       /* Reset the fast retransmit variables. */
966       pcb->dupacks = 0;
967       pcb->lastack = ackno;
968
969       /* Update the congestion control variables (cwnd and
970          ssthresh). */
971       if (pcb->state >= ESTABLISHED) {
972         if (pcb->cwnd < pcb->ssthresh) {
973           if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
974             pcb->cwnd += pcb->mss;
975           }
976           LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));
977         } else {
978           u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
979           if (new_cwnd > pcb->cwnd) {
980             pcb->cwnd = new_cwnd;
981           }
982           LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));
983         }
984       }
985       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",
986                                     ackno,
987                                     pcb->unacked != NULL?
988                                     ntohl(pcb->unacked->tcphdr->seqno): 0,
989                                     pcb->unacked != NULL?
990                                     ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
991
992       /* Remove segment from the unacknowledged list if the incoming
993          ACK acknowlegdes them. */
994       while (pcb->unacked != NULL &&
995              TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
996                          TCP_TCPLEN(pcb->unacked), ackno)) {
997         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",
998                                       ntohl(pcb->unacked->tcphdr->seqno),
999                                       ntohl(pcb->unacked->tcphdr->seqno) +
1000                                       TCP_TCPLEN(pcb->unacked)));
1001
1002         next = pcb->unacked;
1003         pcb->unacked = pcb->unacked->next;
1004
1005         LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
1006         LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
1007         /* Prevent ACK for FIN to generate a sent event */
1008         if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
1009           pcb->acked--;
1010         }
1011
1012         pcb->snd_queuelen -= pbuf_clen(next->p);
1013         tcp_seg_free(next);
1014
1015         LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen));
1016         if (pcb->snd_queuelen != 0) {
1017           LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
1018                       pcb->unsent != NULL);
1019         }
1020       }
1021
1022       /* If there's nothing left to acknowledge, stop the retransmit
1023          timer, otherwise reset it to start again */
1024       if(pcb->unacked == NULL)
1025         pcb->rtime = -1;
1026       else
1027         pcb->rtime = 0;
1028
1029       pcb->polltmr = 0;
1030
1031 #if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS
1032       if (PCB_ISIPV6(pcb)) {
1033         /* Inform neighbor reachability of forward progress. */
1034         nd6_reachability_hint(ip6_current_src_addr());
1035       }
1036 #endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/
1037     } else {
1038       /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */
1039       pcb->acked = 0;
1040     }
1041
1042     /* We go through the ->unsent list to see if any of the segments
1043        on the list are acknowledged by the ACK. This may seem
1044        strange since an "unsent" segment shouldn't be acked. The
1045        rationale is that lwIP puts all outstanding segments on the
1046        ->unsent list after a retransmission, so these segments may
1047        in fact have been sent once. */
1048     while (pcb->unsent != NULL &&
1049            TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + 
1050                            TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) {
1051       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",
1052                                     ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
1053                                     TCP_TCPLEN(pcb->unsent)));
1054
1055       next = pcb->unsent;
1056       pcb->unsent = pcb->unsent->next;
1057       LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
1058       LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
1059       /* Prevent ACK for FIN to generate a sent event */
1060       if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
1061         pcb->acked--;
1062       }
1063       pcb->snd_queuelen -= pbuf_clen(next->p);
1064       tcp_seg_free(next);
1065       LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));
1066       if (pcb->snd_queuelen != 0) {
1067         LWIP_ASSERT("tcp_receive: valid queue length",
1068           pcb->unacked != NULL || pcb->unsent != NULL);
1069       }
1070     }
1071     /* End of ACK for new data processing. */
1072
1073     LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n",
1074                                 pcb->rttest, pcb->rtseq, ackno));
1075
1076     /* RTT estimation calculations. This is done by checking if the
1077        incoming segment acknowledges the segment we use to take a
1078        round-trip time measurement. */
1079     if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {
1080       /* diff between this shouldn't exceed 32K since this are tcp timer ticks
1081          and a round-trip shouldn't be that long... */
1082       m = (s16_t)(tcp_ticks - pcb->rttest);
1083
1084       LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n",
1085                                   m, m * TCP_SLOW_INTERVAL));
1086
1087       /* This is taken directly from VJs original code in his paper */
1088       m = m - (pcb->sa >> 3);
1089       pcb->sa += m;
1090       if (m < 0) {
1091         m = -m;
1092       }
1093       m = m - (pcb->sv >> 2);
1094       pcb->sv += m;
1095       pcb->rto = (pcb->sa >> 3) + pcb->sv;
1096
1097       LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n",
1098                                   pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));
1099
1100       pcb->rttest = 0;
1101     }
1102   }
1103
1104   /* If the incoming segment contains data, we must process it
1105      further. */
1106   if (tcplen > 0) {
1107     /* This code basically does three things:
1108
1109     +) If the incoming segment contains data that is the next
1110     in-sequence data, this data is passed to the application. This
1111     might involve trimming the first edge of the data. The rcv_nxt
1112     variable and the advertised window are adjusted.
1113
1114     +) If the incoming segment has data that is above the next
1115     sequence number expected (->rcv_nxt), the segment is placed on
1116     the ->ooseq queue. This is done by finding the appropriate
1117     place in the ->ooseq queue (which is ordered by sequence
1118     number) and trim the segment in both ends if needed. An
1119     immediate ACK is sent to indicate that we received an
1120     out-of-sequence segment.
1121
1122     +) Finally, we check if the first segment on the ->ooseq queue
1123     now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
1124     rcv_nxt > ooseq->seqno, we must trim the first edge of the
1125     segment on ->ooseq before we adjust rcv_nxt. The data in the
1126     segments that are now on sequence are chained onto the
1127     incoming segment so that we only need to call the application
1128     once.
1129     */
1130
1131     /* First, we check if we must trim the first edge. We have to do
1132        this if the sequence number of the incoming segment is less
1133        than rcv_nxt, and the sequence number plus the length of the
1134        segment is larger than rcv_nxt. */
1135     /*    if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
1136           if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/
1137     if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){
1138       /* Trimming the first edge is done by pushing the payload
1139          pointer in the pbuf downwards. This is somewhat tricky since
1140          we do not want to discard the full contents of the pbuf up to
1141          the new starting point of the data since we have to keep the
1142          TCP header which is present in the first pbuf in the chain.
1143
1144          What is done is really quite a nasty hack: the first pbuf in
1145          the pbuf chain is pointed to by inseg.p. Since we need to be
1146          able to deallocate the whole pbuf, we cannot change this
1147          inseg.p pointer to point to any of the later pbufs in the
1148          chain. Instead, we point the ->payload pointer in the first
1149          pbuf to data in one of the later pbufs. We also set the
1150          inseg.data pointer to point to the right place. This way, the
1151          ->p pointer will still point to the first pbuf, but the
1152          ->p->payload pointer will point to data in another pbuf.
1153
1154          After we are done with adjusting the pbuf pointers we must
1155          adjust the ->data pointer in the seg and the segment
1156          length.*/
1157
1158       off = pcb->rcv_nxt - seqno;
1159       p = inseg.p;
1160       LWIP_ASSERT("inseg.p != NULL", inseg.p);
1161       LWIP_ASSERT("insane offset!", (off < 0x7fff));
1162       if (inseg.p->len < off) {
1163         LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off));
1164         new_tot_len = (u16_t)(inseg.p->tot_len - off);
1165         while (p->len < off) {
1166           off -= p->len;
1167           /* KJM following line changed (with addition of new_tot_len var)
1168              to fix bug #9076
1169              inseg.p->tot_len -= p->len; */
1170           p->tot_len = new_tot_len;
1171           p->len = 0;
1172           p = p->next;
1173         }
1174         if(pbuf_header(p, (s16_t)-off)) {
1175           /* Do we need to cope with this failing?  Assert for now */
1176           LWIP_ASSERT("pbuf_header failed", 0);
1177         }
1178       } else {
1179         if(pbuf_header(inseg.p, (s16_t)-off)) {
1180           /* Do we need to cope with this failing?  Assert for now */
1181           LWIP_ASSERT("pbuf_header failed", 0);
1182         }
1183       }
1184       inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);
1185       inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
1186     }
1187     else {
1188       if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
1189         /* the whole segment is < rcv_nxt */
1190         /* must be a duplicate of a packet that has already been correctly handled */
1191
1192         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));
1193         tcp_ack_now(pcb);
1194       }
1195     }
1196
1197     /* The sequence number must be within the window (above rcv_nxt
1198        and below rcv_nxt + rcv_wnd) in order to be further
1199        processed. */
1200     if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, 
1201                         pcb->rcv_nxt + pcb->rcv_wnd - 1)){
1202       if (pcb->rcv_nxt == seqno) {
1203         /* The incoming segment is the next in sequence. We check if
1204            we have to trim the end of the segment and update rcv_nxt
1205            and pass the data to the application. */
1206         tcplen = TCP_TCPLEN(&inseg);
1207
1208         if (tcplen > pcb->rcv_wnd) {
1209           LWIP_DEBUGF(TCP_INPUT_DEBUG, 
1210                       ("tcp_receive: other end overran receive window"
1211                        "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
1212                        seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
1213           if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
1214             /* Must remove the FIN from the header as we're trimming 
1215              * that byte of sequence-space from the packet */
1216             TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN);
1217           }
1218           /* Adjust length of segment to fit in the window. */
1219           inseg.len = pcb->rcv_wnd;
1220           if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
1221             inseg.len -= 1;
1222           }
1223           pbuf_realloc(inseg.p, inseg.len);
1224           tcplen = TCP_TCPLEN(&inseg);
1225           LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
1226                       (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
1227         }
1228 #if TCP_QUEUE_OOSEQ
1229         /* Received in-sequence data, adjust ooseq data if:
1230            - FIN has been received or
1231            - inseq overlaps with ooseq */
1232         if (pcb->ooseq != NULL) {
1233           if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
1234             LWIP_DEBUGF(TCP_INPUT_DEBUG, 
1235                         ("tcp_receive: received in-order FIN, binning ooseq queue\n"));
1236             /* Received in-order FIN means anything that was received
1237              * out of order must now have been received in-order, so
1238              * bin the ooseq queue */
1239             while (pcb->ooseq != NULL) {
1240               struct tcp_seg *old_ooseq = pcb->ooseq;
1241               pcb->ooseq = pcb->ooseq->next;
1242               tcp_seg_free(old_ooseq);
1243             }
1244           }
1245           else {
1246             next = pcb->ooseq;
1247             /* Remove all segments on ooseq that are covered by inseg already.
1248              * FIN is copied from ooseq to inseg if present. */
1249             while (next &&
1250                    TCP_SEQ_GEQ(seqno + tcplen,
1251                                next->tcphdr->seqno + next->len)) {
1252               /* inseg cannot have FIN here (already processed above) */
1253               if (TCPH_FLAGS(next->tcphdr) & TCP_FIN &&
1254                   (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) {
1255                 TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN);
1256                 tcplen = TCP_TCPLEN(&inseg);
1257               }
1258               prev = next;
1259               next = next->next;
1260               tcp_seg_free(prev);
1261             }
1262             /* Now trim right side of inseg if it overlaps with the first
1263              * segment on ooseq */
1264             if (next &&
1265                 TCP_SEQ_GT(seqno + tcplen,
1266                            next->tcphdr->seqno)) {
1267               /* inseg cannot have FIN here (already processed above) */
1268               inseg.len = (u16_t)(next->tcphdr->seqno - seqno);
1269               if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
1270                 inseg.len -= 1;
1271               }
1272               pbuf_realloc(inseg.p, inseg.len);
1273               tcplen = TCP_TCPLEN(&inseg);
1274               LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n",
1275                           (seqno + tcplen) == next->tcphdr->seqno);
1276             }
1277             pcb->ooseq = next;
1278           }
1279         }
1280 #endif /* TCP_QUEUE_OOSEQ */
1281
1282         pcb->rcv_nxt = seqno + tcplen;
1283
1284         /* Update the receiver's (our) window. */
1285         LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen);
1286         pcb->rcv_wnd -= tcplen;
1287
1288         tcp_update_rcv_ann_wnd(pcb);
1289
1290         /* If there is data in the segment, we make preparations to
1291            pass this up to the application. The ->recv_data variable
1292            is used for holding the pbuf that goes to the
1293            application. The code for reassembling out-of-sequence data
1294            chains its data on this pbuf as well.
1295
1296            If the segment was a FIN, we set the TF_GOT_FIN flag that will
1297            be used to indicate to the application that the remote side has
1298            closed its end of the connection. */
1299         if (inseg.p->tot_len > 0) {
1300           recv_data = inseg.p;
1301           /* Since this pbuf now is the responsibility of the
1302              application, we delete our reference to it so that we won't
1303              (mistakingly) deallocate it. */
1304           inseg.p = NULL;
1305         }
1306         if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
1307           LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
1308           recv_flags |= TF_GOT_FIN;
1309         }
1310
1311 #if TCP_QUEUE_OOSEQ
1312         /* We now check if we have segments on the ->ooseq queue that
1313            are now in sequence. */
1314         while (pcb->ooseq != NULL &&
1315                pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
1316
1317           cseg = pcb->ooseq;
1318           seqno = pcb->ooseq->tcphdr->seqno;
1319
1320           pcb->rcv_nxt += TCP_TCPLEN(cseg);
1321           LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n",
1322                       pcb->rcv_wnd >= TCP_TCPLEN(cseg));
1323           pcb->rcv_wnd -= TCP_TCPLEN(cseg);
1324
1325           tcp_update_rcv_ann_wnd(pcb);
1326
1327           if (cseg->p->tot_len > 0) {
1328             /* Chain this pbuf onto the pbuf that we will pass to
1329                the application. */
1330             if (recv_data) {
1331               pbuf_cat(recv_data, cseg->p);
1332             } else {
1333               recv_data = cseg->p;
1334             }
1335             cseg->p = NULL;
1336           }
1337           if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
1338             LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
1339             recv_flags |= TF_GOT_FIN;
1340             if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */
1341               pcb->state = CLOSE_WAIT;
1342             } 
1343           }
1344
1345           pcb->ooseq = cseg->next;
1346           tcp_seg_free(cseg);
1347         }
1348 #endif /* TCP_QUEUE_OOSEQ */
1349
1350
1351         /* Acknowledge the segment(s). */
1352         tcp_ack(pcb);
1353
1354 #if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS
1355         if (PCB_ISIPV6(pcb)) {
1356           /* Inform neighbor reachability of forward progress. */
1357           nd6_reachability_hint(ip6_current_src_addr());
1358         }
1359 #endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/
1360
1361       } else {
1362         /* We get here if the incoming segment is out-of-sequence. */
1363         tcp_send_empty_ack(pcb);
1364 #if TCP_QUEUE_OOSEQ
1365         /* We queue the segment on the ->ooseq queue. */
1366         if (pcb->ooseq == NULL) {
1367           pcb->ooseq = tcp_seg_copy(&inseg);
1368         } else {
1369           /* If the queue is not empty, we walk through the queue and
1370              try to find a place where the sequence number of the
1371              incoming segment is between the sequence numbers of the
1372              previous and the next segment on the ->ooseq queue. That is
1373              the place where we put the incoming segment. If needed, we
1374              trim the second edges of the previous and the incoming
1375              segment so that it will fit into the sequence.
1376
1377              If the incoming segment has the same sequence number as a
1378              segment on the ->ooseq queue, we discard the segment that
1379              contains less data. */
1380
1381           prev = NULL;
1382           for(next = pcb->ooseq; next != NULL; next = next->next) {
1383             if (seqno == next->tcphdr->seqno) {
1384               /* The sequence number of the incoming segment is the
1385                  same as the sequence number of the segment on
1386                  ->ooseq. We check the lengths to see which one to
1387                  discard. */
1388               if (inseg.len > next->len) {
1389                 /* The incoming segment is larger than the old
1390                    segment. We replace some segments with the new
1391                    one. */
1392                 cseg = tcp_seg_copy(&inseg);
1393                 if (cseg != NULL) {
1394                   if (prev != NULL) {
1395                     prev->next = cseg;
1396                   } else {
1397                     pcb->ooseq = cseg;
1398                   }
1399                   tcp_oos_insert_segment(cseg, next);
1400                 }
1401                 break;
1402               } else {
1403                 /* Either the lenghts are the same or the incoming
1404                    segment was smaller than the old one; in either
1405                    case, we ditch the incoming segment. */
1406                 break;
1407               }
1408             } else {
1409               if (prev == NULL) {
1410                 if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
1411                   /* The sequence number of the incoming segment is lower
1412                      than the sequence number of the first segment on the
1413                      queue. We put the incoming segment first on the
1414                      queue. */
1415                   cseg = tcp_seg_copy(&inseg);
1416                   if (cseg != NULL) {
1417                     pcb->ooseq = cseg;
1418                     tcp_oos_insert_segment(cseg, next);
1419                   }
1420                   break;
1421                 }
1422               } else {
1423                 /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
1424                   TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/
1425                 if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) {
1426                   /* The sequence number of the incoming segment is in
1427                      between the sequence numbers of the previous and
1428                      the next segment on ->ooseq. We trim trim the previous
1429                      segment, delete next segments that included in received segment
1430                      and trim received, if needed. */
1431                   cseg = tcp_seg_copy(&inseg);
1432                   if (cseg != NULL) {
1433                     if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
1434                       /* We need to trim the prev segment. */
1435                       prev->len = (u16_t)(seqno - prev->tcphdr->seqno);
1436                       pbuf_realloc(prev->p, prev->len);
1437                     }
1438                     prev->next = cseg;
1439                     tcp_oos_insert_segment(cseg, next);
1440                   }
1441                   break;
1442                 }
1443               }
1444               /* If the "next" segment is the last segment on the
1445                  ooseq queue, we add the incoming segment to the end
1446                  of the list. */
1447               if (next->next == NULL &&
1448                   TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
1449                 if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
1450                   /* segment "next" already contains all data */
1451                   break;
1452                 }
1453                 next->next = tcp_seg_copy(&inseg);
1454                 if (next->next != NULL) {
1455                   if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
1456                     /* We need to trim the last segment. */
1457                     next->len = (u16_t)(seqno - next->tcphdr->seqno);
1458                     pbuf_realloc(next->p, next->len);
1459                   }
1460                   /* check if the remote side overruns our receive window */
1461                   if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) {
1462                     LWIP_DEBUGF(TCP_INPUT_DEBUG, 
1463                                 ("tcp_receive: other end overran receive window"
1464                                  "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
1465                                  seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
1466                     if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) {
1467                       /* Must remove the FIN from the header as we're trimming 
1468                        * that byte of sequence-space from the packet */
1469                       TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN);
1470                     }
1471                     /* Adjust length of segment to fit in the window. */
1472                     next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno;
1473                     pbuf_realloc(next->next->p, next->next->len);
1474                     tcplen = TCP_TCPLEN(next->next);
1475                     LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
1476                                 (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
1477                   }
1478                 }
1479                 break;
1480               }
1481             }
1482             prev = next;
1483           }
1484         }
1485 #endif /* TCP_QUEUE_OOSEQ */
1486
1487       }
1488     } else {
1489       /* The incoming segment is not withing the window. */
1490       tcp_send_empty_ack(pcb);
1491     }
1492   } else {
1493     /* Segments with length 0 is taken care of here. Segments that
1494        fall out of the window are ACKed. */
1495     /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
1496       TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
1497     if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
1498       tcp_ack_now(pcb);
1499     }
1500   }
1501 }
1502
1503 /**
1504  * Parses the options contained in the incoming segment. 
1505  *
1506  * Called from tcp_listen_input() and tcp_process().
1507  * Currently, only the MSS option is supported!
1508  *
1509  * @param pcb the tcp_pcb for which a segment arrived
1510  */
1511 static void
1512 tcp_parseopt(struct tcp_pcb *pcb)
1513 {
1514   u16_t c, max_c;
1515   u16_t mss;
1516   u8_t *opts, opt;
1517 #if LWIP_TCP_TIMESTAMPS
1518   u32_t tsval;
1519 #endif
1520
1521   opts = (u8_t *)tcphdr + TCP_HLEN;
1522
1523   /* Parse the TCP MSS option, if present. */
1524   if(TCPH_HDRLEN(tcphdr) > 0x5) {
1525     max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2;
1526     for (c = 0; c < max_c; ) {
1527       opt = opts[c];
1528       switch (opt) {
1529       case 0x00:
1530         /* End of options. */
1531         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n"));
1532         return;
1533       case 0x01:
1534         /* NOP option. */
1535         ++c;
1536         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n"));
1537         break;
1538       case 0x02:
1539         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n"));
1540         if (opts[c + 1] != 0x04 || c + 0x04 > max_c) {
1541           /* Bad length */
1542           LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
1543           return;
1544         }
1545         /* An MSS option with the right option length. */
1546         mss = (opts[c + 2] << 8) | opts[c + 3];
1547         /* Limit the mss to the configured TCP_MSS and prevent division by zero */
1548         pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss;
1549         /* Advance to next option */
1550         c += 0x04;
1551         break;
1552 #if LWIP_TCP_TIMESTAMPS
1553       case 0x08:
1554         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n"));
1555         if (opts[c + 1] != 0x0A || c + 0x0A > max_c) {
1556           /* Bad length */
1557           LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
1558           return;
1559         }
1560         /* TCP timestamp option with valid length */
1561         tsval = (opts[c+2]) | (opts[c+3] << 8) | 
1562           (opts[c+4] << 16) | (opts[c+5] << 24);
1563         if (flags & TCP_SYN) {
1564           pcb->ts_recent = ntohl(tsval);
1565           pcb->flags |= TF_TIMESTAMP;
1566         } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) {
1567           pcb->ts_recent = ntohl(tsval);
1568         }
1569         /* Advance to next option */
1570         c += 0x0A;
1571         break;
1572 #endif
1573       default:
1574         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n"));
1575         if (opts[c + 1] == 0) {
1576           LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
1577           /* If the length field is zero, the options are malformed
1578              and we don't process them further. */
1579           return;
1580         }
1581         /* All other options have a length field, so that we easily
1582            can skip past them. */
1583         c += opts[c + 1];
1584       }
1585     }
1586   }
1587 }
1588
1589 #endif /* LWIP_TCP */