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
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(¤t_iphdr_dest, inp) ||
125 ip_addr_ismulticast(¤t_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), ¤t_iphdr_src) &&
177 ip_addr_cmp(&(pcb->local_ip), ¤t_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), ¤t_iphdr_src) &&
202 ip_addr_cmp(&(pcb->local_ip), ¤t_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), ¤t_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), ¤t_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 /* "In the SYN-SENT state (a RST received in response to an initial SYN),
588 the RST is acceptable if the ACK field acknowledges the SYN." */
589 if (ackno == pcb->snd_nxt) {
590 acceptable = 1;
591 }
592 } else {
593 /* "In all states except SYN-SENT, all reset (RST) segments are validated
594 by checking their SEQ-fields." */
595 if (seqno == pcb->rcv_nxt) {
596 acceptable = 1;
597 } else if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd)) {
598 /* If the sequence number is inside the window, we only send an ACK
599 and wait for a re-send with matching sequence number.
600 This violates RFC 793, but is required to protection against
601 CVE-2004-0230 (RST spoofing attack). */
602 tcp_ack_now(pcb);
603 }
604
605 if (acceptable) {
606 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
607 LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
608 recv_flags |= TF_RESET;
609 pcb->flags &= ~TF_ACK_DELAY;
610 return ERR_RST;
611 } else {
612 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
613 seqno, pcb->rcv_nxt));
614 LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
615 seqno, pcb->rcv_nxt));
616 return ERR_OK;
617 }
618 }
619
620 if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) {
621 /* Cope with new connection attempt after remote end crashed */
622 tcp_ack_now(pcb);
623 return ERR_OK;
624 }
625
626 if ((pcb->flags & TF_RXCLOSED) == 0) {
627 /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */
628 pcb->tmr = tcp_ticks;
629 }
630 pcb->keep_cnt_sent = 0;
631
632 tcp_parseopt(pcb);
633
634 /* Do different things depending on the TCP state. */
635 switch (pcb->state) {
636 case SYN_SENT:
637 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,
638 pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
639 /* received SYN ACK with expected sequence number? */
640 if ((flags & TCP_ACK) && (flags & TCP_SYN)
641 && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
642 pcb->snd_buf++;
643 pcb->rcv_nxt = seqno + 1;
644 pcb->rcv_ann_right_edge = pcb->rcv_nxt;
645 pcb->lastack = ackno;
646 pcb->snd_wnd = tcphdr->wnd;
647 pcb->snd_wnd_max = tcphdr->wnd;
648 pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
649 pcb->state = ESTABLISHED;
650
651 #if TCP_CALCULATE_EFF_SEND_MSS
652 pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
653 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
654
655 /* Set ssthresh again after changing pcb->mss (already set in tcp_connect
656 * but for the default value of pcb->mss) */
657 pcb->ssthresh = pcb->mss * 10;
658
659 pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
660 LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0));
661 --pcb->snd_queuelen;
662 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
663 rseg = pcb->unacked;
664 pcb->unacked = rseg->next;
665 tcp_seg_free(rseg);
666
667 /* If there's nothing left to acknowledge, stop the retransmit
668 timer, otherwise reset it to start again */
669 if(pcb->unacked == NULL)
670 pcb->rtime = -1;
671 else {
672 pcb->rtime = 0;
673 pcb->nrtx = 0;
674 }
675
676 /* Call the user specified function to call when sucessfully
677 * connected. */
678 TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
679 if (err == ERR_ABRT) {
680 return ERR_ABRT;
681 }
682 tcp_ack_now(pcb);
683 }
684 /* received ACK? possibly a half-open connection */
685 else if (flags & TCP_ACK) {
686 /* send a RST to bring the other side in a non-synchronized state. */
687 tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
688 tcphdr->dest, tcphdr->src);
689 }
690 break;
691 case SYN_RCVD:
692 if (flags & TCP_ACK) {
693 /* expected ACK number? */
694 if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
695 u16_t old_cwnd;
696 pcb->state = ESTABLISHED;
697 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
698 #if LWIP_CALLBACK_API
699 LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
700 #endif
701 /* Call the accept function. */
702 TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
703 if (err != ERR_OK) {
704 /* If the accept function returns with an error, we abort
705 * the connection. */
706 /* Already aborted? */
707 if (err != ERR_ABRT) {
708 tcp_abort(pcb);
709 }
710 return ERR_ABRT;
711 }
712 old_cwnd = pcb->cwnd;
713 /* If there was any data contained within this ACK,
714 * we'd better pass it on to the application as well. */
715 tcp_receive(pcb);
716
717 /* Prevent ACK for SYN to generate a sent event */
718 if (pcb->acked != 0) {
719 pcb->acked--;
720 }
721
722 pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
723
724 if (recv_flags & TF_GOT_FIN) {
725 tcp_ack_now(pcb);
726 pcb->state = CLOSE_WAIT;
727 }
728 } else {
729 /* incorrect ACK number, send RST */
730 tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
731 tcphdr->dest, tcphdr->src);
732 }
733 } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
734 /* Looks like another copy of the SYN - retransmit our SYN-ACK */
735 tcp_rexmit(pcb);
736 }
737 break;
738 case CLOSE_WAIT:
739 /* FALLTHROUGH */
740 case ESTABLISHED:
741 tcp_receive(pcb);
742 if (recv_flags & TF_GOT_FIN) { /* passive close */
743 tcp_ack_now(pcb);
744 pcb->state = CLOSE_WAIT;
745 }
746 break;
747 case FIN_WAIT_1:
748 tcp_receive(pcb);
749 if (recv_flags & TF_GOT_FIN) {
750 if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
751 LWIP_DEBUGF(TCP_DEBUG,
752 ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
753 tcp_ack_now(pcb);
754 tcp_pcb_purge(pcb);
755 TCP_RMV_ACTIVE(pcb);
756 pcb->state = TIME_WAIT;
757 TCP_REG(&tcp_tw_pcbs, pcb);
758 } else {
759 tcp_ack_now(pcb);
760 pcb->state = CLOSING;
761 }
762 } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
763 pcb->state = FIN_WAIT_2;
764 }
765 break;
766 case FIN_WAIT_2:
767 tcp_receive(pcb);
768 if (recv_flags & TF_GOT_FIN) {
769 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
770 tcp_ack_now(pcb);
771 tcp_pcb_purge(pcb);
772 TCP_RMV_ACTIVE(pcb);
773 pcb->state = TIME_WAIT;
774 TCP_REG(&tcp_tw_pcbs, pcb);
775 }
776 break;
777 case CLOSING:
778 tcp_receive(pcb);
779 if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
780 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
781 tcp_pcb_purge(pcb);
782 TCP_RMV_ACTIVE(pcb);
783 pcb->state = TIME_WAIT;
784 TCP_REG(&tcp_tw_pcbs, pcb);
785 }
786 break;
787 case LAST_ACK:
788 tcp_receive(pcb);
789 if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
790 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
791 /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
792 recv_flags |= TF_CLOSED;
793 }
794 break;
795 default:
796 break;
797 }
798 return ERR_OK;
799 }
800
801 #if TCP_QUEUE_OOSEQ
802 /**
803 * Insert segment into the list (segments covered with new one will be deleted)
804 *
805 * Called from tcp_receive()
806 */
807 static void
808 tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
809 {
810 struct tcp_seg *old_seg;
811
812 if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
813 /* received segment overlaps all following segments */
814 tcp_segs_free(next);
815 next = NULL;
816 }
817 else {
818 /* delete some following segments
819 oos queue may have segments with FIN flag */
820 while (next &&
821 TCP_SEQ_GEQ((seqno + cseg->len),
822 (next->tcphdr->seqno + next->len))) {
823 /* cseg with FIN already processed */
824 if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
825 TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN);
826 }
827 old_seg = next;
828 next = next->next;
829 tcp_seg_free(old_seg);
830 }
831 if (next &&
832 TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
833 /* We need to trim the incoming segment. */
834 cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
835 pbuf_realloc(cseg->p, cseg->len);
836 }
837 }
838 cseg->next = next;
839 }
840 #endif /* TCP_QUEUE_OOSEQ */
841
842 /**
843 * Called by tcp_process. Checks if the given segment is an ACK for outstanding
844 * data, and if so frees the memory of the buffered data. Next, is places the
845 * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment
846 * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until
847 * it has been removed from the buffer.
848 *
849 * If the incoming segment constitutes an ACK for a segment that was used for RTT
850 * estimation, the RTT is estimated here as well.
851 *
852 * Called from tcp_process().
853 */
854 static void
855 tcp_receive(struct tcp_pcb *pcb)
856 {
857 struct tcp_seg *next;
858 #if TCP_QUEUE_OOSEQ
859 struct tcp_seg *prev, *cseg;
860 #endif /* TCP_QUEUE_OOSEQ */
861 struct pbuf *p;
862 s32_t off;
863 s16_t m;
864 u32_t right_wnd_edge;
865 u16_t new_tot_len;
866 int found_dupack = 0;
867 #if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS
868 u32_t ooseq_blen;
869 u16_t ooseq_qlen;
870 #endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */
871
872 LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED);
873
874 if (flags & TCP_ACK) {
875 right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;
876
877 /* Update window. */
878 if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||
879 (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||
880 (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {
881 pcb->snd_wnd = tcphdr->wnd;
882 /* keep track of the biggest window announced by the remote host to calculate
883 the maximum segment size */
884 if (pcb->snd_wnd_max < tcphdr->wnd) {
885 pcb->snd_wnd_max = tcphdr->wnd;
886 }
887 pcb->snd_wl1 = seqno;
888 pcb->snd_wl2 = ackno;
889 if (pcb->snd_wnd == 0) {
890 if (pcb->persist_backoff == 0) {
891 /* start persist timer */
892 pcb->persist_cnt = 0;
893 pcb->persist_backoff = 1;
894 }
895 } else if (pcb->persist_backoff > 0) {
896 /* stop persist timer */
897 pcb->persist_backoff = 0;
898 }
899 LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd));
900 #if TCP_WND_DEBUG
901 } else {
902 if (pcb->snd_wnd != tcphdr->wnd) {
903 LWIP_DEBUGF(TCP_WND_DEBUG,
904 ("tcp_receive: no window update lastack %"U32_F" ackno %"
905 U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",
906 pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));
907 }
908 #endif /* TCP_WND_DEBUG */
909 }
910
911 /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a
912 * duplicate ack if:
913 * 1) It doesn't ACK new data
914 * 2) length of received packet is zero (i.e. no payload)
915 * 3) the advertised window hasn't changed
916 * 4) There is outstanding unacknowledged data (retransmission timer running)
917 * 5) The ACK is == biggest ACK sequence number so far seen (snd_una)
918 *
919 * If it passes all five, should process as a dupack:
920 * a) dupacks < 3: do nothing
921 * b) dupacks == 3: fast retransmit
922 * c) dupacks > 3: increase cwnd
923 *
924 * If it only passes 1-3, should reset dupack counter (and add to
925 * stats, which we don't do in lwIP)
926 *
927 * If it only passes 1, should reset dupack counter
928 *
929 */
930
931 /* Clause 1 */
932 if (TCP_SEQ_LEQ(ackno, pcb->lastack)) {
933 pcb->acked = 0;
934 /* Clause 2 */
935 if (tcplen == 0) {
936 /* Clause 3 */
937 if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){
938 /* Clause 4 */
939 if (pcb->rtime >= 0) {
940 /* Clause 5 */
941 if (pcb->lastack == ackno) {
942 found_dupack = 1;
943 if ((u8_t)(pcb->dupacks + 1) > pcb->dupacks) {
944 ++pcb->dupacks;
945 }
946 if (pcb->dupacks > 3) {
947 /* Inflate the congestion window, but not if it means that
948 the value overflows. */
949 if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
950 pcb->cwnd += pcb->mss;
951 }
952 } else if (pcb->dupacks == 3) {
953 /* Do fast retransmit */
954 tcp_rexmit_fast(pcb);
955 }
956 }
957 }
958 }
959 }
960 /* If Clause (1) or more is true, but not a duplicate ack, reset
961 * count of consecutive duplicate acks */
962 if (!found_dupack) {
963 pcb->dupacks = 0;
964 }
965 } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){
966 /* We come here when the ACK acknowledges new data. */
967
968 /* Reset the "IN Fast Retransmit" flag, since we are no longer
969 in fast retransmit. Also reset the congestion window to the
970 slow start threshold. */
971 if (pcb->flags & TF_INFR) {
972 pcb->flags &= ~TF_INFR;
973 pcb->cwnd = pcb->ssthresh;
974 }
975
976 /* Reset the number of retransmissions. */
977 pcb->nrtx = 0;
978
979 /* Reset the retransmission time-out. */
980 pcb->rto = (pcb->sa >> 3) + pcb->sv;
981
982 /* Update the send buffer space. Diff between the two can never exceed 64K? */
983 pcb->acked = (u16_t)(ackno - pcb->lastack);
984
985 pcb->snd_buf += pcb->acked;
986
987 /* Reset the fast retransmit variables. */
988 pcb->dupacks = 0;
989 pcb->lastack = ackno;
990
991 /* Update the congestion control variables (cwnd and
992 ssthresh). */
993 if (pcb->state >= ESTABLISHED) {
994 if (pcb->cwnd < pcb->ssthresh) {
995 if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
996 pcb->cwnd += pcb->mss;
997 }
998 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));
999 } else {
1000 u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
1001 if (new_cwnd > pcb->cwnd) {
1002 pcb->cwnd = new_cwnd;
1003 }
1004 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));
1005 }
1006 }
1007 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",
1008 ackno,
1009 pcb->unacked != NULL?
1010 ntohl(pcb->unacked->tcphdr->seqno): 0,
1011 pcb->unacked != NULL?
1012 ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
1013
1014 /* Remove segment from the unacknowledged list if the incoming
1015 ACK acknowlegdes them. */
1016 while (pcb->unacked != NULL &&
1017 TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
1018 TCP_TCPLEN(pcb->unacked), ackno)) {
1019 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",
1020 ntohl(pcb->unacked->tcphdr->seqno),
1021 ntohl(pcb->unacked->tcphdr->seqno) +
1022 TCP_TCPLEN(pcb->unacked)));
1023
1024 next = pcb->unacked;
1025 pcb->unacked = pcb->unacked->next;
1026
1027 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
1028 LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
1029 /* Prevent ACK for FIN to generate a sent event */
1030 if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
1031 pcb->acked--;
1032 }
1033
1034 pcb->snd_queuelen -= pbuf_clen(next->p);
1035 tcp_seg_free(next);
1036
1037 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen));
1038 if (pcb->snd_queuelen != 0) {
1039 LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
1040 pcb->unsent != NULL);
1041 }
1042 }
1043
1044 /* If there's nothing left to acknowledge, stop the retransmit
1045 timer, otherwise reset it to start again */
1046 if(pcb->unacked == NULL)
1047 pcb->rtime = -1;
1048 else
1049 pcb->rtime = 0;
1050
1051 pcb->polltmr = 0;
1052 } else {
1053 /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */
1054 pcb->acked = 0;
1055 }
1056
1057 /* We go through the ->unsent list to see if any of the segments
1058 on the list are acknowledged by the ACK. This may seem
1059 strange since an "unsent" segment shouldn't be acked. The
1060 rationale is that lwIP puts all outstanding segments on the
1061 ->unsent list after a retransmission, so these segments may
1062 in fact have been sent once. */
1063 while (pcb->unsent != NULL &&
1064 TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) +
1065 TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) {
1066 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",
1067 ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
1068 TCP_TCPLEN(pcb->unsent)));
1069
1070 next = pcb->unsent;
1071 pcb->unsent = pcb->unsent->next;
1072 #if TCP_OVERSIZE
1073 if (pcb->unsent == NULL) {
1074 pcb->unsent_oversize = 0;
1075 }
1076 #endif /* TCP_OVERSIZE */
1077 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
1078 LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
1079 /* Prevent ACK for FIN to generate a sent event */
1080 if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
1081 pcb->acked--;
1082 }
1083 pcb->snd_queuelen -= pbuf_clen(next->p);
1084 tcp_seg_free(next);
1085 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));
1086 if (pcb->snd_queuelen != 0) {
1087 LWIP_ASSERT("tcp_receive: valid queue length",
1088 pcb->unacked != NULL || pcb->unsent != NULL);
1089 }
1090 }
1091 /* End of ACK for new data processing. */
1092
1093 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n",
1094 pcb->rttest, pcb->rtseq, ackno));
1095
1096 /* RTT estimation calculations. This is done by checking if the
1097 incoming segment acknowledges the segment we use to take a
1098 round-trip time measurement. */
1099 if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {
1100 /* diff between this shouldn't exceed 32K since this are tcp timer ticks
1101 and a round-trip shouldn't be that long... */
1102 m = (s16_t)(tcp_ticks - pcb->rttest);
1103
1104 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n",
1105 m, m * TCP_SLOW_INTERVAL));
1106
1107 /* This is taken directly from VJs original code in his paper */
1108 m = m - (pcb->sa >> 3);
1109 pcb->sa += m;
1110 if (m < 0) {
1111 m = -m;
1112 }
1113 m = m - (pcb->sv >> 2);
1114 pcb->sv += m;
1115 pcb->rto = (pcb->sa >> 3) + pcb->sv;
1116
1117 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n",
1118 pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));
1119
1120 pcb->rttest = 0;
1121 }
1122 }
1123
1124 /* If the incoming segment contains data, we must process it
1125 further unless the pcb already received a FIN.
1126 (RFC 793, chapeter 3.9, "SEGMENT ARRIVES" in states CLOSE-WAIT, CLOSING,
1127 LAST-ACK and TIME-WAIT: "Ignore the segment text.") */
1128 if ((tcplen > 0) && (pcb->state < CLOSE_WAIT)) {
1129 /* This code basically does three things:
1130
1131 +) If the incoming segment contains data that is the next
1132 in-sequence data, this data is passed to the application. This
1133 might involve trimming the first edge of the data. The rcv_nxt
1134 variable and the advertised window are adjusted.
1135
1136 +) If the incoming segment has data that is above the next
1137 sequence number expected (->rcv_nxt), the segment is placed on
1138 the ->ooseq queue. This is done by finding the appropriate
1139 place in the ->ooseq queue (which is ordered by sequence
1140 number) and trim the segment in both ends if needed. An
1141 immediate ACK is sent to indicate that we received an
1142 out-of-sequence segment.
1143
1144 +) Finally, we check if the first segment on the ->ooseq queue
1145 now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
1146 rcv_nxt > ooseq->seqno, we must trim the first edge of the
1147 segment on ->ooseq before we adjust rcv_nxt. The data in the
1148 segments that are now on sequence are chained onto the
1149 incoming segment so that we only need to call the application
1150 once.
1151 */
1152
1153 /* First, we check if we must trim the first edge. We have to do
1154 this if the sequence number of the incoming segment is less
1155 than rcv_nxt, and the sequence number plus the length of the
1156 segment is larger than rcv_nxt. */
1157 /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
1158 if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/
1159 if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){
1160 /* Trimming the first edge is done by pushing the payload
1161 pointer in the pbuf downwards. This is somewhat tricky since
1162 we do not want to discard the full contents of the pbuf up to
1163 the new starting point of the data since we have to keep the
1164 TCP header which is present in the first pbuf in the chain.
1165
1166 What is done is really quite a nasty hack: the first pbuf in
1167 the pbuf chain is pointed to by inseg.p. Since we need to be
1168 able to deallocate the whole pbuf, we cannot change this
1169 inseg.p pointer to point to any of the later pbufs in the
1170 chain. Instead, we point the ->payload pointer in the first
1171 pbuf to data in one of the later pbufs. We also set the
1172 inseg.data pointer to point to the right place. This way, the
1173 ->p pointer will still point to the first pbuf, but the
1174 ->p->payload pointer will point to data in another pbuf.
1175
1176 After we are done with adjusting the pbuf pointers we must
1177 adjust the ->data pointer in the seg and the segment
1178 length.*/
1179
1180 off = pcb->rcv_nxt - seqno;
1181 p = inseg.p;
1182 LWIP_ASSERT("inseg.p != NULL", inseg.p);
1183 LWIP_ASSERT("insane offset!", (off < 0x7fff));
1184 if (inseg.p->len < off) {
1185 LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off));
1186 new_tot_len = (u16_t)(inseg.p->tot_len - off);
1187 while (p->len < off) {
1188 off -= p->len;
1189 /* KJM following line changed (with addition of new_tot_len var)
1190 to fix bug #9076
1191 inseg.p->tot_len -= p->len; */
1192 p->tot_len = new_tot_len;
1193 p->len = 0;
1194 p = p->next;
1195 }
1196 if(pbuf_header(p, (s16_t)-off)) {
1197 /* Do we need to cope with this failing? Assert for now */
1198 LWIP_ASSERT("pbuf_header failed", 0);
1199 }
1200 } else {
1201 if(pbuf_header(inseg.p, (s16_t)-off)) {
1202 /* Do we need to cope with this failing? Assert for now */
1203 LWIP_ASSERT("pbuf_header failed", 0);
1204 }
1205 }
1206 inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);
1207 inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
1208 }
1209 else {
1210 if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
1211 /* the whole segment is < rcv_nxt */
1212 /* must be a duplicate of a packet that has already been correctly handled */
1213
1214 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));
1215 tcp_ack_now(pcb);
1216 }
1217 }
1218
1219 /* The sequence number must be within the window (above rcv_nxt
1220 and below rcv_nxt + rcv_wnd) in order to be further
1221 processed. */
1222 if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
1223 pcb->rcv_nxt + pcb->rcv_wnd - 1)){
1224 if (pcb->rcv_nxt == seqno) {
1225 /* The incoming segment is the next in sequence. We check if
1226 we have to trim the end of the segment and update rcv_nxt
1227 and pass the data to the application. */
1228 tcplen = TCP_TCPLEN(&inseg);
1229
1230 if (tcplen > pcb->rcv_wnd) {
1231 LWIP_DEBUGF(TCP_INPUT_DEBUG,
1232 ("tcp_receive: other end overran receive window"
1233 "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
1234 seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
1235 if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
1236 /* Must remove the FIN from the header as we're trimming
1237 * that byte of sequence-space from the packet */
1238 TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN);
1239 }
1240 /* Adjust length of segment to fit in the window. */
1241 inseg.len = pcb->rcv_wnd;
1242 if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
1243 inseg.len -= 1;
1244 }
1245 pbuf_realloc(inseg.p, inseg.len);
1246 tcplen = TCP_TCPLEN(&inseg);
1247 LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
1248 (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
1249 }
1250 #if TCP_QUEUE_OOSEQ
1251 /* Received in-sequence data, adjust ooseq data if:
1252 - FIN has been received or
1253 - inseq overlaps with ooseq */
1254 if (pcb->ooseq != NULL) {
1255 if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
1256 LWIP_DEBUGF(TCP_INPUT_DEBUG,
1257 ("tcp_receive: received in-order FIN, binning ooseq queue\n"));
1258 /* Received in-order FIN means anything that was received
1259 * out of order must now have been received in-order, so
1260 * bin the ooseq queue */
1261 while (pcb->ooseq != NULL) {
1262 struct tcp_seg *old_ooseq = pcb->ooseq;
1263 pcb->ooseq = pcb->ooseq->next;
1264 tcp_seg_free(old_ooseq);
1265 }
1266 } else {
1267 next = pcb->ooseq;
1268 /* Remove all segments on ooseq that are covered by inseg already.
1269 * FIN is copied from ooseq to inseg if present. */
1270 while (next &&
1271 TCP_SEQ_GEQ(seqno + tcplen,
1272 next->tcphdr->seqno + next->len)) {
1273 /* inseg cannot have FIN here (already processed above) */
1274 if (TCPH_FLAGS(next->tcphdr) & TCP_FIN &&
1275 (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) {
1276 TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN);
1277 tcplen = TCP_TCPLEN(&inseg);
1278 }
1279 prev = next;
1280 next = next->next;
1281 tcp_seg_free(prev);
1282 }
1283 /* Now trim right side of inseg if it overlaps with the first
1284 * segment on ooseq */
1285 if (next &&
1286 TCP_SEQ_GT(seqno + tcplen,
1287 next->tcphdr->seqno)) {
1288 /* inseg cannot have FIN here (already processed above) */
1289 inseg.len = (u16_t)(next->tcphdr->seqno - seqno);
1290 if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
1291 inseg.len -= 1;
1292 }
1293 pbuf_realloc(inseg.p, inseg.len);
1294 tcplen = TCP_TCPLEN(&inseg);
1295 LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n",
1296 (seqno + tcplen) == next->tcphdr->seqno);
1297 }
1298 pcb->ooseq = next;
1299 }
1300 }
1301 #endif /* TCP_QUEUE_OOSEQ */
1302
1303 pcb->rcv_nxt = seqno + tcplen;
1304
1305 /* Update the receiver's (our) window. */
1306 LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen);
1307 pcb->rcv_wnd -= tcplen;
1308
1309 tcp_update_rcv_ann_wnd(pcb);
1310
1311 /* If there is data in the segment, we make preparations to
1312 pass this up to the application. The ->recv_data variable
1313 is used for holding the pbuf that goes to the
1314 application. The code for reassembling out-of-sequence data
1315 chains its data on this pbuf as well.
1316
1317 If the segment was a FIN, we set the TF_GOT_FIN flag that will
1318 be used to indicate to the application that the remote side has
1319 closed its end of the connection. */
1320 if (inseg.p->tot_len > 0) {
1321 recv_data = inseg.p;
1322 /* Since this pbuf now is the responsibility of the
1323 application, we delete our reference to it so that we won't
1324 (mistakingly) deallocate it. */
1325 inseg.p = NULL;
1326 }
1327 if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
1328 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
1329 recv_flags |= TF_GOT_FIN;
1330 }
1331
1332 #if TCP_QUEUE_OOSEQ
1333 /* We now check if we have segments on the ->ooseq queue that
1334 are now in sequence. */
1335 while (pcb->ooseq != NULL &&
1336 pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
1337
1338 cseg = pcb->ooseq;
1339 seqno = pcb->ooseq->tcphdr->seqno;
1340
1341 pcb->rcv_nxt += TCP_TCPLEN(cseg);
1342 LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n",
1343 pcb->rcv_wnd >= TCP_TCPLEN(cseg));
1344 pcb->rcv_wnd -= TCP_TCPLEN(cseg);
1345
1346 tcp_update_rcv_ann_wnd(pcb);
1347
1348 if (cseg->p->tot_len > 0) {
1349 /* Chain this pbuf onto the pbuf that we will pass to
1350 the application. */
1351 if (recv_data) {
1352 pbuf_cat(recv_data, cseg->p);
1353 } else {
1354 recv_data = cseg->p;
1355 }
1356 cseg->p = NULL;
1357 }
1358 if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
1359 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
1360 recv_flags |= TF_GOT_FIN;
1361 if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */
1362 pcb->state = CLOSE_WAIT;
1363 }
1364 }
1365
1366 pcb->ooseq = cseg->next;
1367 tcp_seg_free(cseg);
1368 }
1369 #endif /* TCP_QUEUE_OOSEQ */
1370
1371
1372 /* Acknowledge the segment(s). */
1373 tcp_ack(pcb);
1374
1375 } else {
1376 /* We get here if the incoming segment is out-of-sequence. */
1377 tcp_send_empty_ack(pcb);
1378 #if TCP_QUEUE_OOSEQ
1379 /* We queue the segment on the ->ooseq queue. */
1380 if (pcb->ooseq == NULL) {
1381 pcb->ooseq = tcp_seg_copy(&inseg);
1382 } else {
1383 /* If the queue is not empty, we walk through the queue and
1384 try to find a place where the sequence number of the
1385 incoming segment is between the sequence numbers of the
1386 previous and the next segment on the ->ooseq queue. That is
1387 the place where we put the incoming segment. If needed, we
1388 trim the second edges of the previous and the incoming
1389 segment so that it will fit into the sequence.
1390
1391 If the incoming segment has the same sequence number as a
1392 segment on the ->ooseq queue, we discard the segment that
1393 contains less data. */
1394
1395 prev = NULL;
1396 for(next = pcb->ooseq; next != NULL; next = next->next) {
1397 if (seqno == next->tcphdr->seqno) {
1398 /* The sequence number of the incoming segment is the
1399 same as the sequence number of the segment on
1400 ->ooseq. We check the lengths to see which one to
1401 discard. */
1402 if (inseg.len > next->len) {
1403 /* The incoming segment is larger than the old
1404 segment. We replace some segments with the new
1405 one. */
1406 cseg = tcp_seg_copy(&inseg);
1407 if (cseg != NULL) {
1408 if (prev != NULL) {
1409 prev->next = cseg;
1410 } else {
1411 pcb->ooseq = cseg;
1412 }
1413 tcp_oos_insert_segment(cseg, next);
1414 }
1415 break;
1416 } else {
1417 /* Either the lenghts are the same or the incoming
1418 segment was smaller than the old one; in either
1419 case, we ditch the incoming segment. */
1420 break;
1421 }
1422 } else {
1423 if (prev == NULL) {
1424 if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
1425 /* The sequence number of the incoming segment is lower
1426 than the sequence number of the first segment on the
1427 queue. We put the incoming segment first on the
1428 queue. */
1429 cseg = tcp_seg_copy(&inseg);
1430 if (cseg != NULL) {
1431 pcb->ooseq = cseg;
1432 tcp_oos_insert_segment(cseg, next);
1433 }
1434 break;
1435 }
1436 } else {
1437 /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
1438 TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/
1439 if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) {
1440 /* The sequence number of the incoming segment is in
1441 between the sequence numbers of the previous and
1442 the next segment on ->ooseq. We trim trim the previous
1443 segment, delete next segments that included in received segment
1444 and trim received, if needed. */
1445 cseg = tcp_seg_copy(&inseg);
1446 if (cseg != NULL) {
1447 if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
1448 /* We need to trim the prev segment. */
1449 prev->len = (u16_t)(seqno - prev->tcphdr->seqno);
1450 pbuf_realloc(prev->p, prev->len);
1451 }
1452 prev->next = cseg;
1453 tcp_oos_insert_segment(cseg, next);
1454 }
1455 break;
1456 }
1457 }
1458 /* If the "next" segment is the last segment on the
1459 ooseq queue, we add the incoming segment to the end
1460 of the list. */
1461 if (next->next == NULL &&
1462 TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
1463 if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
1464 /* segment "next" already contains all data */
1465 break;
1466 }
1467 next->next = tcp_seg_copy(&inseg);
1468 if (next->next != NULL) {
1469 if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
1470 /* We need to trim the last segment. */
1471 next->len = (u16_t)(seqno - next->tcphdr->seqno);
1472 pbuf_realloc(next->p, next->len);
1473 }
1474 /* check if the remote side overruns our receive window */
1475 if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) {
1476 LWIP_DEBUGF(TCP_INPUT_DEBUG,
1477 ("tcp_receive: other end overran receive window"
1478 "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
1479 seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
1480 if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) {
1481 /* Must remove the FIN from the header as we're trimming
1482 * that byte of sequence-space from the packet */
1483 TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN);
1484 }
1485 /* Adjust length of segment to fit in the window. */
1486 next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno;
1487 pbuf_realloc(next->next->p, next->next->len);
1488 tcplen = TCP_TCPLEN(next->next);
1489 LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
1490 (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
1491 }
1492 }
1493 break;
1494 }
1495 }
1496 prev = next;
1497 }
1498 }
1499 #if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS
1500 /* Check that the data on ooseq doesn't exceed one of the limits
1501 and throw away everything above that limit. */
1502 ooseq_blen = 0;
1503 ooseq_qlen = 0;
1504 prev = NULL;
1505 for(next = pcb->ooseq; next != NULL; prev = next, next = next->next) {
1506 struct pbuf *p = next->p;
1507 ooseq_blen += p->tot_len;
1508 ooseq_qlen += pbuf_clen(p);
1509 if ((ooseq_blen > TCP_OOSEQ_MAX_BYTES) ||
1510 (ooseq_qlen > TCP_OOSEQ_MAX_PBUFS)) {
1511 /* too much ooseq data, dump this and everything after it */
1512 tcp_segs_free(next);
1513 if (prev == NULL) {
1514 /* first ooseq segment is too much, dump the whole queue */
1515 pcb->ooseq = NULL;
1516 } else {
1517 /* just dump 'next' and everything after it */
1518 prev->next = NULL;
1519 }
1520 break;
1521 }
1522 }
1523 #endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */
1524 #endif /* TCP_QUEUE_OOSEQ */
1525 }
1526 } else {
1527 /* The incoming segment is not withing the window. */
1528 tcp_send_empty_ack(pcb);
1529 }
1530 } else {
1531 /* Segments with length 0 is taken care of here. Segments that
1532 fall out of the window are ACKed. */
1533 /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
1534 TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
1535 if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
1536 tcp_ack_now(pcb);
1537 }
1538 }
1539 }
1540
1541 /**
1542 * Parses the options contained in the incoming segment.
1543 *
1544 * Called from tcp_listen_input() and tcp_process().
1545 * Currently, only the MSS option is supported!
1546 *
1547 * @param pcb the tcp_pcb for which a segment arrived
1548 */
1549 static void
1550 tcp_parseopt(struct tcp_pcb *pcb)
1551 {
1552 u16_t c, max_c;
1553 u16_t mss;
1554 u8_t *opts, opt;
1555 #if LWIP_TCP_TIMESTAMPS
1556 u32_t tsval;
1557 #endif
1558
1559 opts = (u8_t *)tcphdr + TCP_HLEN;
1560
1561 /* Parse the TCP MSS option, if present. */
1562 if(TCPH_HDRLEN(tcphdr) > 0x5) {
1563 max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2;
1564 for (c = 0; c < max_c; ) {
1565 opt = opts[c];
1566 switch (opt) {
1567 case 0x00:
1568 /* End of options. */
1569 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n"));
1570 return;
1571 case 0x01:
1572 /* NOP option. */
1573 ++c;
1574 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n"));
1575 break;
1576 case 0x02:
1577 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n"));
1578 if (opts[c + 1] != 0x04 || c + 0x04 > max_c) {
1579 /* Bad length */
1580 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
1581 return;
1582 }
1583 /* An MSS option with the right option length. */
1584 mss = (opts[c + 2] << 8) | opts[c + 3];
1585 /* Limit the mss to the configured TCP_MSS and prevent division by zero */
1586 pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss;
1587 /* Advance to next option */
1588 c += 0x04;
1589 break;
1590 #if LWIP_TCP_TIMESTAMPS
1591 case 0x08:
1592 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n"));
1593 if (opts[c + 1] != 0x0A || c + 0x0A > max_c) {
1594 /* Bad length */
1595 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
1596 return;
1597 }
1598 /* TCP timestamp option with valid length */
1599 tsval = (opts[c+2]) | (opts[c+3] << 8) |
1600 (opts[c+4] << 16) | (opts[c+5] << 24);
1601 if (flags & TCP_SYN) {
1602 pcb->ts_recent = ntohl(tsval);
1603 pcb->flags |= TF_TIMESTAMP;
1604 } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) {
1605 pcb->ts_recent = ntohl(tsval);
1606 }
1607 /* Advance to next option */
1608 c += 0x0A;
1609 break;
1610 #endif
1611 default:
1612 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n"));
1613 if (opts[c + 1] == 0) {
1614 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
1615 /* If the length field is zero, the options are malformed
1616 and we don't process them further. */
1617 return;
1618 }
1619 /* All other options have a length field, so that we easily
1620 can skip past them. */
1621 c += opts[c + 1];
1622 }
1623 }
1624 }
1625 }
1626
1627 #endif /* LWIP_TCP */
1628