]> git.sur5r.net Git - freertos/blob - Demo/Common/ethernet/lwIP/core/tcp_in.c
Start to re-arrange files to include FreeRTOS+ in main download.
[freertos] / Demo / Common / ethernet / lwIP / core / tcp_in.c
1 /**\r
2  * @file\r
3  *\r
4  * Transmission Control Protocol, incoming traffic\r
5  *\r
6  * The input processing functions of the TCP layer.\r
7  *\r
8  * These functions are generally called in the order (ip_input() ->)\r
9  * tcp_input() -> * tcp_process() -> tcp_receive() (-> application).\r
10  *\r
11  */\r
12 \r
13 /*\r
14  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
15  * All rights reserved.\r
16  *\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
19  *\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
27  *\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
37  * OF SUCH DAMAGE.\r
38  *\r
39  * This file is part of the lwIP TCP/IP stack.\r
40  *\r
41  * Author: Adam Dunkels <adam@sics.se>\r
42  *\r
43  */\r
44 \r
45 #include "lwip/def.h"\r
46 #include "lwip/opt.h"\r
47 \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
52 \r
53 #include "lwip/inet.h"\r
54 #include "lwip/tcp.h"\r
55 \r
56 #include "lwip/stats.h"\r
57 #include "arch/perf.h"\r
58 #include "lwip/snmp.h"\r
59 \r
60 #if LWIP_TCP\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
63    function. */\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
68 static u8_t flags;\r
69 static u16_t tcplen;\r
70 \r
71 static u8_t recv_flags;\r
72 static struct pbuf *recv_data;\r
73 \r
74 struct tcp_pcb *tcp_input_pcb;\r
75 \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
80 \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
83 \r
84 /* tcp_input:\r
85  *\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
89  * ip_input()).\r
90  */\r
91 \r
92 void\r
93 tcp_input(struct pbuf *p, struct netif *inp)\r
94 {\r
95   struct tcp_pcb *pcb, *prev;\r
96   struct tcp_pcb_listen *lpcb;\r
97   u8_t hdrlen;\r
98   err_t err;\r
99 \r
100   PERF_START;\r
101 \r
102   TCP_STATS_INC(tcp.recv);\r
103   snmp_inc_tcpinsegs();\r
104 \r
105   iphdr = p->payload;\r
106   tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);\r
107 \r
108 #if TCP_INPUT_DEBUG\r
109   tcp_debug_print(tcphdr);\r
110 #endif\r
111 \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
118     pbuf_free(p);\r
119     return;\r
120   }\r
121 \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
126     pbuf_free(p);\r
127     return;\r
128   }\r
129 \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
138 #if TCP_DEBUG\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
144     pbuf_free(p);\r
145     return;\r
146   }\r
147 #endif\r
148 \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
153 \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
160 \r
161   flags = TCPH_FLAGS(tcphdr) & TCP_FLAGS;\r
162   tcplen = p->tot_len + ((flags & TCP_FIN || flags & TCP_SYN)? 1: 0);\r
163 \r
164   /* Demultiplex an incoming segment. First, we check if it is destined\r
165      for an active connection. */\r
166   prev = NULL;\r
167 \r
168 \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
177 \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
180          arrivals). */\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
186       }\r
187       LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);\r
188       break;\r
189     }\r
190     prev = pcb;\r
191   }\r
192 \r
193   if (pcb == NULL) {\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
207         pbuf_free(p);\r
208         return;\r
209       }\r
210     }\r
211 \r
212   /* Finally, if we still did not get a match, we check all PCBs that\r
213      are LISTENing for incoming connections. */\r
214     prev = NULL;\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
221            arrivals). */\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
228         }\r
229 \r
230         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));\r
231         tcp_listen_input(lpcb);\r
232         pbuf_free(p);\r
233         return;\r
234       }\r
235       prev = (struct tcp_pcb *)lpcb;\r
236     }\r
237   }\r
238 \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
244 \r
245 \r
246   if (pcb != NULL) {\r
247     /* The incoming segment belongs to a connection. */\r
248 #if TCP_INPUT_DEBUG\r
249 #if TCP_DEBUG\r
250     tcp_debug_print_state(pcb->state);\r
251 #endif /* TCP_DEBUG */\r
252 #endif /* TCP_INPUT_DEBUG */\r
253 \r
254     /* Set up a tcp_seg structure. */\r
255     inseg.next = NULL;\r
256     inseg.len = p->tot_len;\r
257     inseg.dataptr = p->payload;\r
258     inseg.p = p;\r
259     inseg.tcphdr = tcphdr;\r
260 \r
261     recv_data = NULL;\r
262     recv_flags = 0;\r
263 \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
280            PCB. */\r
281         tcp_pcb_remove(&tcp_active_pcbs, pcb);\r
282         memp_free(MEMP_TCP_PCB, pcb);\r
283             } else {\r
284         err = ERR_OK;\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
287            now. */\r
288         if (pcb->acked > 0) {\r
289           TCP_EVENT_SENT(pcb, pcb->acked, err);\r
290         }\r
291 \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
295         }\r
296 \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
301         }\r
302         /* If there were no errors, we try to send something out. */\r
303         if (err == ERR_OK) {\r
304           tcp_output(pcb);\r
305         }\r
306       }\r
307     }\r
308 \r
309 \r
310     /* give up our reference to inseg.p */\r
311     if (inseg.p != NULL)\r
312     {\r
313       pbuf_free(inseg.p);\r
314       inseg.p = NULL;\r
315     }\r
316 #if TCP_INPUT_DEBUG\r
317 #if TCP_DEBUG\r
318     tcp_debug_print_state(pcb->state);\r
319 #endif /* TCP_DEBUG */\r
320 #endif /* TCP_INPUT_DEBUG */\r
321 \r
322   } else {\r
323 \r
324     /* If no matching PCB was found, send a TCP RST (reset) to the\r
325        sender. */\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
333     }\r
334     pbuf_free(p);\r
335   }\r
336 \r
337   LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());\r
338   PERF_STOP("tcp_input");\r
339 }\r
340 \r
341 /* tcp_listen_input():\r
342  *\r
343  * Called by tcp_input() when a segment arrives for a listening\r
344  * connection.\r
345  */\r
346 \r
347 static err_t\r
348 tcp_listen_input(struct tcp_pcb_listen *pcb)\r
349 {\r
350   struct tcp_pcb *npcb;\r
351   u32_t optdata;\r
352 \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
357        RST. */\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
371       return ERR_MEM;\r
372     }\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
390        for it. */\r
391     TCP_REG(&tcp_active_pcbs, npcb);\r
392 \r
393     /* Parse any options in the SYN. */\r
394     tcp_parseopt(npcb);\r
395 \r
396     snmp_inc_tcppassiveopens();\r
397 \r
398     /* Build an MSS option. */\r
399     optdata = htonl(((u32_t)2 << 24) |\r
400         ((u32_t)4 << 16) |\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
406   }\r
407   return ERR_OK;\r
408 }\r
409 \r
410 /* tcp_timewait_input():\r
411  *\r
412  * Called by tcp_input() when a segment arrives for a connection in\r
413  * TIME_WAIT.\r
414  */\r
415 \r
416 static err_t\r
417 tcp_timewait_input(struct tcp_pcb *pcb)\r
418 {\r
419   if (TCP_SEQ_GT(seqno + tcplen, pcb->rcv_nxt)) {\r
420     pcb->rcv_nxt = seqno + tcplen;\r
421   }\r
422   if (tcplen > 0) {\r
423     tcp_ack_now(pcb);\r
424   }\r
425   return tcp_output(pcb);\r
426 }\r
427 \r
428 /* tcp_process\r
429  *\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
434  */\r
435 \r
436 static err_t\r
437 tcp_process(struct tcp_pcb *pcb)\r
438 {\r
439   struct tcp_seg *rseg;\r
440   u8_t acceptable = 0;\r
441   err_t err;\r
442   u8_t accepted_inseq;\r
443 \r
444   err = ERR_OK;\r
445 \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
451         acceptable = 1;\r
452       }\r
453     } else {\r
454       /*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&\r
455           TCP_SEQ_LEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {\r
456       */\r
457       if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {\r
458         acceptable = 1;\r
459       }\r
460     }\r
461 \r
462     if (acceptable) {\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
467       return ERR_RST;\r
468     } else {\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
473       return ERR_OK;\r
474     }\r
475   }\r
476 \r
477   /* Update the PCB (in)activity timer. */\r
478   pcb->tmr = tcp_ticks;\r
479   pcb->keep_cnt = 0;\r
480 \r
481   /* Do different things depending on the TCP state. */\r
482   switch (pcb->state) {\r
483   case SYN_SENT:\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
489       pcb->snd_buf++;\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
501 \r
502       /* Parse any options in the SYNACK. */\r
503       tcp_parseopt(pcb);\r
504 \r
505       /* Call the user specified function to call when sucessfully\r
506        * connected. */\r
507       TCP_EVENT_CONNECTED(pcb, ERR_OK, err);\r
508       tcp_ack(pcb);\r
509     }\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
515     }\r
516     break;\r
517   case SYN_RCVD:\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
522                                 u16_t old_cwnd;\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
527 #endif\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
533           tcp_abort(pcb);\r
534           return ERR_ABRT;\r
535         }\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
539         tcp_receive(pcb);\r
540                                 pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);\r
541       }\r
542       /* incorrect ACK number */\r
543       else {\r
544         /* send RST */\r
545         tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),\r
546           tcphdr->dest, tcphdr->src);\r
547       }\r
548     }\r
549     break;\r
550   case CLOSE_WAIT:\r
551     /* FALLTHROUGH */\r
552   case ESTABLISHED:\r
553     accepted_inseq = tcp_receive(pcb);\r
554     if ((flags & TCP_FIN) && accepted_inseq) { /* passive close */\r
555       tcp_ack_now(pcb);\r
556       pcb->state = CLOSE_WAIT;\r
557     }\r
558     break;\r
559   case FIN_WAIT_1:\r
560     tcp_receive(pcb);\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
565         tcp_ack_now(pcb);\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
570       } else {\r
571         tcp_ack_now(pcb);\r
572         pcb->state = CLOSING;\r
573       }\r
574     } else if (flags & TCP_ACK && ackno == pcb->snd_nxt) {\r
575       pcb->state = FIN_WAIT_2;\r
576     }\r
577     break;\r
578   case FIN_WAIT_2:\r
579     tcp_receive(pcb);\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
582       tcp_ack_now(pcb);\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
587     }\r
588     break;\r
589   case CLOSING:\r
590     tcp_receive(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
593       tcp_ack_now(pcb);\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
598     }\r
599     break;\r
600   case LAST_ACK:\r
601     tcp_receive(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
606     }\r
607     break;\r
608   default:\r
609     break;\r
610   }\r
611   return ERR_OK;\r
612 }\r
613 \r
614 /* tcp_receive:\r
615  *\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
621  *\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
624  *\r
625  * @return 1 if\r
626  */\r
627 \r
628 static u8_t\r
629 tcp_receive(struct tcp_pcb *pcb)\r
630 {\r
631   struct tcp_seg *next;\r
632 #if TCP_QUEUE_OOSEQ\r
633   struct tcp_seg *prev, *cseg;\r
634 #endif\r
635   struct pbuf *p;\r
636   s32_t off;\r
637   s16_t m;\r
638   u32_t right_wnd_edge;\r
639   u16_t new_tot_len;\r
640   u8_t accepted_inseq = 0;\r
641 \r
642   if (flags & TCP_ACK) {\r
643     right_wnd_edge = pcb->snd_wnd + pcb->snd_wl1;\r
644 \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
653 #if TCP_WND_DEBUG\r
654     } else {\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
658       }\r
659 #endif /* TCP_WND_DEBUG */\r
660     }\r
661 \r
662     if (pcb->lastack == ackno) {\r
663       pcb->acked = 0;\r
664 \r
665       if (pcb->snd_wl1 + pcb->snd_wnd == right_wnd_edge){\r
666         ++pcb->dupacks;\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
673             tcp_rexmit(pcb);\r
674             /* Set ssthresh to max (FlightSize / 2, 2*SMSS) */\r
675             /*pcb->ssthresh = LWIP_MAX((pcb->snd_max -\r
676                                       pcb->lastack) / 2,\r
677                                       2 * pcb->mss);*/\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
681             else\r
682               pcb->ssthresh = pcb->cwnd / 2;\r
683 \r
684             pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;\r
685             pcb->flags |= TF_INFR;\r
686           } else {\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
691             }\r
692           }\r
693         }\r
694       } else {\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
697       }\r
698     } else\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
703 \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
710       }\r
711 \r
712       /* Reset the number of retransmissions. */\r
713       pcb->nrtx = 0;\r
714 \r
715       /* Reset the retransmission time-out. */\r
716       pcb->rto = (pcb->sa >> 3) + pcb->sv;\r
717 \r
718       /* Update the send buffer space. */\r
719       pcb->acked = ackno - pcb->lastack;\r
720 \r
721       pcb->snd_buf += pcb->acked;\r
722 \r
723       /* Reset the fast retransmit variables. */\r
724       pcb->dupacks = 0;\r
725       pcb->lastack = ackno;\r
726 \r
727       /* Update the congestion control variables (cwnd and\r
728          ssthresh). */\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
733           }\r
734           LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));\r
735         } else {\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
739           }\r
740           LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));\r
741         }\r
742       }\r
743       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",\r
744                                     ackno,\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
749 \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
759 \r
760         next = pcb->unacked;\r
761         pcb->unacked = pcb->unacked->next;\r
762 \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
766 \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
771         }\r
772       }\r
773       pcb->polltmr = 0;\r
774     }\r
775 \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
786            ) {\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
790 \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
800       }\r
801 \r
802       if (pcb->unsent != NULL) {\r
803         pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno);\r
804       }\r
805     }\r
806     /* End of ACK for new data processing. */\r
807 \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
810 \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
816 \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
819 \r
820       /* This is taken directly from VJs original code in his paper */\r
821       m = m - (pcb->sa >> 3);\r
822       pcb->sa += m;\r
823       if (m < 0) {\r
824         m = -m;\r
825       }\r
826       m = m - (pcb->sv >> 2);\r
827       pcb->sv += m;\r
828       pcb->rto = (pcb->sa >> 3) + pcb->sv;\r
829 \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
832 \r
833       pcb->rttest = 0;\r
834     }\r
835   }\r
836 \r
837   /* If the incoming segment contains data, we must process it\r
838      further. */\r
839   if (tcplen > 0) {\r
840     /* This code basically does three things:\r
841 \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
846 \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
854 \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
861     once.\r
862     */\r
863 \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
876 \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
886 \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
889          length.*/\r
890 \r
891       off = pcb->rcv_nxt - seqno;\r
892       p = inseg.p;\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
897           off -= p->len;\r
898           /* KJM following line changed (with addition of new_tot_len var)\r
899              to fix bug #9076\r
900              inseg.p->tot_len -= p->len; */\r
901           p->tot_len = new_tot_len;\r
902           p->len = 0;\r
903           p = p->next;\r
904         }\r
905         pbuf_header(p, -off);\r
906       } else {\r
907         pbuf_header(inseg.p, -off);\r
908       }\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
914     }\r
915     else {\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
919 \r
920         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));\r
921         tcp_ack_now(pcb);\r
922       }\r
923     }\r
924 \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
927        processed. */\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
940              segment. */\r
941           inseg.len = pcb->ooseq->tcphdr->seqno - seqno;\r
942           pbuf_realloc(inseg.p, inseg.len);\r
943         }\r
944 #endif /* TCP_QUEUE_OOSEQ */\r
945 \r
946         tcplen = TCP_TCPLEN(&inseg);\r
947 \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
950          */\r
951         if (pcb->state != CLOSE_WAIT) {\r
952           pcb->rcv_nxt += tcplen;\r
953         }\r
954 \r
955         /* Update the receiver's (our) window. */\r
956         if (pcb->rcv_wnd < tcplen) {\r
957           pcb->rcv_wnd = 0;\r
958         } else {\r
959           pcb->rcv_wnd -= tcplen;\r
960         }\r
961 \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
967 \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
976           inseg.p = NULL;\r
977         }\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
981         }\r
982 \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
988 \r
989           cseg = pcb->ooseq;\r
990           seqno = pcb->ooseq->tcphdr->seqno;\r
991 \r
992           pcb->rcv_nxt += TCP_TCPLEN(cseg);\r
993           if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) {\r
994             pcb->rcv_wnd = 0;\r
995           } else {\r
996             pcb->rcv_wnd -= TCP_TCPLEN(cseg);\r
997           }\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
1001             if (recv_data) {\r
1002               pbuf_cat(recv_data, cseg->p);\r
1003             } else {\r
1004               recv_data = cseg->p;\r
1005             }\r
1006             cseg->p = NULL;\r
1007           }\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
1013             }\r
1014           }\r
1015 \r
1016 \r
1017           pcb->ooseq = cseg->next;\r
1018           tcp_seg_free(cseg);\r
1019         }\r
1020 #endif /* TCP_QUEUE_OOSEQ */\r
1021 \r
1022 \r
1023         /* Acknowledge the segment(s). */\r
1024         tcp_ack(pcb);\r
1025 \r
1026       } else {\r
1027         /* We get here if the incoming segment is out-of-sequence. */\r
1028         tcp_ack_now(pcb);\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
1033         } else {\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
1041 \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
1045 \r
1046           prev = NULL;\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
1052                  discard. */\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
1056                    one. */\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
1062                   } else {\r
1063                     pcb->ooseq = cseg;\r
1064                   }\r
1065                 }\r
1066                 break;\r
1067               } else {\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
1071                 break;\r
1072               }\r
1073             } else {\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
1079                      queue. */\r
1080 \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
1085                   }\r
1086                   cseg = tcp_seg_copy(&inseg);\r
1087                   if (cseg != NULL) {\r
1088                     cseg->next = next;\r
1089                     pcb->ooseq = cseg;\r
1090                   }\r
1091                   break;\r
1092                 }\r
1093               } else\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
1101                    needed. */\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
1106                 }\r
1107 \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
1116                   }\r
1117                 }\r
1118                 break;\r
1119               }\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
1122                  of the list. */\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
1131                   }\r
1132                 }\r
1133                 break;\r
1134               }\r
1135             }\r
1136             prev = next;\r
1137           }\r
1138         }\r
1139 #endif /* TCP_QUEUE_OOSEQ */\r
1140 \r
1141       }\r
1142     } else {\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
1146         tcp_ack_now(pcb);\r
1147       }\r
1148     }\r
1149   } else {\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
1155       tcp_ack_now(pcb);\r
1156     }\r
1157   }\r
1158   return accepted_inseq;\r
1159 }\r
1160 \r
1161 /*\r
1162  * tcp_parseopt:\r
1163  *\r
1164  * Parses the options contained in the incoming segment. (Code taken\r
1165  * from uIP with only small changes.)\r
1166  *\r
1167  */\r
1168 \r
1169 static void\r
1170 tcp_parseopt(struct tcp_pcb *pcb)\r
1171 {\r
1172   u8_t c;\r
1173   u8_t *opts, opt;\r
1174   u16_t mss;\r
1175 \r
1176   opts = (u8_t *)tcphdr + TCP_HLEN;\r
1177 \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
1181       opt = opts[c];\r
1182       if (opt == 0x00) {\r
1183         /* End of options. */\r
1184   break;\r
1185       } else if (opt == 0x01) {\r
1186         ++c;\r
1187         /* NOP option. */\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
1193 \r
1194         /* And we are done processing options. */\r
1195         break;\r
1196       } else {\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
1200           break;\r
1201         }\r
1202         /* All other options have a length field, so that we easily\r
1203            can skip past them. */\r
1204         c += opts[c + 1];\r
1205       }\r
1206     }\r
1207   }\r
1208 }\r
1209 #endif /* LWIP_TCP */\r
1210 \r
1211 \r