1195972f6Sopenharmony_ci/** 2195972f6Sopenharmony_ci * @file 3195972f6Sopenharmony_ci * Transmission Control Protocol, incoming traffic 4195972f6Sopenharmony_ci * 5195972f6Sopenharmony_ci * The input processing functions of the TCP layer. 6195972f6Sopenharmony_ci * 7195972f6Sopenharmony_ci * These functions are generally called in the order (ip_input() ->) 8195972f6Sopenharmony_ci * tcp_input() -> * tcp_process() -> tcp_receive() (-> application). 9195972f6Sopenharmony_ci * 10195972f6Sopenharmony_ci */ 11195972f6Sopenharmony_ci 12195972f6Sopenharmony_ci/* 13195972f6Sopenharmony_ci * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 14195972f6Sopenharmony_ci * All rights reserved. 15195972f6Sopenharmony_ci * 16195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 17195972f6Sopenharmony_ci * are permitted provided that the following conditions are met: 18195972f6Sopenharmony_ci * 19195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, 20195972f6Sopenharmony_ci * this list of conditions and the following disclaimer. 21195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, 22195972f6Sopenharmony_ci * this list of conditions and the following disclaimer in the documentation 23195972f6Sopenharmony_ci * and/or other materials provided with the distribution. 24195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products 25195972f6Sopenharmony_ci * derived from this software without specific prior written permission. 26195972f6Sopenharmony_ci * 27195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 28195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 29195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 30195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 31195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 32195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 35195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 36195972f6Sopenharmony_ci * OF SUCH DAMAGE. 37195972f6Sopenharmony_ci * 38195972f6Sopenharmony_ci * This file is part of the lwIP TCP/IP stack. 39195972f6Sopenharmony_ci * 40195972f6Sopenharmony_ci * Author: Adam Dunkels <adam@sics.se> 41195972f6Sopenharmony_ci * 42195972f6Sopenharmony_ci */ 43195972f6Sopenharmony_ci 44195972f6Sopenharmony_ci#include "lwip/opt.h" 45195972f6Sopenharmony_ci 46195972f6Sopenharmony_ci#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ 47195972f6Sopenharmony_ci 48195972f6Sopenharmony_ci#include "lwip/priv/tcp_priv.h" 49195972f6Sopenharmony_ci#include "lwip/def.h" 50195972f6Sopenharmony_ci#include "lwip/ip_addr.h" 51195972f6Sopenharmony_ci#include "lwip/netif.h" 52195972f6Sopenharmony_ci#include "lwip/mem.h" 53195972f6Sopenharmony_ci#include "lwip/memp.h" 54195972f6Sopenharmony_ci#include "lwip/inet_chksum.h" 55195972f6Sopenharmony_ci#include "lwip/stats.h" 56195972f6Sopenharmony_ci#include "lwip/ip6.h" 57195972f6Sopenharmony_ci#include "lwip/ip6_addr.h" 58195972f6Sopenharmony_ci#if LWIP_ND6_TCP_REACHABILITY_HINTS 59195972f6Sopenharmony_ci#include "lwip/nd6.h" 60195972f6Sopenharmony_ci#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ 61195972f6Sopenharmony_ci 62195972f6Sopenharmony_ci#include <string.h> 63195972f6Sopenharmony_ci 64195972f6Sopenharmony_ci#ifdef LWIP_HOOK_FILENAME 65195972f6Sopenharmony_ci#include LWIP_HOOK_FILENAME 66195972f6Sopenharmony_ci#endif 67195972f6Sopenharmony_ci 68195972f6Sopenharmony_ci/** Initial CWND calculation as defined RFC 2581 */ 69195972f6Sopenharmony_ci#define LWIP_TCP_CALC_INITIAL_CWND(mss) ((tcpwnd_size_t)LWIP_MIN((4U * (mss)), LWIP_MAX((2U * (mss)), 4380U))) 70195972f6Sopenharmony_ci 71195972f6Sopenharmony_ci/* These variables are global to all functions involved in the input 72195972f6Sopenharmony_ci processing of TCP segments. They are set by the tcp_input() 73195972f6Sopenharmony_ci function. */ 74195972f6Sopenharmony_cistatic struct tcp_seg inseg; 75195972f6Sopenharmony_cistatic struct tcp_hdr *tcphdr; 76195972f6Sopenharmony_cistatic u16_t tcphdr_optlen; 77195972f6Sopenharmony_cistatic u16_t tcphdr_opt1len; 78195972f6Sopenharmony_cistatic u8_t *tcphdr_opt2; 79195972f6Sopenharmony_cistatic u16_t tcp_optidx; 80195972f6Sopenharmony_cistatic u32_t seqno, ackno; 81195972f6Sopenharmony_cistatic tcpwnd_size_t recv_acked; 82195972f6Sopenharmony_cistatic u16_t tcplen; 83195972f6Sopenharmony_cistatic u8_t flags; 84195972f6Sopenharmony_ci 85195972f6Sopenharmony_cistatic u8_t recv_flags; 86195972f6Sopenharmony_cistatic struct pbuf *recv_data; 87195972f6Sopenharmony_ci 88195972f6Sopenharmony_cistruct tcp_pcb *tcp_input_pcb; 89195972f6Sopenharmony_ci 90195972f6Sopenharmony_ci/* Forward declarations. */ 91195972f6Sopenharmony_cistatic err_t tcp_process(struct tcp_pcb *pcb); 92195972f6Sopenharmony_cistatic void tcp_receive(struct tcp_pcb *pcb); 93195972f6Sopenharmony_cistatic void tcp_parseopt(struct tcp_pcb *pcb); 94195972f6Sopenharmony_ci 95195972f6Sopenharmony_cistatic void tcp_listen_input(struct tcp_pcb_listen *pcb); 96195972f6Sopenharmony_cistatic void tcp_timewait_input(struct tcp_pcb *pcb); 97195972f6Sopenharmony_ci 98195972f6Sopenharmony_cistatic int tcp_input_delayed_close(struct tcp_pcb *pcb); 99195972f6Sopenharmony_ci 100195972f6Sopenharmony_ci#if LWIP_TCP_SACK_OUT 101195972f6Sopenharmony_cistatic void tcp_add_sack(struct tcp_pcb *pcb, u32_t left, u32_t right); 102195972f6Sopenharmony_cistatic void tcp_remove_sacks_lt(struct tcp_pcb *pcb, u32_t seq); 103195972f6Sopenharmony_ci#if defined(TCP_OOSEQ_BYTES_LIMIT) || defined(TCP_OOSEQ_PBUFS_LIMIT) 104195972f6Sopenharmony_cistatic void tcp_remove_sacks_gt(struct tcp_pcb *pcb, u32_t seq); 105195972f6Sopenharmony_ci#endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */ 106195972f6Sopenharmony_ci#endif /* LWIP_TCP_SACK_OUT */ 107195972f6Sopenharmony_ci 108195972f6Sopenharmony_ci/** 109195972f6Sopenharmony_ci * The initial input processing of TCP. It verifies the TCP header, demultiplexes 110195972f6Sopenharmony_ci * the segment between the PCBs and passes it on to tcp_process(), which implements 111195972f6Sopenharmony_ci * the TCP finite state machine. This function is called by the IP layer (in 112195972f6Sopenharmony_ci * ip_input()). 113195972f6Sopenharmony_ci * 114195972f6Sopenharmony_ci * @param p received TCP segment to process (p->payload pointing to the TCP header) 115195972f6Sopenharmony_ci * @param inp network interface on which this segment was received 116195972f6Sopenharmony_ci */ 117195972f6Sopenharmony_civoid 118195972f6Sopenharmony_citcp_input(struct pbuf *p, struct netif *inp) 119195972f6Sopenharmony_ci{ 120195972f6Sopenharmony_ci struct tcp_pcb *pcb, *prev; 121195972f6Sopenharmony_ci struct tcp_pcb_listen *lpcb; 122195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 123195972f6Sopenharmony_ci struct net_group *group = get_net_group_from_netif(inp); 124195972f6Sopenharmony_ci#endif 125195972f6Sopenharmony_ci#if SO_REUSE 126195972f6Sopenharmony_ci struct tcp_pcb *lpcb_prev = NULL; 127195972f6Sopenharmony_ci struct tcp_pcb_listen *lpcb_any = NULL; 128195972f6Sopenharmony_ci#endif /* SO_REUSE */ 129195972f6Sopenharmony_ci u8_t hdrlen_bytes; 130195972f6Sopenharmony_ci err_t err; 131195972f6Sopenharmony_ci 132195972f6Sopenharmony_ci LWIP_UNUSED_ARG(inp); 133195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 134195972f6Sopenharmony_ci LWIP_ASSERT("tcp_input: invalid pbuf", p != NULL); 135195972f6Sopenharmony_ci 136195972f6Sopenharmony_ci PERF_START; 137195972f6Sopenharmony_ci 138195972f6Sopenharmony_ci TCP_STATS_INC(tcp.recv); 139195972f6Sopenharmony_ci MIB2_STATS_INC(mib2.tcpinsegs); 140195972f6Sopenharmony_ci 141195972f6Sopenharmony_ci tcphdr = (struct tcp_hdr *)p->payload; 142195972f6Sopenharmony_ci 143195972f6Sopenharmony_ci#if TCP_INPUT_DEBUG 144195972f6Sopenharmony_ci tcp_debug_print(tcphdr); 145195972f6Sopenharmony_ci#endif 146195972f6Sopenharmony_ci 147195972f6Sopenharmony_ci /* Check that TCP header fits in payload */ 148195972f6Sopenharmony_ci if (p->len < TCP_HLEN) { 149195972f6Sopenharmony_ci /* drop short packets */ 150195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len)); 151195972f6Sopenharmony_ci TCP_STATS_INC(tcp.lenerr); 152195972f6Sopenharmony_ci goto dropped; 153195972f6Sopenharmony_ci } 154195972f6Sopenharmony_ci 155195972f6Sopenharmony_ci /* Don't even process incoming broadcasts/multicasts. */ 156195972f6Sopenharmony_ci if (ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()) || 157195972f6Sopenharmony_ci ip_addr_ismulticast(ip_current_dest_addr())) { 158195972f6Sopenharmony_ci TCP_STATS_INC(tcp.proterr); 159195972f6Sopenharmony_ci goto dropped; 160195972f6Sopenharmony_ci } 161195972f6Sopenharmony_ci 162195972f6Sopenharmony_ci#if CHECKSUM_CHECK_TCP 163195972f6Sopenharmony_ci IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_TCP) { 164195972f6Sopenharmony_ci /* Verify TCP checksum. */ 165195972f6Sopenharmony_ci u16_t chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, 166195972f6Sopenharmony_ci ip_current_src_addr(), ip_current_dest_addr()); 167195972f6Sopenharmony_ci if (chksum != 0) { 168195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", 169195972f6Sopenharmony_ci chksum)); 170195972f6Sopenharmony_ci tcp_debug_print(tcphdr); 171195972f6Sopenharmony_ci TCP_STATS_INC(tcp.chkerr); 172195972f6Sopenharmony_ci goto dropped; 173195972f6Sopenharmony_ci } 174195972f6Sopenharmony_ci } 175195972f6Sopenharmony_ci#endif /* CHECKSUM_CHECK_TCP */ 176195972f6Sopenharmony_ci 177195972f6Sopenharmony_ci /* sanity-check header length */ 178195972f6Sopenharmony_ci hdrlen_bytes = TCPH_HDRLEN_BYTES(tcphdr); 179195972f6Sopenharmony_ci if ((hdrlen_bytes < TCP_HLEN) || (hdrlen_bytes > p->tot_len)) { 180195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: invalid header length (%"U16_F")\n", (u16_t)hdrlen_bytes)); 181195972f6Sopenharmony_ci TCP_STATS_INC(tcp.lenerr); 182195972f6Sopenharmony_ci goto dropped; 183195972f6Sopenharmony_ci } 184195972f6Sopenharmony_ci 185195972f6Sopenharmony_ci /* Move the payload pointer in the pbuf so that it points to the 186195972f6Sopenharmony_ci TCP data instead of the TCP header. */ 187195972f6Sopenharmony_ci tcphdr_optlen = (u16_t)(hdrlen_bytes - TCP_HLEN); 188195972f6Sopenharmony_ci tcphdr_opt2 = NULL; 189195972f6Sopenharmony_ci if (p->len >= hdrlen_bytes) { 190195972f6Sopenharmony_ci /* all options are in the first pbuf */ 191195972f6Sopenharmony_ci tcphdr_opt1len = tcphdr_optlen; 192195972f6Sopenharmony_ci pbuf_remove_header(p, hdrlen_bytes); /* cannot fail */ 193195972f6Sopenharmony_ci } else { 194195972f6Sopenharmony_ci u16_t opt2len; 195195972f6Sopenharmony_ci /* TCP header fits into first pbuf, options don't - data is in the next pbuf */ 196195972f6Sopenharmony_ci /* there must be a next pbuf, due to hdrlen_bytes sanity check above */ 197195972f6Sopenharmony_ci LWIP_ASSERT("p->next != NULL", p->next != NULL); 198195972f6Sopenharmony_ci 199195972f6Sopenharmony_ci /* advance over the TCP header (cannot fail) */ 200195972f6Sopenharmony_ci pbuf_remove_header(p, TCP_HLEN); 201195972f6Sopenharmony_ci 202195972f6Sopenharmony_ci /* determine how long the first and second parts of the options are */ 203195972f6Sopenharmony_ci tcphdr_opt1len = p->len; 204195972f6Sopenharmony_ci opt2len = (u16_t)(tcphdr_optlen - tcphdr_opt1len); 205195972f6Sopenharmony_ci 206195972f6Sopenharmony_ci /* options continue in the next pbuf: set p to zero length and hide the 207195972f6Sopenharmony_ci options in the next pbuf (adjusting p->tot_len) */ 208195972f6Sopenharmony_ci pbuf_remove_header(p, tcphdr_opt1len); 209195972f6Sopenharmony_ci 210195972f6Sopenharmony_ci /* check that the options fit in the second pbuf */ 211195972f6Sopenharmony_ci if (opt2len > p->next->len) { 212195972f6Sopenharmony_ci /* drop short packets */ 213195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: options overflow second pbuf (%"U16_F" bytes)\n", p->next->len)); 214195972f6Sopenharmony_ci TCP_STATS_INC(tcp.lenerr); 215195972f6Sopenharmony_ci goto dropped; 216195972f6Sopenharmony_ci } 217195972f6Sopenharmony_ci 218195972f6Sopenharmony_ci /* remember the pointer to the second part of the options */ 219195972f6Sopenharmony_ci tcphdr_opt2 = (u8_t *)p->next->payload; 220195972f6Sopenharmony_ci 221195972f6Sopenharmony_ci /* advance p->next to point after the options, and manually 222195972f6Sopenharmony_ci adjust p->tot_len to keep it consistent with the changed p->next */ 223195972f6Sopenharmony_ci pbuf_remove_header(p->next, opt2len); 224195972f6Sopenharmony_ci p->tot_len = (u16_t)(p->tot_len - opt2len); 225195972f6Sopenharmony_ci 226195972f6Sopenharmony_ci LWIP_ASSERT("p->len == 0", p->len == 0); 227195972f6Sopenharmony_ci LWIP_ASSERT("p->tot_len == p->next->tot_len", p->tot_len == p->next->tot_len); 228195972f6Sopenharmony_ci } 229195972f6Sopenharmony_ci 230195972f6Sopenharmony_ci /* Convert fields in TCP header to host byte order. */ 231195972f6Sopenharmony_ci tcphdr->src = lwip_ntohs(tcphdr->src); 232195972f6Sopenharmony_ci tcphdr->dest = lwip_ntohs(tcphdr->dest); 233195972f6Sopenharmony_ci seqno = tcphdr->seqno = lwip_ntohl(tcphdr->seqno); 234195972f6Sopenharmony_ci ackno = tcphdr->ackno = lwip_ntohl(tcphdr->ackno); 235195972f6Sopenharmony_ci tcphdr->wnd = lwip_ntohs(tcphdr->wnd); 236195972f6Sopenharmony_ci 237195972f6Sopenharmony_ci flags = TCPH_FLAGS(tcphdr); 238195972f6Sopenharmony_ci tcplen = p->tot_len; 239195972f6Sopenharmony_ci if (flags & (TCP_FIN | TCP_SYN)) { 240195972f6Sopenharmony_ci tcplen++; 241195972f6Sopenharmony_ci if (tcplen < p->tot_len) { 242195972f6Sopenharmony_ci /* u16_t overflow, cannot handle this */ 243195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: length u16_t overflow, cannot handle this\n")); 244195972f6Sopenharmony_ci TCP_STATS_INC(tcp.lenerr); 245195972f6Sopenharmony_ci goto dropped; 246195972f6Sopenharmony_ci } 247195972f6Sopenharmony_ci } 248195972f6Sopenharmony_ci 249195972f6Sopenharmony_ci /* Demultiplex an incoming segment. First, we check if it is destined 250195972f6Sopenharmony_ci for an active connection. */ 251195972f6Sopenharmony_ci prev = NULL; 252195972f6Sopenharmony_ci 253195972f6Sopenharmony_ci for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { 254195972f6Sopenharmony_ci LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); 255195972f6Sopenharmony_ci LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); 256195972f6Sopenharmony_ci LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); 257195972f6Sopenharmony_ci 258195972f6Sopenharmony_ci /* check if PCB is bound to specific netif */ 259195972f6Sopenharmony_ci if ((pcb->netif_idx != NETIF_NO_INDEX) && 260195972f6Sopenharmony_ci (pcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { 261195972f6Sopenharmony_ci prev = pcb; 262195972f6Sopenharmony_ci continue; 263195972f6Sopenharmony_ci } 264195972f6Sopenharmony_ci 265195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 266195972f6Sopenharmony_ci if (group == get_net_group_from_tcp_pcb(pcb) && 267195972f6Sopenharmony_ci pcb->remote_port == tcphdr->src && 268195972f6Sopenharmony_ci#else 269195972f6Sopenharmony_ci if (pcb->remote_port == tcphdr->src && 270195972f6Sopenharmony_ci#endif 271195972f6Sopenharmony_ci pcb->local_port == tcphdr->dest && 272195972f6Sopenharmony_ci ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) && 273195972f6Sopenharmony_ci ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { 274195972f6Sopenharmony_ci /* Move this PCB to the front of the list so that subsequent 275195972f6Sopenharmony_ci lookups will be faster (we exploit locality in TCP segment 276195972f6Sopenharmony_ci arrivals). */ 277195972f6Sopenharmony_ci LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb); 278195972f6Sopenharmony_ci if (prev != NULL) { 279195972f6Sopenharmony_ci prev->next = pcb->next; 280195972f6Sopenharmony_ci pcb->next = tcp_active_pcbs; 281195972f6Sopenharmony_ci tcp_active_pcbs = pcb; 282195972f6Sopenharmony_ci } else { 283195972f6Sopenharmony_ci TCP_STATS_INC(tcp.cachehit); 284195972f6Sopenharmony_ci } 285195972f6Sopenharmony_ci LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb); 286195972f6Sopenharmony_ci break; 287195972f6Sopenharmony_ci } 288195972f6Sopenharmony_ci prev = pcb; 289195972f6Sopenharmony_ci } 290195972f6Sopenharmony_ci 291195972f6Sopenharmony_ci if (pcb == NULL) { 292195972f6Sopenharmony_ci /* If it did not go to an active connection, we check the connections 293195972f6Sopenharmony_ci in the TIME-WAIT state. */ 294195972f6Sopenharmony_ci for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { 295195972f6Sopenharmony_ci LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); 296195972f6Sopenharmony_ci 297195972f6Sopenharmony_ci /* check if PCB is bound to specific netif */ 298195972f6Sopenharmony_ci if ((pcb->netif_idx != NETIF_NO_INDEX) && 299195972f6Sopenharmony_ci (pcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { 300195972f6Sopenharmony_ci continue; 301195972f6Sopenharmony_ci } 302195972f6Sopenharmony_ci 303195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 304195972f6Sopenharmony_ci if (group == get_net_group_from_tcp_pcb(pcb) && 305195972f6Sopenharmony_ci pcb->remote_port == tcphdr->src && 306195972f6Sopenharmony_ci#else 307195972f6Sopenharmony_ci if (pcb->remote_port == tcphdr->src && 308195972f6Sopenharmony_ci#endif 309195972f6Sopenharmony_ci pcb->local_port == tcphdr->dest && 310195972f6Sopenharmony_ci ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) && 311195972f6Sopenharmony_ci ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { 312195972f6Sopenharmony_ci /* We don't really care enough to move this PCB to the front 313195972f6Sopenharmony_ci of the list since we are not very likely to receive that 314195972f6Sopenharmony_ci many segments for connections in TIME-WAIT. */ 315195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n")); 316195972f6Sopenharmony_ci#ifdef LWIP_HOOK_TCP_INPACKET_PCB 317195972f6Sopenharmony_ci if (LWIP_HOOK_TCP_INPACKET_PCB(pcb, tcphdr, tcphdr_optlen, tcphdr_opt1len, 318195972f6Sopenharmony_ci tcphdr_opt2, p) == ERR_OK) 319195972f6Sopenharmony_ci#endif 320195972f6Sopenharmony_ci { 321195972f6Sopenharmony_ci tcp_timewait_input(pcb); 322195972f6Sopenharmony_ci } 323195972f6Sopenharmony_ci pbuf_free(p); 324195972f6Sopenharmony_ci return; 325195972f6Sopenharmony_ci } 326195972f6Sopenharmony_ci } 327195972f6Sopenharmony_ci 328195972f6Sopenharmony_ci /* Finally, if we still did not get a match, we check all PCBs that 329195972f6Sopenharmony_ci are LISTENing for incoming connections. */ 330195972f6Sopenharmony_ci prev = NULL; 331195972f6Sopenharmony_ci for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { 332195972f6Sopenharmony_ci /* check if PCB is bound to specific netif */ 333195972f6Sopenharmony_ci if ((lpcb->netif_idx != NETIF_NO_INDEX) && 334195972f6Sopenharmony_ci (lpcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { 335195972f6Sopenharmony_ci prev = (struct tcp_pcb *)lpcb; 336195972f6Sopenharmony_ci continue; 337195972f6Sopenharmony_ci } 338195972f6Sopenharmony_ci 339195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 340195972f6Sopenharmony_ci if (group == get_net_group_from_tcp_pcb((struct tcp_pcb *)lpcb) && lpcb->local_port == tcphdr->dest) { 341195972f6Sopenharmony_ci#else 342195972f6Sopenharmony_ci if (lpcb->local_port == tcphdr->dest) { 343195972f6Sopenharmony_ci#endif 344195972f6Sopenharmony_ci if (IP_IS_ANY_TYPE_VAL(lpcb->local_ip)) { 345195972f6Sopenharmony_ci /* found an ANY TYPE (IPv4/IPv6) match */ 346195972f6Sopenharmony_ci#if SO_REUSE 347195972f6Sopenharmony_ci lpcb_any = lpcb; 348195972f6Sopenharmony_ci lpcb_prev = prev; 349195972f6Sopenharmony_ci#else /* SO_REUSE */ 350195972f6Sopenharmony_ci break; 351195972f6Sopenharmony_ci#endif /* SO_REUSE */ 352195972f6Sopenharmony_ci } else if (IP_ADDR_PCB_VERSION_MATCH_EXACT(lpcb, ip_current_dest_addr())) { 353195972f6Sopenharmony_ci if (ip_addr_cmp(&lpcb->local_ip, ip_current_dest_addr())) { 354195972f6Sopenharmony_ci /* found an exact match */ 355195972f6Sopenharmony_ci break; 356195972f6Sopenharmony_ci } else if (ip_addr_isany(&lpcb->local_ip)) { 357195972f6Sopenharmony_ci /* found an ANY-match */ 358195972f6Sopenharmony_ci#if SO_REUSE 359195972f6Sopenharmony_ci lpcb_any = lpcb; 360195972f6Sopenharmony_ci lpcb_prev = prev; 361195972f6Sopenharmony_ci#else /* SO_REUSE */ 362195972f6Sopenharmony_ci break; 363195972f6Sopenharmony_ci#endif /* SO_REUSE */ 364195972f6Sopenharmony_ci } 365195972f6Sopenharmony_ci } 366195972f6Sopenharmony_ci } 367195972f6Sopenharmony_ci prev = (struct tcp_pcb *)lpcb; 368195972f6Sopenharmony_ci } 369195972f6Sopenharmony_ci#if SO_REUSE 370195972f6Sopenharmony_ci /* first try specific local IP */ 371195972f6Sopenharmony_ci if (lpcb == NULL) { 372195972f6Sopenharmony_ci /* only pass to ANY if no specific local IP has been found */ 373195972f6Sopenharmony_ci lpcb = lpcb_any; 374195972f6Sopenharmony_ci prev = lpcb_prev; 375195972f6Sopenharmony_ci } 376195972f6Sopenharmony_ci#endif /* SO_REUSE */ 377195972f6Sopenharmony_ci if (lpcb != NULL) { 378195972f6Sopenharmony_ci /* Move this PCB to the front of the list so that subsequent 379195972f6Sopenharmony_ci lookups will be faster (we exploit locality in TCP segment 380195972f6Sopenharmony_ci arrivals). */ 381195972f6Sopenharmony_ci if (prev != NULL) { 382195972f6Sopenharmony_ci ((struct tcp_pcb_listen *)prev)->next = lpcb->next; 383195972f6Sopenharmony_ci /* our successor is the remainder of the listening list */ 384195972f6Sopenharmony_ci lpcb->next = tcp_listen_pcbs.listen_pcbs; 385195972f6Sopenharmony_ci /* put this listening pcb at the head of the listening list */ 386195972f6Sopenharmony_ci tcp_listen_pcbs.listen_pcbs = lpcb; 387195972f6Sopenharmony_ci } else { 388195972f6Sopenharmony_ci TCP_STATS_INC(tcp.cachehit); 389195972f6Sopenharmony_ci } 390195972f6Sopenharmony_ci 391195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); 392195972f6Sopenharmony_ci#ifdef LWIP_HOOK_TCP_INPACKET_PCB 393195972f6Sopenharmony_ci if (LWIP_HOOK_TCP_INPACKET_PCB((struct tcp_pcb *)lpcb, tcphdr, tcphdr_optlen, 394195972f6Sopenharmony_ci tcphdr_opt1len, tcphdr_opt2, p) == ERR_OK) 395195972f6Sopenharmony_ci#endif 396195972f6Sopenharmony_ci { 397195972f6Sopenharmony_ci tcp_listen_input(lpcb); 398195972f6Sopenharmony_ci } 399195972f6Sopenharmony_ci pbuf_free(p); 400195972f6Sopenharmony_ci return; 401195972f6Sopenharmony_ci } 402195972f6Sopenharmony_ci } 403195972f6Sopenharmony_ci 404195972f6Sopenharmony_ci#if TCP_INPUT_DEBUG 405195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags ")); 406195972f6Sopenharmony_ci tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); 407195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n")); 408195972f6Sopenharmony_ci#endif /* TCP_INPUT_DEBUG */ 409195972f6Sopenharmony_ci 410195972f6Sopenharmony_ci 411195972f6Sopenharmony_ci#ifdef LWIP_HOOK_TCP_INPACKET_PCB 412195972f6Sopenharmony_ci if ((pcb != NULL) && LWIP_HOOK_TCP_INPACKET_PCB(pcb, tcphdr, tcphdr_optlen, 413195972f6Sopenharmony_ci tcphdr_opt1len, tcphdr_opt2, p) != ERR_OK) { 414195972f6Sopenharmony_ci pbuf_free(p); 415195972f6Sopenharmony_ci return; 416195972f6Sopenharmony_ci } 417195972f6Sopenharmony_ci#endif 418195972f6Sopenharmony_ci if (pcb != NULL) { 419195972f6Sopenharmony_ci /* The incoming segment belongs to a connection. */ 420195972f6Sopenharmony_ci#if TCP_INPUT_DEBUG 421195972f6Sopenharmony_ci tcp_debug_print_state(pcb->state); 422195972f6Sopenharmony_ci#endif /* TCP_INPUT_DEBUG */ 423195972f6Sopenharmony_ci 424195972f6Sopenharmony_ci /* Set up a tcp_seg structure. */ 425195972f6Sopenharmony_ci inseg.next = NULL; 426195972f6Sopenharmony_ci inseg.len = p->tot_len; 427195972f6Sopenharmony_ci inseg.p = p; 428195972f6Sopenharmony_ci inseg.tcphdr = tcphdr; 429195972f6Sopenharmony_ci 430195972f6Sopenharmony_ci recv_data = NULL; 431195972f6Sopenharmony_ci recv_flags = 0; 432195972f6Sopenharmony_ci recv_acked = 0; 433195972f6Sopenharmony_ci 434195972f6Sopenharmony_ci if (flags & TCP_PSH) { 435195972f6Sopenharmony_ci p->flags |= PBUF_FLAG_PUSH; 436195972f6Sopenharmony_ci } 437195972f6Sopenharmony_ci 438195972f6Sopenharmony_ci /* If there is data which was previously "refused" by upper layer */ 439195972f6Sopenharmony_ci if (pcb->refused_data != NULL) { 440195972f6Sopenharmony_ci if ((tcp_process_refused_data(pcb) == ERR_ABRT) || 441195972f6Sopenharmony_ci ((pcb->refused_data != NULL) && (tcplen > 0))) { 442195972f6Sopenharmony_ci /* pcb has been aborted or refused data is still refused and the new 443195972f6Sopenharmony_ci segment contains data */ 444195972f6Sopenharmony_ci if (pcb->rcv_ann_wnd == 0) { 445195972f6Sopenharmony_ci /* this is a zero-window probe, we respond to it with current RCV.NXT 446195972f6Sopenharmony_ci and drop the data segment */ 447195972f6Sopenharmony_ci tcp_send_empty_ack(pcb); 448195972f6Sopenharmony_ci } 449195972f6Sopenharmony_ci TCP_STATS_INC(tcp.drop); 450195972f6Sopenharmony_ci MIB2_STATS_INC(mib2.tcpinerrs); 451195972f6Sopenharmony_ci goto aborted; 452195972f6Sopenharmony_ci } 453195972f6Sopenharmony_ci } 454195972f6Sopenharmony_ci tcp_input_pcb = pcb; 455195972f6Sopenharmony_ci err = tcp_process(pcb); 456195972f6Sopenharmony_ci /* A return value of ERR_ABRT means that tcp_abort() was called 457195972f6Sopenharmony_ci and that the pcb has been freed. If so, we don't do anything. */ 458195972f6Sopenharmony_ci if (err != ERR_ABRT) { 459195972f6Sopenharmony_ci if (recv_flags & TF_RESET) { 460195972f6Sopenharmony_ci /* TF_RESET means that the connection was reset by the other 461195972f6Sopenharmony_ci end. We then call the error callback to inform the 462195972f6Sopenharmony_ci application that the connection is dead before we 463195972f6Sopenharmony_ci deallocate the PCB. */ 464195972f6Sopenharmony_ci TCP_EVENT_ERR(pcb->state, pcb->errf, pcb->callback_arg, ERR_RST); 465195972f6Sopenharmony_ci tcp_pcb_remove(&tcp_active_pcbs, pcb); 466195972f6Sopenharmony_ci tcp_free(pcb); 467195972f6Sopenharmony_ci } else { 468195972f6Sopenharmony_ci err = ERR_OK; 469195972f6Sopenharmony_ci /* If the application has registered a "sent" function to be 470195972f6Sopenharmony_ci called when new send buffer space is available, we call it 471195972f6Sopenharmony_ci now. */ 472195972f6Sopenharmony_ci if (recv_acked > 0) { 473195972f6Sopenharmony_ci u16_t acked16; 474195972f6Sopenharmony_ci#if LWIP_WND_SCALE 475195972f6Sopenharmony_ci /* recv_acked is u32_t but the sent callback only takes a u16_t, 476195972f6Sopenharmony_ci so we might have to call it multiple times. */ 477195972f6Sopenharmony_ci u32_t acked = recv_acked; 478195972f6Sopenharmony_ci while (acked > 0) { 479195972f6Sopenharmony_ci acked16 = (u16_t)LWIP_MIN(acked, 0xffffu); 480195972f6Sopenharmony_ci acked -= acked16; 481195972f6Sopenharmony_ci#else 482195972f6Sopenharmony_ci { 483195972f6Sopenharmony_ci acked16 = recv_acked; 484195972f6Sopenharmony_ci#endif 485195972f6Sopenharmony_ci TCP_EVENT_SENT(pcb, (u16_t)acked16, err); 486195972f6Sopenharmony_ci if (err == ERR_ABRT) { 487195972f6Sopenharmony_ci goto aborted; 488195972f6Sopenharmony_ci } 489195972f6Sopenharmony_ci } 490195972f6Sopenharmony_ci recv_acked = 0; 491195972f6Sopenharmony_ci } 492195972f6Sopenharmony_ci if (tcp_input_delayed_close(pcb)) { 493195972f6Sopenharmony_ci goto aborted; 494195972f6Sopenharmony_ci } 495195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE 496195972f6Sopenharmony_ci while (recv_data != NULL) { 497195972f6Sopenharmony_ci struct pbuf *rest = NULL; 498195972f6Sopenharmony_ci pbuf_split_64k(recv_data, &rest); 499195972f6Sopenharmony_ci#else /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ 500195972f6Sopenharmony_ci if (recv_data != NULL) { 501195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ 502195972f6Sopenharmony_ci 503195972f6Sopenharmony_ci LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL); 504195972f6Sopenharmony_ci if (pcb->flags & TF_RXCLOSED) { 505195972f6Sopenharmony_ci /* received data although already closed -> abort (send RST) to 506195972f6Sopenharmony_ci notify the remote host that not all data has been processed */ 507195972f6Sopenharmony_ci pbuf_free(recv_data); 508195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE 509195972f6Sopenharmony_ci if (rest != NULL) { 510195972f6Sopenharmony_ci pbuf_free(rest); 511195972f6Sopenharmony_ci } 512195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ 513195972f6Sopenharmony_ci tcp_abort(pcb); 514195972f6Sopenharmony_ci goto aborted; 515195972f6Sopenharmony_ci } 516195972f6Sopenharmony_ci 517195972f6Sopenharmony_ci /* Notify application that data has been received. */ 518195972f6Sopenharmony_ci TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); 519195972f6Sopenharmony_ci if (err == ERR_ABRT) { 520195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE 521195972f6Sopenharmony_ci if (rest != NULL) { 522195972f6Sopenharmony_ci pbuf_free(rest); 523195972f6Sopenharmony_ci } 524195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ 525195972f6Sopenharmony_ci goto aborted; 526195972f6Sopenharmony_ci } 527195972f6Sopenharmony_ci 528195972f6Sopenharmony_ci /* If the upper layer can't receive this data, store it */ 529195972f6Sopenharmony_ci if (err != ERR_OK) { 530195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE 531195972f6Sopenharmony_ci if (rest != NULL) { 532195972f6Sopenharmony_ci pbuf_cat(recv_data, rest); 533195972f6Sopenharmony_ci } 534195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ 535195972f6Sopenharmony_ci pcb->refused_data = recv_data; 536195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n")); 537195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE 538195972f6Sopenharmony_ci break; 539195972f6Sopenharmony_ci } else { 540195972f6Sopenharmony_ci /* Upper layer received the data, go on with the rest if > 64K */ 541195972f6Sopenharmony_ci recv_data = rest; 542195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ 543195972f6Sopenharmony_ci } 544195972f6Sopenharmony_ci } 545195972f6Sopenharmony_ci 546195972f6Sopenharmony_ci /* If a FIN segment was received, we call the callback 547195972f6Sopenharmony_ci function with a NULL buffer to indicate EOF. */ 548195972f6Sopenharmony_ci if (recv_flags & TF_GOT_FIN) { 549195972f6Sopenharmony_ci if (pcb->refused_data != NULL) { 550195972f6Sopenharmony_ci /* Delay this if we have refused data. */ 551195972f6Sopenharmony_ci pcb->refused_data->flags |= PBUF_FLAG_TCP_FIN; 552195972f6Sopenharmony_ci } else { 553195972f6Sopenharmony_ci /* correct rcv_wnd as the application won't call tcp_recved() 554195972f6Sopenharmony_ci for the FIN's seqno */ 555195972f6Sopenharmony_ci if (pcb->rcv_wnd != TCP_WND_MAX(pcb)) { 556195972f6Sopenharmony_ci pcb->rcv_wnd++; 557195972f6Sopenharmony_ci } 558195972f6Sopenharmony_ci TCP_EVENT_CLOSED(pcb, err); 559195972f6Sopenharmony_ci if (err == ERR_ABRT) { 560195972f6Sopenharmony_ci goto aborted; 561195972f6Sopenharmony_ci } 562195972f6Sopenharmony_ci } 563195972f6Sopenharmony_ci } 564195972f6Sopenharmony_ci 565195972f6Sopenharmony_ci tcp_input_pcb = NULL; 566195972f6Sopenharmony_ci if (tcp_input_delayed_close(pcb)) { 567195972f6Sopenharmony_ci goto aborted; 568195972f6Sopenharmony_ci } 569195972f6Sopenharmony_ci /* Try to send something out. */ 570195972f6Sopenharmony_ci tcp_output(pcb); 571195972f6Sopenharmony_ci#if TCP_INPUT_DEBUG 572195972f6Sopenharmony_ci#if TCP_DEBUG 573195972f6Sopenharmony_ci tcp_debug_print_state(pcb->state); 574195972f6Sopenharmony_ci#endif /* TCP_DEBUG */ 575195972f6Sopenharmony_ci#endif /* TCP_INPUT_DEBUG */ 576195972f6Sopenharmony_ci } 577195972f6Sopenharmony_ci } 578195972f6Sopenharmony_ci /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()). 579195972f6Sopenharmony_ci Below this line, 'pcb' may not be dereferenced! */ 580195972f6Sopenharmony_ciaborted: 581195972f6Sopenharmony_ci tcp_input_pcb = NULL; 582195972f6Sopenharmony_ci recv_data = NULL; 583195972f6Sopenharmony_ci 584195972f6Sopenharmony_ci /* give up our reference to inseg.p */ 585195972f6Sopenharmony_ci if (inseg.p != NULL) { 586195972f6Sopenharmony_ci pbuf_free(inseg.p); 587195972f6Sopenharmony_ci inseg.p = NULL; 588195972f6Sopenharmony_ci } 589195972f6Sopenharmony_ci } else { 590195972f6Sopenharmony_ci /* If no matching PCB was found, send a TCP RST (reset) to the 591195972f6Sopenharmony_ci sender. */ 592195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n")); 593195972f6Sopenharmony_ci if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { 594195972f6Sopenharmony_ci TCP_STATS_INC(tcp.proterr); 595195972f6Sopenharmony_ci TCP_STATS_INC(tcp.drop); 596195972f6Sopenharmony_ci tcp_rst(NULL, ackno, seqno + tcplen, ip_current_dest_addr(), 597195972f6Sopenharmony_ci ip_current_src_addr(), tcphdr->dest, tcphdr->src); 598195972f6Sopenharmony_ci } 599195972f6Sopenharmony_ci pbuf_free(p); 600195972f6Sopenharmony_ci } 601195972f6Sopenharmony_ci 602195972f6Sopenharmony_ci LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); 603195972f6Sopenharmony_ci PERF_STOP("tcp_input"); 604195972f6Sopenharmony_ci return; 605195972f6Sopenharmony_cidropped: 606195972f6Sopenharmony_ci TCP_STATS_INC(tcp.drop); 607195972f6Sopenharmony_ci MIB2_STATS_INC(mib2.tcpinerrs); 608195972f6Sopenharmony_ci pbuf_free(p); 609195972f6Sopenharmony_ci} 610195972f6Sopenharmony_ci 611195972f6Sopenharmony_ci/** Called from tcp_input to check for TF_CLOSED flag. This results in closing 612195972f6Sopenharmony_ci * and deallocating a pcb at the correct place to ensure noone references it 613195972f6Sopenharmony_ci * any more. 614195972f6Sopenharmony_ci * @returns 1 if the pcb has been closed and deallocated, 0 otherwise 615195972f6Sopenharmony_ci */ 616195972f6Sopenharmony_cistatic int 617195972f6Sopenharmony_citcp_input_delayed_close(struct tcp_pcb *pcb) 618195972f6Sopenharmony_ci{ 619195972f6Sopenharmony_ci LWIP_ASSERT("tcp_input_delayed_close: invalid pcb", pcb != NULL); 620195972f6Sopenharmony_ci 621195972f6Sopenharmony_ci if (recv_flags & TF_CLOSED) { 622195972f6Sopenharmony_ci /* The connection has been closed and we will deallocate the 623195972f6Sopenharmony_ci PCB. */ 624195972f6Sopenharmony_ci if (!(pcb->flags & TF_RXCLOSED)) { 625195972f6Sopenharmony_ci /* Connection closed although the application has only shut down the 626195972f6Sopenharmony_ci tx side: call the PCB's err callback and indicate the closure to 627195972f6Sopenharmony_ci ensure the application doesn't continue using the PCB. */ 628195972f6Sopenharmony_ci TCP_EVENT_ERR(pcb->state, pcb->errf, pcb->callback_arg, ERR_CLSD); 629195972f6Sopenharmony_ci } 630195972f6Sopenharmony_ci tcp_pcb_remove(&tcp_active_pcbs, pcb); 631195972f6Sopenharmony_ci tcp_free(pcb); 632195972f6Sopenharmony_ci return 1; 633195972f6Sopenharmony_ci } 634195972f6Sopenharmony_ci return 0; 635195972f6Sopenharmony_ci} 636195972f6Sopenharmony_ci 637195972f6Sopenharmony_ci/** 638195972f6Sopenharmony_ci * Called by tcp_input() when a segment arrives for a listening 639195972f6Sopenharmony_ci * connection (from tcp_input()). 640195972f6Sopenharmony_ci * 641195972f6Sopenharmony_ci * @param pcb the tcp_pcb_listen for which a segment arrived 642195972f6Sopenharmony_ci * 643195972f6Sopenharmony_ci * @note the segment which arrived is saved in global variables, therefore only the pcb 644195972f6Sopenharmony_ci * involved is passed as a parameter to this function 645195972f6Sopenharmony_ci */ 646195972f6Sopenharmony_cistatic void 647195972f6Sopenharmony_citcp_listen_input(struct tcp_pcb_listen *pcb) 648195972f6Sopenharmony_ci{ 649195972f6Sopenharmony_ci struct tcp_pcb *npcb; 650195972f6Sopenharmony_ci u32_t iss; 651195972f6Sopenharmony_ci err_t rc; 652195972f6Sopenharmony_ci 653195972f6Sopenharmony_ci if (flags & TCP_RST) { 654195972f6Sopenharmony_ci /* An incoming RST should be ignored. Return. */ 655195972f6Sopenharmony_ci return; 656195972f6Sopenharmony_ci } 657195972f6Sopenharmony_ci 658195972f6Sopenharmony_ci LWIP_ASSERT("tcp_listen_input: invalid pcb", pcb != NULL); 659195972f6Sopenharmony_ci 660195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 661195972f6Sopenharmony_ci struct net_group *group = get_net_group_from_tcp_pcb((struct tcp_pcb *)pcb); 662195972f6Sopenharmony_ci#endif 663195972f6Sopenharmony_ci /* In the LISTEN state, we check for incoming SYN segments, 664195972f6Sopenharmony_ci creates a new PCB, and responds with a SYN|ACK. */ 665195972f6Sopenharmony_ci if (flags & TCP_ACK) { 666195972f6Sopenharmony_ci /* For incoming segments with the ACK flag set, respond with a 667195972f6Sopenharmony_ci RST. */ 668195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); 669195972f6Sopenharmony_ci tcp_rst((const struct tcp_pcb *)pcb, ackno, seqno + tcplen, ip_current_dest_addr(), 670195972f6Sopenharmony_ci ip_current_src_addr(), tcphdr->dest, tcphdr->src); 671195972f6Sopenharmony_ci } else if (flags & TCP_SYN) { 672195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); 673195972f6Sopenharmony_ci#if TCP_LISTEN_BACKLOG 674195972f6Sopenharmony_ci if (pcb->accepts_pending >= pcb->backlog) { 675195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest)); 676195972f6Sopenharmony_ci return; 677195972f6Sopenharmony_ci } 678195972f6Sopenharmony_ci#endif /* TCP_LISTEN_BACKLOG */ 679195972f6Sopenharmony_ci npcb = tcp_alloc(pcb->prio); 680195972f6Sopenharmony_ci /* If a new PCB could not be created (probably due to lack of memory), 681195972f6Sopenharmony_ci we don't do anything, but rely on the sender will retransmit the 682195972f6Sopenharmony_ci SYN at a time when we have more memory available. */ 683195972f6Sopenharmony_ci if (npcb == NULL) { 684195972f6Sopenharmony_ci err_t err; 685195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); 686195972f6Sopenharmony_ci TCP_STATS_INC(tcp.memerr); 687195972f6Sopenharmony_ci TCP_EVENT_ACCEPT(pcb, NULL, pcb->callback_arg, ERR_MEM, err); 688195972f6Sopenharmony_ci LWIP_UNUSED_ARG(err); /* err not useful here */ 689195972f6Sopenharmony_ci return; 690195972f6Sopenharmony_ci } 691195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 692195972f6Sopenharmony_ci set_tcp_pcb_net_group(npcb, group); 693195972f6Sopenharmony_ci#endif 694195972f6Sopenharmony_ci#if TCP_LISTEN_BACKLOG 695195972f6Sopenharmony_ci pcb->accepts_pending++; 696195972f6Sopenharmony_ci tcp_set_flags(npcb, TF_BACKLOGPEND); 697195972f6Sopenharmony_ci#endif /* TCP_LISTEN_BACKLOG */ 698195972f6Sopenharmony_ci /* Set up the new PCB. */ 699195972f6Sopenharmony_ci ip_addr_copy(npcb->local_ip, *ip_current_dest_addr()); 700195972f6Sopenharmony_ci ip_addr_copy(npcb->remote_ip, *ip_current_src_addr()); 701195972f6Sopenharmony_ci npcb->local_port = pcb->local_port; 702195972f6Sopenharmony_ci npcb->remote_port = tcphdr->src; 703195972f6Sopenharmony_ci npcb->state = SYN_RCVD; 704195972f6Sopenharmony_ci npcb->rcv_nxt = seqno + 1; 705195972f6Sopenharmony_ci npcb->rcv_ann_right_edge = npcb->rcv_nxt; 706195972f6Sopenharmony_ci iss = tcp_next_iss(npcb); 707195972f6Sopenharmony_ci npcb->snd_wl2 = iss; 708195972f6Sopenharmony_ci npcb->snd_nxt = iss; 709195972f6Sopenharmony_ci npcb->lastack = iss; 710195972f6Sopenharmony_ci npcb->snd_lbb = iss; 711195972f6Sopenharmony_ci npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ 712195972f6Sopenharmony_ci npcb->callback_arg = pcb->callback_arg; 713195972f6Sopenharmony_ci#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG 714195972f6Sopenharmony_ci npcb->listener = pcb; 715195972f6Sopenharmony_ci#endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ 716195972f6Sopenharmony_ci /* inherit socket options */ 717195972f6Sopenharmony_ci npcb->so_options = pcb->so_options & SOF_INHERITED; 718195972f6Sopenharmony_ci npcb->netif_idx = pcb->netif_idx; 719195972f6Sopenharmony_ci /* Register the new PCB so that we can begin receiving segments 720195972f6Sopenharmony_ci for it. */ 721195972f6Sopenharmony_ci TCP_REG_ACTIVE(npcb); 722195972f6Sopenharmony_ci 723195972f6Sopenharmony_ci /* Parse any options in the SYN. */ 724195972f6Sopenharmony_ci tcp_parseopt(npcb); 725195972f6Sopenharmony_ci npcb->snd_wnd = tcphdr->wnd; 726195972f6Sopenharmony_ci npcb->snd_wnd_max = npcb->snd_wnd; 727195972f6Sopenharmony_ci 728195972f6Sopenharmony_ci#if TCP_CALCULATE_EFF_SEND_MSS 729195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 730195972f6Sopenharmony_ci npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip, &npcb->remote_ip, group); 731195972f6Sopenharmony_ci#else 732195972f6Sopenharmony_ci npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip, &npcb->remote_ip); 733195972f6Sopenharmony_ci#endif 734195972f6Sopenharmony_ci#endif /* TCP_CALCULATE_EFF_SEND_MSS */ 735195972f6Sopenharmony_ci 736195972f6Sopenharmony_ci MIB2_STATS_INC(mib2.tcppassiveopens); 737195972f6Sopenharmony_ci 738195972f6Sopenharmony_ci#if LWIP_TCP_PCB_NUM_EXT_ARGS 739195972f6Sopenharmony_ci if (tcp_ext_arg_invoke_callbacks_passive_open(pcb, npcb) != ERR_OK) { 740195972f6Sopenharmony_ci tcp_abandon(npcb, 0); 741195972f6Sopenharmony_ci return; 742195972f6Sopenharmony_ci } 743195972f6Sopenharmony_ci#endif 744195972f6Sopenharmony_ci 745195972f6Sopenharmony_ci /* Send a SYN|ACK together with the MSS option. */ 746195972f6Sopenharmony_ci rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK); 747195972f6Sopenharmony_ci if (rc != ERR_OK) { 748195972f6Sopenharmony_ci tcp_abandon(npcb, 0); 749195972f6Sopenharmony_ci return; 750195972f6Sopenharmony_ci } 751195972f6Sopenharmony_ci tcp_output(npcb); 752195972f6Sopenharmony_ci } 753195972f6Sopenharmony_ci return; 754195972f6Sopenharmony_ci} 755195972f6Sopenharmony_ci 756195972f6Sopenharmony_ci/** 757195972f6Sopenharmony_ci * Called by tcp_input() when a segment arrives for a connection in 758195972f6Sopenharmony_ci * TIME_WAIT. 759195972f6Sopenharmony_ci * 760195972f6Sopenharmony_ci * @param pcb the tcp_pcb for which a segment arrived 761195972f6Sopenharmony_ci * 762195972f6Sopenharmony_ci * @note the segment which arrived is saved in global variables, therefore only the pcb 763195972f6Sopenharmony_ci * involved is passed as a parameter to this function 764195972f6Sopenharmony_ci */ 765195972f6Sopenharmony_cistatic void 766195972f6Sopenharmony_citcp_timewait_input(struct tcp_pcb *pcb) 767195972f6Sopenharmony_ci{ 768195972f6Sopenharmony_ci /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */ 769195972f6Sopenharmony_ci /* RFC 793 3.9 Event Processing - Segment Arrives: 770195972f6Sopenharmony_ci * - first check sequence number - we skip that one in TIME_WAIT (always 771195972f6Sopenharmony_ci * acceptable since we only send ACKs) 772195972f6Sopenharmony_ci * - second check the RST bit (... return) */ 773195972f6Sopenharmony_ci if (flags & TCP_RST) { 774195972f6Sopenharmony_ci return; 775195972f6Sopenharmony_ci } 776195972f6Sopenharmony_ci 777195972f6Sopenharmony_ci LWIP_ASSERT("tcp_timewait_input: invalid pcb", pcb != NULL); 778195972f6Sopenharmony_ci 779195972f6Sopenharmony_ci /* - fourth, check the SYN bit, */ 780195972f6Sopenharmony_ci if (flags & TCP_SYN) { 781195972f6Sopenharmony_ci /* If an incoming segment is not acceptable, an acknowledgment 782195972f6Sopenharmony_ci should be sent in reply */ 783195972f6Sopenharmony_ci if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd)) { 784195972f6Sopenharmony_ci /* If the SYN is in the window it is an error, send a reset */ 785195972f6Sopenharmony_ci tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), 786195972f6Sopenharmony_ci ip_current_src_addr(), tcphdr->dest, tcphdr->src); 787195972f6Sopenharmony_ci return; 788195972f6Sopenharmony_ci } 789195972f6Sopenharmony_ci } else if (flags & TCP_FIN) { 790195972f6Sopenharmony_ci /* - eighth, check the FIN bit: Remain in the TIME-WAIT state. 791195972f6Sopenharmony_ci Restart the 2 MSL time-wait timeout.*/ 792195972f6Sopenharmony_ci pcb->tmr = tcp_ticks; 793195972f6Sopenharmony_ci } 794195972f6Sopenharmony_ci 795195972f6Sopenharmony_ci if ((tcplen > 0)) { 796195972f6Sopenharmony_ci /* Acknowledge data, FIN or out-of-window SYN */ 797195972f6Sopenharmony_ci tcp_ack_now(pcb); 798195972f6Sopenharmony_ci tcp_output(pcb); 799195972f6Sopenharmony_ci } 800195972f6Sopenharmony_ci return; 801195972f6Sopenharmony_ci} 802195972f6Sopenharmony_ci 803195972f6Sopenharmony_ci/** 804195972f6Sopenharmony_ci * Implements the TCP state machine. Called by tcp_input. In some 805195972f6Sopenharmony_ci * states tcp_receive() is called to receive data. The tcp_seg 806195972f6Sopenharmony_ci * argument will be freed by the caller (tcp_input()) unless the 807195972f6Sopenharmony_ci * recv_data pointer in the pcb is set. 808195972f6Sopenharmony_ci * 809195972f6Sopenharmony_ci * @param pcb the tcp_pcb for which a segment arrived 810195972f6Sopenharmony_ci * 811195972f6Sopenharmony_ci * @note the segment which arrived is saved in global variables, therefore only the pcb 812195972f6Sopenharmony_ci * involved is passed as a parameter to this function 813195972f6Sopenharmony_ci */ 814195972f6Sopenharmony_cistatic err_t 815195972f6Sopenharmony_citcp_process(struct tcp_pcb *pcb) 816195972f6Sopenharmony_ci{ 817195972f6Sopenharmony_ci struct tcp_seg *rseg; 818195972f6Sopenharmony_ci u8_t acceptable = 0; 819195972f6Sopenharmony_ci err_t err; 820195972f6Sopenharmony_ci 821195972f6Sopenharmony_ci err = ERR_OK; 822195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 823195972f6Sopenharmony_ci struct net_group *group = get_net_group_from_tcp_pcb(pcb); 824195972f6Sopenharmony_ci#endif 825195972f6Sopenharmony_ci 826195972f6Sopenharmony_ci LWIP_ASSERT("tcp_process: invalid pcb", pcb != NULL); 827195972f6Sopenharmony_ci 828195972f6Sopenharmony_ci /* Process incoming RST segments. */ 829195972f6Sopenharmony_ci if (flags & TCP_RST) { 830195972f6Sopenharmony_ci /* First, determine if the reset is acceptable. */ 831195972f6Sopenharmony_ci if (pcb->state == SYN_SENT) { 832195972f6Sopenharmony_ci /* "In the SYN-SENT state (a RST received in response to an initial SYN), 833195972f6Sopenharmony_ci the RST is acceptable if the ACK field acknowledges the SYN." */ 834195972f6Sopenharmony_ci if (ackno == pcb->snd_nxt) { 835195972f6Sopenharmony_ci acceptable = 1; 836195972f6Sopenharmony_ci } 837195972f6Sopenharmony_ci } else { 838195972f6Sopenharmony_ci /* "In all states except SYN-SENT, all reset (RST) segments are validated 839195972f6Sopenharmony_ci by checking their SEQ-fields." */ 840195972f6Sopenharmony_ci if (seqno == pcb->rcv_nxt) { 841195972f6Sopenharmony_ci acceptable = 1; 842195972f6Sopenharmony_ci } else if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, 843195972f6Sopenharmony_ci pcb->rcv_nxt + pcb->rcv_wnd)) { 844195972f6Sopenharmony_ci /* If the sequence number is inside the window, we send a challenge ACK 845195972f6Sopenharmony_ci and wait for a re-send with matching sequence number. 846195972f6Sopenharmony_ci This follows RFC 5961 section 3.2 and addresses CVE-2004-0230 847195972f6Sopenharmony_ci (RST spoofing attack), which is present in RFC 793 RST handling. */ 848195972f6Sopenharmony_ci tcp_ack_now(pcb); 849195972f6Sopenharmony_ci } 850195972f6Sopenharmony_ci } 851195972f6Sopenharmony_ci 852195972f6Sopenharmony_ci if (acceptable) { 853195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n")); 854195972f6Sopenharmony_ci LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED); 855195972f6Sopenharmony_ci recv_flags |= TF_RESET; 856195972f6Sopenharmony_ci tcp_clear_flags(pcb, TF_ACK_DELAY); 857195972f6Sopenharmony_ci return ERR_RST; 858195972f6Sopenharmony_ci } else { 859195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", 860195972f6Sopenharmony_ci seqno, pcb->rcv_nxt)); 861195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", 862195972f6Sopenharmony_ci seqno, pcb->rcv_nxt)); 863195972f6Sopenharmony_ci return ERR_OK; 864195972f6Sopenharmony_ci } 865195972f6Sopenharmony_ci } 866195972f6Sopenharmony_ci 867195972f6Sopenharmony_ci if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { 868195972f6Sopenharmony_ci /* Cope with new connection attempt after remote end crashed */ 869195972f6Sopenharmony_ci tcp_ack_now(pcb); 870195972f6Sopenharmony_ci return ERR_OK; 871195972f6Sopenharmony_ci } 872195972f6Sopenharmony_ci 873195972f6Sopenharmony_ci if ((pcb->flags & TF_RXCLOSED) == 0) { 874195972f6Sopenharmony_ci /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */ 875195972f6Sopenharmony_ci pcb->tmr = tcp_ticks; 876195972f6Sopenharmony_ci } 877195972f6Sopenharmony_ci pcb->keep_cnt_sent = 0; 878195972f6Sopenharmony_ci pcb->persist_probe = 0; 879195972f6Sopenharmony_ci 880195972f6Sopenharmony_ci tcp_parseopt(pcb); 881195972f6Sopenharmony_ci 882195972f6Sopenharmony_ci /* Do different things depending on the TCP state. */ 883195972f6Sopenharmony_ci switch (pcb->state) { 884195972f6Sopenharmony_ci case SYN_SENT: 885195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %s %"U32_F"\n", 886195972f6Sopenharmony_ci ackno, pcb->snd_nxt, pcb->unacked ? "" : " empty:", 887195972f6Sopenharmony_ci pcb->unacked ? lwip_ntohl(pcb->unacked->tcphdr->seqno) : 0)); 888195972f6Sopenharmony_ci /* received SYN ACK with expected sequence number? */ 889195972f6Sopenharmony_ci if ((flags & TCP_ACK) && (flags & TCP_SYN) 890195972f6Sopenharmony_ci && (ackno == pcb->lastack + 1)) { 891195972f6Sopenharmony_ci pcb->rcv_nxt = seqno + 1; 892195972f6Sopenharmony_ci pcb->rcv_ann_right_edge = pcb->rcv_nxt; 893195972f6Sopenharmony_ci pcb->lastack = ackno; 894195972f6Sopenharmony_ci pcb->snd_wnd = tcphdr->wnd; 895195972f6Sopenharmony_ci pcb->snd_wnd_max = pcb->snd_wnd; 896195972f6Sopenharmony_ci pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */ 897195972f6Sopenharmony_ci pcb->state = ESTABLISHED; 898195972f6Sopenharmony_ci 899195972f6Sopenharmony_ci#if TCP_CALCULATE_EFF_SEND_MSS 900195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 901195972f6Sopenharmony_ci pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip, group); 902195972f6Sopenharmony_ci#else 903195972f6Sopenharmony_ci pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip); 904195972f6Sopenharmony_ci#endif 905195972f6Sopenharmony_ci#endif /* TCP_CALCULATE_EFF_SEND_MSS */ 906195972f6Sopenharmony_ci 907195972f6Sopenharmony_ci pcb->cwnd = LWIP_TCP_CALC_INITIAL_CWND(pcb->mss); 908195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_process (SENT): cwnd %"TCPWNDSIZE_F 909195972f6Sopenharmony_ci " ssthresh %"TCPWNDSIZE_F"\n", 910195972f6Sopenharmony_ci pcb->cwnd, pcb->ssthresh)); 911195972f6Sopenharmony_ci LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0)); 912195972f6Sopenharmony_ci --pcb->snd_queuelen; 913195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"TCPWNDSIZE_F"\n", (tcpwnd_size_t)pcb->snd_queuelen)); 914195972f6Sopenharmony_ci rseg = pcb->unacked; 915195972f6Sopenharmony_ci if (rseg == NULL) { 916195972f6Sopenharmony_ci /* might happen if tcp_output fails in tcp_rexmit_rto() 917195972f6Sopenharmony_ci in which case the segment is on the unsent list */ 918195972f6Sopenharmony_ci rseg = pcb->unsent; 919195972f6Sopenharmony_ci LWIP_ASSERT("no segment to free", rseg != NULL); 920195972f6Sopenharmony_ci pcb->unsent = rseg->next; 921195972f6Sopenharmony_ci } else { 922195972f6Sopenharmony_ci pcb->unacked = rseg->next; 923195972f6Sopenharmony_ci } 924195972f6Sopenharmony_ci tcp_seg_free(rseg); 925195972f6Sopenharmony_ci 926195972f6Sopenharmony_ci /* If there's nothing left to acknowledge, stop the retransmit 927195972f6Sopenharmony_ci timer, otherwise reset it to start again */ 928195972f6Sopenharmony_ci if (pcb->unacked == NULL) { 929195972f6Sopenharmony_ci pcb->rtime = -1; 930195972f6Sopenharmony_ci } else { 931195972f6Sopenharmony_ci pcb->rtime = 0; 932195972f6Sopenharmony_ci pcb->nrtx = 0; 933195972f6Sopenharmony_ci } 934195972f6Sopenharmony_ci 935195972f6Sopenharmony_ci /* Call the user specified function to call when successfully 936195972f6Sopenharmony_ci * connected. */ 937195972f6Sopenharmony_ci TCP_EVENT_CONNECTED(pcb, ERR_OK, err); 938195972f6Sopenharmony_ci if (err == ERR_ABRT) { 939195972f6Sopenharmony_ci return ERR_ABRT; 940195972f6Sopenharmony_ci } 941195972f6Sopenharmony_ci tcp_ack_now(pcb); 942195972f6Sopenharmony_ci } 943195972f6Sopenharmony_ci /* received ACK? possibly a half-open connection */ 944195972f6Sopenharmony_ci else if (flags & TCP_ACK) { 945195972f6Sopenharmony_ci /* send a RST to bring the other side in a non-synchronized state. */ 946195972f6Sopenharmony_ci tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), 947195972f6Sopenharmony_ci ip_current_src_addr(), tcphdr->dest, tcphdr->src); 948195972f6Sopenharmony_ci /* Resend SYN immediately (don't wait for rto timeout) to establish 949195972f6Sopenharmony_ci connection faster, but do not send more SYNs than we otherwise would 950195972f6Sopenharmony_ci have, or we might get caught in a loop on loopback interfaces. */ 951195972f6Sopenharmony_ci if (pcb->nrtx < TCP_SYNMAXRTX) { 952195972f6Sopenharmony_ci pcb->rtime = 0; 953195972f6Sopenharmony_ci tcp_rexmit_rto(pcb); 954195972f6Sopenharmony_ci } 955195972f6Sopenharmony_ci } 956195972f6Sopenharmony_ci break; 957195972f6Sopenharmony_ci case SYN_RCVD: 958195972f6Sopenharmony_ci if (flags & TCP_ACK) { 959195972f6Sopenharmony_ci /* expected ACK number? */ 960195972f6Sopenharmony_ci if (TCP_SEQ_BETWEEN(ackno, pcb->lastack + 1, pcb->snd_nxt)) { 961195972f6Sopenharmony_ci pcb->state = ESTABLISHED; 962195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); 963195972f6Sopenharmony_ci#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG 964195972f6Sopenharmony_ci if (pcb->listener == NULL) { 965195972f6Sopenharmony_ci /* listen pcb might be closed by now */ 966195972f6Sopenharmony_ci err = ERR_VAL; 967195972f6Sopenharmony_ci } else 968195972f6Sopenharmony_ci#endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ 969195972f6Sopenharmony_ci { 970195972f6Sopenharmony_ci#if LWIP_CALLBACK_API 971195972f6Sopenharmony_ci LWIP_ASSERT("pcb->listener->accept != NULL", pcb->listener->accept != NULL); 972195972f6Sopenharmony_ci#endif 973195972f6Sopenharmony_ci tcp_backlog_accepted(pcb); 974195972f6Sopenharmony_ci /* Call the accept function. */ 975195972f6Sopenharmony_ci TCP_EVENT_ACCEPT(pcb->listener, pcb, pcb->callback_arg, ERR_OK, err); 976195972f6Sopenharmony_ci } 977195972f6Sopenharmony_ci if (err != ERR_OK) { 978195972f6Sopenharmony_ci /* If the accept function returns with an error, we abort 979195972f6Sopenharmony_ci * the connection. */ 980195972f6Sopenharmony_ci /* Already aborted? */ 981195972f6Sopenharmony_ci if (err != ERR_ABRT) { 982195972f6Sopenharmony_ci tcp_abort(pcb); 983195972f6Sopenharmony_ci } 984195972f6Sopenharmony_ci return ERR_ABRT; 985195972f6Sopenharmony_ci } 986195972f6Sopenharmony_ci /* If there was any data contained within this ACK, 987195972f6Sopenharmony_ci * we'd better pass it on to the application as well. */ 988195972f6Sopenharmony_ci tcp_receive(pcb); 989195972f6Sopenharmony_ci 990195972f6Sopenharmony_ci /* Prevent ACK for SYN to generate a sent event */ 991195972f6Sopenharmony_ci if (recv_acked != 0) { 992195972f6Sopenharmony_ci recv_acked--; 993195972f6Sopenharmony_ci } 994195972f6Sopenharmony_ci 995195972f6Sopenharmony_ci pcb->cwnd = LWIP_TCP_CALC_INITIAL_CWND(pcb->mss); 996195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_process (SYN_RCVD): cwnd %"TCPWNDSIZE_F 997195972f6Sopenharmony_ci " ssthresh %"TCPWNDSIZE_F"\n", 998195972f6Sopenharmony_ci pcb->cwnd, pcb->ssthresh)); 999195972f6Sopenharmony_ci 1000195972f6Sopenharmony_ci if (recv_flags & TF_GOT_FIN) { 1001195972f6Sopenharmony_ci tcp_ack_now(pcb); 1002195972f6Sopenharmony_ci pcb->state = CLOSE_WAIT; 1003195972f6Sopenharmony_ci } 1004195972f6Sopenharmony_ci } else { 1005195972f6Sopenharmony_ci /* incorrect ACK number, send RST */ 1006195972f6Sopenharmony_ci tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), 1007195972f6Sopenharmony_ci ip_current_src_addr(), tcphdr->dest, tcphdr->src); 1008195972f6Sopenharmony_ci } 1009195972f6Sopenharmony_ci } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { 1010195972f6Sopenharmony_ci /* Looks like another copy of the SYN - retransmit our SYN-ACK */ 1011195972f6Sopenharmony_ci tcp_rexmit(pcb); 1012195972f6Sopenharmony_ci } 1013195972f6Sopenharmony_ci break; 1014195972f6Sopenharmony_ci case CLOSE_WAIT: 1015195972f6Sopenharmony_ci /* FALLTHROUGH */ 1016195972f6Sopenharmony_ci case ESTABLISHED: 1017195972f6Sopenharmony_ci tcp_receive(pcb); 1018195972f6Sopenharmony_ci if (recv_flags & TF_GOT_FIN) { /* passive close */ 1019195972f6Sopenharmony_ci tcp_ack_now(pcb); 1020195972f6Sopenharmony_ci pcb->state = CLOSE_WAIT; 1021195972f6Sopenharmony_ci } 1022195972f6Sopenharmony_ci break; 1023195972f6Sopenharmony_ci case FIN_WAIT_1: 1024195972f6Sopenharmony_ci tcp_receive(pcb); 1025195972f6Sopenharmony_ci if (recv_flags & TF_GOT_FIN) { 1026195972f6Sopenharmony_ci if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) && 1027195972f6Sopenharmony_ci pcb->unsent == NULL) { 1028195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, 1029195972f6Sopenharmony_ci ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); 1030195972f6Sopenharmony_ci tcp_ack_now(pcb); 1031195972f6Sopenharmony_ci tcp_pcb_purge(pcb); 1032195972f6Sopenharmony_ci TCP_RMV_ACTIVE(pcb); 1033195972f6Sopenharmony_ci pcb->state = TIME_WAIT; 1034195972f6Sopenharmony_ci TCP_REG(&tcp_tw_pcbs, pcb); 1035195972f6Sopenharmony_ci } else { 1036195972f6Sopenharmony_ci tcp_ack_now(pcb); 1037195972f6Sopenharmony_ci pcb->state = CLOSING; 1038195972f6Sopenharmony_ci } 1039195972f6Sopenharmony_ci } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) && 1040195972f6Sopenharmony_ci pcb->unsent == NULL) { 1041195972f6Sopenharmony_ci pcb->state = FIN_WAIT_2; 1042195972f6Sopenharmony_ci } 1043195972f6Sopenharmony_ci break; 1044195972f6Sopenharmony_ci case FIN_WAIT_2: 1045195972f6Sopenharmony_ci tcp_receive(pcb); 1046195972f6Sopenharmony_ci if (recv_flags & TF_GOT_FIN) { 1047195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); 1048195972f6Sopenharmony_ci tcp_ack_now(pcb); 1049195972f6Sopenharmony_ci tcp_pcb_purge(pcb); 1050195972f6Sopenharmony_ci TCP_RMV_ACTIVE(pcb); 1051195972f6Sopenharmony_ci pcb->state = TIME_WAIT; 1052195972f6Sopenharmony_ci TCP_REG(&tcp_tw_pcbs, pcb); 1053195972f6Sopenharmony_ci } 1054195972f6Sopenharmony_ci break; 1055195972f6Sopenharmony_ci case CLOSING: 1056195972f6Sopenharmony_ci tcp_receive(pcb); 1057195972f6Sopenharmony_ci if ((flags & TCP_ACK) && ackno == pcb->snd_nxt && pcb->unsent == NULL) { 1058195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); 1059195972f6Sopenharmony_ci tcp_pcb_purge(pcb); 1060195972f6Sopenharmony_ci TCP_RMV_ACTIVE(pcb); 1061195972f6Sopenharmony_ci pcb->state = TIME_WAIT; 1062195972f6Sopenharmony_ci TCP_REG(&tcp_tw_pcbs, pcb); 1063195972f6Sopenharmony_ci } 1064195972f6Sopenharmony_ci break; 1065195972f6Sopenharmony_ci case LAST_ACK: 1066195972f6Sopenharmony_ci tcp_receive(pcb); 1067195972f6Sopenharmony_ci if ((flags & TCP_ACK) && ackno == pcb->snd_nxt && pcb->unsent == NULL) { 1068195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); 1069195972f6Sopenharmony_ci /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */ 1070195972f6Sopenharmony_ci recv_flags |= TF_CLOSED; 1071195972f6Sopenharmony_ci } 1072195972f6Sopenharmony_ci break; 1073195972f6Sopenharmony_ci default: 1074195972f6Sopenharmony_ci break; 1075195972f6Sopenharmony_ci } 1076195972f6Sopenharmony_ci return ERR_OK; 1077195972f6Sopenharmony_ci} 1078195972f6Sopenharmony_ci 1079195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ 1080195972f6Sopenharmony_ci/** 1081195972f6Sopenharmony_ci * Insert segment into the list (segments covered with new one will be deleted) 1082195972f6Sopenharmony_ci * 1083195972f6Sopenharmony_ci * Called from tcp_receive() 1084195972f6Sopenharmony_ci */ 1085195972f6Sopenharmony_cistatic void 1086195972f6Sopenharmony_citcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next) 1087195972f6Sopenharmony_ci{ 1088195972f6Sopenharmony_ci struct tcp_seg *old_seg; 1089195972f6Sopenharmony_ci 1090195972f6Sopenharmony_ci LWIP_ASSERT("tcp_oos_insert_segment: invalid cseg", cseg != NULL); 1091195972f6Sopenharmony_ci 1092195972f6Sopenharmony_ci if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { 1093195972f6Sopenharmony_ci /* received segment overlaps all following segments */ 1094195972f6Sopenharmony_ci tcp_segs_free(next); 1095195972f6Sopenharmony_ci next = NULL; 1096195972f6Sopenharmony_ci } else { 1097195972f6Sopenharmony_ci /* delete some following segments 1098195972f6Sopenharmony_ci oos queue may have segments with FIN flag */ 1099195972f6Sopenharmony_ci while (next && 1100195972f6Sopenharmony_ci TCP_SEQ_GEQ((seqno + cseg->len), 1101195972f6Sopenharmony_ci (next->tcphdr->seqno + next->len))) { 1102195972f6Sopenharmony_ci /* cseg with FIN already processed */ 1103195972f6Sopenharmony_ci if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { 1104195972f6Sopenharmony_ci TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN); 1105195972f6Sopenharmony_ci } 1106195972f6Sopenharmony_ci old_seg = next; 1107195972f6Sopenharmony_ci next = next->next; 1108195972f6Sopenharmony_ci tcp_seg_free(old_seg); 1109195972f6Sopenharmony_ci } 1110195972f6Sopenharmony_ci if (next && 1111195972f6Sopenharmony_ci TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) { 1112195972f6Sopenharmony_ci /* We need to trim the incoming segment. */ 1113195972f6Sopenharmony_ci cseg->len = (u16_t)(next->tcphdr->seqno - seqno); 1114195972f6Sopenharmony_ci pbuf_realloc(cseg->p, cseg->len); 1115195972f6Sopenharmony_ci } 1116195972f6Sopenharmony_ci } 1117195972f6Sopenharmony_ci cseg->next = next; 1118195972f6Sopenharmony_ci} 1119195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ */ 1120195972f6Sopenharmony_ci 1121195972f6Sopenharmony_ci/** Remove segments from a list if the incoming ACK acknowledges them */ 1122195972f6Sopenharmony_cistatic struct tcp_seg * 1123195972f6Sopenharmony_citcp_free_acked_segments(struct tcp_pcb *pcb, struct tcp_seg *seg_list, const char *dbg_list_name, 1124195972f6Sopenharmony_ci struct tcp_seg *dbg_other_seg_list) 1125195972f6Sopenharmony_ci{ 1126195972f6Sopenharmony_ci struct tcp_seg *next; 1127195972f6Sopenharmony_ci u16_t clen; 1128195972f6Sopenharmony_ci 1129195972f6Sopenharmony_ci LWIP_UNUSED_ARG(dbg_list_name); 1130195972f6Sopenharmony_ci LWIP_UNUSED_ARG(dbg_other_seg_list); 1131195972f6Sopenharmony_ci 1132195972f6Sopenharmony_ci while (seg_list != NULL && 1133195972f6Sopenharmony_ci TCP_SEQ_LEQ(lwip_ntohl(seg_list->tcphdr->seqno) + 1134195972f6Sopenharmony_ci TCP_TCPLEN(seg_list), ackno)) { 1135195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->%s\n", 1136195972f6Sopenharmony_ci lwip_ntohl(seg_list->tcphdr->seqno), 1137195972f6Sopenharmony_ci lwip_ntohl(seg_list->tcphdr->seqno) + TCP_TCPLEN(seg_list), 1138195972f6Sopenharmony_ci dbg_list_name)); 1139195972f6Sopenharmony_ci 1140195972f6Sopenharmony_ci next = seg_list; 1141195972f6Sopenharmony_ci seg_list = seg_list->next; 1142195972f6Sopenharmony_ci 1143195972f6Sopenharmony_ci clen = pbuf_clen(next->p); 1144195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"TCPWNDSIZE_F" ... ", 1145195972f6Sopenharmony_ci (tcpwnd_size_t)pcb->snd_queuelen)); 1146195972f6Sopenharmony_ci LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= clen)); 1147195972f6Sopenharmony_ci 1148195972f6Sopenharmony_ci pcb->snd_queuelen = (u16_t)(pcb->snd_queuelen - clen); 1149195972f6Sopenharmony_ci recv_acked = (tcpwnd_size_t)(recv_acked + next->len); 1150195972f6Sopenharmony_ci tcp_seg_free(next); 1151195972f6Sopenharmony_ci 1152195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"TCPWNDSIZE_F" (after freeing %s)\n", 1153195972f6Sopenharmony_ci (tcpwnd_size_t)pcb->snd_queuelen, 1154195972f6Sopenharmony_ci dbg_list_name)); 1155195972f6Sopenharmony_ci if (pcb->snd_queuelen != 0) { 1156195972f6Sopenharmony_ci LWIP_ASSERT("tcp_receive: valid queue length", 1157195972f6Sopenharmony_ci seg_list != NULL || dbg_other_seg_list != NULL); 1158195972f6Sopenharmony_ci } 1159195972f6Sopenharmony_ci } 1160195972f6Sopenharmony_ci return seg_list; 1161195972f6Sopenharmony_ci} 1162195972f6Sopenharmony_ci 1163195972f6Sopenharmony_ci/** 1164195972f6Sopenharmony_ci * Called by tcp_process. Checks if the given segment is an ACK for outstanding 1165195972f6Sopenharmony_ci * data, and if so frees the memory of the buffered data. Next, it places the 1166195972f6Sopenharmony_ci * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment 1167195972f6Sopenharmony_ci * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until 1168195972f6Sopenharmony_ci * it has been removed from the buffer. 1169195972f6Sopenharmony_ci * 1170195972f6Sopenharmony_ci * If the incoming segment constitutes an ACK for a segment that was used for RTT 1171195972f6Sopenharmony_ci * estimation, the RTT is estimated here as well. 1172195972f6Sopenharmony_ci * 1173195972f6Sopenharmony_ci * Called from tcp_process(). 1174195972f6Sopenharmony_ci */ 1175195972f6Sopenharmony_cistatic void 1176195972f6Sopenharmony_citcp_receive(struct tcp_pcb *pcb) 1177195972f6Sopenharmony_ci{ 1178195972f6Sopenharmony_ci s16_t m; 1179195972f6Sopenharmony_ci u32_t right_wnd_edge; 1180195972f6Sopenharmony_ci int found_dupack = 0; 1181195972f6Sopenharmony_ci 1182195972f6Sopenharmony_ci LWIP_ASSERT("tcp_receive: invalid pcb", pcb != NULL); 1183195972f6Sopenharmony_ci LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED); 1184195972f6Sopenharmony_ci 1185195972f6Sopenharmony_ci if (flags & TCP_ACK) { 1186195972f6Sopenharmony_ci right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2; 1187195972f6Sopenharmony_ci 1188195972f6Sopenharmony_ci /* Update window. */ 1189195972f6Sopenharmony_ci if (TCP_SEQ_LT(pcb->snd_wl1, seqno) || 1190195972f6Sopenharmony_ci (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) || 1191195972f6Sopenharmony_ci (pcb->snd_wl2 == ackno && (u32_t)SND_WND_SCALE(pcb, tcphdr->wnd) > pcb->snd_wnd)) { 1192195972f6Sopenharmony_ci pcb->snd_wnd = SND_WND_SCALE(pcb, tcphdr->wnd); 1193195972f6Sopenharmony_ci /* keep track of the biggest window announced by the remote host to calculate 1194195972f6Sopenharmony_ci the maximum segment size */ 1195195972f6Sopenharmony_ci if (pcb->snd_wnd_max < pcb->snd_wnd) { 1196195972f6Sopenharmony_ci pcb->snd_wnd_max = pcb->snd_wnd; 1197195972f6Sopenharmony_ci } 1198195972f6Sopenharmony_ci pcb->snd_wl1 = seqno; 1199195972f6Sopenharmony_ci pcb->snd_wl2 = ackno; 1200195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"TCPWNDSIZE_F"\n", pcb->snd_wnd)); 1201195972f6Sopenharmony_ci#if TCP_WND_DEBUG 1202195972f6Sopenharmony_ci } else { 1203195972f6Sopenharmony_ci if (pcb->snd_wnd != (tcpwnd_size_t)SND_WND_SCALE(pcb, tcphdr->wnd)) { 1204195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_WND_DEBUG, 1205195972f6Sopenharmony_ci ("tcp_receive: no window update lastack %"U32_F" ackno %" 1206195972f6Sopenharmony_ci U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n", 1207195972f6Sopenharmony_ci pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2)); 1208195972f6Sopenharmony_ci } 1209195972f6Sopenharmony_ci#endif /* TCP_WND_DEBUG */ 1210195972f6Sopenharmony_ci } 1211195972f6Sopenharmony_ci 1212195972f6Sopenharmony_ci /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a 1213195972f6Sopenharmony_ci * duplicate ack if: 1214195972f6Sopenharmony_ci * 1) It doesn't ACK new data 1215195972f6Sopenharmony_ci * 2) length of received packet is zero (i.e. no payload) 1216195972f6Sopenharmony_ci * 3) the advertised window hasn't changed 1217195972f6Sopenharmony_ci * 4) There is outstanding unacknowledged data (retransmission timer running) 1218195972f6Sopenharmony_ci * 5) The ACK is == biggest ACK sequence number so far seen (snd_una) 1219195972f6Sopenharmony_ci * 1220195972f6Sopenharmony_ci * If it passes all five, should process as a dupack: 1221195972f6Sopenharmony_ci * a) dupacks < 3: do nothing 1222195972f6Sopenharmony_ci * b) dupacks == 3: fast retransmit 1223195972f6Sopenharmony_ci * c) dupacks > 3: increase cwnd 1224195972f6Sopenharmony_ci * 1225195972f6Sopenharmony_ci * If it only passes 1-3, should reset dupack counter (and add to 1226195972f6Sopenharmony_ci * stats, which we don't do in lwIP) 1227195972f6Sopenharmony_ci * 1228195972f6Sopenharmony_ci * If it only passes 1, should reset dupack counter 1229195972f6Sopenharmony_ci * 1230195972f6Sopenharmony_ci */ 1231195972f6Sopenharmony_ci 1232195972f6Sopenharmony_ci /* Clause 1 */ 1233195972f6Sopenharmony_ci if (TCP_SEQ_LEQ(ackno, pcb->lastack)) { 1234195972f6Sopenharmony_ci /* Clause 2 */ 1235195972f6Sopenharmony_ci if (tcplen == 0) { 1236195972f6Sopenharmony_ci /* Clause 3 */ 1237195972f6Sopenharmony_ci if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge) { 1238195972f6Sopenharmony_ci /* Clause 4 */ 1239195972f6Sopenharmony_ci if (pcb->rtime >= 0) { 1240195972f6Sopenharmony_ci /* Clause 5 */ 1241195972f6Sopenharmony_ci if (pcb->lastack == ackno) { 1242195972f6Sopenharmony_ci found_dupack = 1; 1243195972f6Sopenharmony_ci if ((u8_t)(pcb->dupacks + 1) > pcb->dupacks) { 1244195972f6Sopenharmony_ci ++pcb->dupacks; 1245195972f6Sopenharmony_ci } 1246195972f6Sopenharmony_ci if (pcb->dupacks > 3) { 1247195972f6Sopenharmony_ci /* Inflate the congestion window */ 1248195972f6Sopenharmony_ci TCP_WND_INC(pcb->cwnd, pcb->mss); 1249195972f6Sopenharmony_ci } 1250195972f6Sopenharmony_ci if (pcb->dupacks >= 3) { 1251195972f6Sopenharmony_ci /* Do fast retransmit (checked via TF_INFR, not via dupacks count) */ 1252195972f6Sopenharmony_ci tcp_rexmit_fast(pcb); 1253195972f6Sopenharmony_ci } 1254195972f6Sopenharmony_ci } 1255195972f6Sopenharmony_ci } 1256195972f6Sopenharmony_ci } 1257195972f6Sopenharmony_ci } 1258195972f6Sopenharmony_ci /* If Clause (1) or more is true, but not a duplicate ack, reset 1259195972f6Sopenharmony_ci * count of consecutive duplicate acks */ 1260195972f6Sopenharmony_ci if (!found_dupack) { 1261195972f6Sopenharmony_ci pcb->dupacks = 0; 1262195972f6Sopenharmony_ci } 1263195972f6Sopenharmony_ci } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack + 1, pcb->snd_nxt)) { 1264195972f6Sopenharmony_ci /* We come here when the ACK acknowledges new data. */ 1265195972f6Sopenharmony_ci tcpwnd_size_t acked; 1266195972f6Sopenharmony_ci 1267195972f6Sopenharmony_ci /* Reset the "IN Fast Retransmit" flag, since we are no longer 1268195972f6Sopenharmony_ci in fast retransmit. Also reset the congestion window to the 1269195972f6Sopenharmony_ci slow start threshold. */ 1270195972f6Sopenharmony_ci if (pcb->flags & TF_INFR) { 1271195972f6Sopenharmony_ci tcp_clear_flags(pcb, TF_INFR); 1272195972f6Sopenharmony_ci pcb->cwnd = pcb->ssthresh; 1273195972f6Sopenharmony_ci pcb->bytes_acked = 0; 1274195972f6Sopenharmony_ci } 1275195972f6Sopenharmony_ci 1276195972f6Sopenharmony_ci /* Reset the number of retransmissions. */ 1277195972f6Sopenharmony_ci pcb->nrtx = 0; 1278195972f6Sopenharmony_ci 1279195972f6Sopenharmony_ci /* Reset the retransmission time-out. */ 1280195972f6Sopenharmony_ci pcb->rto = (s16_t)((pcb->sa >> 3) + pcb->sv); 1281195972f6Sopenharmony_ci 1282195972f6Sopenharmony_ci /* Record how much data this ACK acks */ 1283195972f6Sopenharmony_ci acked = (tcpwnd_size_t)(ackno - pcb->lastack); 1284195972f6Sopenharmony_ci 1285195972f6Sopenharmony_ci /* Reset the fast retransmit variables. */ 1286195972f6Sopenharmony_ci pcb->dupacks = 0; 1287195972f6Sopenharmony_ci pcb->lastack = ackno; 1288195972f6Sopenharmony_ci 1289195972f6Sopenharmony_ci /* Update the congestion control variables (cwnd and 1290195972f6Sopenharmony_ci ssthresh). */ 1291195972f6Sopenharmony_ci if (pcb->state >= ESTABLISHED) { 1292195972f6Sopenharmony_ci if (pcb->cwnd < pcb->ssthresh) { 1293195972f6Sopenharmony_ci tcpwnd_size_t increase; 1294195972f6Sopenharmony_ci /* limit to 1 SMSS segment during period following RTO */ 1295195972f6Sopenharmony_ci u8_t num_seg = (pcb->flags & TF_RTO) ? 1 : 2; 1296195972f6Sopenharmony_ci /* RFC 3465, section 2.2 Slow Start */ 1297195972f6Sopenharmony_ci increase = LWIP_MIN(acked, (tcpwnd_size_t)(num_seg * pcb->mss)); 1298195972f6Sopenharmony_ci TCP_WND_INC(pcb->cwnd, increase); 1299195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"TCPWNDSIZE_F"\n", pcb->cwnd)); 1300195972f6Sopenharmony_ci } else { 1301195972f6Sopenharmony_ci /* RFC 3465, section 2.1 Congestion Avoidance */ 1302195972f6Sopenharmony_ci TCP_WND_INC(pcb->bytes_acked, acked); 1303195972f6Sopenharmony_ci if (pcb->bytes_acked >= pcb->cwnd) { 1304195972f6Sopenharmony_ci pcb->bytes_acked = (tcpwnd_size_t)(pcb->bytes_acked - pcb->cwnd); 1305195972f6Sopenharmony_ci TCP_WND_INC(pcb->cwnd, pcb->mss); 1306195972f6Sopenharmony_ci } 1307195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"TCPWNDSIZE_F"\n", pcb->cwnd)); 1308195972f6Sopenharmony_ci } 1309195972f6Sopenharmony_ci } 1310195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n", 1311195972f6Sopenharmony_ci ackno, 1312195972f6Sopenharmony_ci pcb->unacked != NULL ? 1313195972f6Sopenharmony_ci lwip_ntohl(pcb->unacked->tcphdr->seqno) : 0, 1314195972f6Sopenharmony_ci pcb->unacked != NULL ? 1315195972f6Sopenharmony_ci lwip_ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked) : 0)); 1316195972f6Sopenharmony_ci 1317195972f6Sopenharmony_ci /* Remove segment from the unacknowledged list if the incoming 1318195972f6Sopenharmony_ci ACK acknowledges them. */ 1319195972f6Sopenharmony_ci pcb->unacked = tcp_free_acked_segments(pcb, pcb->unacked, "unacked", pcb->unsent); 1320195972f6Sopenharmony_ci /* We go through the ->unsent list to see if any of the segments 1321195972f6Sopenharmony_ci on the list are acknowledged by the ACK. This may seem 1322195972f6Sopenharmony_ci strange since an "unsent" segment shouldn't be acked. The 1323195972f6Sopenharmony_ci rationale is that lwIP puts all outstanding segments on the 1324195972f6Sopenharmony_ci ->unsent list after a retransmission, so these segments may 1325195972f6Sopenharmony_ci in fact have been sent once. */ 1326195972f6Sopenharmony_ci pcb->unsent = tcp_free_acked_segments(pcb, pcb->unsent, "unsent", pcb->unacked); 1327195972f6Sopenharmony_ci 1328195972f6Sopenharmony_ci /* If there's nothing left to acknowledge, stop the retransmit 1329195972f6Sopenharmony_ci timer, otherwise reset it to start again */ 1330195972f6Sopenharmony_ci if (pcb->unacked == NULL) { 1331195972f6Sopenharmony_ci pcb->rtime = -1; 1332195972f6Sopenharmony_ci } else { 1333195972f6Sopenharmony_ci pcb->rtime = 0; 1334195972f6Sopenharmony_ci } 1335195972f6Sopenharmony_ci 1336195972f6Sopenharmony_ci pcb->polltmr = 0; 1337195972f6Sopenharmony_ci 1338195972f6Sopenharmony_ci#if TCP_OVERSIZE 1339195972f6Sopenharmony_ci if (pcb->unsent == NULL) { 1340195972f6Sopenharmony_ci pcb->unsent_oversize = 0; 1341195972f6Sopenharmony_ci } 1342195972f6Sopenharmony_ci#endif /* TCP_OVERSIZE */ 1343195972f6Sopenharmony_ci 1344195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS 1345195972f6Sopenharmony_ci if (ip_current_is_v6()) { 1346195972f6Sopenharmony_ci /* Inform neighbor reachability of forward progress. */ 1347195972f6Sopenharmony_ci nd6_reachability_hint(ip6_current_src_addr()); 1348195972f6Sopenharmony_ci } 1349195972f6Sopenharmony_ci#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/ 1350195972f6Sopenharmony_ci 1351195972f6Sopenharmony_ci pcb->snd_buf = (tcpwnd_size_t)(pcb->snd_buf + recv_acked); 1352195972f6Sopenharmony_ci /* check if this ACK ends our retransmission of in-flight data */ 1353195972f6Sopenharmony_ci if (pcb->flags & TF_RTO) { 1354195972f6Sopenharmony_ci /* RTO is done if 1355195972f6Sopenharmony_ci 1) both queues are empty or 1356195972f6Sopenharmony_ci 2) unacked is empty and unsent head contains data not part of RTO or 1357195972f6Sopenharmony_ci 3) unacked head contains data not part of RTO */ 1358195972f6Sopenharmony_ci if (pcb->unacked == NULL) { 1359195972f6Sopenharmony_ci if ((pcb->unsent == NULL) || 1360195972f6Sopenharmony_ci (TCP_SEQ_LEQ(pcb->rto_end, lwip_ntohl(pcb->unsent->tcphdr->seqno)))) { 1361195972f6Sopenharmony_ci tcp_clear_flags(pcb, TF_RTO); 1362195972f6Sopenharmony_ci } 1363195972f6Sopenharmony_ci } else if (TCP_SEQ_LEQ(pcb->rto_end, lwip_ntohl(pcb->unacked->tcphdr->seqno))) { 1364195972f6Sopenharmony_ci tcp_clear_flags(pcb, TF_RTO); 1365195972f6Sopenharmony_ci } 1366195972f6Sopenharmony_ci } 1367195972f6Sopenharmony_ci /* End of ACK for new data processing. */ 1368195972f6Sopenharmony_ci } else { 1369195972f6Sopenharmony_ci /* Out of sequence ACK, didn't really ack anything */ 1370195972f6Sopenharmony_ci tcp_send_empty_ack(pcb); 1371195972f6Sopenharmony_ci } 1372195972f6Sopenharmony_ci 1373195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n", 1374195972f6Sopenharmony_ci pcb->rttest, pcb->rtseq, ackno)); 1375195972f6Sopenharmony_ci 1376195972f6Sopenharmony_ci /* RTT estimation calculations. This is done by checking if the 1377195972f6Sopenharmony_ci incoming segment acknowledges the segment we use to take a 1378195972f6Sopenharmony_ci round-trip time measurement. */ 1379195972f6Sopenharmony_ci if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) { 1380195972f6Sopenharmony_ci /* diff between this shouldn't exceed 32K since this are tcp timer ticks 1381195972f6Sopenharmony_ci and a round-trip shouldn't be that long... */ 1382195972f6Sopenharmony_ci m = (s16_t)(tcp_ticks - pcb->rttest); 1383195972f6Sopenharmony_ci 1384195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n", 1385195972f6Sopenharmony_ci m, (u16_t)(m * TCP_SLOW_INTERVAL))); 1386195972f6Sopenharmony_ci 1387195972f6Sopenharmony_ci /* This is taken directly from VJs original code in his paper */ 1388195972f6Sopenharmony_ci m = (s16_t)(m - (pcb->sa >> 3)); 1389195972f6Sopenharmony_ci pcb->sa = (s16_t)(pcb->sa + m); 1390195972f6Sopenharmony_ci if (m < 0) { 1391195972f6Sopenharmony_ci m = (s16_t) - m; 1392195972f6Sopenharmony_ci } 1393195972f6Sopenharmony_ci m = (s16_t)(m - (pcb->sv >> 2)); 1394195972f6Sopenharmony_ci pcb->sv = (s16_t)(pcb->sv + m); 1395195972f6Sopenharmony_ci pcb->rto = (s16_t)((pcb->sa >> 3) + pcb->sv); 1396195972f6Sopenharmony_ci 1397195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n", 1398195972f6Sopenharmony_ci pcb->rto, (u16_t)(pcb->rto * TCP_SLOW_INTERVAL))); 1399195972f6Sopenharmony_ci 1400195972f6Sopenharmony_ci pcb->rttest = 0; 1401195972f6Sopenharmony_ci } 1402195972f6Sopenharmony_ci } 1403195972f6Sopenharmony_ci 1404195972f6Sopenharmony_ci /* If the incoming segment contains data, we must process it 1405195972f6Sopenharmony_ci further unless the pcb already received a FIN. 1406195972f6Sopenharmony_ci (RFC 793, chapter 3.9, "SEGMENT ARRIVES" in states CLOSE-WAIT, CLOSING, 1407195972f6Sopenharmony_ci LAST-ACK and TIME-WAIT: "Ignore the segment text.") */ 1408195972f6Sopenharmony_ci if ((tcplen > 0) && (pcb->state < CLOSE_WAIT)) { 1409195972f6Sopenharmony_ci /* This code basically does three things: 1410195972f6Sopenharmony_ci 1411195972f6Sopenharmony_ci +) If the incoming segment contains data that is the next 1412195972f6Sopenharmony_ci in-sequence data, this data is passed to the application. This 1413195972f6Sopenharmony_ci might involve trimming the first edge of the data. The rcv_nxt 1414195972f6Sopenharmony_ci variable and the advertised window are adjusted. 1415195972f6Sopenharmony_ci 1416195972f6Sopenharmony_ci +) If the incoming segment has data that is above the next 1417195972f6Sopenharmony_ci sequence number expected (->rcv_nxt), the segment is placed on 1418195972f6Sopenharmony_ci the ->ooseq queue. This is done by finding the appropriate 1419195972f6Sopenharmony_ci place in the ->ooseq queue (which is ordered by sequence 1420195972f6Sopenharmony_ci number) and trim the segment in both ends if needed. An 1421195972f6Sopenharmony_ci immediate ACK is sent to indicate that we received an 1422195972f6Sopenharmony_ci out-of-sequence segment. 1423195972f6Sopenharmony_ci 1424195972f6Sopenharmony_ci +) Finally, we check if the first segment on the ->ooseq queue 1425195972f6Sopenharmony_ci now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If 1426195972f6Sopenharmony_ci rcv_nxt > ooseq->seqno, we must trim the first edge of the 1427195972f6Sopenharmony_ci segment on ->ooseq before we adjust rcv_nxt. The data in the 1428195972f6Sopenharmony_ci segments that are now on sequence are chained onto the 1429195972f6Sopenharmony_ci incoming segment so that we only need to call the application 1430195972f6Sopenharmony_ci once. 1431195972f6Sopenharmony_ci */ 1432195972f6Sopenharmony_ci 1433195972f6Sopenharmony_ci /* First, we check if we must trim the first edge. We have to do 1434195972f6Sopenharmony_ci this if the sequence number of the incoming segment is less 1435195972f6Sopenharmony_ci than rcv_nxt, and the sequence number plus the length of the 1436195972f6Sopenharmony_ci segment is larger than rcv_nxt. */ 1437195972f6Sopenharmony_ci /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)) { 1438195972f6Sopenharmony_ci if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/ 1439195972f6Sopenharmony_ci if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)) { 1440195972f6Sopenharmony_ci /* Trimming the first edge is done by pushing the payload 1441195972f6Sopenharmony_ci pointer in the pbuf downwards. This is somewhat tricky since 1442195972f6Sopenharmony_ci we do not want to discard the full contents of the pbuf up to 1443195972f6Sopenharmony_ci the new starting point of the data since we have to keep the 1444195972f6Sopenharmony_ci TCP header which is present in the first pbuf in the chain. 1445195972f6Sopenharmony_ci 1446195972f6Sopenharmony_ci What is done is really quite a nasty hack: the first pbuf in 1447195972f6Sopenharmony_ci the pbuf chain is pointed to by inseg.p. Since we need to be 1448195972f6Sopenharmony_ci able to deallocate the whole pbuf, we cannot change this 1449195972f6Sopenharmony_ci inseg.p pointer to point to any of the later pbufs in the 1450195972f6Sopenharmony_ci chain. Instead, we point the ->payload pointer in the first 1451195972f6Sopenharmony_ci pbuf to data in one of the later pbufs. We also set the 1452195972f6Sopenharmony_ci inseg.data pointer to point to the right place. This way, the 1453195972f6Sopenharmony_ci ->p pointer will still point to the first pbuf, but the 1454195972f6Sopenharmony_ci ->p->payload pointer will point to data in another pbuf. 1455195972f6Sopenharmony_ci 1456195972f6Sopenharmony_ci After we are done with adjusting the pbuf pointers we must 1457195972f6Sopenharmony_ci adjust the ->data pointer in the seg and the segment 1458195972f6Sopenharmony_ci length.*/ 1459195972f6Sopenharmony_ci 1460195972f6Sopenharmony_ci struct pbuf *p = inseg.p; 1461195972f6Sopenharmony_ci u32_t off32 = pcb->rcv_nxt - seqno; 1462195972f6Sopenharmony_ci u16_t new_tot_len, off; 1463195972f6Sopenharmony_ci LWIP_ASSERT("inseg.p != NULL", inseg.p); 1464195972f6Sopenharmony_ci LWIP_ASSERT("insane offset!", (off32 < 0xffff)); 1465195972f6Sopenharmony_ci off = (u16_t)off32; 1466195972f6Sopenharmony_ci LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off)); 1467195972f6Sopenharmony_ci inseg.len -= off; 1468195972f6Sopenharmony_ci new_tot_len = (u16_t)(inseg.p->tot_len - off); 1469195972f6Sopenharmony_ci while (p->len < off) { 1470195972f6Sopenharmony_ci off -= p->len; 1471195972f6Sopenharmony_ci /* all pbufs up to and including this one have len==0, so tot_len is equal */ 1472195972f6Sopenharmony_ci p->tot_len = new_tot_len; 1473195972f6Sopenharmony_ci p->len = 0; 1474195972f6Sopenharmony_ci p = p->next; 1475195972f6Sopenharmony_ci } 1476195972f6Sopenharmony_ci /* cannot fail... */ 1477195972f6Sopenharmony_ci pbuf_remove_header(p, off); 1478195972f6Sopenharmony_ci inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; 1479195972f6Sopenharmony_ci } else { 1480195972f6Sopenharmony_ci if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)) { 1481195972f6Sopenharmony_ci /* the whole segment is < rcv_nxt */ 1482195972f6Sopenharmony_ci /* must be a duplicate of a packet that has already been correctly handled */ 1483195972f6Sopenharmony_ci 1484195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno)); 1485195972f6Sopenharmony_ci tcp_ack_now(pcb); 1486195972f6Sopenharmony_ci } 1487195972f6Sopenharmony_ci } 1488195972f6Sopenharmony_ci 1489195972f6Sopenharmony_ci /* The sequence number must be within the window (above rcv_nxt 1490195972f6Sopenharmony_ci and below rcv_nxt + rcv_wnd) in order to be further 1491195972f6Sopenharmony_ci processed. */ 1492195972f6Sopenharmony_ci if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, 1493195972f6Sopenharmony_ci pcb->rcv_nxt + pcb->rcv_wnd - 1)) { 1494195972f6Sopenharmony_ci if (pcb->rcv_nxt == seqno) { 1495195972f6Sopenharmony_ci /* The incoming segment is the next in sequence. We check if 1496195972f6Sopenharmony_ci we have to trim the end of the segment and update rcv_nxt 1497195972f6Sopenharmony_ci and pass the data to the application. */ 1498195972f6Sopenharmony_ci tcplen = TCP_TCPLEN(&inseg); 1499195972f6Sopenharmony_ci 1500195972f6Sopenharmony_ci if (tcplen > pcb->rcv_wnd) { 1501195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, 1502195972f6Sopenharmony_ci ("tcp_receive: other end overran receive window" 1503195972f6Sopenharmony_ci "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", 1504195972f6Sopenharmony_ci seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); 1505195972f6Sopenharmony_ci if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { 1506195972f6Sopenharmony_ci /* Must remove the FIN from the header as we're trimming 1507195972f6Sopenharmony_ci * that byte of sequence-space from the packet */ 1508195972f6Sopenharmony_ci TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) & ~(unsigned int)TCP_FIN); 1509195972f6Sopenharmony_ci } 1510195972f6Sopenharmony_ci /* Adjust length of segment to fit in the window. */ 1511195972f6Sopenharmony_ci TCPWND_CHECK16(pcb->rcv_wnd); 1512195972f6Sopenharmony_ci inseg.len = (u16_t)pcb->rcv_wnd; 1513195972f6Sopenharmony_ci if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { 1514195972f6Sopenharmony_ci inseg.len -= 1; 1515195972f6Sopenharmony_ci } 1516195972f6Sopenharmony_ci pbuf_realloc(inseg.p, inseg.len); 1517195972f6Sopenharmony_ci tcplen = TCP_TCPLEN(&inseg); 1518195972f6Sopenharmony_ci LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", 1519195972f6Sopenharmony_ci (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); 1520195972f6Sopenharmony_ci } 1521195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ 1522195972f6Sopenharmony_ci /* Received in-sequence data, adjust ooseq data if: 1523195972f6Sopenharmony_ci - FIN has been received or 1524195972f6Sopenharmony_ci - inseq overlaps with ooseq */ 1525195972f6Sopenharmony_ci if (pcb->ooseq != NULL) { 1526195972f6Sopenharmony_ci if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { 1527195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, 1528195972f6Sopenharmony_ci ("tcp_receive: received in-order FIN, binning ooseq queue\n")); 1529195972f6Sopenharmony_ci /* Received in-order FIN means anything that was received 1530195972f6Sopenharmony_ci * out of order must now have been received in-order, so 1531195972f6Sopenharmony_ci * bin the ooseq queue */ 1532195972f6Sopenharmony_ci while (pcb->ooseq != NULL) { 1533195972f6Sopenharmony_ci struct tcp_seg *old_ooseq = pcb->ooseq; 1534195972f6Sopenharmony_ci pcb->ooseq = pcb->ooseq->next; 1535195972f6Sopenharmony_ci tcp_seg_free(old_ooseq); 1536195972f6Sopenharmony_ci } 1537195972f6Sopenharmony_ci } else { 1538195972f6Sopenharmony_ci struct tcp_seg *next = pcb->ooseq; 1539195972f6Sopenharmony_ci /* Remove all segments on ooseq that are covered by inseg already. 1540195972f6Sopenharmony_ci * FIN is copied from ooseq to inseg if present. */ 1541195972f6Sopenharmony_ci while (next && 1542195972f6Sopenharmony_ci TCP_SEQ_GEQ(seqno + tcplen, 1543195972f6Sopenharmony_ci next->tcphdr->seqno + next->len)) { 1544195972f6Sopenharmony_ci struct tcp_seg *tmp; 1545195972f6Sopenharmony_ci /* inseg cannot have FIN here (already processed above) */ 1546195972f6Sopenharmony_ci if ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0 && 1547195972f6Sopenharmony_ci (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) { 1548195972f6Sopenharmony_ci TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN); 1549195972f6Sopenharmony_ci tcplen = TCP_TCPLEN(&inseg); 1550195972f6Sopenharmony_ci } 1551195972f6Sopenharmony_ci tmp = next; 1552195972f6Sopenharmony_ci next = next->next; 1553195972f6Sopenharmony_ci tcp_seg_free(tmp); 1554195972f6Sopenharmony_ci } 1555195972f6Sopenharmony_ci /* Now trim right side of inseg if it overlaps with the first 1556195972f6Sopenharmony_ci * segment on ooseq */ 1557195972f6Sopenharmony_ci if (next && 1558195972f6Sopenharmony_ci TCP_SEQ_GT(seqno + tcplen, 1559195972f6Sopenharmony_ci next->tcphdr->seqno)) { 1560195972f6Sopenharmony_ci /* inseg cannot have FIN here (already processed above) */ 1561195972f6Sopenharmony_ci inseg.len = (u16_t)(next->tcphdr->seqno - seqno); 1562195972f6Sopenharmony_ci if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { 1563195972f6Sopenharmony_ci inseg.len -= 1; 1564195972f6Sopenharmony_ci } 1565195972f6Sopenharmony_ci pbuf_realloc(inseg.p, inseg.len); 1566195972f6Sopenharmony_ci tcplen = TCP_TCPLEN(&inseg); 1567195972f6Sopenharmony_ci LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n", 1568195972f6Sopenharmony_ci (seqno + tcplen) == next->tcphdr->seqno); 1569195972f6Sopenharmony_ci } 1570195972f6Sopenharmony_ci pcb->ooseq = next; 1571195972f6Sopenharmony_ci } 1572195972f6Sopenharmony_ci } 1573195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ */ 1574195972f6Sopenharmony_ci 1575195972f6Sopenharmony_ci pcb->rcv_nxt = seqno + tcplen; 1576195972f6Sopenharmony_ci 1577195972f6Sopenharmony_ci /* Update the receiver's (our) window. */ 1578195972f6Sopenharmony_ci LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen); 1579195972f6Sopenharmony_ci pcb->rcv_wnd -= tcplen; 1580195972f6Sopenharmony_ci 1581195972f6Sopenharmony_ci tcp_update_rcv_ann_wnd(pcb); 1582195972f6Sopenharmony_ci 1583195972f6Sopenharmony_ci /* If there is data in the segment, we make preparations to 1584195972f6Sopenharmony_ci pass this up to the application. The ->recv_data variable 1585195972f6Sopenharmony_ci is used for holding the pbuf that goes to the 1586195972f6Sopenharmony_ci application. The code for reassembling out-of-sequence data 1587195972f6Sopenharmony_ci chains its data on this pbuf as well. 1588195972f6Sopenharmony_ci 1589195972f6Sopenharmony_ci If the segment was a FIN, we set the TF_GOT_FIN flag that will 1590195972f6Sopenharmony_ci be used to indicate to the application that the remote side has 1591195972f6Sopenharmony_ci closed its end of the connection. */ 1592195972f6Sopenharmony_ci if (inseg.p->tot_len > 0) { 1593195972f6Sopenharmony_ci recv_data = inseg.p; 1594195972f6Sopenharmony_ci /* Since this pbuf now is the responsibility of the 1595195972f6Sopenharmony_ci application, we delete our reference to it so that we won't 1596195972f6Sopenharmony_ci (mistakingly) deallocate it. */ 1597195972f6Sopenharmony_ci inseg.p = NULL; 1598195972f6Sopenharmony_ci } 1599195972f6Sopenharmony_ci if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { 1600195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n")); 1601195972f6Sopenharmony_ci recv_flags |= TF_GOT_FIN; 1602195972f6Sopenharmony_ci } 1603195972f6Sopenharmony_ci 1604195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ 1605195972f6Sopenharmony_ci /* We now check if we have segments on the ->ooseq queue that 1606195972f6Sopenharmony_ci are now in sequence. */ 1607195972f6Sopenharmony_ci while (pcb->ooseq != NULL && 1608195972f6Sopenharmony_ci pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) { 1609195972f6Sopenharmony_ci 1610195972f6Sopenharmony_ci struct tcp_seg *cseg = pcb->ooseq; 1611195972f6Sopenharmony_ci seqno = pcb->ooseq->tcphdr->seqno; 1612195972f6Sopenharmony_ci 1613195972f6Sopenharmony_ci pcb->rcv_nxt += TCP_TCPLEN(cseg); 1614195972f6Sopenharmony_ci LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n", 1615195972f6Sopenharmony_ci pcb->rcv_wnd >= TCP_TCPLEN(cseg)); 1616195972f6Sopenharmony_ci pcb->rcv_wnd -= TCP_TCPLEN(cseg); 1617195972f6Sopenharmony_ci 1618195972f6Sopenharmony_ci tcp_update_rcv_ann_wnd(pcb); 1619195972f6Sopenharmony_ci 1620195972f6Sopenharmony_ci if (cseg->p->tot_len > 0) { 1621195972f6Sopenharmony_ci /* Chain this pbuf onto the pbuf that we will pass to 1622195972f6Sopenharmony_ci the application. */ 1623195972f6Sopenharmony_ci /* With window scaling, this can overflow recv_data->tot_len, but 1624195972f6Sopenharmony_ci that's not a problem since we explicitly fix that before passing 1625195972f6Sopenharmony_ci recv_data to the application. */ 1626195972f6Sopenharmony_ci if (recv_data) { 1627195972f6Sopenharmony_ci pbuf_cat(recv_data, cseg->p); 1628195972f6Sopenharmony_ci } else { 1629195972f6Sopenharmony_ci recv_data = cseg->p; 1630195972f6Sopenharmony_ci } 1631195972f6Sopenharmony_ci cseg->p = NULL; 1632195972f6Sopenharmony_ci } 1633195972f6Sopenharmony_ci if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { 1634195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n")); 1635195972f6Sopenharmony_ci recv_flags |= TF_GOT_FIN; 1636195972f6Sopenharmony_ci if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */ 1637195972f6Sopenharmony_ci pcb->state = CLOSE_WAIT; 1638195972f6Sopenharmony_ci } 1639195972f6Sopenharmony_ci } 1640195972f6Sopenharmony_ci 1641195972f6Sopenharmony_ci pcb->ooseq = cseg->next; 1642195972f6Sopenharmony_ci tcp_seg_free(cseg); 1643195972f6Sopenharmony_ci } 1644195972f6Sopenharmony_ci#if LWIP_TCP_SACK_OUT 1645195972f6Sopenharmony_ci if (pcb->flags & TF_SACK) { 1646195972f6Sopenharmony_ci if (pcb->ooseq != NULL) { 1647195972f6Sopenharmony_ci /* Some segments may have been removed from ooseq, let's remove all SACKs that 1648195972f6Sopenharmony_ci describe anything before the new beginning of that list. */ 1649195972f6Sopenharmony_ci tcp_remove_sacks_lt(pcb, pcb->ooseq->tcphdr->seqno); 1650195972f6Sopenharmony_ci } else if (LWIP_TCP_SACK_VALID(pcb, 0)) { 1651195972f6Sopenharmony_ci /* ooseq has been cleared. Nothing to SACK */ 1652195972f6Sopenharmony_ci memset(pcb->rcv_sacks, 0, sizeof(pcb->rcv_sacks)); 1653195972f6Sopenharmony_ci } 1654195972f6Sopenharmony_ci } 1655195972f6Sopenharmony_ci#endif /* LWIP_TCP_SACK_OUT */ 1656195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ */ 1657195972f6Sopenharmony_ci 1658195972f6Sopenharmony_ci 1659195972f6Sopenharmony_ci /* Acknowledge the segment(s). */ 1660195972f6Sopenharmony_ci tcp_ack(pcb); 1661195972f6Sopenharmony_ci 1662195972f6Sopenharmony_ci#if LWIP_TCP_SACK_OUT 1663195972f6Sopenharmony_ci if (LWIP_TCP_SACK_VALID(pcb, 0)) { 1664195972f6Sopenharmony_ci /* Normally the ACK for the data received could be piggy-backed on a data packet, 1665195972f6Sopenharmony_ci but lwIP currently does not support including SACKs in data packets. So we force 1666195972f6Sopenharmony_ci it to respond with an empty ACK packet (only if there is at least one SACK to be sent). 1667195972f6Sopenharmony_ci NOTE: tcp_send_empty_ack() on success clears the ACK flags (set by tcp_ack()) */ 1668195972f6Sopenharmony_ci tcp_send_empty_ack(pcb); 1669195972f6Sopenharmony_ci } 1670195972f6Sopenharmony_ci#endif /* LWIP_TCP_SACK_OUT */ 1671195972f6Sopenharmony_ci 1672195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS 1673195972f6Sopenharmony_ci if (ip_current_is_v6()) { 1674195972f6Sopenharmony_ci /* Inform neighbor reachability of forward progress. */ 1675195972f6Sopenharmony_ci nd6_reachability_hint(ip6_current_src_addr()); 1676195972f6Sopenharmony_ci } 1677195972f6Sopenharmony_ci#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/ 1678195972f6Sopenharmony_ci 1679195972f6Sopenharmony_ci } else { 1680195972f6Sopenharmony_ci /* We get here if the incoming segment is out-of-sequence. */ 1681195972f6Sopenharmony_ci 1682195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ 1683195972f6Sopenharmony_ci /* We queue the segment on the ->ooseq queue. */ 1684195972f6Sopenharmony_ci if (pcb->ooseq == NULL) { 1685195972f6Sopenharmony_ci pcb->ooseq = tcp_seg_copy(&inseg); 1686195972f6Sopenharmony_ci#if LWIP_TCP_SACK_OUT 1687195972f6Sopenharmony_ci if (pcb->flags & TF_SACK) { 1688195972f6Sopenharmony_ci /* All the SACKs should be invalid, so we can simply store the most recent one: */ 1689195972f6Sopenharmony_ci pcb->rcv_sacks[0].left = seqno; 1690195972f6Sopenharmony_ci pcb->rcv_sacks[0].right = seqno + inseg.len; 1691195972f6Sopenharmony_ci } 1692195972f6Sopenharmony_ci#endif /* LWIP_TCP_SACK_OUT */ 1693195972f6Sopenharmony_ci } else { 1694195972f6Sopenharmony_ci /* If the queue is not empty, we walk through the queue and 1695195972f6Sopenharmony_ci try to find a place where the sequence number of the 1696195972f6Sopenharmony_ci incoming segment is between the sequence numbers of the 1697195972f6Sopenharmony_ci previous and the next segment on the ->ooseq queue. That is 1698195972f6Sopenharmony_ci the place where we put the incoming segment. If needed, we 1699195972f6Sopenharmony_ci trim the second edges of the previous and the incoming 1700195972f6Sopenharmony_ci segment so that it will fit into the sequence. 1701195972f6Sopenharmony_ci 1702195972f6Sopenharmony_ci If the incoming segment has the same sequence number as a 1703195972f6Sopenharmony_ci segment on the ->ooseq queue, we discard the segment that 1704195972f6Sopenharmony_ci contains less data. */ 1705195972f6Sopenharmony_ci 1706195972f6Sopenharmony_ci#if LWIP_TCP_SACK_OUT 1707195972f6Sopenharmony_ci /* This is the left edge of the lowest possible SACK range. 1708195972f6Sopenharmony_ci It may start before the newly received segment (possibly adjusted below). */ 1709195972f6Sopenharmony_ci u32_t sackbeg = TCP_SEQ_LT(seqno, pcb->ooseq->tcphdr->seqno) ? seqno : pcb->ooseq->tcphdr->seqno; 1710195972f6Sopenharmony_ci#endif /* LWIP_TCP_SACK_OUT */ 1711195972f6Sopenharmony_ci struct tcp_seg *next, *prev = NULL; 1712195972f6Sopenharmony_ci for (next = pcb->ooseq; next != NULL; next = next->next) { 1713195972f6Sopenharmony_ci if (seqno == next->tcphdr->seqno) { 1714195972f6Sopenharmony_ci /* The sequence number of the incoming segment is the 1715195972f6Sopenharmony_ci same as the sequence number of the segment on 1716195972f6Sopenharmony_ci ->ooseq. We check the lengths to see which one to 1717195972f6Sopenharmony_ci discard. */ 1718195972f6Sopenharmony_ci if (inseg.len > next->len) { 1719195972f6Sopenharmony_ci /* The incoming segment is larger than the old 1720195972f6Sopenharmony_ci segment. We replace some segments with the new 1721195972f6Sopenharmony_ci one. */ 1722195972f6Sopenharmony_ci struct tcp_seg *cseg = tcp_seg_copy(&inseg); 1723195972f6Sopenharmony_ci if (cseg != NULL) { 1724195972f6Sopenharmony_ci if (prev != NULL) { 1725195972f6Sopenharmony_ci prev->next = cseg; 1726195972f6Sopenharmony_ci } else { 1727195972f6Sopenharmony_ci pcb->ooseq = cseg; 1728195972f6Sopenharmony_ci } 1729195972f6Sopenharmony_ci tcp_oos_insert_segment(cseg, next); 1730195972f6Sopenharmony_ci } 1731195972f6Sopenharmony_ci break; 1732195972f6Sopenharmony_ci } else { 1733195972f6Sopenharmony_ci /* Either the lengths are the same or the incoming 1734195972f6Sopenharmony_ci segment was smaller than the old one; in either 1735195972f6Sopenharmony_ci case, we ditch the incoming segment. */ 1736195972f6Sopenharmony_ci break; 1737195972f6Sopenharmony_ci } 1738195972f6Sopenharmony_ci } else { 1739195972f6Sopenharmony_ci if (prev == NULL) { 1740195972f6Sopenharmony_ci if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) { 1741195972f6Sopenharmony_ci /* The sequence number of the incoming segment is lower 1742195972f6Sopenharmony_ci than the sequence number of the first segment on the 1743195972f6Sopenharmony_ci queue. We put the incoming segment first on the 1744195972f6Sopenharmony_ci queue. */ 1745195972f6Sopenharmony_ci struct tcp_seg *cseg = tcp_seg_copy(&inseg); 1746195972f6Sopenharmony_ci if (cseg != NULL) { 1747195972f6Sopenharmony_ci pcb->ooseq = cseg; 1748195972f6Sopenharmony_ci tcp_oos_insert_segment(cseg, next); 1749195972f6Sopenharmony_ci } 1750195972f6Sopenharmony_ci break; 1751195972f6Sopenharmony_ci } 1752195972f6Sopenharmony_ci } else { 1753195972f6Sopenharmony_ci /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) && 1754195972f6Sopenharmony_ci TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/ 1755195972f6Sopenharmony_ci if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno + 1, next->tcphdr->seqno - 1)) { 1756195972f6Sopenharmony_ci /* The sequence number of the incoming segment is in 1757195972f6Sopenharmony_ci between the sequence numbers of the previous and 1758195972f6Sopenharmony_ci the next segment on ->ooseq. We trim trim the previous 1759195972f6Sopenharmony_ci segment, delete next segments that included in received segment 1760195972f6Sopenharmony_ci and trim received, if needed. */ 1761195972f6Sopenharmony_ci struct tcp_seg *cseg = tcp_seg_copy(&inseg); 1762195972f6Sopenharmony_ci if (cseg != NULL) { 1763195972f6Sopenharmony_ci if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) { 1764195972f6Sopenharmony_ci /* We need to trim the prev segment. */ 1765195972f6Sopenharmony_ci prev->len = (u16_t)(seqno - prev->tcphdr->seqno); 1766195972f6Sopenharmony_ci pbuf_realloc(prev->p, prev->len); 1767195972f6Sopenharmony_ci } 1768195972f6Sopenharmony_ci prev->next = cseg; 1769195972f6Sopenharmony_ci tcp_oos_insert_segment(cseg, next); 1770195972f6Sopenharmony_ci } 1771195972f6Sopenharmony_ci break; 1772195972f6Sopenharmony_ci } 1773195972f6Sopenharmony_ci } 1774195972f6Sopenharmony_ci 1775195972f6Sopenharmony_ci#if LWIP_TCP_SACK_OUT 1776195972f6Sopenharmony_ci /* The new segment goes after the 'next' one. If there is a "hole" in sequence numbers 1777195972f6Sopenharmony_ci between 'prev' and the beginning of 'next', we want to move sackbeg. */ 1778195972f6Sopenharmony_ci if (prev != NULL && prev->tcphdr->seqno + prev->len != next->tcphdr->seqno) { 1779195972f6Sopenharmony_ci sackbeg = next->tcphdr->seqno; 1780195972f6Sopenharmony_ci } 1781195972f6Sopenharmony_ci#endif /* LWIP_TCP_SACK_OUT */ 1782195972f6Sopenharmony_ci 1783195972f6Sopenharmony_ci /* We don't use 'prev' below, so let's set it to current 'next'. 1784195972f6Sopenharmony_ci This way even if we break the loop below, 'prev' will be pointing 1785195972f6Sopenharmony_ci at the segment right in front of the newly added one. */ 1786195972f6Sopenharmony_ci prev = next; 1787195972f6Sopenharmony_ci 1788195972f6Sopenharmony_ci /* If the "next" segment is the last segment on the 1789195972f6Sopenharmony_ci ooseq queue, we add the incoming segment to the end 1790195972f6Sopenharmony_ci of the list. */ 1791195972f6Sopenharmony_ci if (next->next == NULL && 1792195972f6Sopenharmony_ci TCP_SEQ_GT(seqno, next->tcphdr->seqno)) { 1793195972f6Sopenharmony_ci if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { 1794195972f6Sopenharmony_ci /* segment "next" already contains all data */ 1795195972f6Sopenharmony_ci break; 1796195972f6Sopenharmony_ci } 1797195972f6Sopenharmony_ci next->next = tcp_seg_copy(&inseg); 1798195972f6Sopenharmony_ci if (next->next != NULL) { 1799195972f6Sopenharmony_ci if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) { 1800195972f6Sopenharmony_ci /* We need to trim the last segment. */ 1801195972f6Sopenharmony_ci next->len = (u16_t)(seqno - next->tcphdr->seqno); 1802195972f6Sopenharmony_ci pbuf_realloc(next->p, next->len); 1803195972f6Sopenharmony_ci } 1804195972f6Sopenharmony_ci /* check if the remote side overruns our receive window */ 1805195972f6Sopenharmony_ci if (TCP_SEQ_GT((u32_t)tcplen + seqno, pcb->rcv_nxt + (u32_t)pcb->rcv_wnd)) { 1806195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, 1807195972f6Sopenharmony_ci ("tcp_receive: other end overran receive window" 1808195972f6Sopenharmony_ci "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", 1809195972f6Sopenharmony_ci seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); 1810195972f6Sopenharmony_ci if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) { 1811195972f6Sopenharmony_ci /* Must remove the FIN from the header as we're trimming 1812195972f6Sopenharmony_ci * that byte of sequence-space from the packet */ 1813195972f6Sopenharmony_ci TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) & ~TCP_FIN); 1814195972f6Sopenharmony_ci } 1815195972f6Sopenharmony_ci /* Adjust length of segment to fit in the window. */ 1816195972f6Sopenharmony_ci next->next->len = (u16_t)(pcb->rcv_nxt + pcb->rcv_wnd - seqno); 1817195972f6Sopenharmony_ci pbuf_realloc(next->next->p, next->next->len); 1818195972f6Sopenharmony_ci tcplen = TCP_TCPLEN(next->next); 1819195972f6Sopenharmony_ci LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", 1820195972f6Sopenharmony_ci (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); 1821195972f6Sopenharmony_ci } 1822195972f6Sopenharmony_ci } 1823195972f6Sopenharmony_ci break; 1824195972f6Sopenharmony_ci } 1825195972f6Sopenharmony_ci } 1826195972f6Sopenharmony_ci } 1827195972f6Sopenharmony_ci 1828195972f6Sopenharmony_ci#if LWIP_TCP_SACK_OUT 1829195972f6Sopenharmony_ci if (pcb->flags & TF_SACK) { 1830195972f6Sopenharmony_ci if (prev == NULL) { 1831195972f6Sopenharmony_ci /* The new segment is at the beginning. sackbeg should already be set properly. 1832195972f6Sopenharmony_ci We need to find the right edge. */ 1833195972f6Sopenharmony_ci next = pcb->ooseq; 1834195972f6Sopenharmony_ci } else if (prev->next != NULL) { 1835195972f6Sopenharmony_ci /* The new segment was added after 'prev'. If there is a "hole" between 'prev' and 'prev->next', 1836195972f6Sopenharmony_ci we need to move sackbeg. After that we should find the right edge. */ 1837195972f6Sopenharmony_ci next = prev->next; 1838195972f6Sopenharmony_ci if (prev->tcphdr->seqno + prev->len != next->tcphdr->seqno) { 1839195972f6Sopenharmony_ci sackbeg = next->tcphdr->seqno; 1840195972f6Sopenharmony_ci } 1841195972f6Sopenharmony_ci } else { 1842195972f6Sopenharmony_ci next = NULL; 1843195972f6Sopenharmony_ci } 1844195972f6Sopenharmony_ci if (next != NULL) { 1845195972f6Sopenharmony_ci u32_t sackend = next->tcphdr->seqno; 1846195972f6Sopenharmony_ci for ( ; (next != NULL) && (sackend == next->tcphdr->seqno); next = next->next) { 1847195972f6Sopenharmony_ci sackend += next->len; 1848195972f6Sopenharmony_ci } 1849195972f6Sopenharmony_ci tcp_add_sack(pcb, sackbeg, sackend); 1850195972f6Sopenharmony_ci } 1851195972f6Sopenharmony_ci } 1852195972f6Sopenharmony_ci#endif /* LWIP_TCP_SACK_OUT */ 1853195972f6Sopenharmony_ci } 1854195972f6Sopenharmony_ci#if defined(TCP_OOSEQ_BYTES_LIMIT) || defined(TCP_OOSEQ_PBUFS_LIMIT) 1855195972f6Sopenharmony_ci { 1856195972f6Sopenharmony_ci /* Check that the data on ooseq doesn't exceed one of the limits 1857195972f6Sopenharmony_ci and throw away everything above that limit. */ 1858195972f6Sopenharmony_ci#ifdef TCP_OOSEQ_BYTES_LIMIT 1859195972f6Sopenharmony_ci const u32_t ooseq_max_blen = TCP_OOSEQ_BYTES_LIMIT(pcb); 1860195972f6Sopenharmony_ci u32_t ooseq_blen = 0; 1861195972f6Sopenharmony_ci#endif 1862195972f6Sopenharmony_ci#ifdef TCP_OOSEQ_PBUFS_LIMIT 1863195972f6Sopenharmony_ci const u16_t ooseq_max_qlen = TCP_OOSEQ_PBUFS_LIMIT(pcb); 1864195972f6Sopenharmony_ci u16_t ooseq_qlen = 0; 1865195972f6Sopenharmony_ci#endif 1866195972f6Sopenharmony_ci struct tcp_seg *next, *prev = NULL; 1867195972f6Sopenharmony_ci for (next = pcb->ooseq; next != NULL; prev = next, next = next->next) { 1868195972f6Sopenharmony_ci struct pbuf *p = next->p; 1869195972f6Sopenharmony_ci int stop_here = 0; 1870195972f6Sopenharmony_ci#ifdef TCP_OOSEQ_BYTES_LIMIT 1871195972f6Sopenharmony_ci ooseq_blen += p->tot_len; 1872195972f6Sopenharmony_ci if (ooseq_blen > ooseq_max_blen) { 1873195972f6Sopenharmony_ci stop_here = 1; 1874195972f6Sopenharmony_ci } 1875195972f6Sopenharmony_ci#endif 1876195972f6Sopenharmony_ci#ifdef TCP_OOSEQ_PBUFS_LIMIT 1877195972f6Sopenharmony_ci ooseq_qlen += pbuf_clen(p); 1878195972f6Sopenharmony_ci if (ooseq_qlen > ooseq_max_qlen) { 1879195972f6Sopenharmony_ci stop_here = 1; 1880195972f6Sopenharmony_ci } 1881195972f6Sopenharmony_ci#endif 1882195972f6Sopenharmony_ci if (stop_here) { 1883195972f6Sopenharmony_ci#if LWIP_TCP_SACK_OUT 1884195972f6Sopenharmony_ci if (pcb->flags & TF_SACK) { 1885195972f6Sopenharmony_ci /* Let's remove all SACKs from next's seqno up. */ 1886195972f6Sopenharmony_ci tcp_remove_sacks_gt(pcb, next->tcphdr->seqno); 1887195972f6Sopenharmony_ci } 1888195972f6Sopenharmony_ci#endif /* LWIP_TCP_SACK_OUT */ 1889195972f6Sopenharmony_ci /* too much ooseq data, dump this and everything after it */ 1890195972f6Sopenharmony_ci tcp_segs_free(next); 1891195972f6Sopenharmony_ci if (prev == NULL) { 1892195972f6Sopenharmony_ci /* first ooseq segment is too much, dump the whole queue */ 1893195972f6Sopenharmony_ci pcb->ooseq = NULL; 1894195972f6Sopenharmony_ci } else { 1895195972f6Sopenharmony_ci /* just dump 'next' and everything after it */ 1896195972f6Sopenharmony_ci prev->next = NULL; 1897195972f6Sopenharmony_ci } 1898195972f6Sopenharmony_ci break; 1899195972f6Sopenharmony_ci } 1900195972f6Sopenharmony_ci } 1901195972f6Sopenharmony_ci } 1902195972f6Sopenharmony_ci#endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */ 1903195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ */ 1904195972f6Sopenharmony_ci 1905195972f6Sopenharmony_ci /* We send the ACK packet after we've (potentially) dealt with SACKs, 1906195972f6Sopenharmony_ci so they can be included in the acknowledgment. */ 1907195972f6Sopenharmony_ci tcp_send_empty_ack(pcb); 1908195972f6Sopenharmony_ci } 1909195972f6Sopenharmony_ci } else { 1910195972f6Sopenharmony_ci /* The incoming segment is not within the window. */ 1911195972f6Sopenharmony_ci tcp_send_empty_ack(pcb); 1912195972f6Sopenharmony_ci } 1913195972f6Sopenharmony_ci } else { 1914195972f6Sopenharmony_ci /* Segments with length 0 is taken care of here. Segments that 1915195972f6Sopenharmony_ci fall out of the window are ACKed. */ 1916195972f6Sopenharmony_ci if (!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)) { 1917195972f6Sopenharmony_ci tcp_ack_now(pcb); 1918195972f6Sopenharmony_ci } 1919195972f6Sopenharmony_ci } 1920195972f6Sopenharmony_ci} 1921195972f6Sopenharmony_ci 1922195972f6Sopenharmony_cistatic u8_t 1923195972f6Sopenharmony_citcp_get_next_optbyte(void) 1924195972f6Sopenharmony_ci{ 1925195972f6Sopenharmony_ci u16_t optidx = tcp_optidx++; 1926195972f6Sopenharmony_ci if ((tcphdr_opt2 == NULL) || (optidx < tcphdr_opt1len)) { 1927195972f6Sopenharmony_ci u8_t *opts = (u8_t *)tcphdr + TCP_HLEN; 1928195972f6Sopenharmony_ci return opts[optidx]; 1929195972f6Sopenharmony_ci } else { 1930195972f6Sopenharmony_ci u8_t idx = (u8_t)(optidx - tcphdr_opt1len); 1931195972f6Sopenharmony_ci return tcphdr_opt2[idx]; 1932195972f6Sopenharmony_ci } 1933195972f6Sopenharmony_ci} 1934195972f6Sopenharmony_ci 1935195972f6Sopenharmony_ci/** 1936195972f6Sopenharmony_ci * Parses the options contained in the incoming segment. 1937195972f6Sopenharmony_ci * 1938195972f6Sopenharmony_ci * Called from tcp_listen_input() and tcp_process(). 1939195972f6Sopenharmony_ci * Currently, only the MSS option is supported! 1940195972f6Sopenharmony_ci * 1941195972f6Sopenharmony_ci * @param pcb the tcp_pcb for which a segment arrived 1942195972f6Sopenharmony_ci */ 1943195972f6Sopenharmony_cistatic void 1944195972f6Sopenharmony_citcp_parseopt(struct tcp_pcb *pcb) 1945195972f6Sopenharmony_ci{ 1946195972f6Sopenharmony_ci u8_t data; 1947195972f6Sopenharmony_ci u16_t mss; 1948195972f6Sopenharmony_ci#if LWIP_TCP_TIMESTAMPS 1949195972f6Sopenharmony_ci u32_t tsval; 1950195972f6Sopenharmony_ci#endif 1951195972f6Sopenharmony_ci 1952195972f6Sopenharmony_ci LWIP_ASSERT("tcp_parseopt: invalid pcb", pcb != NULL); 1953195972f6Sopenharmony_ci 1954195972f6Sopenharmony_ci /* Parse the TCP MSS option, if present. */ 1955195972f6Sopenharmony_ci if (tcphdr_optlen != 0) { 1956195972f6Sopenharmony_ci for (tcp_optidx = 0; tcp_optidx < tcphdr_optlen; ) { 1957195972f6Sopenharmony_ci u8_t opt = tcp_get_next_optbyte(); 1958195972f6Sopenharmony_ci switch (opt) { 1959195972f6Sopenharmony_ci case LWIP_TCP_OPT_EOL: 1960195972f6Sopenharmony_ci /* End of options. */ 1961195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n")); 1962195972f6Sopenharmony_ci return; 1963195972f6Sopenharmony_ci case LWIP_TCP_OPT_NOP: 1964195972f6Sopenharmony_ci /* NOP option. */ 1965195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n")); 1966195972f6Sopenharmony_ci break; 1967195972f6Sopenharmony_ci case LWIP_TCP_OPT_MSS: 1968195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n")); 1969195972f6Sopenharmony_ci if (tcp_get_next_optbyte() != LWIP_TCP_OPT_LEN_MSS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_MSS) > tcphdr_optlen) { 1970195972f6Sopenharmony_ci /* Bad length */ 1971195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); 1972195972f6Sopenharmony_ci return; 1973195972f6Sopenharmony_ci } 1974195972f6Sopenharmony_ci /* An MSS option with the right option length. */ 1975195972f6Sopenharmony_ci mss = (u16_t)(tcp_get_next_optbyte() << 8); 1976195972f6Sopenharmony_ci mss |= tcp_get_next_optbyte(); 1977195972f6Sopenharmony_ci /* Limit the mss to the configured TCP_MSS and prevent division by zero */ 1978195972f6Sopenharmony_ci pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss; 1979195972f6Sopenharmony_ci break; 1980195972f6Sopenharmony_ci#if LWIP_WND_SCALE 1981195972f6Sopenharmony_ci case LWIP_TCP_OPT_WS: 1982195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: WND_SCALE\n")); 1983195972f6Sopenharmony_ci if (tcp_get_next_optbyte() != LWIP_TCP_OPT_LEN_WS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_WS) > tcphdr_optlen) { 1984195972f6Sopenharmony_ci /* Bad length */ 1985195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); 1986195972f6Sopenharmony_ci return; 1987195972f6Sopenharmony_ci } 1988195972f6Sopenharmony_ci /* An WND_SCALE option with the right option length. */ 1989195972f6Sopenharmony_ci data = tcp_get_next_optbyte(); 1990195972f6Sopenharmony_ci /* If syn was received with wnd scale option, 1991195972f6Sopenharmony_ci activate wnd scale opt, but only if this is not a retransmission */ 1992195972f6Sopenharmony_ci if ((flags & TCP_SYN) && !(pcb->flags & TF_WND_SCALE)) { 1993195972f6Sopenharmony_ci pcb->snd_scale = data; 1994195972f6Sopenharmony_ci if (pcb->snd_scale > 14U) { 1995195972f6Sopenharmony_ci pcb->snd_scale = 14U; 1996195972f6Sopenharmony_ci } 1997195972f6Sopenharmony_ci pcb->rcv_scale = TCP_RCV_SCALE; 1998195972f6Sopenharmony_ci tcp_set_flags(pcb, TF_WND_SCALE); 1999195972f6Sopenharmony_ci /* window scaling is enabled, we can use the full receive window */ 2000195972f6Sopenharmony_ci LWIP_ASSERT("window not at default value", pcb->rcv_wnd == TCPWND_MIN16(TCP_WND)); 2001195972f6Sopenharmony_ci LWIP_ASSERT("window not at default value", pcb->rcv_ann_wnd == TCPWND_MIN16(TCP_WND)); 2002195972f6Sopenharmony_ci pcb->rcv_wnd = pcb->rcv_ann_wnd = TCP_WND; 2003195972f6Sopenharmony_ci } 2004195972f6Sopenharmony_ci break; 2005195972f6Sopenharmony_ci#endif /* LWIP_WND_SCALE */ 2006195972f6Sopenharmony_ci#if LWIP_TCP_TIMESTAMPS 2007195972f6Sopenharmony_ci case LWIP_TCP_OPT_TS: 2008195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n")); 2009195972f6Sopenharmony_ci if (tcp_get_next_optbyte() != LWIP_TCP_OPT_LEN_TS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_TS) > tcphdr_optlen) { 2010195972f6Sopenharmony_ci /* Bad length */ 2011195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); 2012195972f6Sopenharmony_ci return; 2013195972f6Sopenharmony_ci } 2014195972f6Sopenharmony_ci /* TCP timestamp option with valid length */ 2015195972f6Sopenharmony_ci tsval = tcp_get_next_optbyte(); 2016195972f6Sopenharmony_ci tsval |= (tcp_get_next_optbyte() << 8); 2017195972f6Sopenharmony_ci tsval |= (tcp_get_next_optbyte() << 16); 2018195972f6Sopenharmony_ci tsval |= (tcp_get_next_optbyte() << 24); 2019195972f6Sopenharmony_ci if (flags & TCP_SYN) { 2020195972f6Sopenharmony_ci pcb->ts_recent = lwip_ntohl(tsval); 2021195972f6Sopenharmony_ci /* Enable sending timestamps in every segment now that we know 2022195972f6Sopenharmony_ci the remote host supports it. */ 2023195972f6Sopenharmony_ci tcp_set_flags(pcb, TF_TIMESTAMP); 2024195972f6Sopenharmony_ci } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno + tcplen)) { 2025195972f6Sopenharmony_ci pcb->ts_recent = lwip_ntohl(tsval); 2026195972f6Sopenharmony_ci } 2027195972f6Sopenharmony_ci /* Advance to next option (6 bytes already read) */ 2028195972f6Sopenharmony_ci tcp_optidx += LWIP_TCP_OPT_LEN_TS - 6; 2029195972f6Sopenharmony_ci break; 2030195972f6Sopenharmony_ci#endif /* LWIP_TCP_TIMESTAMPS */ 2031195972f6Sopenharmony_ci#if LWIP_TCP_SACK_OUT 2032195972f6Sopenharmony_ci case LWIP_TCP_OPT_SACK_PERM: 2033195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: SACK_PERM\n")); 2034195972f6Sopenharmony_ci if (tcp_get_next_optbyte() != LWIP_TCP_OPT_LEN_SACK_PERM || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_SACK_PERM) > tcphdr_optlen) { 2035195972f6Sopenharmony_ci /* Bad length */ 2036195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); 2037195972f6Sopenharmony_ci return; 2038195972f6Sopenharmony_ci } 2039195972f6Sopenharmony_ci /* TCP SACK_PERM option with valid length */ 2040195972f6Sopenharmony_ci if (flags & TCP_SYN) { 2041195972f6Sopenharmony_ci /* We only set it if we receive it in a SYN (or SYN+ACK) packet */ 2042195972f6Sopenharmony_ci tcp_set_flags(pcb, TF_SACK); 2043195972f6Sopenharmony_ci } 2044195972f6Sopenharmony_ci break; 2045195972f6Sopenharmony_ci#endif /* LWIP_TCP_SACK_OUT */ 2046195972f6Sopenharmony_ci default: 2047195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n")); 2048195972f6Sopenharmony_ci data = tcp_get_next_optbyte(); 2049195972f6Sopenharmony_ci if (data < 2) { 2050195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); 2051195972f6Sopenharmony_ci /* If the length field is zero, the options are malformed 2052195972f6Sopenharmony_ci and we don't process them further. */ 2053195972f6Sopenharmony_ci return; 2054195972f6Sopenharmony_ci } 2055195972f6Sopenharmony_ci /* All other options have a length field, so that we easily 2056195972f6Sopenharmony_ci can skip past them. */ 2057195972f6Sopenharmony_ci tcp_optidx += data - 2; 2058195972f6Sopenharmony_ci } 2059195972f6Sopenharmony_ci } 2060195972f6Sopenharmony_ci } 2061195972f6Sopenharmony_ci} 2062195972f6Sopenharmony_ci 2063195972f6Sopenharmony_civoid 2064195972f6Sopenharmony_citcp_trigger_input_pcb_close(void) 2065195972f6Sopenharmony_ci{ 2066195972f6Sopenharmony_ci recv_flags |= TF_CLOSED; 2067195972f6Sopenharmony_ci} 2068195972f6Sopenharmony_ci 2069195972f6Sopenharmony_ci#if LWIP_TCP_SACK_OUT 2070195972f6Sopenharmony_ci/** 2071195972f6Sopenharmony_ci * Called by tcp_receive() to add new SACK entry. 2072195972f6Sopenharmony_ci * 2073195972f6Sopenharmony_ci * The new SACK entry will be placed at the beginning of rcv_sacks[], as the newest one. 2074195972f6Sopenharmony_ci * Existing SACK entries will be "pushed back", to preserve their order. 2075195972f6Sopenharmony_ci * This is the behavior described in RFC 2018, section 4. 2076195972f6Sopenharmony_ci * 2077195972f6Sopenharmony_ci * @param pcb the tcp_pcb for which a segment arrived 2078195972f6Sopenharmony_ci * @param left the left side of the SACK (the first sequence number) 2079195972f6Sopenharmony_ci * @param right the right side of the SACK (the first sequence number past this SACK) 2080195972f6Sopenharmony_ci */ 2081195972f6Sopenharmony_cistatic void 2082195972f6Sopenharmony_citcp_add_sack(struct tcp_pcb *pcb, u32_t left, u32_t right) 2083195972f6Sopenharmony_ci{ 2084195972f6Sopenharmony_ci u8_t i; 2085195972f6Sopenharmony_ci u8_t unused_idx; 2086195972f6Sopenharmony_ci 2087195972f6Sopenharmony_ci if ((pcb->flags & TF_SACK) == 0 || !TCP_SEQ_LT(left, right)) { 2088195972f6Sopenharmony_ci return; 2089195972f6Sopenharmony_ci } 2090195972f6Sopenharmony_ci 2091195972f6Sopenharmony_ci /* First, let's remove all SACKs that are no longer needed (because they overlap with the newest one), 2092195972f6Sopenharmony_ci while moving all other SACKs forward. 2093195972f6Sopenharmony_ci We run this loop for all entries, until we find the first invalid one. 2094195972f6Sopenharmony_ci There is no point checking after that. */ 2095195972f6Sopenharmony_ci for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && LWIP_TCP_SACK_VALID(pcb, i); ++i) { 2096195972f6Sopenharmony_ci /* We only want to use SACK at [i] if it doesn't overlap with left:right range. 2097195972f6Sopenharmony_ci It does not overlap if its right side is before the newly added SACK, 2098195972f6Sopenharmony_ci or if its left side is after the newly added SACK. 2099195972f6Sopenharmony_ci NOTE: The equality should not really happen, but it doesn't hurt. */ 2100195972f6Sopenharmony_ci if (TCP_SEQ_LEQ(pcb->rcv_sacks[i].right, left) || TCP_SEQ_LEQ(right, pcb->rcv_sacks[i].left)) { 2101195972f6Sopenharmony_ci if (unused_idx != i) { 2102195972f6Sopenharmony_ci /* We don't need to copy if it's already in the right spot */ 2103195972f6Sopenharmony_ci pcb->rcv_sacks[unused_idx] = pcb->rcv_sacks[i]; 2104195972f6Sopenharmony_ci } 2105195972f6Sopenharmony_ci ++unused_idx; 2106195972f6Sopenharmony_ci } 2107195972f6Sopenharmony_ci } 2108195972f6Sopenharmony_ci 2109195972f6Sopenharmony_ci /* Now 'unused_idx' is the index of the first invalid SACK entry, 2110195972f6Sopenharmony_ci anywhere between 0 (no valid entries) and LWIP_TCP_MAX_SACK_NUM (all entries are valid). 2111195972f6Sopenharmony_ci We want to clear this and all following SACKs. 2112195972f6Sopenharmony_ci However, we will be adding another one in the front (and shifting everything else back). 2113195972f6Sopenharmony_ci So let's just iterate from the back, and set each entry to the one to the left if it's valid, 2114195972f6Sopenharmony_ci or to 0 if it is not. */ 2115195972f6Sopenharmony_ci for (i = LWIP_TCP_MAX_SACK_NUM - 1; i > 0; --i) { 2116195972f6Sopenharmony_ci /* [i] is the index we are setting, and the value should be at index [i-1], 2117195972f6Sopenharmony_ci or 0 if that index is unused (>= unused_idx). */ 2118195972f6Sopenharmony_ci if (i - 1 >= unused_idx) { 2119195972f6Sopenharmony_ci /* [i-1] is unused. Let's clear [i]. */ 2120195972f6Sopenharmony_ci pcb->rcv_sacks[i].left = pcb->rcv_sacks[i].right = 0; 2121195972f6Sopenharmony_ci } else { 2122195972f6Sopenharmony_ci pcb->rcv_sacks[i] = pcb->rcv_sacks[i - 1]; 2123195972f6Sopenharmony_ci } 2124195972f6Sopenharmony_ci } 2125195972f6Sopenharmony_ci 2126195972f6Sopenharmony_ci /* And now we can store the newest SACK */ 2127195972f6Sopenharmony_ci pcb->rcv_sacks[0].left = left; 2128195972f6Sopenharmony_ci pcb->rcv_sacks[0].right = right; 2129195972f6Sopenharmony_ci} 2130195972f6Sopenharmony_ci 2131195972f6Sopenharmony_ci/** 2132195972f6Sopenharmony_ci * Called to remove a range of SACKs. 2133195972f6Sopenharmony_ci * 2134195972f6Sopenharmony_ci * SACK entries will be removed or adjusted to not acknowledge any sequence 2135195972f6Sopenharmony_ci * numbers that are less than 'seq' passed. It not only invalidates entries, 2136195972f6Sopenharmony_ci * but also moves all entries that are still valid to the beginning. 2137195972f6Sopenharmony_ci * 2138195972f6Sopenharmony_ci * @param pcb the tcp_pcb to modify 2139195972f6Sopenharmony_ci * @param seq the lowest sequence number to keep in SACK entries 2140195972f6Sopenharmony_ci */ 2141195972f6Sopenharmony_cistatic void 2142195972f6Sopenharmony_citcp_remove_sacks_lt(struct tcp_pcb *pcb, u32_t seq) 2143195972f6Sopenharmony_ci{ 2144195972f6Sopenharmony_ci u8_t i; 2145195972f6Sopenharmony_ci u8_t unused_idx; 2146195972f6Sopenharmony_ci 2147195972f6Sopenharmony_ci /* We run this loop for all entries, until we find the first invalid one. 2148195972f6Sopenharmony_ci There is no point checking after that. */ 2149195972f6Sopenharmony_ci for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && LWIP_TCP_SACK_VALID(pcb, i); ++i) { 2150195972f6Sopenharmony_ci /* We only want to use SACK at index [i] if its right side is > 'seq'. */ 2151195972f6Sopenharmony_ci if (TCP_SEQ_GT(pcb->rcv_sacks[i].right, seq)) { 2152195972f6Sopenharmony_ci if (unused_idx != i) { 2153195972f6Sopenharmony_ci /* We only copy it if it's not in the right spot already. */ 2154195972f6Sopenharmony_ci pcb->rcv_sacks[unused_idx] = pcb->rcv_sacks[i]; 2155195972f6Sopenharmony_ci } 2156195972f6Sopenharmony_ci /* NOTE: It is possible that its left side is < 'seq', in which case we should adjust it. */ 2157195972f6Sopenharmony_ci if (TCP_SEQ_LT(pcb->rcv_sacks[unused_idx].left, seq)) { 2158195972f6Sopenharmony_ci pcb->rcv_sacks[unused_idx].left = seq; 2159195972f6Sopenharmony_ci } 2160195972f6Sopenharmony_ci ++unused_idx; 2161195972f6Sopenharmony_ci } 2162195972f6Sopenharmony_ci } 2163195972f6Sopenharmony_ci 2164195972f6Sopenharmony_ci /* We also need to invalidate everything from 'unused_idx' till the end */ 2165195972f6Sopenharmony_ci for (i = unused_idx; i < LWIP_TCP_MAX_SACK_NUM; ++i) { 2166195972f6Sopenharmony_ci pcb->rcv_sacks[i].left = pcb->rcv_sacks[i].right = 0; 2167195972f6Sopenharmony_ci } 2168195972f6Sopenharmony_ci} 2169195972f6Sopenharmony_ci 2170195972f6Sopenharmony_ci#if defined(TCP_OOSEQ_BYTES_LIMIT) || defined(TCP_OOSEQ_PBUFS_LIMIT) 2171195972f6Sopenharmony_ci/** 2172195972f6Sopenharmony_ci * Called to remove a range of SACKs. 2173195972f6Sopenharmony_ci * 2174195972f6Sopenharmony_ci * SACK entries will be removed or adjusted to not acknowledge any sequence 2175195972f6Sopenharmony_ci * numbers that are greater than (or equal to) 'seq' passed. It not only invalidates entries, 2176195972f6Sopenharmony_ci * but also moves all entries that are still valid to the beginning. 2177195972f6Sopenharmony_ci * 2178195972f6Sopenharmony_ci * @param pcb the tcp_pcb to modify 2179195972f6Sopenharmony_ci * @param seq the highest sequence number to keep in SACK entries 2180195972f6Sopenharmony_ci */ 2181195972f6Sopenharmony_cistatic void 2182195972f6Sopenharmony_citcp_remove_sacks_gt(struct tcp_pcb *pcb, u32_t seq) 2183195972f6Sopenharmony_ci{ 2184195972f6Sopenharmony_ci u8_t i; 2185195972f6Sopenharmony_ci u8_t unused_idx; 2186195972f6Sopenharmony_ci 2187195972f6Sopenharmony_ci /* We run this loop for all entries, until we find the first invalid one. 2188195972f6Sopenharmony_ci There is no point checking after that. */ 2189195972f6Sopenharmony_ci for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && LWIP_TCP_SACK_VALID(pcb, i); ++i) { 2190195972f6Sopenharmony_ci /* We only want to use SACK at index [i] if its left side is < 'seq'. */ 2191195972f6Sopenharmony_ci if (TCP_SEQ_LT(pcb->rcv_sacks[i].left, seq)) { 2192195972f6Sopenharmony_ci if (unused_idx != i) { 2193195972f6Sopenharmony_ci /* We only copy it if it's not in the right spot already. */ 2194195972f6Sopenharmony_ci pcb->rcv_sacks[unused_idx] = pcb->rcv_sacks[i]; 2195195972f6Sopenharmony_ci } 2196195972f6Sopenharmony_ci /* NOTE: It is possible that its right side is > 'seq', in which case we should adjust it. */ 2197195972f6Sopenharmony_ci if (TCP_SEQ_GT(pcb->rcv_sacks[unused_idx].right, seq)) { 2198195972f6Sopenharmony_ci pcb->rcv_sacks[unused_idx].right = seq; 2199195972f6Sopenharmony_ci } 2200195972f6Sopenharmony_ci ++unused_idx; 2201195972f6Sopenharmony_ci } 2202195972f6Sopenharmony_ci } 2203195972f6Sopenharmony_ci 2204195972f6Sopenharmony_ci /* We also need to invalidate everything from 'unused_idx' till the end */ 2205195972f6Sopenharmony_ci for (i = unused_idx; i < LWIP_TCP_MAX_SACK_NUM; ++i) { 2206195972f6Sopenharmony_ci pcb->rcv_sacks[i].left = pcb->rcv_sacks[i].right = 0; 2207195972f6Sopenharmony_ci } 2208195972f6Sopenharmony_ci} 2209195972f6Sopenharmony_ci#endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */ 2210195972f6Sopenharmony_ci 2211195972f6Sopenharmony_ci#endif /* LWIP_TCP_SACK_OUT */ 2212195972f6Sopenharmony_ci 2213195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 2214