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