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