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