Deprecated fork of old network stack source from github. Please use official library instead: https://mbed.org/users/mbed_official/code/EthernetInterface/
tcp_in.c
00001 /** 00002 * @file 00003 * Transmission Control Protocol, incoming traffic 00004 * 00005 * The input processing functions of the TCP layer. 00006 * 00007 * These functions are generally called in the order (ip_input() ->) 00008 * tcp_input() -> * tcp_process() -> tcp_receive() (-> application). 00009 * 00010 */ 00011 00012 /* 00013 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 00014 * All rights reserved. 00015 * 00016 * Redistribution and use in source and binary forms, with or without modification, 00017 * are permitted provided that the following conditions are met: 00018 * 00019 * 1. Redistributions of source code must retain the above copyright notice, 00020 * this list of conditions and the following disclaimer. 00021 * 2. Redistributions in binary form must reproduce the above copyright notice, 00022 * this list of conditions and the following disclaimer in the documentation 00023 * and/or other materials provided with the distribution. 00024 * 3. The name of the author may not be used to endorse or promote products 00025 * derived from this software without specific prior written permission. 00026 * 00027 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00028 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00029 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00030 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00031 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00032 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00033 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00034 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00035 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00036 * OF SUCH DAMAGE. 00037 * 00038 * This file is part of the lwIP TCP/IP stack. 00039 * 00040 * Author: Adam Dunkels <adam@sics.se> 00041 * 00042 */ 00043 00044 #include "lwip/opt.h" 00045 00046 #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ 00047 00048 #include "lwip/tcp_impl.h" 00049 #include "lwip/def.h" 00050 #include "lwip/ip_addr.h" 00051 #include "lwip/netif.h" 00052 #include "lwip/mem.h" 00053 #include "lwip/memp.h" 00054 #include "lwip/inet_chksum.h" 00055 #include "lwip/stats.h" 00056 #include "lwip/snmp.h" 00057 #include "arch/perf.h" 00058 00059 /* These variables are global to all functions involved in the input 00060 processing of TCP segments. They are set by the tcp_input() 00061 function. */ 00062 static struct tcp_seg inseg; 00063 static struct tcp_hdr *tcphdr; 00064 static struct ip_hdr *iphdr; 00065 static u32_t seqno, ackno; 00066 static u8_t flags; 00067 static u16_t tcplen; 00068 00069 static u8_t recv_flags; 00070 static struct pbuf *recv_data; 00071 00072 struct tcp_pcb *tcp_input_pcb; 00073 00074 /* Forward declarations. */ 00075 static err_t tcp_process(struct tcp_pcb *pcb); 00076 static void tcp_receive(struct tcp_pcb *pcb); 00077 static void tcp_parseopt(struct tcp_pcb *pcb); 00078 00079 static err_t tcp_listen_input(struct tcp_pcb_listen *pcb); 00080 static err_t tcp_timewait_input(struct tcp_pcb *pcb); 00081 00082 /** 00083 * The initial input processing of TCP. It verifies the TCP header, demultiplexes 00084 * the segment between the PCBs and passes it on to tcp_process(), which implements 00085 * the TCP finite state machine. This function is called by the IP layer (in 00086 * ip_input()). 00087 * 00088 * @param p received TCP segment to process (p->payload pointing to the IP header) 00089 * @param inp network interface on which this segment was received 00090 */ 00091 void 00092 tcp_input(struct pbuf *p, struct netif *inp) 00093 { 00094 struct tcp_pcb *pcb, *prev; 00095 struct tcp_pcb_listen *lpcb; 00096 #if SO_REUSE 00097 struct tcp_pcb *lpcb_prev = NULL; 00098 struct tcp_pcb_listen *lpcb_any = NULL; 00099 #endif /* SO_REUSE */ 00100 u8_t hdrlen; 00101 err_t err; 00102 00103 PERF_START; 00104 00105 TCP_STATS_INC(tcp.recv); 00106 snmp_inc_tcpinsegs(); 00107 00108 iphdr = (struct ip_hdr *)p->payload; 00109 tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4); 00110 00111 #if TCP_INPUT_DEBUG 00112 tcp_debug_print(tcphdr); 00113 #endif 00114 00115 /* remove header from payload */ 00116 if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) { 00117 /* drop short packets */ 00118 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len)); 00119 TCP_STATS_INC(tcp.lenerr); 00120 TCP_STATS_INC(tcp.drop); 00121 snmp_inc_tcpinerrs(); 00122 pbuf_free(p); 00123 return; 00124 } 00125 00126 /* Don't even process incoming broadcasts/multicasts. */ 00127 if (ip_addr_isbroadcast(¤t_iphdr_dest, inp) || 00128 ip_addr_ismulticast(¤t_iphdr_dest)) { 00129 TCP_STATS_INC(tcp.proterr); 00130 TCP_STATS_INC(tcp.drop); 00131 snmp_inc_tcpinerrs(); 00132 pbuf_free(p); 00133 return; 00134 } 00135 00136 #if CHECKSUM_CHECK_TCP 00137 /* Verify TCP checksum. */ 00138 if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), 00139 IP_PROTO_TCP, p->tot_len) != 0) { 00140 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", 00141 inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), 00142 IP_PROTO_TCP, p->tot_len))); 00143 #if TCP_DEBUG 00144 tcp_debug_print(tcphdr); 00145 #endif /* TCP_DEBUG */ 00146 TCP_STATS_INC(tcp.chkerr); 00147 TCP_STATS_INC(tcp.drop); 00148 snmp_inc_tcpinerrs(); 00149 pbuf_free(p); 00150 return; 00151 } 00152 #endif 00153 00154 /* Move the payload pointer in the pbuf so that it points to the 00155 TCP data instead of the TCP header. */ 00156 hdrlen = TCPH_HDRLEN(tcphdr); 00157 if(pbuf_header(p, -(hdrlen * 4))){ 00158 /* drop short packets */ 00159 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n")); 00160 TCP_STATS_INC(tcp.lenerr); 00161 TCP_STATS_INC(tcp.drop); 00162 snmp_inc_tcpinerrs(); 00163 pbuf_free(p); 00164 return; 00165 } 00166 00167 /* Convert fields in TCP header to host byte order. */ 00168 tcphdr->src = ntohs(tcphdr->src); 00169 tcphdr->dest = ntohs(tcphdr->dest); 00170 seqno = tcphdr->seqno = ntohl(tcphdr->seqno); 00171 ackno = tcphdr->ackno = ntohl(tcphdr->ackno); 00172 tcphdr->wnd = ntohs(tcphdr->wnd); 00173 00174 flags = TCPH_FLAGS(tcphdr); 00175 tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0); 00176 00177 /* Demultiplex an incoming segment. First, we check if it is destined 00178 for an active connection. */ 00179 prev = NULL; 00180 00181 00182 for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { 00183 LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); 00184 LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); 00185 LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); 00186 if (pcb->remote_port == tcphdr->src && 00187 pcb->local_port == tcphdr->dest && 00188 ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) && 00189 ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) { 00190 00191 /* Move this PCB to the front of the list so that subsequent 00192 lookups will be faster (we exploit locality in TCP segment 00193 arrivals). */ 00194 LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb); 00195 if (prev != NULL) { 00196 prev->next = pcb->next; 00197 pcb->next = tcp_active_pcbs; 00198 tcp_active_pcbs = pcb; 00199 } 00200 LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb); 00201 break; 00202 } 00203 prev = pcb; 00204 } 00205 00206 if (pcb == NULL) { 00207 /* If it did not go to an active connection, we check the connections 00208 in the TIME-WAIT state. */ 00209 for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { 00210 LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); 00211 if (pcb->remote_port == tcphdr->src && 00212 pcb->local_port == tcphdr->dest && 00213 ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) && 00214 ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) { 00215 /* We don't really care enough to move this PCB to the front 00216 of the list since we are not very likely to receive that 00217 many segments for connections in TIME-WAIT. */ 00218 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n")); 00219 tcp_timewait_input(pcb); 00220 pbuf_free(p); 00221 return; 00222 } 00223 } 00224 00225 /* Finally, if we still did not get a match, we check all PCBs that 00226 are LISTENing for incoming connections. */ 00227 prev = NULL; 00228 for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { 00229 if (lpcb->local_port == tcphdr->dest) { 00230 #if SO_REUSE 00231 if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest)) { 00232 /* found an exact match */ 00233 break; 00234 } else if(ip_addr_isany(&(lpcb->local_ip))) { 00235 /* found an ANY-match */ 00236 lpcb_any = lpcb; 00237 lpcb_prev = prev; 00238 } 00239 #else /* SO_REUSE */ 00240 if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest) || 00241 ip_addr_isany(&(lpcb->local_ip))) { 00242 /* found a match */ 00243 break; 00244 } 00245 #endif /* SO_REUSE */ 00246 } 00247 prev = (struct tcp_pcb *)lpcb; 00248 } 00249 #if SO_REUSE 00250 /* first try specific local IP */ 00251 if (lpcb == NULL) { 00252 /* only pass to ANY if no specific local IP has been found */ 00253 lpcb = lpcb_any; 00254 prev = lpcb_prev; 00255 } 00256 #endif /* SO_REUSE */ 00257 if (lpcb != NULL) { 00258 /* Move this PCB to the front of the list so that subsequent 00259 lookups will be faster (we exploit locality in TCP segment 00260 arrivals). */ 00261 if (prev != NULL) { 00262 ((struct tcp_pcb_listen *)prev)->next = lpcb->next; 00263 /* our successor is the remainder of the listening list */ 00264 lpcb->next = tcp_listen_pcbs.listen_pcbs; 00265 /* put this listening pcb at the head of the listening list */ 00266 tcp_listen_pcbs.listen_pcbs = lpcb; 00267 } 00268 00269 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); 00270 tcp_listen_input(lpcb); 00271 pbuf_free(p); 00272 return; 00273 } 00274 } 00275 00276 #if TCP_INPUT_DEBUG 00277 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags ")); 00278 tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); 00279 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n")); 00280 #endif /* TCP_INPUT_DEBUG */ 00281 00282 00283 if (pcb != NULL) { 00284 /* The incoming segment belongs to a connection. */ 00285 #if TCP_INPUT_DEBUG 00286 #if TCP_DEBUG 00287 tcp_debug_print_state(pcb->state); 00288 #endif /* TCP_DEBUG */ 00289 #endif /* TCP_INPUT_DEBUG */ 00290 00291 /* Set up a tcp_seg structure. */ 00292 inseg.next = NULL; 00293 inseg.len = p->tot_len; 00294 inseg.p = p; 00295 inseg.tcphdr = tcphdr; 00296 00297 recv_data = NULL; 00298 recv_flags = 0; 00299 00300 /* If there is data which was previously "refused" by upper layer */ 00301 if (pcb->refused_data != NULL) { 00302 /* Notify again application with data previously received. */ 00303 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n")); 00304 TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err); 00305 if (err == ERR_OK) { 00306 pcb->refused_data = NULL; 00307 } else if ((err == ERR_ABRT) || (tcplen > 0)) { 00308 /* if err == ERR_ABRT, 'pcb' is already deallocated */ 00309 /* Drop incoming packets because pcb is "full" (only if the incoming 00310 segment contains data). */ 00311 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); 00312 TCP_STATS_INC(tcp.drop); 00313 snmp_inc_tcpinerrs(); 00314 pbuf_free(p); 00315 return; 00316 } 00317 } 00318 tcp_input_pcb = pcb; 00319 err = tcp_process(pcb); 00320 /* A return value of ERR_ABRT means that tcp_abort() was called 00321 and that the pcb has been freed. If so, we don't do anything. */ 00322 if (err != ERR_ABRT) { 00323 if (recv_flags & TF_RESET) { 00324 /* TF_RESET means that the connection was reset by the other 00325 end. We then call the error callback to inform the 00326 application that the connection is dead before we 00327 deallocate the PCB. */ 00328 TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST); 00329 tcp_pcb_remove(&tcp_active_pcbs, pcb); 00330 memp_free(MEMP_TCP_PCB, pcb); 00331 } else if (recv_flags & TF_CLOSED) { 00332 /* The connection has been closed and we will deallocate the 00333 PCB. */ 00334 tcp_pcb_remove(&tcp_active_pcbs, pcb); 00335 memp_free(MEMP_TCP_PCB, pcb); 00336 } else { 00337 err = ERR_OK; 00338 /* If the application has registered a "sent" function to be 00339 called when new send buffer space is available, we call it 00340 now. */ 00341 if (pcb->acked > 0) { 00342 TCP_EVENT_SENT(pcb, pcb->acked, err); 00343 if (err == ERR_ABRT) { 00344 goto aborted; 00345 } 00346 } 00347 00348 if (recv_data != NULL) { 00349 LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL); 00350 if (pcb->flags & TF_RXCLOSED) { 00351 /* received data although already closed -> abort (send RST) to 00352 notify the remote host that not all data has been processed */ 00353 pbuf_free(recv_data); 00354 tcp_abort(pcb); 00355 goto aborted; 00356 } 00357 if (flags & TCP_PSH) { 00358 recv_data->flags |= PBUF_FLAG_PUSH; 00359 } 00360 00361 /* Notify application that data has been received. */ 00362 TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); 00363 if (err == ERR_ABRT) { 00364 goto aborted; 00365 } 00366 00367 /* If the upper layer can't receive this data, store it */ 00368 if (err != ERR_OK) { 00369 pcb->refused_data = recv_data; 00370 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n")); 00371 } 00372 } 00373 00374 /* If a FIN segment was received, we call the callback 00375 function with a NULL buffer to indicate EOF. */ 00376 if (recv_flags & TF_GOT_FIN) { 00377 /* correct rcv_wnd as the application won't call tcp_recved() 00378 for the FIN's seqno */ 00379 if (pcb->rcv_wnd != TCP_WND) { 00380 pcb->rcv_wnd++; 00381 } 00382 TCP_EVENT_CLOSED(pcb, err); 00383 if (err == ERR_ABRT) { 00384 goto aborted; 00385 } 00386 } 00387 00388 tcp_input_pcb = NULL; 00389 /* Try to send something out. */ 00390 tcp_output(pcb); 00391 #if TCP_INPUT_DEBUG 00392 #if TCP_DEBUG 00393 tcp_debug_print_state(pcb->state); 00394 #endif /* TCP_DEBUG */ 00395 #endif /* TCP_INPUT_DEBUG */ 00396 } 00397 } 00398 /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()). 00399 Below this line, 'pcb' may not be dereferenced! */ 00400 aborted: 00401 tcp_input_pcb = NULL; 00402 recv_data = NULL; 00403 00404 /* give up our reference to inseg.p */ 00405 if (inseg.p != NULL) 00406 { 00407 pbuf_free(inseg.p); 00408 inseg.p = NULL; 00409 } 00410 } else { 00411 00412 /* If no matching PCB was found, send a TCP RST (reset) to the 00413 sender. */ 00414 LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n")); 00415 if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { 00416 TCP_STATS_INC(tcp.proterr); 00417 TCP_STATS_INC(tcp.drop); 00418 tcp_rst(ackno, seqno + tcplen, 00419 ip_current_dest_addr(), ip_current_src_addr(), 00420 tcphdr->dest, tcphdr->src); 00421 } 00422 pbuf_free(p); 00423 } 00424 00425 LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); 00426 PERF_STOP("tcp_input"); 00427 } 00428 00429 /** 00430 * Called by tcp_input() when a segment arrives for a listening 00431 * connection (from tcp_input()). 00432 * 00433 * @param pcb the tcp_pcb_listen for which a segment arrived 00434 * @return ERR_OK if the segment was processed 00435 * another err_t on error 00436 * 00437 * @note the return value is not (yet?) used in tcp_input() 00438 * @note the segment which arrived is saved in global variables, therefore only the pcb 00439 * involved is passed as a parameter to this function 00440 */ 00441 static err_t 00442 tcp_listen_input(struct tcp_pcb_listen *pcb) 00443 { 00444 struct tcp_pcb *npcb; 00445 err_t rc; 00446 00447 /* In the LISTEN state, we check for incoming SYN segments, 00448 creates a new PCB, and responds with a SYN|ACK. */ 00449 if (flags & TCP_ACK) { 00450 /* For incoming segments with the ACK flag set, respond with a 00451 RST. */ 00452 LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); 00453 tcp_rst(ackno + 1, seqno + tcplen, 00454 ip_current_dest_addr(), ip_current_src_addr(), 00455 tcphdr->dest, tcphdr->src); 00456 } else if (flags & TCP_SYN) { 00457 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); 00458 #if TCP_LISTEN_BACKLOG 00459 if (pcb->accepts_pending >= pcb->backlog) { 00460 LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest)); 00461 return ERR_ABRT; 00462 } 00463 #endif /* TCP_LISTEN_BACKLOG */ 00464 npcb = tcp_alloc(pcb->prio); 00465 /* If a new PCB could not be created (probably due to lack of memory), 00466 we don't do anything, but rely on the sender will retransmit the 00467 SYN at a time when we have more memory available. */ 00468 if (npcb == NULL) { 00469 LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); 00470 TCP_STATS_INC(tcp.memerr); 00471 return ERR_MEM; 00472 } 00473 #if TCP_LISTEN_BACKLOG 00474 pcb->accepts_pending++; 00475 #endif /* TCP_LISTEN_BACKLOG */ 00476 /* Set up the new PCB. */ 00477 ip_addr_copy(npcb->local_ip, current_iphdr_dest); 00478 npcb->local_port = pcb->local_port; 00479 ip_addr_copy(npcb->remote_ip, current_iphdr_src); 00480 npcb->remote_port = tcphdr->src; 00481 npcb->state = SYN_RCVD; 00482 npcb->rcv_nxt = seqno + 1; 00483 npcb->rcv_ann_right_edge = npcb->rcv_nxt; 00484 npcb->snd_wnd = tcphdr->wnd; 00485 npcb->ssthresh = npcb->snd_wnd; 00486 npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ 00487 npcb->callback_arg = pcb->callback_arg; 00488 #if LWIP_CALLBACK_API 00489 npcb->accept = pcb->accept; 00490 #endif /* LWIP_CALLBACK_API */ 00491 /* inherit socket options */ 00492 npcb->so_options = pcb->so_options & SOF_INHERITED; 00493 /* Register the new PCB so that we can begin receiving segments 00494 for it. */ 00495 TCP_REG(&tcp_active_pcbs, npcb); 00496 00497 /* Parse any options in the SYN. */ 00498 tcp_parseopt(npcb); 00499 #if TCP_CALCULATE_EFF_SEND_MSS 00500 npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip)); 00501 #endif /* TCP_CALCULATE_EFF_SEND_MSS */ 00502 00503 snmp_inc_tcppassiveopens(); 00504 00505 /* Send a SYN|ACK together with the MSS option. */ 00506 rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK); 00507 if (rc != ERR_OK) { 00508 tcp_abandon(npcb, 0); 00509 return rc; 00510 } 00511 return tcp_output(npcb); 00512 } 00513 return ERR_OK; 00514 } 00515 00516 /** 00517 * Called by tcp_input() when a segment arrives for a connection in 00518 * TIME_WAIT. 00519 * 00520 * @param pcb the tcp_pcb for which a segment arrived 00521 * 00522 * @note the segment which arrived is saved in global variables, therefore only the pcb 00523 * involved is passed as a parameter to this function 00524 */ 00525 static err_t 00526 tcp_timewait_input(struct tcp_pcb *pcb) 00527 { 00528 /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */ 00529 /* RFC 793 3.9 Event Processing - Segment Arrives: 00530 * - first check sequence number - we skip that one in TIME_WAIT (always 00531 * acceptable since we only send ACKs) 00532 * - second check the RST bit (... return) */ 00533 if (flags & TCP_RST) { 00534 return ERR_OK; 00535 } 00536 /* - fourth, check the SYN bit, */ 00537 if (flags & TCP_SYN) { 00538 /* If an incoming segment is not acceptable, an acknowledgment 00539 should be sent in reply */ 00540 if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) { 00541 /* If the SYN is in the window it is an error, send a reset */ 00542 tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), 00543 tcphdr->dest, tcphdr->src); 00544 return ERR_OK; 00545 } 00546 } else if (flags & TCP_FIN) { 00547 /* - eighth, check the FIN bit: Remain in the TIME-WAIT state. 00548 Restart the 2 MSL time-wait timeout.*/ 00549 pcb->tmr = tcp_ticks; 00550 } 00551 00552 if ((tcplen > 0)) { 00553 /* Acknowledge data, FIN or out-of-window SYN */ 00554 pcb->flags |= TF_ACK_NOW; 00555 return tcp_output(pcb); 00556 } 00557 return ERR_OK; 00558 } 00559 00560 /** 00561 * Implements the TCP state machine. Called by tcp_input. In some 00562 * states tcp_receive() is called to receive data. The tcp_seg 00563 * argument will be freed by the caller (tcp_input()) unless the 00564 * recv_data pointer in the pcb is set. 00565 * 00566 * @param pcb the tcp_pcb for which a segment arrived 00567 * 00568 * @note the segment which arrived is saved in global variables, therefore only the pcb 00569 * involved is passed as a parameter to this function 00570 */ 00571 static err_t 00572 tcp_process(struct tcp_pcb *pcb) 00573 { 00574 struct tcp_seg *rseg; 00575 u8_t acceptable = 0; 00576 err_t err; 00577 00578 err = ERR_OK; 00579 00580 /* Process incoming RST segments. */ 00581 if (flags & TCP_RST) { 00582 /* First, determine if the reset is acceptable. */ 00583 if (pcb->state == SYN_SENT) { 00584 if (ackno == pcb->snd_nxt) { 00585 acceptable = 1; 00586 } 00587 } else { 00588 if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, 00589 pcb->rcv_nxt+pcb->rcv_wnd)) { 00590 acceptable = 1; 00591 } 00592 } 00593 00594 if (acceptable) { 00595 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n")); 00596 LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED); 00597 recv_flags |= TF_RESET; 00598 pcb->flags &= ~TF_ACK_DELAY; 00599 return ERR_RST; 00600 } else { 00601 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", 00602 seqno, pcb->rcv_nxt)); 00603 LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", 00604 seqno, pcb->rcv_nxt)); 00605 return ERR_OK; 00606 } 00607 } 00608 00609 if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { 00610 /* Cope with new connection attempt after remote end crashed */ 00611 tcp_ack_now(pcb); 00612 return ERR_OK; 00613 } 00614 00615 if ((pcb->flags & TF_RXCLOSED) == 0) { 00616 /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */ 00617 pcb->tmr = tcp_ticks; 00618 } 00619 pcb->keep_cnt_sent = 0; 00620 00621 tcp_parseopt(pcb); 00622 00623 /* Do different things depending on the TCP state. */ 00624 switch (pcb->state) { 00625 case SYN_SENT: 00626 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno, 00627 pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno))); 00628 /* received SYN ACK with expected sequence number? */ 00629 if ((flags & TCP_ACK) && (flags & TCP_SYN) 00630 && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) { 00631 pcb->snd_buf++; 00632 pcb->rcv_nxt = seqno + 1; 00633 pcb->rcv_ann_right_edge = pcb->rcv_nxt; 00634 pcb->lastack = ackno; 00635 pcb->snd_wnd = tcphdr->wnd; 00636 pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */ 00637 pcb->state = ESTABLISHED; 00638 00639 #if TCP_CALCULATE_EFF_SEND_MSS 00640 pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip)); 00641 #endif /* TCP_CALCULATE_EFF_SEND_MSS */ 00642 00643 /* Set ssthresh again after changing pcb->mss (already set in tcp_connect 00644 * but for the default value of pcb->mss) */ 00645 pcb->ssthresh = pcb->mss * 10; 00646 00647 pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss); 00648 LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0)); 00649 --pcb->snd_queuelen; 00650 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen)); 00651 rseg = pcb->unacked; 00652 pcb->unacked = rseg->next; 00653 00654 /* If there's nothing left to acknowledge, stop the retransmit 00655 timer, otherwise reset it to start again */ 00656 if(pcb->unacked == NULL) 00657 pcb->rtime = -1; 00658 else { 00659 pcb->rtime = 0; 00660 pcb->nrtx = 0; 00661 } 00662 00663 tcp_seg_free(rseg); 00664 00665 /* Call the user specified function to call when sucessfully 00666 * connected. */ 00667 TCP_EVENT_CONNECTED(pcb, ERR_OK, err); 00668 if (err == ERR_ABRT) { 00669 return ERR_ABRT; 00670 } 00671 tcp_ack_now(pcb); 00672 } 00673 /* received ACK? possibly a half-open connection */ 00674 else if (flags & TCP_ACK) { 00675 /* send a RST to bring the other side in a non-synchronized state. */ 00676 tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), 00677 tcphdr->dest, tcphdr->src); 00678 } 00679 break; 00680 case SYN_RCVD: 00681 if (flags & TCP_ACK) { 00682 /* expected ACK number? */ 00683 if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) { 00684 u16_t old_cwnd; 00685 pcb->state = ESTABLISHED; 00686 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); 00687 #if LWIP_CALLBACK_API 00688 LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL); 00689 #endif 00690 /* Call the accept function. */ 00691 TCP_EVENT_ACCEPT(pcb, ERR_OK, err); 00692 if (err != ERR_OK) { 00693 /* If the accept function returns with an error, we abort 00694 * the connection. */ 00695 /* Already aborted? */ 00696 if (err != ERR_ABRT) { 00697 tcp_abort(pcb); 00698 } 00699 return ERR_ABRT; 00700 } 00701 old_cwnd = pcb->cwnd; 00702 /* If there was any data contained within this ACK, 00703 * we'd better pass it on to the application as well. */ 00704 tcp_receive(pcb); 00705 00706 /* Prevent ACK for SYN to generate a sent event */ 00707 if (pcb->acked != 0) { 00708 pcb->acked--; 00709 } 00710 00711 pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss); 00712 00713 if (recv_flags & TF_GOT_FIN) { 00714 tcp_ack_now(pcb); 00715 pcb->state = CLOSE_WAIT; 00716 } 00717 } else { 00718 /* incorrect ACK number, send RST */ 00719 tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), 00720 tcphdr->dest, tcphdr->src); 00721 } 00722 } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { 00723 /* Looks like another copy of the SYN - retransmit our SYN-ACK */ 00724 tcp_rexmit(pcb); 00725 } 00726 break; 00727 case CLOSE_WAIT: 00728 /* FALLTHROUGH */ 00729 case ESTABLISHED: 00730 tcp_receive(pcb); 00731 if (recv_flags & TF_GOT_FIN) { /* passive close */ 00732 tcp_ack_now(pcb); 00733 pcb->state = CLOSE_WAIT; 00734 } 00735 break; 00736 case FIN_WAIT_1: 00737 tcp_receive(pcb); 00738 if (recv_flags & TF_GOT_FIN) { 00739 if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { 00740 LWIP_DEBUGF(TCP_DEBUG, 00741 ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); 00742 tcp_ack_now(pcb); 00743 tcp_pcb_purge(pcb); 00744 TCP_RMV(&tcp_active_pcbs, pcb); 00745 pcb->state = TIME_WAIT; 00746 TCP_REG(&tcp_tw_pcbs, pcb); 00747 } else { 00748 tcp_ack_now(pcb); 00749 pcb->state = CLOSING; 00750 } 00751 } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { 00752 pcb->state = FIN_WAIT_2; 00753 } 00754 break; 00755 case FIN_WAIT_2: 00756 tcp_receive(pcb); 00757 if (recv_flags & TF_GOT_FIN) { 00758 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); 00759 tcp_ack_now(pcb); 00760 tcp_pcb_purge(pcb); 00761 TCP_RMV(&tcp_active_pcbs, pcb); 00762 pcb->state = TIME_WAIT; 00763 TCP_REG(&tcp_tw_pcbs, pcb); 00764 } 00765 break; 00766 case CLOSING: 00767 tcp_receive(pcb); 00768 if (flags & TCP_ACK && ackno == pcb->snd_nxt) { 00769 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); 00770 tcp_pcb_purge(pcb); 00771 TCP_RMV(&tcp_active_pcbs, pcb); 00772 pcb->state = TIME_WAIT; 00773 TCP_REG(&tcp_tw_pcbs, pcb); 00774 } 00775 break; 00776 case LAST_ACK: 00777 tcp_receive(pcb); 00778 if (flags & TCP_ACK && ackno == pcb->snd_nxt) { 00779 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); 00780 /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */ 00781 recv_flags |= TF_CLOSED; 00782 } 00783 break; 00784 default: 00785 break; 00786 } 00787 return ERR_OK; 00788 } 00789 00790 #if TCP_QUEUE_OOSEQ 00791 /** 00792 * Insert segment into the list (segments covered with new one will be deleted) 00793 * 00794 * Called from tcp_receive() 00795 */ 00796 static void 00797 tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next) 00798 { 00799 struct tcp_seg *old_seg; 00800 00801 if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { 00802 /* received segment overlaps all following segments */ 00803 tcp_segs_free(next); 00804 next = NULL; 00805 } 00806 else { 00807 /* delete some following segments 00808 oos queue may have segments with FIN flag */ 00809 while (next && 00810 TCP_SEQ_GEQ((seqno + cseg->len), 00811 (next->tcphdr->seqno + next->len))) { 00812 /* cseg with FIN already processed */ 00813 if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { 00814 TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN); 00815 } 00816 old_seg = next; 00817 next = next->next; 00818 tcp_seg_free(old_seg); 00819 } 00820 if (next && 00821 TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) { 00822 /* We need to trim the incoming segment. */ 00823 cseg->len = (u16_t)(next->tcphdr->seqno - seqno); 00824 pbuf_realloc(cseg->p, cseg->len); 00825 } 00826 } 00827 cseg->next = next; 00828 } 00829 #endif /* TCP_QUEUE_OOSEQ */ 00830 00831 /** 00832 * Called by tcp_process. Checks if the given segment is an ACK for outstanding 00833 * data, and if so frees the memory of the buffered data. Next, is places the 00834 * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment 00835 * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until 00836 * i it has been removed from the buffer. 00837 * 00838 * If the incoming segment constitutes an ACK for a segment that was used for RTT 00839 * estimation, the RTT is estimated here as well. 00840 * 00841 * Called from tcp_process(). 00842 */ 00843 static void 00844 tcp_receive(struct tcp_pcb *pcb) 00845 { 00846 struct tcp_seg *next; 00847 #if TCP_QUEUE_OOSEQ 00848 struct tcp_seg *prev, *cseg; 00849 #endif /* TCP_QUEUE_OOSEQ */ 00850 struct pbuf *p; 00851 s32_t off; 00852 s16_t m; 00853 u32_t right_wnd_edge; 00854 u16_t new_tot_len; 00855 int found_dupack = 0; 00856 00857 if (flags & TCP_ACK) { 00858 right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2; 00859 00860 /* Update window. */ 00861 if (TCP_SEQ_LT(pcb->snd_wl1, seqno) || 00862 (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) || 00863 (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) { 00864 pcb->snd_wnd = tcphdr->wnd; 00865 pcb->snd_wl1 = seqno; 00866 pcb->snd_wl2 = ackno; 00867 if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) { 00868 pcb->persist_backoff = 0; 00869 } 00870 LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd)); 00871 #if TCP_WND_DEBUG 00872 } else { 00873 if (pcb->snd_wnd != tcphdr->wnd) { 00874 LWIP_DEBUGF(TCP_WND_DEBUG, 00875 ("tcp_receive: no window update lastack %"U32_F" ackno %" 00876 U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n", 00877 pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2)); 00878 } 00879 #endif /* TCP_WND_DEBUG */ 00880 } 00881 00882 /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a 00883 * duplicate ack if: 00884 * 1) It doesn't ACK new data 00885 * 2) length of received packet is zero (i.e. no payload) 00886 * 3) the advertised window hasn't changed 00887 * 4) There is outstanding unacknowledged data (retransmission timer running) 00888 * 5) The ACK is == biggest ACK sequence number so far seen (snd_una) 00889 * 00890 * If it passes all five, should process as a dupack: 00891 * a) dupacks < 3: do nothing 00892 * b) dupacks == 3: fast retransmit 00893 * c) dupacks > 3: increase cwnd 00894 * 00895 * If it only passes 1-3, should reset dupack counter (and add to 00896 * stats, which we don't do in lwIP) 00897 * 00898 * If it only passes 1, should reset dupack counter 00899 * 00900 */ 00901 00902 /* Clause 1 */ 00903 if (TCP_SEQ_LEQ(ackno, pcb->lastack)) { 00904 pcb->acked = 0; 00905 /* Clause 2 */ 00906 if (tcplen == 0) { 00907 /* Clause 3 */ 00908 if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){ 00909 /* Clause 4 */ 00910 if (pcb->rtime >= 0) { 00911 /* Clause 5 */ 00912 if (pcb->lastack == ackno) { 00913 found_dupack = 1; 00914 if (pcb->dupacks + 1 > pcb->dupacks) 00915 ++pcb->dupacks; 00916 if (pcb->dupacks > 3) { 00917 /* Inflate the congestion window, but not if it means that 00918 the value overflows. */ 00919 if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { 00920 pcb->cwnd += pcb->mss; 00921 } 00922 } else if (pcb->dupacks == 3) { 00923 /* Do fast retransmit */ 00924 tcp_rexmit_fast(pcb); 00925 } 00926 } 00927 } 00928 } 00929 } 00930 /* If Clause (1) or more is true, but not a duplicate ack, reset 00931 * count of consecutive duplicate acks */ 00932 if (!found_dupack) { 00933 pcb->dupacks = 0; 00934 } 00935 } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){ 00936 /* We come here when the ACK acknowledges new data. */ 00937 00938 /* Reset the "IN Fast Retransmit" flag, since we are no longer 00939 in fast retransmit. Also reset the congestion window to the 00940 slow start threshold. */ 00941 if (pcb->flags & TF_INFR) { 00942 pcb->flags &= ~TF_INFR; 00943 pcb->cwnd = pcb->ssthresh; 00944 } 00945 00946 /* Reset the number of retransmissions. */ 00947 pcb->nrtx = 0; 00948 00949 /* Reset the retransmission time-out. */ 00950 pcb->rto = (pcb->sa >> 3) + pcb->sv; 00951 00952 /* Update the send buffer space. Diff between the two can never exceed 64K? */ 00953 pcb->acked = (u16_t)(ackno - pcb->lastack); 00954 00955 pcb->snd_buf += pcb->acked; 00956 00957 /* Reset the fast retransmit variables. */ 00958 pcb->dupacks = 0; 00959 pcb->lastack = ackno; 00960 00961 /* Update the congestion control variables (cwnd and 00962 ssthresh). */ 00963 if (pcb->state >= ESTABLISHED) { 00964 if (pcb->cwnd < pcb->ssthresh) { 00965 if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { 00966 pcb->cwnd += pcb->mss; 00967 } 00968 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd)); 00969 } else { 00970 u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd); 00971 if (new_cwnd > pcb->cwnd) { 00972 pcb->cwnd = new_cwnd; 00973 } 00974 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd)); 00975 } 00976 } 00977 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n", 00978 ackno, 00979 pcb->unacked != NULL? 00980 ntohl(pcb->unacked->tcphdr->seqno): 0, 00981 pcb->unacked != NULL? 00982 ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0)); 00983 00984 /* Remove segment from the unacknowledged list if the incoming 00985 ACK acknowlegdes them. */ 00986 while (pcb->unacked != NULL && 00987 TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) + 00988 TCP_TCPLEN(pcb->unacked), ackno)) { 00989 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n", 00990 ntohl(pcb->unacked->tcphdr->seqno), 00991 ntohl(pcb->unacked->tcphdr->seqno) + 00992 TCP_TCPLEN(pcb->unacked))); 00993 00994 next = pcb->unacked; 00995 pcb->unacked = pcb->unacked->next; 00996 00997 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen)); 00998 LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); 00999 /* Prevent ACK for FIN to generate a sent event */ 01000 if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) { 01001 pcb->acked--; 01002 } 01003 01004 pcb->snd_queuelen -= pbuf_clen(next->p); 01005 tcp_seg_free(next); 01006 01007 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen)); 01008 if (pcb->snd_queuelen != 0) { 01009 LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL || 01010 pcb->unsent != NULL); 01011 } 01012 } 01013 01014 /* If there's nothing left to acknowledge, stop the retransmit 01015 timer, otherwise reset it to start again */ 01016 if(pcb->unacked == NULL) 01017 pcb->rtime = -1; 01018 else 01019 pcb->rtime = 0; 01020 01021 pcb->polltmr = 0; 01022 } else { 01023 /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */ 01024 pcb->acked = 0; 01025 } 01026 01027 /* We go through the ->unsent list to see if any of the segments 01028 on the list are acknowledged by the ACK. This may seem 01029 strange since an "unsent" segment shouldn't be acked. The 01030 rationale is that lwIP puts all outstanding segments on the 01031 ->unsent list after a retransmission, so these segments may 01032 in fact have been sent once. */ 01033 while (pcb->unsent != NULL && 01034 TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + 01035 TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) { 01036 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n", 01037 ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) + 01038 TCP_TCPLEN(pcb->unsent))); 01039 01040 next = pcb->unsent; 01041 pcb->unsent = pcb->unsent->next; 01042 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen)); 01043 LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); 01044 /* Prevent ACK for FIN to generate a sent event */ 01045 if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) { 01046 pcb->acked--; 01047 } 01048 pcb->snd_queuelen -= pbuf_clen(next->p); 01049 tcp_seg_free(next); 01050 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen)); 01051 if (pcb->snd_queuelen != 0) { 01052 LWIP_ASSERT("tcp_receive: valid queue length", 01053 pcb->unacked != NULL || pcb->unsent != NULL); 01054 } 01055 } 01056 /* End of ACK for new data processing. */ 01057 01058 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n", 01059 pcb->rttest, pcb->rtseq, ackno)); 01060 01061 /* RTT estimation calculations. This is done by checking if the 01062 incoming segment acknowledges the segment we use to take a 01063 round-trip time measurement. */ 01064 if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) { 01065 /* diff between this shouldn't exceed 32K since this are tcp timer ticks 01066 and a round-trip shouldn't be that long... */ 01067 m = (s16_t)(tcp_ticks - pcb->rttest); 01068 01069 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n", 01070 m, m * TCP_SLOW_INTERVAL)); 01071 01072 /* This is taken directly from VJs original code in his paper */ 01073 m = m - (pcb->sa >> 3); 01074 pcb->sa += m; 01075 if (m < 0) { 01076 m = -m; 01077 } 01078 m = m - (pcb->sv >> 2); 01079 pcb->sv += m; 01080 pcb->rto = (pcb->sa >> 3) + pcb->sv; 01081 01082 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n", 01083 pcb->rto, pcb->rto * TCP_SLOW_INTERVAL)); 01084 01085 pcb->rttest = 0; 01086 } 01087 } 01088 01089 /* If the incoming segment contains data, we must process it 01090 further. */ 01091 if (tcplen > 0) { 01092 /* This code basically does three things: 01093 01094 +) If the incoming segment contains data that is the next 01095 in-sequence data, this data is passed to the application. This 01096 might involve trimming the first edge of the data. The rcv_nxt 01097 variable and the advertised window are adjusted. 01098 01099 +) If the incoming segment has data that is above the next 01100 sequence number expected (->rcv_nxt), the segment is placed on 01101 the ->ooseq queue. This is done by finding the appropriate 01102 place in the ->ooseq queue (which is ordered by sequence 01103 number) and trim the segment in both ends if needed. An 01104 immediate ACK is sent to indicate that we received an 01105 out-of-sequence segment. 01106 01107 +) Finally, we check if the first segment on the ->ooseq queue 01108 now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If 01109 rcv_nxt > ooseq->seqno, we must trim the first edge of the 01110 segment on ->ooseq before we adjust rcv_nxt. The data in the 01111 segments that are now on sequence are chained onto the 01112 incoming segment so that we only need to call the application 01113 once. 01114 */ 01115 01116 /* First, we check if we must trim the first edge. We have to do 01117 this if the sequence number of the incoming segment is less 01118 than rcv_nxt, and the sequence number plus the length of the 01119 segment is larger than rcv_nxt. */ 01120 /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){ 01121 if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/ 01122 if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){ 01123 /* Trimming the first edge is done by pushing the payload 01124 pointer in the pbuf downwards. This is somewhat tricky since 01125 we do not want to discard the full contents of the pbuf up to 01126 the new starting point of the data since we have to keep the 01127 TCP header which is present in the first pbuf in the chain. 01128 01129 What is done is really quite a nasty hack: the first pbuf in 01130 the pbuf chain is pointed to by inseg.p. Since we need to be 01131 able to deallocate the whole pbuf, we cannot change this 01132 inseg.p pointer to point to any of the later pbufs in the 01133 chain. Instead, we point the ->payload pointer in the first 01134 pbuf to data in one of the later pbufs. We also set the 01135 inseg.data pointer to point to the right place. This way, the 01136 ->p pointer will still point to the first pbuf, but the 01137 ->p->payload pointer will point to data in another pbuf. 01138 01139 After we are done with adjusting the pbuf pointers we must 01140 adjust the ->data pointer in the seg and the segment 01141 length.*/ 01142 01143 off = pcb->rcv_nxt - seqno; 01144 p = inseg.p; 01145 LWIP_ASSERT("inseg.p != NULL", inseg.p); 01146 LWIP_ASSERT("insane offset!", (off < 0x7fff)); 01147 if (inseg.p->len < off) { 01148 LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off)); 01149 new_tot_len = (u16_t)(inseg.p->tot_len - off); 01150 while (p->len < off) { 01151 off -= p->len; 01152 /* KJM following line changed (with addition of new_tot_len var) 01153 to fix bug #9076 01154 inseg.p->tot_len -= p->len; */ 01155 p->tot_len = new_tot_len; 01156 p->len = 0; 01157 p = p->next; 01158 } 01159 if(pbuf_header(p, (s16_t)-off)) { 01160 /* Do we need to cope with this failing? Assert for now */ 01161 LWIP_ASSERT("pbuf_header failed", 0); 01162 } 01163 } else { 01164 if(pbuf_header(inseg.p, (s16_t)-off)) { 01165 /* Do we need to cope with this failing? Assert for now */ 01166 LWIP_ASSERT("pbuf_header failed", 0); 01167 } 01168 } 01169 inseg.len -= (u16_t)(pcb->rcv_nxt - seqno); 01170 inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; 01171 } 01172 else { 01173 if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){ 01174 /* the whole segment is < rcv_nxt */ 01175 /* must be a duplicate of a packet that has already been correctly handled */ 01176 01177 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno)); 01178 tcp_ack_now(pcb); 01179 } 01180 } 01181 01182 /* The sequence number must be within the window (above rcv_nxt 01183 and below rcv_nxt + rcv_wnd) in order to be further 01184 processed. */ 01185 if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, 01186 pcb->rcv_nxt + pcb->rcv_wnd - 1)){ 01187 if (pcb->rcv_nxt == seqno) { 01188 /* The incoming segment is the next in sequence. We check if 01189 we have to trim the end of the segment and update rcv_nxt 01190 and pass the data to the application. */ 01191 tcplen = TCP_TCPLEN(&inseg); 01192 01193 if (tcplen > pcb->rcv_wnd) { 01194 LWIP_DEBUGF(TCP_INPUT_DEBUG, 01195 ("tcp_receive: other end overran receive window" 01196 "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", 01197 seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); 01198 if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { 01199 /* Must remove the FIN from the header as we're trimming 01200 * that byte of sequence-space from the packet */ 01201 TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN); 01202 } 01203 /* Adjust length of segment to fit in the window. */ 01204 inseg.len = pcb->rcv_wnd; 01205 if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { 01206 inseg.len -= 1; 01207 } 01208 pbuf_realloc(inseg.p, inseg.len); 01209 tcplen = TCP_TCPLEN(&inseg); 01210 LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", 01211 (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); 01212 } 01213 #if TCP_QUEUE_OOSEQ 01214 /* Received in-sequence data, adjust ooseq data if: 01215 - FIN has been received or 01216 - inseq overlaps with ooseq */ 01217 if (pcb->ooseq != NULL) { 01218 if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { 01219 LWIP_DEBUGF(TCP_INPUT_DEBUG, 01220 ("tcp_receive: received in-order FIN, binning ooseq queue\n")); 01221 /* Received in-order FIN means anything that was received 01222 * out of order must now have been received in-order, so 01223 * bin the ooseq queue */ 01224 while (pcb->ooseq != NULL) { 01225 struct tcp_seg *old_ooseq = pcb->ooseq; 01226 pcb->ooseq = pcb->ooseq->next; 01227 tcp_seg_free(old_ooseq); 01228 } 01229 } 01230 else { 01231 next = pcb->ooseq; 01232 /* Remove all segments on ooseq that are covered by inseg already. 01233 * FIN is copied from ooseq to inseg if present. */ 01234 while (next && 01235 TCP_SEQ_GEQ(seqno + tcplen, 01236 next->tcphdr->seqno + next->len)) { 01237 /* inseg cannot have FIN here (already processed above) */ 01238 if (TCPH_FLAGS(next->tcphdr) & TCP_FIN && 01239 (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) { 01240 TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN); 01241 tcplen = TCP_TCPLEN(&inseg); 01242 } 01243 prev = next; 01244 next = next->next; 01245 tcp_seg_free(prev); 01246 } 01247 /* Now trim right side of inseg if it overlaps with the first 01248 * segment on ooseq */ 01249 if (next && 01250 TCP_SEQ_GT(seqno + tcplen, 01251 next->tcphdr->seqno)) { 01252 /* inseg cannot have FIN here (already processed above) */ 01253 inseg.len = (u16_t)(next->tcphdr->seqno - seqno); 01254 if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { 01255 inseg.len -= 1; 01256 } 01257 pbuf_realloc(inseg.p, inseg.len); 01258 tcplen = TCP_TCPLEN(&inseg); 01259 LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n", 01260 (seqno + tcplen) == next->tcphdr->seqno); 01261 } 01262 pcb->ooseq = next; 01263 } 01264 } 01265 #endif /* TCP_QUEUE_OOSEQ */ 01266 01267 pcb->rcv_nxt = seqno + tcplen; 01268 01269 /* Update the receiver's (our) window. */ 01270 LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen); 01271 pcb->rcv_wnd -= tcplen; 01272 01273 tcp_update_rcv_ann_wnd(pcb); 01274 01275 /* If there is data in the segment, we make preparations to 01276 pass this up to the application. The ->recv_data variable 01277 is used for holding the pbuf that goes to the 01278 application. The code for reassembling out-of-sequence data 01279 chains its data on this pbuf as well. 01280 01281 If the segment was a FIN, we set the TF_GOT_FIN flag that will 01282 be used to indicate to the application that the remote side has 01283 closed its end of the connection. */ 01284 if (inseg.p->tot_len > 0) { 01285 recv_data = inseg.p; 01286 /* Since this pbuf now is the responsibility of the 01287 application, we delete our reference to it so that we won't 01288 (mistakingly) deallocate it. */ 01289 inseg.p = NULL; 01290 } 01291 if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { 01292 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n")); 01293 recv_flags |= TF_GOT_FIN; 01294 } 01295 01296 #if TCP_QUEUE_OOSEQ 01297 /* We now check if we have segments on the ->ooseq queue that 01298 are now in sequence. */ 01299 while (pcb->ooseq != NULL && 01300 pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) { 01301 01302 cseg = pcb->ooseq; 01303 seqno = pcb->ooseq->tcphdr->seqno; 01304 01305 pcb->rcv_nxt += TCP_TCPLEN(cseg); 01306 LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n", 01307 pcb->rcv_wnd >= TCP_TCPLEN(cseg)); 01308 pcb->rcv_wnd -= TCP_TCPLEN(cseg); 01309 01310 tcp_update_rcv_ann_wnd(pcb); 01311 01312 if (cseg->p->tot_len > 0) { 01313 /* Chain this pbuf onto the pbuf that we will pass to 01314 the application. */ 01315 if (recv_data) { 01316 pbuf_cat(recv_data, cseg->p); 01317 } else { 01318 recv_data = cseg->p; 01319 } 01320 cseg->p = NULL; 01321 } 01322 if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { 01323 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n")); 01324 recv_flags |= TF_GOT_FIN; 01325 if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */ 01326 pcb->state = CLOSE_WAIT; 01327 } 01328 } 01329 01330 pcb->ooseq = cseg->next; 01331 tcp_seg_free(cseg); 01332 } 01333 #endif /* TCP_QUEUE_OOSEQ */ 01334 01335 01336 /* Acknowledge the segment(s). */ 01337 tcp_ack(pcb); 01338 01339 } else { 01340 /* We get here if the incoming segment is out-of-sequence. */ 01341 tcp_send_empty_ack(pcb); 01342 #if TCP_QUEUE_OOSEQ 01343 /* We queue the segment on the ->ooseq queue. */ 01344 if (pcb->ooseq == NULL) { 01345 pcb->ooseq = tcp_seg_copy(&inseg); 01346 } else { 01347 /* If the queue is not empty, we walk through the queue and 01348 try to find a place where the sequence number of the 01349 incoming segment is between the sequence numbers of the 01350 previous and the next segment on the ->ooseq queue. That is 01351 the place where we put the incoming segment. If needed, we 01352 trim the second edges of the previous and the incoming 01353 segment so that it will fit into the sequence. 01354 01355 If the incoming segment has the same sequence number as a 01356 segment on the ->ooseq queue, we discard the segment that 01357 contains less data. */ 01358 01359 prev = NULL; 01360 for(next = pcb->ooseq; next != NULL; next = next->next) { 01361 if (seqno == next->tcphdr->seqno) { 01362 /* The sequence number of the incoming segment is the 01363 same as the sequence number of the segment on 01364 ->ooseq. We check the lengths to see which one to 01365 discard. */ 01366 if (inseg.len > next->len) { 01367 /* The incoming segment is larger than the old 01368 segment. We replace some segments with the new 01369 one. */ 01370 cseg = tcp_seg_copy(&inseg); 01371 if (cseg != NULL) { 01372 if (prev != NULL) { 01373 prev->next = cseg; 01374 } else { 01375 pcb->ooseq = cseg; 01376 } 01377 tcp_oos_insert_segment(cseg, next); 01378 } 01379 break; 01380 } else { 01381 /* Either the lenghts are the same or the incoming 01382 segment was smaller than the old one; in either 01383 case, we ditch the incoming segment. */ 01384 break; 01385 } 01386 } else { 01387 if (prev == NULL) { 01388 if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) { 01389 /* The sequence number of the incoming segment is lower 01390 than the sequence number of the first segment on the 01391 queue. We put the incoming segment first on the 01392 queue. */ 01393 cseg = tcp_seg_copy(&inseg); 01394 if (cseg != NULL) { 01395 pcb->ooseq = cseg; 01396 tcp_oos_insert_segment(cseg, next); 01397 } 01398 break; 01399 } 01400 } else { 01401 /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) && 01402 TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/ 01403 if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) { 01404 /* The sequence number of the incoming segment is in 01405 between the sequence numbers of the previous and 01406 the next segment on ->ooseq. We trim trim the previous 01407 segment, delete next segments that included in received segment 01408 and trim received, if needed. */ 01409 cseg = tcp_seg_copy(&inseg); 01410 if (cseg != NULL) { 01411 if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) { 01412 /* We need to trim the prev segment. */ 01413 prev->len = (u16_t)(seqno - prev->tcphdr->seqno); 01414 pbuf_realloc(prev->p, prev->len); 01415 } 01416 prev->next = cseg; 01417 tcp_oos_insert_segment(cseg, next); 01418 } 01419 break; 01420 } 01421 } 01422 /* If the "next" segment is the last segment on the 01423 ooseq queue, we add the incoming segment to the end 01424 of the list. */ 01425 if (next->next == NULL && 01426 TCP_SEQ_GT(seqno, next->tcphdr->seqno)) { 01427 if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { 01428 /* segment "next" already contains all data */ 01429 break; 01430 } 01431 next->next = tcp_seg_copy(&inseg); 01432 if (next->next != NULL) { 01433 if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) { 01434 /* We need to trim the last segment. */ 01435 next->len = (u16_t)(seqno - next->tcphdr->seqno); 01436 pbuf_realloc(next->p, next->len); 01437 } 01438 /* check if the remote side overruns our receive window */ 01439 if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) { 01440 LWIP_DEBUGF(TCP_INPUT_DEBUG, 01441 ("tcp_receive: other end overran receive window" 01442 "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", 01443 seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); 01444 if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) { 01445 /* Must remove the FIN from the header as we're trimming 01446 * that byte of sequence-space from the packet */ 01447 TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN); 01448 } 01449 /* Adjust length of segment to fit in the window. */ 01450 next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno; 01451 pbuf_realloc(next->next->p, next->next->len); 01452 tcplen = TCP_TCPLEN(next->next); 01453 LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", 01454 (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); 01455 } 01456 } 01457 break; 01458 } 01459 } 01460 prev = next; 01461 } 01462 } 01463 #endif /* TCP_QUEUE_OOSEQ */ 01464 01465 } 01466 } else { 01467 /* The incoming segment is not withing the window. */ 01468 tcp_send_empty_ack(pcb); 01469 } 01470 } else { 01471 /* Segments with length 0 is taken care of here. Segments that 01472 fall out of the window are ACKed. */ 01473 /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) || 01474 TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/ 01475 if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){ 01476 tcp_ack_now(pcb); 01477 } 01478 } 01479 } 01480 01481 /** 01482 * Parses the options contained in the incoming segment. 01483 * 01484 * Called from tcp_listen_input() and tcp_process(). 01485 * Currently, only the MSS option is supported! 01486 * 01487 * @param pcb the tcp_pcb for which a segment arrived 01488 */ 01489 static void 01490 tcp_parseopt(struct tcp_pcb *pcb) 01491 { 01492 u16_t c, max_c; 01493 u16_t mss; 01494 u8_t *opts, opt; 01495 #if LWIP_TCP_TIMESTAMPS 01496 u32_t tsval; 01497 #endif 01498 01499 opts = (u8_t *)tcphdr + TCP_HLEN; 01500 01501 /* Parse the TCP MSS option, if present. */ 01502 if(TCPH_HDRLEN(tcphdr) > 0x5) { 01503 max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2; 01504 for (c = 0; c < max_c; ) { 01505 opt = opts[c]; 01506 switch (opt) { 01507 case 0x00: 01508 /* End of options. */ 01509 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n")); 01510 return; 01511 case 0x01: 01512 /* NOP option. */ 01513 ++c; 01514 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n")); 01515 break; 01516 case 0x02: 01517 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n")); 01518 if (opts[c + 1] != 0x04 || c + 0x04 > max_c) { 01519 /* Bad length */ 01520 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); 01521 return; 01522 } 01523 /* An MSS option with the right option length. */ 01524 mss = (opts[c + 2] << 8) | opts[c + 3]; 01525 /* Limit the mss to the configured TCP_MSS and prevent division by zero */ 01526 pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss; 01527 /* Advance to next option */ 01528 c += 0x04; 01529 break; 01530 #if LWIP_TCP_TIMESTAMPS 01531 case 0x08: 01532 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n")); 01533 if (opts[c + 1] != 0x0A || c + 0x0A > max_c) { 01534 /* Bad length */ 01535 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); 01536 return; 01537 } 01538 /* TCP timestamp option with valid length */ 01539 tsval = (opts[c+2]) | (opts[c+3] << 8) | 01540 (opts[c+4] << 16) | (opts[c+5] << 24); 01541 if (flags & TCP_SYN) { 01542 pcb->ts_recent = ntohl(tsval); 01543 pcb->flags |= TF_TIMESTAMP; 01544 } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) { 01545 pcb->ts_recent = ntohl(tsval); 01546 } 01547 /* Advance to next option */ 01548 c += 0x0A; 01549 break; 01550 #endif 01551 default: 01552 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n")); 01553 if (opts[c + 1] == 0) { 01554 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); 01555 /* If the length field is zero, the options are malformed 01556 and we don't process them further. */ 01557 return; 01558 } 01559 /* All other options have a length field, so that we easily 01560 can skip past them. */ 01561 c += opts[c + 1]; 01562 } 01563 } 01564 } 01565 } 01566 01567 #endif /* LWIP_TCP */
Generated on Tue Jul 12 2022 23:10:20 by 1.7.2