Lorcan Smith
/
Enet_SPI
SNMP agent attached to SPI slave
Embed:
(wiki syntax)
Show/hide line numbers
tcp_in.c
Go to the documentation of this file.
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.dataptr = p->payload; 00295 inseg.p = p; 00296 inseg.tcphdr = tcphdr; 00297 00298 recv_data = NULL; 00299 recv_flags = 0; 00300 00301 /* If there is data which was previously "refused" by upper layer */ 00302 if (pcb->refused_data != NULL) { 00303 /* Notify again application with data previously received. */ 00304 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n")); 00305 TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err); 00306 if (err == ERR_OK) { 00307 pcb->refused_data = NULL; 00308 } else { 00309 /* if err == ERR_ABRT, 'pcb' is already deallocated */ 00310 /* drop incoming packets, because pcb is "full" */ 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 if (pcb->flags & TF_RXCLOSED) { 00350 /* received data although already closed -> abort (send RST) to 00351 notify the remote host that not all data has been processed */ 00352 pbuf_free(recv_data); 00353 tcp_abort(pcb); 00354 goto aborted; 00355 } 00356 if (flags & TCP_PSH) { 00357 recv_data->flags |= PBUF_FLAG_PUSH; 00358 } 00359 00360 /* Notify application that data has been received. */ 00361 TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); 00362 if (err == ERR_ABRT) { 00363 goto aborted; 00364 } 00365 00366 /* If the upper layer can't receive this data, store it */ 00367 if (err != ERR_OK) { 00368 pcb->refused_data = recv_data; 00369 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n")); 00370 } 00371 } 00372 00373 /* If a FIN segment was received, we call the callback 00374 function with a NULL buffer to indicate EOF. */ 00375 if (recv_flags & TF_GOT_FIN) { 00376 /* correct rcv_wnd as the application won't call tcp_recved() 00377 for the FIN's seqno */ 00378 if (pcb->rcv_wnd != TCP_WND) { 00379 pcb->rcv_wnd++; 00380 } 00381 TCP_EVENT_CLOSED(pcb, err); 00382 if (err == ERR_ABRT) { 00383 goto aborted; 00384 } 00385 } 00386 00387 tcp_input_pcb = NULL; 00388 /* Try to send something out. */ 00389 tcp_output(pcb); 00390 #if TCP_INPUT_DEBUG 00391 #if TCP_DEBUG 00392 tcp_debug_print_state(pcb->state); 00393 #endif /* TCP_DEBUG */ 00394 #endif /* TCP_INPUT_DEBUG */ 00395 } 00396 } 00397 /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()). 00398 Below this line, 'pcb' may not be dereferenced! */ 00399 aborted: 00400 tcp_input_pcb = NULL; 00401 recv_data = NULL; 00402 00403 /* give up our reference to inseg.p */ 00404 if (inseg.p != NULL) 00405 { 00406 pbuf_free(inseg.p); 00407 inseg.p = NULL; 00408 } 00409 } else { 00410 00411 /* If no matching PCB was found, send a TCP RST (reset) to the 00412 sender. */ 00413 LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n")); 00414 if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { 00415 TCP_STATS_INC(tcp.proterr); 00416 TCP_STATS_INC(tcp.drop); 00417 tcp_rst(ackno, seqno + tcplen, 00418 ip_current_dest_addr(), ip_current_src_addr(), 00419 tcphdr->dest, tcphdr->src); 00420 } 00421 pbuf_free(p); 00422 } 00423 00424 LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); 00425 PERF_STOP("tcp_input"); 00426 } 00427 00428 /** 00429 * Called by tcp_input() when a segment arrives for a listening 00430 * connection (from tcp_input()). 00431 * 00432 * @param pcb the tcp_pcb_listen for which a segment arrived 00433 * @return ERR_OK if the segment was processed 00434 * another err_t on error 00435 * 00436 * @note the return value is not (yet?) used in tcp_input() 00437 * @note the segment which arrived is saved in global variables, therefore only the pcb 00438 * involved is passed as a parameter to this function 00439 */ 00440 static err_t 00441 tcp_listen_input(struct tcp_pcb_listen *pcb) 00442 { 00443 struct tcp_pcb *npcb; 00444 err_t rc; 00445 00446 /* In the LISTEN state, we check for incoming SYN segments, 00447 creates a new PCB, and responds with a SYN|ACK. */ 00448 if (flags & TCP_ACK) { 00449 /* For incoming segments with the ACK flag set, respond with a 00450 RST. */ 00451 LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); 00452 tcp_rst(ackno + 1, seqno + tcplen, 00453 ip_current_dest_addr(), ip_current_src_addr(), 00454 tcphdr->dest, tcphdr->src); 00455 } else if (flags & TCP_SYN) { 00456 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); 00457 #if TCP_LISTEN_BACKLOG 00458 if (pcb->accepts_pending >= pcb->backlog) { 00459 LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest)); 00460 return ERR_ABRT; 00461 } 00462 #endif /* TCP_LISTEN_BACKLOG */ 00463 npcb = tcp_alloc(pcb->prio); 00464 /* If a new PCB could not be created (probably due to lack of memory), 00465 we don't do anything, but rely on the sender will retransmit the 00466 SYN at a time when we have more memory available. */ 00467 if (npcb == NULL) { 00468 LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); 00469 TCP_STATS_INC(tcp.memerr); 00470 return ERR_MEM; 00471 } 00472 #if TCP_LISTEN_BACKLOG 00473 pcb->accepts_pending++; 00474 #endif /* TCP_LISTEN_BACKLOG */ 00475 /* Set up the new PCB. */ 00476 ip_addr_copy(npcb->local_ip, current_iphdr_dest); 00477 npcb->local_port = pcb->local_port; 00478 ip_addr_copy(npcb->remote_ip, current_iphdr_src); 00479 npcb->remote_port = tcphdr->src; 00480 npcb->state = SYN_RCVD; 00481 npcb->rcv_nxt = seqno + 1; 00482 npcb->rcv_ann_right_edge = npcb->rcv_nxt; 00483 npcb->snd_wnd = tcphdr->wnd; 00484 npcb->ssthresh = npcb->snd_wnd; 00485 npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ 00486 npcb->callback_arg = pcb->callback_arg; 00487 #if LWIP_CALLBACK_API 00488 npcb->accept = pcb->accept; 00489 #endif /* LWIP_CALLBACK_API */ 00490 /* inherit socket options */ 00491 npcb->so_options = pcb->so_options & SOF_INHERITED; 00492 /* Register the new PCB so that we can begin receiving segments 00493 for it. */ 00494 TCP_REG(&tcp_active_pcbs, npcb); 00495 00496 /* Parse any options in the SYN. */ 00497 tcp_parseopt(npcb); 00498 #if TCP_CALCULATE_EFF_SEND_MSS 00499 npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip)); 00500 #endif /* TCP_CALCULATE_EFF_SEND_MSS */ 00501 00502 snmp_inc_tcppassiveopens(); 00503 00504 /* Send a SYN|ACK together with the MSS option. */ 00505 rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK); 00506 if (rc != ERR_OK) { 00507 tcp_abandon(npcb, 0); 00508 return rc; 00509 } 00510 return tcp_output(npcb); 00511 } 00512 return ERR_OK; 00513 } 00514 00515 /** 00516 * Called by tcp_input() when a segment arrives for a connection in 00517 * TIME_WAIT. 00518 * 00519 * @param pcb the tcp_pcb for which a segment arrived 00520 * 00521 * @note the segment which arrived is saved in global variables, therefore only the pcb 00522 * involved is passed as a parameter to this function 00523 */ 00524 static err_t 00525 tcp_timewait_input(struct tcp_pcb *pcb) 00526 { 00527 /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */ 00528 /* RFC 793 3.9 Event Processing - Segment Arrives: 00529 * - first check sequence number - we skip that one in TIME_WAIT (always 00530 * acceptable since we only send ACKs) 00531 * - second check the RST bit (... return) */ 00532 if (flags & TCP_RST) { 00533 return ERR_OK; 00534 } 00535 /* - fourth, check the SYN bit, */ 00536 if (flags & TCP_SYN) { 00537 /* If an incoming segment is not acceptable, an acknowledgment 00538 should be sent in reply */ 00539 if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) { 00540 /* If the SYN is in the window it is an error, send a reset */ 00541 tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), 00542 tcphdr->dest, tcphdr->src); 00543 return ERR_OK; 00544 } 00545 } else if (flags & TCP_FIN) { 00546 /* - eighth, check the FIN bit: Remain in the TIME-WAIT state. 00547 Restart the 2 MSL time-wait timeout.*/ 00548 pcb->tmr = tcp_ticks; 00549 } 00550 00551 if ((tcplen > 0)) { 00552 /* Acknowledge data, FIN or out-of-window SYN */ 00553 pcb->flags |= TF_ACK_NOW; 00554 return tcp_output(pcb); 00555 } 00556 return ERR_OK; 00557 } 00558 00559 /** 00560 * Implements the TCP state machine. Called by tcp_input. In some 00561 * states tcp_receive() is called to receive data. The tcp_seg 00562 * argument will be freed by the caller (tcp_input()) unless the 00563 * recv_data pointer in the pcb is set. 00564 * 00565 * @param pcb the tcp_pcb for which a segment arrived 00566 * 00567 * @note the segment which arrived is saved in global variables, therefore only the pcb 00568 * involved is passed as a parameter to this function 00569 */ 00570 static err_t 00571 tcp_process(struct tcp_pcb *pcb) 00572 { 00573 struct tcp_seg *rseg; 00574 u8_t acceptable = 0; 00575 err_t err; 00576 00577 err = ERR_OK; 00578 00579 /* Process incoming RST segments. */ 00580 if (flags & TCP_RST) { 00581 /* First, determine if the reset is acceptable. */ 00582 if (pcb->state == SYN_SENT) { 00583 if (ackno == pcb->snd_nxt) { 00584 acceptable = 1; 00585 } 00586 } else { 00587 if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, 00588 pcb->rcv_nxt+pcb->rcv_wnd)) { 00589 acceptable = 1; 00590 } 00591 } 00592 00593 if (acceptable) { 00594 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n")); 00595 LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED); 00596 recv_flags |= TF_RESET; 00597 pcb->flags &= ~TF_ACK_DELAY; 00598 return ERR_RST; 00599 } else { 00600 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", 00601 seqno, pcb->rcv_nxt)); 00602 LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", 00603 seqno, pcb->rcv_nxt)); 00604 return ERR_OK; 00605 } 00606 } 00607 00608 if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { 00609 /* Cope with new connection attempt after remote end crashed */ 00610 tcp_ack_now(pcb); 00611 return ERR_OK; 00612 } 00613 00614 if ((pcb->flags & TF_RXCLOSED) == 0) { 00615 /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */ 00616 pcb->tmr = tcp_ticks; 00617 } 00618 pcb->keep_cnt_sent = 0; 00619 00620 tcp_parseopt(pcb); 00621 00622 /* Do different things depending on the TCP state. */ 00623 switch (pcb->state) { 00624 case SYN_SENT: 00625 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno, 00626 pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno))); 00627 /* received SYN ACK with expected sequence number? */ 00628 if ((flags & TCP_ACK) && (flags & TCP_SYN) 00629 && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) { 00630 pcb->snd_buf++; 00631 pcb->rcv_nxt = seqno + 1; 00632 pcb->rcv_ann_right_edge = pcb->rcv_nxt; 00633 pcb->lastack = ackno; 00634 pcb->snd_wnd = tcphdr->wnd; 00635 pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */ 00636 pcb->state = ESTABLISHED; 00637 00638 #if TCP_CALCULATE_EFF_SEND_MSS 00639 pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip)); 00640 #endif /* TCP_CALCULATE_EFF_SEND_MSS */ 00641 00642 /* Set ssthresh again after changing pcb->mss (already set in tcp_connect 00643 * but for the default value of pcb->mss) */ 00644 pcb->ssthresh = pcb->mss * 10; 00645 00646 pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss); 00647 LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0)); 00648 --pcb->snd_queuelen; 00649 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen)); 00650 rseg = pcb->unacked; 00651 pcb->unacked = rseg->next; 00652 00653 /* If there's nothing left to acknowledge, stop the retransmit 00654 timer, otherwise reset it to start again */ 00655 if(pcb->unacked == NULL) 00656 pcb->rtime = -1; 00657 else { 00658 pcb->rtime = 0; 00659 pcb->nrtx = 0; 00660 } 00661 00662 tcp_seg_free(rseg); 00663 00664 /* Call the user specified function to call when sucessfully 00665 * connected. */ 00666 TCP_EVENT_CONNECTED(pcb, ERR_OK, err); 00667 if (err == ERR_ABRT) { 00668 return ERR_ABRT; 00669 } 00670 tcp_ack_now(pcb); 00671 } 00672 /* received ACK? possibly a half-open connection */ 00673 else if (flags & TCP_ACK) { 00674 /* send a RST to bring the other side in a non-synchronized state. */ 00675 tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), 00676 tcphdr->dest, tcphdr->src); 00677 } 00678 break; 00679 case SYN_RCVD: 00680 if (flags & TCP_ACK) { 00681 /* expected ACK number? */ 00682 if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) { 00683 u16_t old_cwnd; 00684 pcb->state = ESTABLISHED; 00685 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); 00686 #if LWIP_CALLBACK_API 00687 LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL); 00688 #endif 00689 /* Call the accept function. */ 00690 TCP_EVENT_ACCEPT(pcb, ERR_OK, err); 00691 if (err != ERR_OK) { 00692 /* If the accept function returns with an error, we abort 00693 * the connection. */ 00694 /* Already aborted? */ 00695 if (err != ERR_ABRT) { 00696 tcp_abort(pcb); 00697 } 00698 return ERR_ABRT; 00699 } 00700 old_cwnd = pcb->cwnd; 00701 /* If there was any data contained within this ACK, 00702 * we'd better pass it on to the application as well. */ 00703 tcp_receive(pcb); 00704 00705 /* Prevent ACK for SYN to generate a sent event */ 00706 if (pcb->acked != 0) { 00707 pcb->acked--; 00708 } 00709 00710 pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss); 00711 00712 if (recv_flags & TF_GOT_FIN) { 00713 tcp_ack_now(pcb); 00714 pcb->state = CLOSE_WAIT; 00715 } 00716 } else { 00717 /* incorrect ACK number, send RST */ 00718 tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), 00719 tcphdr->dest, tcphdr->src); 00720 } 00721 } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { 00722 /* Looks like another copy of the SYN - retransmit our SYN-ACK */ 00723 tcp_rexmit(pcb); 00724 } 00725 break; 00726 case CLOSE_WAIT: 00727 /* FALLTHROUGH */ 00728 case ESTABLISHED: 00729 tcp_receive(pcb); 00730 if (recv_flags & TF_GOT_FIN) { /* passive close */ 00731 tcp_ack_now(pcb); 00732 pcb->state = CLOSE_WAIT; 00733 } 00734 break; 00735 case FIN_WAIT_1: 00736 tcp_receive(pcb); 00737 if (recv_flags & TF_GOT_FIN) { 00738 if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { 00739 LWIP_DEBUGF(TCP_DEBUG, 00740 ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); 00741 tcp_ack_now(pcb); 00742 tcp_pcb_purge(pcb); 00743 TCP_RMV(&tcp_active_pcbs, pcb); 00744 pcb->state = TIME_WAIT; 00745 TCP_REG(&tcp_tw_pcbs, pcb); 00746 } else { 00747 tcp_ack_now(pcb); 00748 pcb->state = CLOSING; 00749 } 00750 } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { 00751 pcb->state = FIN_WAIT_2; 00752 } 00753 break; 00754 case FIN_WAIT_2: 00755 tcp_receive(pcb); 00756 if (recv_flags & TF_GOT_FIN) { 00757 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); 00758 tcp_ack_now(pcb); 00759 tcp_pcb_purge(pcb); 00760 TCP_RMV(&tcp_active_pcbs, pcb); 00761 pcb->state = TIME_WAIT; 00762 TCP_REG(&tcp_tw_pcbs, pcb); 00763 } 00764 break; 00765 case CLOSING: 00766 tcp_receive(pcb); 00767 if (flags & TCP_ACK && ackno == pcb->snd_nxt) { 00768 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); 00769 tcp_pcb_purge(pcb); 00770 TCP_RMV(&tcp_active_pcbs, pcb); 00771 pcb->state = TIME_WAIT; 00772 TCP_REG(&tcp_tw_pcbs, pcb); 00773 } 00774 break; 00775 case LAST_ACK: 00776 tcp_receive(pcb); 00777 if (flags & TCP_ACK && ackno == pcb->snd_nxt) { 00778 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); 00779 /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */ 00780 recv_flags |= TF_CLOSED; 00781 } 00782 break; 00783 default: 00784 break; 00785 } 00786 return ERR_OK; 00787 } 00788 00789 #if TCP_QUEUE_OOSEQ 00790 /** 00791 * Insert segment into the list (segments covered with new one will be deleted) 00792 * 00793 * Called from tcp_receive() 00794 */ 00795 static void 00796 tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next) 00797 { 00798 struct tcp_seg *old_seg; 00799 00800 if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { 00801 /* received segment overlaps all following segments */ 00802 tcp_segs_free(next); 00803 next = NULL; 00804 } 00805 else { 00806 /* delete some following segments 00807 oos queue may have segments with FIN flag */ 00808 while (next && 00809 TCP_SEQ_GEQ((seqno + cseg->len), 00810 (next->tcphdr->seqno + next->len))) { 00811 /* cseg with FIN already processed */ 00812 if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { 00813 TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN); 00814 } 00815 old_seg = next; 00816 next = next->next; 00817 tcp_seg_free(old_seg); 00818 } 00819 if (next && 00820 TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) { 00821 /* We need to trim the incoming segment. */ 00822 cseg->len = (u16_t)(next->tcphdr->seqno - seqno); 00823 pbuf_realloc(cseg->p, cseg->len); 00824 } 00825 } 00826 cseg->next = next; 00827 } 00828 #endif /* TCP_QUEUE_OOSEQ */ 00829 00830 /** 00831 * Called by tcp_process. Checks if the given segment is an ACK for outstanding 00832 * data, and if so frees the memory of the buffered data. Next, is places the 00833 * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment 00834 * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until 00835 * i it has been removed from the buffer. 00836 * 00837 * If the incoming segment constitutes an ACK for a segment that was used for RTT 00838 * estimation, the RTT is estimated here as well. 00839 * 00840 * Called from tcp_process(). 00841 */ 00842 static void 00843 tcp_receive(struct tcp_pcb *pcb) 00844 { 00845 struct tcp_seg *next; 00846 #if TCP_QUEUE_OOSEQ 00847 struct tcp_seg *prev, *cseg; 00848 #endif /* TCP_QUEUE_OOSEQ */ 00849 struct pbuf *p; 00850 s32_t off; 00851 s16_t m; 00852 u32_t right_wnd_edge; 00853 u16_t new_tot_len; 00854 int found_dupack = 0; 00855 00856 if (flags & TCP_ACK) { 00857 right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2; 00858 00859 /* Update window. */ 00860 if (TCP_SEQ_LT(pcb->snd_wl1, seqno) || 00861 (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) || 00862 (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) { 00863 pcb->snd_wnd = tcphdr->wnd; 00864 pcb->snd_wl1 = seqno; 00865 pcb->snd_wl2 = ackno; 00866 if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) { 00867 pcb->persist_backoff = 0; 00868 } 00869 LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd)); 00870 #if TCP_WND_DEBUG 00871 } else { 00872 if (pcb->snd_wnd != tcphdr->wnd) { 00873 LWIP_DEBUGF(TCP_WND_DEBUG, 00874 ("tcp_receive: no window update lastack %"U32_F" ackno %" 00875 U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n", 00876 pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2)); 00877 } 00878 #endif /* TCP_WND_DEBUG */ 00879 } 00880 00881 /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a 00882 * duplicate ack if: 00883 * 1) It doesn't ACK new data 00884 * 2) length of received packet is zero (i.e. no payload) 00885 * 3) the advertised window hasn't changed 00886 * 4) There is outstanding unacknowledged data (retransmission timer running) 00887 * 5) The ACK is == biggest ACK sequence number so far seen (snd_una) 00888 * 00889 * If it passes all five, should process as a dupack: 00890 * a) dupacks < 3: do nothing 00891 * b) dupacks == 3: fast retransmit 00892 * c) dupacks > 3: increase cwnd 00893 * 00894 * If it only passes 1-3, should reset dupack counter (and add to 00895 * stats, which we don't do in lwIP) 00896 * 00897 * If it only passes 1, should reset dupack counter 00898 * 00899 */ 00900 00901 /* Clause 1 */ 00902 if (TCP_SEQ_LEQ(ackno, pcb->lastack)) { 00903 pcb->acked = 0; 00904 /* Clause 2 */ 00905 if (tcplen == 0) { 00906 /* Clause 3 */ 00907 if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){ 00908 /* Clause 4 */ 00909 if (pcb->rtime >= 0) { 00910 /* Clause 5 */ 00911 if (pcb->lastack == ackno) { 00912 found_dupack = 1; 00913 if (pcb->dupacks + 1 > pcb->dupacks) 00914 ++pcb->dupacks; 00915 if (pcb->dupacks > 3) { 00916 /* Inflate the congestion window, but not if it means that 00917 the value overflows. */ 00918 if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { 00919 pcb->cwnd += pcb->mss; 00920 } 00921 } else if (pcb->dupacks == 3) { 00922 /* Do fast retransmit */ 00923 tcp_rexmit_fast(pcb); 00924 } 00925 } 00926 } 00927 } 00928 } 00929 /* If Clause (1) or more is true, but not a duplicate ack, reset 00930 * count of consecutive duplicate acks */ 00931 if (!found_dupack) { 00932 pcb->dupacks = 0; 00933 } 00934 } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){ 00935 /* We come here when the ACK acknowledges new data. */ 00936 00937 /* Reset the "IN Fast Retransmit" flag, since we are no longer 00938 in fast retransmit. Also reset the congestion window to the 00939 slow start threshold. */ 00940 if (pcb->flags & TF_INFR) { 00941 pcb->flags &= ~TF_INFR; 00942 pcb->cwnd = pcb->ssthresh; 00943 } 00944 00945 /* Reset the number of retransmissions. */ 00946 pcb->nrtx = 0; 00947 00948 /* Reset the retransmission time-out. */ 00949 pcb->rto = (pcb->sa >> 3) + pcb->sv; 00950 00951 /* Update the send buffer space. Diff between the two can never exceed 64K? */ 00952 pcb->acked = (u16_t)(ackno - pcb->lastack); 00953 00954 pcb->snd_buf += pcb->acked; 00955 00956 /* Reset the fast retransmit variables. */ 00957 pcb->dupacks = 0; 00958 pcb->lastack = ackno; 00959 00960 /* Update the congestion control variables (cwnd and 00961 ssthresh). */ 00962 if (pcb->state >= ESTABLISHED) { 00963 if (pcb->cwnd < pcb->ssthresh) { 00964 if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { 00965 pcb->cwnd += pcb->mss; 00966 } 00967 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd)); 00968 } else { 00969 u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd); 00970 if (new_cwnd > pcb->cwnd) { 00971 pcb->cwnd = new_cwnd; 00972 } 00973 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd)); 00974 } 00975 } 00976 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n", 00977 ackno, 00978 pcb->unacked != NULL? 00979 ntohl(pcb->unacked->tcphdr->seqno): 0, 00980 pcb->unacked != NULL? 00981 ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0)); 00982 00983 /* Remove segment from the unacknowledged list if the incoming 00984 ACK acknowlegdes them. */ 00985 while (pcb->unacked != NULL && 00986 TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) + 00987 TCP_TCPLEN(pcb->unacked), ackno)) { 00988 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n", 00989 ntohl(pcb->unacked->tcphdr->seqno), 00990 ntohl(pcb->unacked->tcphdr->seqno) + 00991 TCP_TCPLEN(pcb->unacked))); 00992 00993 next = pcb->unacked; 00994 pcb->unacked = pcb->unacked->next; 00995 00996 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen)); 00997 LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); 00998 /* Prevent ACK for FIN to generate a sent event */ 00999 if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) { 01000 pcb->acked--; 01001 } 01002 01003 pcb->snd_queuelen -= pbuf_clen(next->p); 01004 tcp_seg_free(next); 01005 01006 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen)); 01007 if (pcb->snd_queuelen != 0) { 01008 LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL || 01009 pcb->unsent != NULL); 01010 } 01011 } 01012 01013 /* If there's nothing left to acknowledge, stop the retransmit 01014 timer, otherwise reset it to start again */ 01015 if(pcb->unacked == NULL) 01016 pcb->rtime = -1; 01017 else 01018 pcb->rtime = 0; 01019 01020 pcb->polltmr = 0; 01021 } else { 01022 /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */ 01023 pcb->acked = 0; 01024 } 01025 01026 /* We go through the ->unsent list to see if any of the segments 01027 on the list are acknowledged by the ACK. This may seem 01028 strange since an "unsent" segment shouldn't be acked. The 01029 rationale is that lwIP puts all outstanding segments on the 01030 ->unsent list after a retransmission, so these segments may 01031 in fact have been sent once. */ 01032 while (pcb->unsent != NULL && 01033 TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + 01034 TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) { 01035 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n", 01036 ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) + 01037 TCP_TCPLEN(pcb->unsent))); 01038 01039 next = pcb->unsent; 01040 pcb->unsent = pcb->unsent->next; 01041 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen)); 01042 LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); 01043 /* Prevent ACK for FIN to generate a sent event */ 01044 if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) { 01045 pcb->acked--; 01046 } 01047 pcb->snd_queuelen -= pbuf_clen(next->p); 01048 tcp_seg_free(next); 01049 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen)); 01050 if (pcb->snd_queuelen != 0) { 01051 LWIP_ASSERT("tcp_receive: valid queue length", 01052 pcb->unacked != NULL || pcb->unsent != NULL); 01053 } 01054 } 01055 /* End of ACK for new data processing. */ 01056 01057 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n", 01058 pcb->rttest, pcb->rtseq, ackno)); 01059 01060 /* RTT estimation calculations. This is done by checking if the 01061 incoming segment acknowledges the segment we use to take a 01062 round-trip time measurement. */ 01063 if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) { 01064 /* diff between this shouldn't exceed 32K since this are tcp timer ticks 01065 and a round-trip shouldn't be that long... */ 01066 m = (s16_t)(tcp_ticks - pcb->rttest); 01067 01068 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n", 01069 m, m * TCP_SLOW_INTERVAL)); 01070 01071 /* This is taken directly from VJs original code in his paper */ 01072 m = m - (pcb->sa >> 3); 01073 pcb->sa += m; 01074 if (m < 0) { 01075 m = -m; 01076 } 01077 m = m - (pcb->sv >> 2); 01078 pcb->sv += m; 01079 pcb->rto = (pcb->sa >> 3) + pcb->sv; 01080 01081 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n", 01082 pcb->rto, pcb->rto * TCP_SLOW_INTERVAL)); 01083 01084 pcb->rttest = 0; 01085 } 01086 } 01087 01088 /* If the incoming segment contains data, we must process it 01089 further. */ 01090 if (tcplen > 0) { 01091 /* This code basically does three things: 01092 01093 +) If the incoming segment contains data that is the next 01094 in-sequence data, this data is passed to the application. This 01095 might involve trimming the first edge of the data. The rcv_nxt 01096 variable and the advertised window are adjusted. 01097 01098 +) If the incoming segment has data that is above the next 01099 sequence number expected (->rcv_nxt), the segment is placed on 01100 the ->ooseq queue. This is done by finding the appropriate 01101 place in the ->ooseq queue (which is ordered by sequence 01102 number) and trim the segment in both ends if needed. An 01103 immediate ACK is sent to indicate that we received an 01104 out-of-sequence segment. 01105 01106 +) Finally, we check if the first segment on the ->ooseq queue 01107 now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If 01108 rcv_nxt > ooseq->seqno, we must trim the first edge of the 01109 segment on ->ooseq before we adjust rcv_nxt. The data in the 01110 segments that are now on sequence are chained onto the 01111 incoming segment so that we only need to call the application 01112 once. 01113 */ 01114 01115 /* First, we check if we must trim the first edge. We have to do 01116 this if the sequence number of the incoming segment is less 01117 than rcv_nxt, and the sequence number plus the length of the 01118 segment is larger than rcv_nxt. */ 01119 /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){ 01120 if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/ 01121 if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){ 01122 /* Trimming the first edge is done by pushing the payload 01123 pointer in the pbuf downwards. This is somewhat tricky since 01124 we do not want to discard the full contents of the pbuf up to 01125 the new starting point of the data since we have to keep the 01126 TCP header which is present in the first pbuf in the chain. 01127 01128 What is done is really quite a nasty hack: the first pbuf in 01129 the pbuf chain is pointed to by inseg.p. Since we need to be 01130 able to deallocate the whole pbuf, we cannot change this 01131 inseg.p pointer to point to any of the later pbufs in the 01132 chain. Instead, we point the ->payload pointer in the first 01133 pbuf to data in one of the later pbufs. We also set the 01134 inseg.data pointer to point to the right place. This way, the 01135 ->p pointer will still point to the first pbuf, but the 01136 ->p->payload pointer will point to data in another pbuf. 01137 01138 After we are done with adjusting the pbuf pointers we must 01139 adjust the ->data pointer in the seg and the segment 01140 length.*/ 01141 01142 off = pcb->rcv_nxt - seqno; 01143 p = inseg.p; 01144 LWIP_ASSERT("inseg.p != NULL", inseg.p); 01145 LWIP_ASSERT("insane offset!", (off < 0x7fff)); 01146 if (inseg.p->len < off) { 01147 LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off)); 01148 new_tot_len = (u16_t)(inseg.p->tot_len - off); 01149 while (p->len < off) { 01150 off -= p->len; 01151 /* KJM following line changed (with addition of new_tot_len var) 01152 to fix bug #9076 01153 inseg.p->tot_len -= p->len; */ 01154 p->tot_len = new_tot_len; 01155 p->len = 0; 01156 p = p->next; 01157 } 01158 if(pbuf_header(p, (s16_t)-off)) { 01159 /* Do we need to cope with this failing? Assert for now */ 01160 LWIP_ASSERT("pbuf_header failed", 0); 01161 } 01162 } else { 01163 if(pbuf_header(inseg.p, (s16_t)-off)) { 01164 /* Do we need to cope with this failing? Assert for now */ 01165 LWIP_ASSERT("pbuf_header failed", 0); 01166 } 01167 } 01168 /* KJM following line changed to use p->payload rather than inseg->p->payload 01169 to fix bug #9076 */ 01170 inseg.dataptr = p->payload; 01171 inseg.len -= (u16_t)(pcb->rcv_nxt - seqno); 01172 inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; 01173 } 01174 else { 01175 if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){ 01176 /* the whole segment is < rcv_nxt */ 01177 /* must be a duplicate of a packet that has already been correctly handled */ 01178 01179 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno)); 01180 tcp_ack_now(pcb); 01181 } 01182 } 01183 01184 /* The sequence number must be within the window (above rcv_nxt 01185 and below rcv_nxt + rcv_wnd) in order to be further 01186 processed. */ 01187 if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, 01188 pcb->rcv_nxt + pcb->rcv_wnd - 1)){ 01189 if (pcb->rcv_nxt == seqno) { 01190 /* The incoming segment is the next in sequence. We check if 01191 we have to trim the end of the segment and update rcv_nxt 01192 and pass the data to the application. */ 01193 tcplen = TCP_TCPLEN(&inseg); 01194 01195 if (tcplen > pcb->rcv_wnd) { 01196 LWIP_DEBUGF(TCP_INPUT_DEBUG, 01197 ("tcp_receive: other end overran receive window" 01198 "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", 01199 seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); 01200 if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { 01201 /* Must remove the FIN from the header as we're trimming 01202 * that byte of sequence-space from the packet */ 01203 TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN); 01204 } 01205 /* Adjust length of segment to fit in the window. */ 01206 inseg.len = pcb->rcv_wnd; 01207 if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { 01208 inseg.len -= 1; 01209 } 01210 pbuf_realloc(inseg.p, inseg.len); 01211 tcplen = TCP_TCPLEN(&inseg); 01212 LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", 01213 (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); 01214 } 01215 #if TCP_QUEUE_OOSEQ 01216 /* Received in-sequence data, adjust ooseq data if: 01217 - FIN has been received or 01218 - inseq overlaps with ooseq */ 01219 if (pcb->ooseq != NULL) { 01220 if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { 01221 LWIP_DEBUGF(TCP_INPUT_DEBUG, 01222 ("tcp_receive: received in-order FIN, binning ooseq queue\n")); 01223 /* Received in-order FIN means anything that was received 01224 * out of order must now have been received in-order, so 01225 * bin the ooseq queue */ 01226 while (pcb->ooseq != NULL) { 01227 struct tcp_seg *old_ooseq = pcb->ooseq; 01228 pcb->ooseq = pcb->ooseq->next; 01229 tcp_seg_free(old_ooseq); 01230 } 01231 } 01232 else { 01233 next = pcb->ooseq; 01234 /* Remove all segments on ooseq that are covered by inseg already. 01235 * FIN is copied from ooseq to inseg if present. */ 01236 while (next && 01237 TCP_SEQ_GEQ(seqno + tcplen, 01238 next->tcphdr->seqno + next->len)) { 01239 /* inseg cannot have FIN here (already processed above) */ 01240 if (TCPH_FLAGS(next->tcphdr) & TCP_FIN && 01241 (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) { 01242 TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN); 01243 tcplen = TCP_TCPLEN(&inseg); 01244 } 01245 prev = next; 01246 next = next->next; 01247 tcp_seg_free(prev); 01248 } 01249 /* Now trim right side of inseg if it overlaps with the first 01250 * segment on ooseq */ 01251 if (next && 01252 TCP_SEQ_GT(seqno + tcplen, 01253 next->tcphdr->seqno)) { 01254 /* inseg cannot have FIN here (already processed above) */ 01255 inseg.len = (u16_t)(next->tcphdr->seqno - seqno); 01256 if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { 01257 inseg.len -= 1; 01258 } 01259 pbuf_realloc(inseg.p, inseg.len); 01260 tcplen = TCP_TCPLEN(&inseg); 01261 LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n", 01262 (seqno + tcplen) == next->tcphdr->seqno); 01263 } 01264 pcb->ooseq = next; 01265 } 01266 } 01267 #endif /* TCP_QUEUE_OOSEQ */ 01268 01269 pcb->rcv_nxt = seqno + tcplen; 01270 01271 /* Update the receiver's (our) window. */ 01272 LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen); 01273 pcb->rcv_wnd -= tcplen; 01274 01275 tcp_update_rcv_ann_wnd(pcb); 01276 01277 /* If there is data in the segment, we make preparations to 01278 pass this up to the application. The ->recv_data variable 01279 is used for holding the pbuf that goes to the 01280 application. The code for reassembling out-of-sequence data 01281 chains its data on this pbuf as well. 01282 01283 If the segment was a FIN, we set the TF_GOT_FIN flag that will 01284 be used to indicate to the application that the remote side has 01285 closed its end of the connection. */ 01286 if (inseg.p->tot_len > 0) { 01287 recv_data = inseg.p; 01288 /* Since this pbuf now is the responsibility of the 01289 application, we delete our reference to it so that we won't 01290 (mistakingly) deallocate it. */ 01291 inseg.p = NULL; 01292 } 01293 if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { 01294 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n")); 01295 recv_flags |= TF_GOT_FIN; 01296 } 01297 01298 #if TCP_QUEUE_OOSEQ 01299 /* We now check if we have segments on the ->ooseq queue that 01300 are now in sequence. */ 01301 while (pcb->ooseq != NULL && 01302 pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) { 01303 01304 cseg = pcb->ooseq; 01305 seqno = pcb->ooseq->tcphdr->seqno; 01306 01307 pcb->rcv_nxt += TCP_TCPLEN(cseg); 01308 LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n", 01309 pcb->rcv_wnd >= TCP_TCPLEN(cseg)); 01310 pcb->rcv_wnd -= TCP_TCPLEN(cseg); 01311 01312 tcp_update_rcv_ann_wnd(pcb); 01313 01314 if (cseg->p->tot_len > 0) { 01315 /* Chain this pbuf onto the pbuf that we will pass to 01316 the application. */ 01317 if (recv_data) { 01318 pbuf_cat(recv_data, cseg->p); 01319 } else { 01320 recv_data = cseg->p; 01321 } 01322 cseg->p = NULL; 01323 } 01324 if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { 01325 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n")); 01326 recv_flags |= TF_GOT_FIN; 01327 if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */ 01328 pcb->state = CLOSE_WAIT; 01329 } 01330 } 01331 01332 pcb->ooseq = cseg->next; 01333 tcp_seg_free(cseg); 01334 } 01335 #endif /* TCP_QUEUE_OOSEQ */ 01336 01337 01338 /* Acknowledge the segment(s). */ 01339 tcp_ack(pcb); 01340 01341 } else { 01342 /* We get here if the incoming segment is out-of-sequence. */ 01343 tcp_send_empty_ack(pcb); 01344 #if TCP_QUEUE_OOSEQ 01345 /* We queue the segment on the ->ooseq queue. */ 01346 if (pcb->ooseq == NULL) { 01347 pcb->ooseq = tcp_seg_copy(&inseg); 01348 } else { 01349 /* If the queue is not empty, we walk through the queue and 01350 try to find a place where the sequence number of the 01351 incoming segment is between the sequence numbers of the 01352 previous and the next segment on the ->ooseq queue. That is 01353 the place where we put the incoming segment. If needed, we 01354 trim the second edges of the previous and the incoming 01355 segment so that it will fit into the sequence. 01356 01357 If the incoming segment has the same sequence number as a 01358 segment on the ->ooseq queue, we discard the segment that 01359 contains less data. */ 01360 01361 prev = NULL; 01362 for(next = pcb->ooseq; next != NULL; next = next->next) { 01363 if (seqno == next->tcphdr->seqno) { 01364 /* The sequence number of the incoming segment is the 01365 same as the sequence number of the segment on 01366 ->ooseq. We check the lengths to see which one to 01367 discard. */ 01368 if (inseg.len > next->len) { 01369 /* The incoming segment is larger than the old 01370 segment. We replace some segments with the new 01371 one. */ 01372 cseg = tcp_seg_copy(&inseg); 01373 if (cseg != NULL) { 01374 if (prev != NULL) { 01375 prev->next = cseg; 01376 } else { 01377 pcb->ooseq = cseg; 01378 } 01379 tcp_oos_insert_segment(cseg, next); 01380 } 01381 break; 01382 } else { 01383 /* Either the lenghts are the same or the incoming 01384 segment was smaller than the old one; in either 01385 case, we ditch the incoming segment. */ 01386 break; 01387 } 01388 } else { 01389 if (prev == NULL) { 01390 if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) { 01391 /* The sequence number of the incoming segment is lower 01392 than the sequence number of the first segment on the 01393 queue. We put the incoming segment first on the 01394 queue. */ 01395 cseg = tcp_seg_copy(&inseg); 01396 if (cseg != NULL) { 01397 pcb->ooseq = cseg; 01398 tcp_oos_insert_segment(cseg, next); 01399 } 01400 break; 01401 } 01402 } else { 01403 /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) && 01404 TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/ 01405 if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) { 01406 /* The sequence number of the incoming segment is in 01407 between the sequence numbers of the previous and 01408 the next segment on ->ooseq. We trim trim the previous 01409 segment, delete next segments that included in received segment 01410 and trim received, if needed. */ 01411 cseg = tcp_seg_copy(&inseg); 01412 if (cseg != NULL) { 01413 if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) { 01414 /* We need to trim the prev segment. */ 01415 prev->len = (u16_t)(seqno - prev->tcphdr->seqno); 01416 pbuf_realloc(prev->p, prev->len); 01417 } 01418 prev->next = cseg; 01419 tcp_oos_insert_segment(cseg, next); 01420 } 01421 break; 01422 } 01423 } 01424 /* If the "next" segment is the last segment on the 01425 ooseq queue, we add the incoming segment to the end 01426 of the list. */ 01427 if (next->next == NULL && 01428 TCP_SEQ_GT(seqno, next->tcphdr->seqno)) { 01429 if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { 01430 /* segment "next" already contains all data */ 01431 break; 01432 } 01433 next->next = tcp_seg_copy(&inseg); 01434 if (next->next != NULL) { 01435 if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) { 01436 /* We need to trim the last segment. */ 01437 next->len = (u16_t)(seqno - next->tcphdr->seqno); 01438 pbuf_realloc(next->p, next->len); 01439 } 01440 /* check if the remote side overruns our receive window */ 01441 if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) { 01442 LWIP_DEBUGF(TCP_INPUT_DEBUG, 01443 ("tcp_receive: other end overran receive window" 01444 "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", 01445 seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); 01446 if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) { 01447 /* Must remove the FIN from the header as we're trimming 01448 * that byte of sequence-space from the packet */ 01449 TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN); 01450 } 01451 /* Adjust length of segment to fit in the window. */ 01452 next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno; 01453 pbuf_realloc(next->next->p, next->next->len); 01454 tcplen = TCP_TCPLEN(next->next); 01455 LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", 01456 (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); 01457 } 01458 } 01459 break; 01460 } 01461 } 01462 prev = next; 01463 } 01464 } 01465 #endif /* TCP_QUEUE_OOSEQ */ 01466 01467 } 01468 } else { 01469 /* The incoming segment is not withing the window. */ 01470 tcp_send_empty_ack(pcb); 01471 } 01472 } else { 01473 /* Segments with length 0 is taken care of here. Segments that 01474 fall out of the window are ACKed. */ 01475 /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) || 01476 TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/ 01477 if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){ 01478 tcp_ack_now(pcb); 01479 } 01480 } 01481 } 01482 01483 /** 01484 * Parses the options contained in the incoming segment. 01485 * 01486 * Called from tcp_listen_input() and tcp_process(). 01487 * Currently, only the MSS option is supported! 01488 * 01489 * @param pcb the tcp_pcb for which a segment arrived 01490 */ 01491 static void 01492 tcp_parseopt(struct tcp_pcb *pcb) 01493 { 01494 u16_t c, max_c; 01495 u16_t mss; 01496 u8_t *opts, opt; 01497 #if LWIP_TCP_TIMESTAMPS 01498 u32_t tsval; 01499 #endif 01500 01501 opts = (u8_t *)tcphdr + TCP_HLEN; 01502 01503 /* Parse the TCP MSS option, if present. */ 01504 if(TCPH_HDRLEN(tcphdr) > 0x5) { 01505 max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2; 01506 for (c = 0; c < max_c; ) { 01507 opt = opts[c]; 01508 switch (opt) { 01509 case 0x00: 01510 /* End of options. */ 01511 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n")); 01512 return; 01513 case 0x01: 01514 /* NOP option. */ 01515 ++c; 01516 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n")); 01517 break; 01518 case 0x02: 01519 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n")); 01520 if (opts[c + 1] != 0x04 || c + 0x04 > max_c) { 01521 /* Bad length */ 01522 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); 01523 return; 01524 } 01525 /* An MSS option with the right option length. */ 01526 mss = (opts[c + 2] << 8) | opts[c + 3]; 01527 /* Limit the mss to the configured TCP_MSS and prevent division by zero */ 01528 pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss; 01529 /* Advance to next option */ 01530 c += 0x04; 01531 break; 01532 #if LWIP_TCP_TIMESTAMPS 01533 case 0x08: 01534 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n")); 01535 if (opts[c + 1] != 0x0A || c + 0x0A > max_c) { 01536 /* Bad length */ 01537 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); 01538 return; 01539 } 01540 /* TCP timestamp option with valid length */ 01541 tsval = (opts[c+2]) | (opts[c+3] << 8) | 01542 (opts[c+4] << 16) | (opts[c+5] << 24); 01543 if (flags & TCP_SYN) { 01544 pcb->ts_recent = ntohl(tsval); 01545 pcb->flags |= TF_TIMESTAMP; 01546 } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) { 01547 pcb->ts_recent = ntohl(tsval); 01548 } 01549 /* Advance to next option */ 01550 c += 0x0A; 01551 break; 01552 #endif 01553 default: 01554 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n")); 01555 if (opts[c + 1] == 0) { 01556 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); 01557 /* If the length field is zero, the options are malformed 01558 and we don't process them further. */ 01559 return; 01560 } 01561 /* All other options have a length field, so that we easily 01562 can skip past them. */ 01563 c += opts[c + 1]; 01564 } 01565 } 01566 } 01567 } 01568 01569 #endif /* LWIP_TCP */
Generated on Tue Jul 12 2022 19:17:30 by 1.7.2