source: UsbWattMeter/trunk/lwip-1.4.1/src/core/tcp_in.c@ 164

Last change on this file since 164 was 164, checked in by coas-nagasima, 6 years ago

TOPPERS/ECNLサンプルアプリ「USB充電器電力計」を追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 58.8 KB
Line 
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. */
62static struct tcp_seg inseg;
63static struct tcp_hdr *tcphdr;
64static struct ip_hdr *iphdr;
65static u32_t seqno, ackno;
66static u8_t flags;
67static u16_t tcplen;
68
69static u8_t recv_flags;
70static struct pbuf *recv_data;
71
72struct tcp_pcb *tcp_input_pcb;
73
74/* Forward declarations. */
75static err_t tcp_process(struct tcp_pcb *pcb);
76static void tcp_receive(struct tcp_pcb *pcb);
77static void tcp_parseopt(struct tcp_pcb *pcb);
78
79static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);
80static 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 */
91void
92tcp_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! */
393aborted:
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;
421dropped:
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 */
439static err_t
440tcp_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 */
528static err_t
529tcp_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 */
574static err_t
575tcp_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 */
799static void
800tcp_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 */
846static void
847tcp_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 */
1541static void
1542tcp_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 */
Note: See TracBrowser for help on using the repository browser.