4 * Transmission Control Protocol, incoming traffic
\r
6 * The input processing functions of the TCP layer.
\r
8 * These functions are generally called in the order (ip_input() ->)
\r
9 * tcp_input() -> * tcp_process() -> tcp_receive() (-> application).
\r
14 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
\r
15 * All rights reserved.
\r
17 * Redistribution and use in source and binary forms, with or without modification,
\r
18 * are permitted provided that the following conditions are met:
\r
20 * 1. Redistributions of source code must retain the above copyright notice,
\r
21 * this list of conditions and the following disclaimer.
\r
22 * 2. Redistributions in binary form must reproduce the above copyright notice,
\r
23 * this list of conditions and the following disclaimer in the documentation
\r
24 * and/or other materials provided with the distribution.
\r
25 * 3. The name of the author may not be used to endorse or promote products
\r
26 * derived from this software without specific prior written permission.
\r
28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
\r
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
30 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
\r
31 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
\r
32 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
\r
33 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
\r
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
\r
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
\r
36 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
\r
39 * This file is part of the lwIP TCP/IP stack.
\r
41 * Author: Adam Dunkels <adam@sics.se>
\r
45 #include "lwip/def.h"
\r
46 #include "lwip/opt.h"
\r
48 #include "lwip/ip_addr.h"
\r
49 #include "lwip/netif.h"
\r
50 #include "lwip/mem.h"
\r
51 #include "lwip/memp.h"
\r
53 #include "lwip/inet.h"
\r
54 #include "lwip/tcp.h"
\r
56 #include "lwip/stats.h"
\r
57 #include "arch/perf.h"
\r
58 #include "lwip/snmp.h"
\r
61 /* These variables are global to all functions involved in the input
\r
62 processing of TCP segments. They are set by the tcp_input()
\r
64 static struct tcp_seg inseg;
\r
65 static struct tcp_hdr *tcphdr;
\r
66 static struct ip_hdr *iphdr;
\r
67 static u32_t seqno, ackno;
\r
69 static u16_t tcplen;
\r
71 static u8_t recv_flags;
\r
72 static struct pbuf *recv_data;
\r
74 struct tcp_pcb *tcp_input_pcb;
\r
76 /* Forward declarations. */
\r
77 static err_t tcp_process(struct tcp_pcb *pcb);
\r
78 static u8_t tcp_receive(struct tcp_pcb *pcb);
\r
79 static void tcp_parseopt(struct tcp_pcb *pcb);
\r
81 static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);
\r
82 static err_t tcp_timewait_input(struct tcp_pcb *pcb);
\r
86 * The initial input processing of TCP. It verifies the TCP header, demultiplexes
\r
87 * the segment between the PCBs and passes it on to tcp_process(), which implements
\r
88 * the TCP finite state machine. This function is called by the IP layer (in
\r
93 tcp_input(struct pbuf *p, struct netif *inp)
\r
95 struct tcp_pcb *pcb, *prev;
\r
96 struct tcp_pcb_listen *lpcb;
\r
102 TCP_STATS_INC(tcp.recv);
\r
103 snmp_inc_tcpinsegs();
\r
105 iphdr = p->payload;
\r
106 tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
\r
108 #if TCP_INPUT_DEBUG
\r
109 tcp_debug_print(tcphdr);
\r
112 /* remove header from payload */
\r
113 if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {
\r
114 /* drop short packets */
\r
115 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));
\r
116 TCP_STATS_INC(tcp.lenerr);
\r
117 TCP_STATS_INC(tcp.drop);
\r
122 /* Don't even process incoming broadcasts/multicasts. */
\r
123 if (ip_addr_isbroadcast(&(iphdr->dest), inp) ||
\r
124 ip_addr_ismulticast(&(iphdr->dest))) {
\r
125 snmp_inc_tcpinerrs();
\r
130 #if CHECKSUM_CHECK_TCP
\r
131 /* Verify TCP checksum. */
\r
132 if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
\r
133 (struct ip_addr *)&(iphdr->dest),
\r
134 IP_PROTO_TCP, p->tot_len) != 0) {
\r
135 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",
\r
136 inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), (struct ip_addr *)&(iphdr->dest),
\r
137 IP_PROTO_TCP, p->tot_len)));
\r
139 tcp_debug_print(tcphdr);
\r
140 #endif /* TCP_DEBUG */
\r
141 TCP_STATS_INC(tcp.chkerr);
\r
142 TCP_STATS_INC(tcp.drop);
\r
143 snmp_inc_tcpinerrs();
\r
149 /* Move the payload pointer in the pbuf so that it points to the
\r
150 TCP data instead of the TCP header. */
\r
151 hdrlen = TCPH_HDRLEN(tcphdr);
\r
152 pbuf_header(p, -(hdrlen * 4));
\r
154 /* Convert fields in TCP header to host byte order. */
\r
155 tcphdr->src = ntohs(tcphdr->src);
\r
156 tcphdr->dest = ntohs(tcphdr->dest);
\r
157 seqno = tcphdr->seqno = ntohl(tcphdr->seqno);
\r
158 ackno = tcphdr->ackno = ntohl(tcphdr->ackno);
\r
159 tcphdr->wnd = ntohs(tcphdr->wnd);
\r
161 flags = TCPH_FLAGS(tcphdr) & TCP_FLAGS;
\r
162 tcplen = p->tot_len + ((flags & TCP_FIN || flags & TCP_SYN)? 1: 0);
\r
164 /* Demultiplex an incoming segment. First, we check if it is destined
\r
165 for an active connection. */
\r
169 for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
\r
170 LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);
\r
171 LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
\r
172 LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
\r
173 if (pcb->remote_port == tcphdr->src &&
\r
174 pcb->local_port == tcphdr->dest &&
\r
175 ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&
\r
176 ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {
\r
178 /* Move this PCB to the front of the list so that subsequent
\r
179 lookups will be faster (we exploit locality in TCP segment
\r
181 LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);
\r
182 if (prev != NULL) {
\r
183 prev->next = pcb->next;
\r
184 pcb->next = tcp_active_pcbs;
\r
185 tcp_active_pcbs = pcb;
\r
187 LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);
\r
194 /* If it did not go to an active connection, we check the connections
\r
195 in the TIME-WAIT state. */
\r
196 for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
\r
197 LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
\r
198 if (pcb->remote_port == tcphdr->src &&
\r
199 pcb->local_port == tcphdr->dest &&
\r
200 ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&
\r
201 ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {
\r
202 /* We don't really care enough to move this PCB to the front
\r
203 of the list since we are not very likely to receive that
\r
204 many segments for connections in TIME-WAIT. */
\r
205 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n"));
\r
206 tcp_timewait_input(pcb);
\r
212 /* Finally, if we still did not get a match, we check all PCBs that
\r
213 are LISTENing for incoming connections. */
\r
215 for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
\r
216 if ((ip_addr_isany(&(lpcb->local_ip)) ||
\r
217 ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) &&
\r
218 lpcb->local_port == tcphdr->dest) {
\r
219 /* Move this PCB to the front of the list so that subsequent
\r
220 lookups will be faster (we exploit locality in TCP segment
\r
222 if (prev != NULL) {
\r
223 ((struct tcp_pcb_listen *)prev)->next = lpcb->next;
\r
224 /* our successor is the remainder of the listening list */
\r
225 lpcb->next = tcp_listen_pcbs.listen_pcbs;
\r
226 /* put this listening pcb at the head of the listening list */
\r
227 tcp_listen_pcbs.listen_pcbs = lpcb;
\r
230 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));
\r
231 tcp_listen_input(lpcb);
\r
235 prev = (struct tcp_pcb *)lpcb;
\r
239 #if TCP_INPUT_DEBUG
\r
240 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags "));
\r
241 tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
\r
242 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"));
\r
243 #endif /* TCP_INPUT_DEBUG */
\r
247 /* The incoming segment belongs to a connection. */
\r
248 #if TCP_INPUT_DEBUG
\r
250 tcp_debug_print_state(pcb->state);
\r
251 #endif /* TCP_DEBUG */
\r
252 #endif /* TCP_INPUT_DEBUG */
\r
254 /* Set up a tcp_seg structure. */
\r
256 inseg.len = p->tot_len;
\r
257 inseg.dataptr = p->payload;
\r
259 inseg.tcphdr = tcphdr;
\r
264 tcp_input_pcb = pcb;
\r
265 err = tcp_process(pcb);
\r
266 tcp_input_pcb = NULL;
\r
267 /* A return value of ERR_ABRT means that tcp_abort() was called
\r
268 and that the pcb has been freed. If so, we don't do anything. */
\r
269 if (err != ERR_ABRT) {
\r
270 if (recv_flags & TF_RESET) {
\r
271 /* TF_RESET means that the connection was reset by the other
\r
272 end. We then call the error callback to inform the
\r
273 application that the connection is dead before we
\r
274 deallocate the PCB. */
\r
275 TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);
\r
276 tcp_pcb_remove(&tcp_active_pcbs, pcb);
\r
277 memp_free(MEMP_TCP_PCB, pcb);
\r
278 } else if (recv_flags & TF_CLOSED) {
\r
279 /* The connection has been closed and we will deallocate the
\r
281 tcp_pcb_remove(&tcp_active_pcbs, pcb);
\r
282 memp_free(MEMP_TCP_PCB, pcb);
\r
285 /* If the application has registered a "sent" function to be
\r
286 called when new send buffer space is available, we call it
\r
288 if (pcb->acked > 0) {
\r
289 TCP_EVENT_SENT(pcb, pcb->acked, err);
\r
292 if (recv_data != NULL) {
\r
293 /* Notify application that data has been received. */
\r
294 TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
\r
297 /* If a FIN segment was received, we call the callback
\r
298 function with a NULL buffer to indicate EOF. */
\r
299 if (recv_flags & TF_GOT_FIN) {
\r
300 TCP_EVENT_RECV(pcb, NULL, ERR_OK, err);
\r
302 /* If there were no errors, we try to send something out. */
\r
303 if (err == ERR_OK) {
\r
310 /* give up our reference to inseg.p */
\r
311 if (inseg.p != NULL)
\r
313 pbuf_free(inseg.p);
\r
316 #if TCP_INPUT_DEBUG
\r
318 tcp_debug_print_state(pcb->state);
\r
319 #endif /* TCP_DEBUG */
\r
320 #endif /* TCP_INPUT_DEBUG */
\r
324 /* If no matching PCB was found, send a TCP RST (reset) to the
\r
326 LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));
\r
327 if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {
\r
328 TCP_STATS_INC(tcp.proterr);
\r
329 TCP_STATS_INC(tcp.drop);
\r
330 tcp_rst(ackno, seqno + tcplen,
\r
331 &(iphdr->dest), &(iphdr->src),
\r
332 tcphdr->dest, tcphdr->src);
\r
337 LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
\r
338 PERF_STOP("tcp_input");
\r
341 /* tcp_listen_input():
\r
343 * Called by tcp_input() when a segment arrives for a listening
\r
348 tcp_listen_input(struct tcp_pcb_listen *pcb)
\r
350 struct tcp_pcb *npcb;
\r
353 /* In the LISTEN state, we check for incoming SYN segments,
\r
354 creates a new PCB, and responds with a SYN|ACK. */
\r
355 if (flags & TCP_ACK) {
\r
356 /* For incoming segments with the ACK flag set, respond with a
\r
358 LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
\r
359 tcp_rst(ackno + 1, seqno + tcplen,
\r
360 &(iphdr->dest), &(iphdr->src),
\r
361 tcphdr->dest, tcphdr->src);
\r
362 } else if (flags & TCP_SYN) {
\r
363 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
\r
364 npcb = tcp_alloc(pcb->prio);
\r
365 /* If a new PCB could not be created (probably due to lack of memory),
\r
366 we don't do anything, but rely on the sender will retransmit the
\r
367 SYN at a time when we have more memory available. */
\r
368 if (npcb == NULL) {
\r
369 LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));
\r
370 TCP_STATS_INC(tcp.memerr);
\r
373 /* Set up the new PCB. */
\r
374 ip_addr_set(&(npcb->local_ip), &(iphdr->dest));
\r
375 npcb->local_port = pcb->local_port;
\r
376 ip_addr_set(&(npcb->remote_ip), &(iphdr->src));
\r
377 npcb->remote_port = tcphdr->src;
\r
378 npcb->state = SYN_RCVD;
\r
379 npcb->rcv_nxt = seqno + 1;
\r
380 npcb->snd_wnd = tcphdr->wnd;
\r
381 npcb->ssthresh = npcb->snd_wnd;
\r
382 npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
\r
383 npcb->callback_arg = pcb->callback_arg;
\r
384 #if LWIP_CALLBACK_API
\r
385 npcb->accept = pcb->accept;
\r
386 #endif /* LWIP_CALLBACK_API */
\r
387 /* inherit socket options */
\r
388 npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER);
\r
389 /* Register the new PCB so that we can begin receiving segments
\r
391 TCP_REG(&tcp_active_pcbs, npcb);
\r
393 /* Parse any options in the SYN. */
\r
394 tcp_parseopt(npcb);
\r
396 snmp_inc_tcppassiveopens();
\r
398 /* Build an MSS option. */
\r
399 optdata = htonl(((u32_t)2 << 24) |
\r
401 (((u32_t)npcb->mss / 256) << 8) |
\r
402 (npcb->mss & 255));
\r
403 /* Send a SYN|ACK together with the MSS option. */
\r
404 tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, (u8_t *)&optdata, 4);
\r
405 return tcp_output(npcb);
\r
410 /* tcp_timewait_input():
\r
412 * Called by tcp_input() when a segment arrives for a connection in
\r
417 tcp_timewait_input(struct tcp_pcb *pcb)
\r
419 if (TCP_SEQ_GT(seqno + tcplen, pcb->rcv_nxt)) {
\r
420 pcb->rcv_nxt = seqno + tcplen;
\r
425 return tcp_output(pcb);
\r
430 * Implements the TCP state machine. Called by tcp_input. In some
\r
431 * states tcp_receive() is called to receive data. The tcp_seg
\r
432 * argument will be freed by the caller (tcp_input()) unless the
\r
433 * recv_data pointer in the pcb is set.
\r
437 tcp_process(struct tcp_pcb *pcb)
\r
439 struct tcp_seg *rseg;
\r
440 u8_t acceptable = 0;
\r
442 u8_t accepted_inseq;
\r
446 /* Process incoming RST segments. */
\r
447 if (flags & TCP_RST) {
\r
448 /* First, determine if the reset is acceptable. */
\r
449 if (pcb->state == SYN_SENT) {
\r
450 if (ackno == pcb->snd_nxt) {
\r
454 /*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&
\r
455 TCP_SEQ_LEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {
\r
457 if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
\r
463 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
\r
464 LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
\r
465 recv_flags = TF_RESET;
\r
466 pcb->flags &= ~TF_ACK_DELAY;
\r
469 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
\r
470 seqno, pcb->rcv_nxt));
\r
471 LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
\r
472 seqno, pcb->rcv_nxt));
\r
477 /* Update the PCB (in)activity timer. */
\r
478 pcb->tmr = tcp_ticks;
\r
481 /* Do different things depending on the TCP state. */
\r
482 switch (pcb->state) {
\r
484 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,
\r
485 pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
\r
486 /* received SYN ACK with expected sequence number? */
\r
487 if ((flags & TCP_ACK) && (flags & TCP_SYN)
\r
488 && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
\r
490 pcb->rcv_nxt = seqno + 1;
\r
491 pcb->lastack = ackno;
\r
492 pcb->snd_wnd = tcphdr->wnd;
\r
493 pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
\r
494 pcb->state = ESTABLISHED;
\r
495 pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
\r
496 --pcb->snd_queuelen;
\r
497 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
\r
498 rseg = pcb->unacked;
\r
499 pcb->unacked = rseg->next;
\r
500 tcp_seg_free(rseg);
\r
502 /* Parse any options in the SYNACK. */
\r
505 /* Call the user specified function to call when sucessfully
\r
507 TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
\r
510 /* received ACK? possibly a half-open connection */
\r
511 else if (flags & TCP_ACK) {
\r
512 /* send a RST to bring the other side in a non-synchronized state. */
\r
513 tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
\r
514 tcphdr->dest, tcphdr->src);
\r
518 if (flags & TCP_ACK &&
\r
519 !(flags & TCP_RST)) {
\r
520 /* expected ACK number? */
\r
521 if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
\r
523 pcb->state = ESTABLISHED;
\r
524 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
\r
525 #if LWIP_CALLBACK_API
\r
526 LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
\r
528 /* Call the accept function. */
\r
529 TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
\r
530 if (err != ERR_OK) {
\r
531 /* If the accept function returns with an error, we abort
\r
532 * the connection. */
\r
536 old_cwnd = pcb->cwnd;
\r
537 /* If there was any data contained within this ACK,
\r
538 * we'd better pass it on to the application as well. */
\r
540 pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
\r
542 /* incorrect ACK number */
\r
545 tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
\r
546 tcphdr->dest, tcphdr->src);
\r
553 accepted_inseq = tcp_receive(pcb);
\r
554 if ((flags & TCP_FIN) && accepted_inseq) { /* passive close */
\r
556 pcb->state = CLOSE_WAIT;
\r
561 if (flags & TCP_FIN) {
\r
562 if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
\r
563 LWIP_DEBUGF(TCP_DEBUG,
\r
564 ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
\r
566 tcp_pcb_purge(pcb);
\r
567 TCP_RMV(&tcp_active_pcbs, pcb);
\r
568 pcb->state = TIME_WAIT;
\r
569 TCP_REG(&tcp_tw_pcbs, pcb);
\r
572 pcb->state = CLOSING;
\r
574 } else if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
\r
575 pcb->state = FIN_WAIT_2;
\r
580 if (flags & TCP_FIN) {
\r
581 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
\r
583 tcp_pcb_purge(pcb);
\r
584 TCP_RMV(&tcp_active_pcbs, pcb);
\r
585 pcb->state = TIME_WAIT;
\r
586 TCP_REG(&tcp_tw_pcbs, pcb);
\r
591 if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
\r
592 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
\r
594 tcp_pcb_purge(pcb);
\r
595 TCP_RMV(&tcp_active_pcbs, pcb);
\r
596 pcb->state = TIME_WAIT;
\r
597 TCP_REG(&tcp_tw_pcbs, pcb);
\r
602 if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
\r
603 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
\r
604 pcb->state = CLOSED;
\r
605 recv_flags = TF_CLOSED;
\r
616 * Called by tcp_process. Checks if the given segment is an ACK for outstanding
\r
617 * data, and if so frees the memory of the buffered data. Next, is places the
\r
618 * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment
\r
619 * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until
\r
620 * i it has been removed from the buffer.
\r
622 * If the incoming segment constitutes an ACK for a segment that was used for RTT
\r
623 * estimation, the RTT is estimated here as well.
\r
629 tcp_receive(struct tcp_pcb *pcb)
\r
631 struct tcp_seg *next;
\r
632 #if TCP_QUEUE_OOSEQ
\r
633 struct tcp_seg *prev, *cseg;
\r
638 u32_t right_wnd_edge;
\r
640 u8_t accepted_inseq = 0;
\r
642 if (flags & TCP_ACK) {
\r
643 right_wnd_edge = pcb->snd_wnd + pcb->snd_wl1;
\r
645 /* Update window. */
\r
646 if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||
\r
647 (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||
\r
648 (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {
\r
649 pcb->snd_wnd = tcphdr->wnd;
\r
650 pcb->snd_wl1 = seqno;
\r
651 pcb->snd_wl2 = ackno;
\r
652 LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U32_F"\n", pcb->snd_wnd));
\r
655 if (pcb->snd_wnd != tcphdr->wnd) {
\r
656 LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: no window update lastack %"U32_F" snd_max %"U32_F" ackno %"U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",
\r
657 pcb->lastack, pcb->snd_max, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));
\r
659 #endif /* TCP_WND_DEBUG */
\r
662 if (pcb->lastack == ackno) {
\r
665 if (pcb->snd_wl1 + pcb->snd_wnd == right_wnd_edge){
\r
667 if (pcb->dupacks >= 3 && pcb->unacked != NULL) {
\r
668 if (!(pcb->flags & TF_INFR)) {
\r
669 /* This is fast retransmit. Retransmit the first unacked segment. */
\r
670 LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %"U16_F" (%"U32_F"), fast retransmit %"U32_F"\n",
\r
671 (u16_t)pcb->dupacks, pcb->lastack,
\r
672 ntohl(pcb->unacked->tcphdr->seqno)));
\r
674 /* Set ssthresh to max (FlightSize / 2, 2*SMSS) */
\r
675 /*pcb->ssthresh = LWIP_MAX((pcb->snd_max -
\r
678 /* Set ssthresh to half of the minimum of the currenct cwnd and the advertised window */
\r
679 if (pcb->cwnd > pcb->snd_wnd)
\r
680 pcb->ssthresh = pcb->snd_wnd / 2;
\r
682 pcb->ssthresh = pcb->cwnd / 2;
\r
684 pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
\r
685 pcb->flags |= TF_INFR;
\r
687 /* Inflate the congestion window, but not if it means that
\r
688 the value overflows. */
\r
689 if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
\r
690 pcb->cwnd += pcb->mss;
\r
695 LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n",
\r
696 pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge));
\r
699 /*if (TCP_SEQ_LT(pcb->lastack, ackno) &&
\r
700 TCP_SEQ_LEQ(ackno, pcb->snd_max)) { */
\r
701 if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_max)){
\r
702 /* We come here when the ACK acknowledges new data. */
\r
704 /* Reset the "IN Fast Retransmit" flag, since we are no longer
\r
705 in fast retransmit. Also reset the congestion window to the
\r
706 slow start threshold. */
\r
707 if (pcb->flags & TF_INFR) {
\r
708 pcb->flags &= ~TF_INFR;
\r
709 pcb->cwnd = pcb->ssthresh;
\r
712 /* Reset the number of retransmissions. */
\r
715 /* Reset the retransmission time-out. */
\r
716 pcb->rto = (pcb->sa >> 3) + pcb->sv;
\r
718 /* Update the send buffer space. */
\r
719 pcb->acked = ackno - pcb->lastack;
\r
721 pcb->snd_buf += pcb->acked;
\r
723 /* Reset the fast retransmit variables. */
\r
725 pcb->lastack = ackno;
\r
727 /* Update the congestion control variables (cwnd and
\r
729 if (pcb->state >= ESTABLISHED) {
\r
730 if (pcb->cwnd < pcb->ssthresh) {
\r
731 if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
\r
732 pcb->cwnd += pcb->mss;
\r
734 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));
\r
736 u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
\r
737 if (new_cwnd > pcb->cwnd) {
\r
738 pcb->cwnd = new_cwnd;
\r
740 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));
\r
743 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",
\r
745 pcb->unacked != NULL?
\r
746 ntohl(pcb->unacked->tcphdr->seqno): 0,
\r
747 pcb->unacked != NULL?
\r
748 ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
\r
750 /* Remove segment from the unacknowledged list if the incoming
\r
751 ACK acknowlegdes them. */
\r
752 while (pcb->unacked != NULL &&
\r
753 TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
\r
754 TCP_TCPLEN(pcb->unacked), ackno)) {
\r
755 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",
\r
756 ntohl(pcb->unacked->tcphdr->seqno),
\r
757 ntohl(pcb->unacked->tcphdr->seqno) +
\r
758 TCP_TCPLEN(pcb->unacked)));
\r
760 next = pcb->unacked;
\r
761 pcb->unacked = pcb->unacked->next;
\r
763 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
\r
764 pcb->snd_queuelen -= pbuf_clen(next->p);
\r
765 tcp_seg_free(next);
\r
767 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen));
\r
768 if (pcb->snd_queuelen != 0) {
\r
769 LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
\r
770 pcb->unsent != NULL);
\r
776 /* We go through the ->unsent list to see if any of the segments
\r
777 on the list are acknowledged by the ACK. This may seem
\r
778 strange since an "unsent" segment shouldn't be acked. The
\r
779 rationale is that lwIP puts all outstanding segments on the
\r
780 ->unsent list after a retransmission, so these segments may
\r
781 in fact have been sent once. */
\r
782 while (pcb->unsent != NULL &&
\r
783 /*TCP_SEQ_LEQ(ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), ackno) &&
\r
784 TCP_SEQ_LEQ(ackno, pcb->snd_max)*/
\r
785 TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), pcb->snd_max)
\r
787 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",
\r
788 ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
\r
789 TCP_TCPLEN(pcb->unsent)));
\r
791 next = pcb->unsent;
\r
792 pcb->unsent = pcb->unsent->next;
\r
793 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
\r
794 pcb->snd_queuelen -= pbuf_clen(next->p);
\r
795 tcp_seg_free(next);
\r
796 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));
\r
797 if (pcb->snd_queuelen != 0) {
\r
798 LWIP_ASSERT("tcp_receive: valid queue length",
\r
799 pcb->unacked != NULL || pcb->unsent != NULL);
\r
802 if (pcb->unsent != NULL) {
\r
803 pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno);
\r
806 /* End of ACK for new data processing. */
\r
808 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n",
\r
809 pcb->rttest, pcb->rtseq, ackno));
\r
811 /* RTT estimation calculations. This is done by checking if the
\r
812 incoming segment acknowledges the segment we use to take a
\r
813 round-trip time measurement. */
\r
814 if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {
\r
815 m = tcp_ticks - pcb->rttest;
\r
817 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n",
\r
818 m, m * TCP_SLOW_INTERVAL));
\r
820 /* This is taken directly from VJs original code in his paper */
\r
821 m = m - (pcb->sa >> 3);
\r
826 m = m - (pcb->sv >> 2);
\r
828 pcb->rto = (pcb->sa >> 3) + pcb->sv;
\r
830 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" miliseconds)\n",
\r
831 pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));
\r
837 /* If the incoming segment contains data, we must process it
\r
840 /* This code basically does three things:
\r
842 +) If the incoming segment contains data that is the next
\r
843 in-sequence data, this data is passed to the application. This
\r
844 might involve trimming the first edge of the data. The rcv_nxt
\r
845 variable and the advertised window are adjusted.
\r
847 +) If the incoming segment has data that is above the next
\r
848 sequence number expected (->rcv_nxt), the segment is placed on
\r
849 the ->ooseq queue. This is done by finding the appropriate
\r
850 place in the ->ooseq queue (which is ordered by sequence
\r
851 number) and trim the segment in both ends if needed. An
\r
852 immediate ACK is sent to indicate that we received an
\r
853 out-of-sequence segment.
\r
855 +) Finally, we check if the first segment on the ->ooseq queue
\r
856 now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
\r
857 rcv_nxt > ooseq->seqno, we must trim the first edge of the
\r
858 segment on ->ooseq before we adjust rcv_nxt. The data in the
\r
859 segments that are now on sequence are chained onto the
\r
860 incoming segment so that we only need to call the application
\r
864 /* First, we check if we must trim the first edge. We have to do
\r
865 this if the sequence number of the incoming segment is less
\r
866 than rcv_nxt, and the sequence number plus the length of the
\r
867 segment is larger than rcv_nxt. */
\r
868 /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
\r
869 if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/
\r
870 if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){
\r
871 /* Trimming the first edge is done by pushing the payload
\r
872 pointer in the pbuf downwards. This is somewhat tricky since
\r
873 we do not want to discard the full contents of the pbuf up to
\r
874 the new starting point of the data since we have to keep the
\r
875 TCP header which is present in the first pbuf in the chain.
\r
877 What is done is really quite a nasty hack: the first pbuf in
\r
878 the pbuf chain is pointed to by inseg.p. Since we need to be
\r
879 able to deallocate the whole pbuf, we cannot change this
\r
880 inseg.p pointer to point to any of the later pbufs in the
\r
881 chain. Instead, we point the ->payload pointer in the first
\r
882 pbuf to data in one of the later pbufs. We also set the
\r
883 inseg.data pointer to point to the right place. This way, the
\r
884 ->p pointer will still point to the first pbuf, but the
\r
885 ->p->payload pointer will point to data in another pbuf.
\r
887 After we are done with adjusting the pbuf pointers we must
\r
888 adjust the ->data pointer in the seg and the segment
\r
891 off = pcb->rcv_nxt - seqno;
\r
893 LWIP_ASSERT("inseg.p != NULL", inseg.p);
\r
894 if (inseg.p->len < off) {
\r
895 new_tot_len = inseg.p->tot_len - off;
\r
896 while (p->len < off) {
\r
898 /* KJM following line changed (with addition of new_tot_len var)
\r
900 inseg.p->tot_len -= p->len; */
\r
901 p->tot_len = new_tot_len;
\r
905 pbuf_header(p, -off);
\r
907 pbuf_header(inseg.p, -off);
\r
909 /* KJM following line changed to use p->payload rather than inseg->p->payload
\r
910 to fix bug #9076 */
\r
911 inseg.dataptr = p->payload;
\r
912 inseg.len -= pcb->rcv_nxt - seqno;
\r
913 inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
\r
916 if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
\r
917 /* the whole segment is < rcv_nxt */
\r
918 /* must be a duplicate of a packet that has already been correctly handled */
\r
920 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));
\r
925 /* The sequence number must be within the window (above rcv_nxt
\r
926 and below rcv_nxt + rcv_wnd) in order to be further
\r
928 /*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&
\r
929 TCP_SEQ_LT(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
\r
930 if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)){
\r
931 if (pcb->rcv_nxt == seqno) {
\r
932 accepted_inseq = 1;
\r
933 /* The incoming segment is the next in sequence. We check if
\r
934 we have to trim the end of the segment and update rcv_nxt
\r
935 and pass the data to the application. */
\r
936 #if TCP_QUEUE_OOSEQ
\r
937 if (pcb->ooseq != NULL &&
\r
938 TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + inseg.len)) {
\r
939 /* We have to trim the second edge of the incoming
\r
941 inseg.len = pcb->ooseq->tcphdr->seqno - seqno;
\r
942 pbuf_realloc(inseg.p, inseg.len);
\r
944 #endif /* TCP_QUEUE_OOSEQ */
\r
946 tcplen = TCP_TCPLEN(&inseg);
\r
948 /* First received FIN will be ACKed +1, on any successive (duplicate)
\r
949 * FINs we are already in CLOSE_WAIT and have already done +1.
\r
951 if (pcb->state != CLOSE_WAIT) {
\r
952 pcb->rcv_nxt += tcplen;
\r
955 /* Update the receiver's (our) window. */
\r
956 if (pcb->rcv_wnd < tcplen) {
\r
959 pcb->rcv_wnd -= tcplen;
\r
962 /* If there is data in the segment, we make preparations to
\r
963 pass this up to the application. The ->recv_data variable
\r
964 is used for holding the pbuf that goes to the
\r
965 application. The code for reassembling out-of-sequence data
\r
966 chains its data on this pbuf as well.
\r
968 If the segment was a FIN, we set the TF_GOT_FIN flag that will
\r
969 be used to indicate to the application that the remote side has
\r
970 closed its end of the connection. */
\r
971 if (inseg.p->tot_len > 0) {
\r
972 recv_data = inseg.p;
\r
973 /* Since this pbuf now is the responsibility of the
\r
974 application, we delete our reference to it so that we won't
\r
975 (mistakingly) deallocate it. */
\r
978 if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
\r
979 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
\r
980 recv_flags = TF_GOT_FIN;
\r
983 #if TCP_QUEUE_OOSEQ
\r
984 /* We now check if we have segments on the ->ooseq queue that
\r
985 is now in sequence. */
\r
986 while (pcb->ooseq != NULL &&
\r
987 pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
\r
990 seqno = pcb->ooseq->tcphdr->seqno;
\r
992 pcb->rcv_nxt += TCP_TCPLEN(cseg);
\r
993 if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) {
\r
996 pcb->rcv_wnd -= TCP_TCPLEN(cseg);
\r
998 if (cseg->p->tot_len > 0) {
\r
999 /* Chain this pbuf onto the pbuf that we will pass to
\r
1000 the application. */
\r
1002 pbuf_cat(recv_data, cseg->p);
\r
1004 recv_data = cseg->p;
\r
1008 if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
\r
1009 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
\r
1010 recv_flags = TF_GOT_FIN;
\r
1011 if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */
\r
1012 pcb->state = CLOSE_WAIT;
\r
1017 pcb->ooseq = cseg->next;
\r
1018 tcp_seg_free(cseg);
\r
1020 #endif /* TCP_QUEUE_OOSEQ */
\r
1023 /* Acknowledge the segment(s). */
\r
1027 /* We get here if the incoming segment is out-of-sequence. */
\r
1029 #if TCP_QUEUE_OOSEQ
\r
1030 /* We queue the segment on the ->ooseq queue. */
\r
1031 if (pcb->ooseq == NULL) {
\r
1032 pcb->ooseq = tcp_seg_copy(&inseg);
\r
1034 /* If the queue is not empty, we walk through the queue and
\r
1035 try to find a place where the sequence number of the
\r
1036 incoming segment is between the sequence numbers of the
\r
1037 previous and the next segment on the ->ooseq queue. That is
\r
1038 the place where we put the incoming segment. If needed, we
\r
1039 trim the second edges of the previous and the incoming
\r
1040 segment so that it will fit into the sequence.
\r
1042 If the incoming segment has the same sequence number as a
\r
1043 segment on the ->ooseq queue, we discard the segment that
\r
1044 contains less data. */
\r
1047 for(next = pcb->ooseq; next != NULL; next = next->next) {
\r
1048 if (seqno == next->tcphdr->seqno) {
\r
1049 /* The sequence number of the incoming segment is the
\r
1050 same as the sequence number of the segment on
\r
1051 ->ooseq. We check the lengths to see which one to
\r
1053 if (inseg.len > next->len) {
\r
1054 /* The incoming segment is larger than the old
\r
1055 segment. We replace the old segment with the new
\r
1057 cseg = tcp_seg_copy(&inseg);
\r
1058 if (cseg != NULL) {
\r
1059 cseg->next = next->next;
\r
1060 if (prev != NULL) {
\r
1061 prev->next = cseg;
\r
1063 pcb->ooseq = cseg;
\r
1068 /* Either the lenghts are the same or the incoming
\r
1069 segment was smaller than the old one; in either
\r
1070 case, we ditch the incoming segment. */
\r
1074 if (prev == NULL) {
\r
1075 if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
\r
1076 /* The sequence number of the incoming segment is lower
\r
1077 than the sequence number of the first segment on the
\r
1078 queue. We put the incoming segment first on the
\r
1081 if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
\r
1082 /* We need to trim the incoming segment. */
\r
1083 inseg.len = next->tcphdr->seqno - seqno;
\r
1084 pbuf_realloc(inseg.p, inseg.len);
\r
1086 cseg = tcp_seg_copy(&inseg);
\r
1087 if (cseg != NULL) {
\r
1088 cseg->next = next;
\r
1089 pcb->ooseq = cseg;
\r
1094 /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
\r
1095 TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/
\r
1096 if(TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)){
\r
1097 /* The sequence number of the incoming segment is in
\r
1098 between the sequence numbers of the previous and
\r
1099 the next segment on ->ooseq. We trim and insert the
\r
1100 incoming segment and trim the previous segment, if
\r
1102 if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
\r
1103 /* We need to trim the incoming segment. */
\r
1104 inseg.len = next->tcphdr->seqno - seqno;
\r
1105 pbuf_realloc(inseg.p, inseg.len);
\r
1108 cseg = tcp_seg_copy(&inseg);
\r
1109 if (cseg != NULL) {
\r
1110 cseg->next = next;
\r
1111 prev->next = cseg;
\r
1112 if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
\r
1113 /* We need to trim the prev segment. */
\r
1114 prev->len = seqno - prev->tcphdr->seqno;
\r
1115 pbuf_realloc(prev->p, prev->len);
\r
1120 /* If the "next" segment is the last segment on the
\r
1121 ooseq queue, we add the incoming segment to the end
\r
1123 if (next->next == NULL &&
\r
1124 TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
\r
1125 next->next = tcp_seg_copy(&inseg);
\r
1126 if (next->next != NULL) {
\r
1127 if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
\r
1128 /* We need to trim the last segment. */
\r
1129 next->len = seqno - next->tcphdr->seqno;
\r
1130 pbuf_realloc(next->p, next->len);
\r
1139 #endif /* TCP_QUEUE_OOSEQ */
\r
1143 /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
\r
1144 TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
\r
1145 if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
\r
1150 /* Segments with length 0 is taken care of here. Segments that
\r
1151 fall out of the window are ACKed. */
\r
1152 /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
\r
1153 TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
\r
1154 if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
\r
1158 return accepted_inseq;
\r
1164 * Parses the options contained in the incoming segment. (Code taken
\r
1165 * from uIP with only small changes.)
\r
1170 tcp_parseopt(struct tcp_pcb *pcb)
\r
1176 opts = (u8_t *)tcphdr + TCP_HLEN;
\r
1178 /* Parse the TCP MSS option, if present. */
\r
1179 if(TCPH_HDRLEN(tcphdr) > 0x5) {
\r
1180 for(c = 0; c < (TCPH_HDRLEN(tcphdr) - 5) << 2 ;) {
\r
1182 if (opt == 0x00) {
\r
1183 /* End of options. */
\r
1185 } else if (opt == 0x01) {
\r
1188 } else if (opt == 0x02 &&
\r
1189 opts[c + 1] == 0x04) {
\r
1190 /* An MSS option with the right option length. */
\r
1191 mss = (opts[c + 2] << 8) | opts[c + 3];
\r
1192 pcb->mss = mss > TCP_MSS? TCP_MSS: mss;
\r
1194 /* And we are done processing options. */
\r
1197 if (opts[c + 1] == 0) {
\r
1198 /* If the length field is zero, the options are malformed
\r
1199 and we don't process them further. */
\r
1202 /* All other options have a length field, so that we easily
\r
1203 can skip past them. */
\r
1209 #endif /* LWIP_TCP */
\r