1195972f6Sopenharmony_ci/** 2195972f6Sopenharmony_ci * @file 3195972f6Sopenharmony_ci * Transmission Control Protocol for IP 4195972f6Sopenharmony_ci * See also @ref tcp_raw 5195972f6Sopenharmony_ci * 6195972f6Sopenharmony_ci * @defgroup tcp_raw TCP 7195972f6Sopenharmony_ci * @ingroup callbackstyle_api 8195972f6Sopenharmony_ci * Transmission Control Protocol for IP\n 9195972f6Sopenharmony_ci * @see @ref api 10195972f6Sopenharmony_ci * 11195972f6Sopenharmony_ci * Common functions for the TCP implementation, such as functions 12195972f6Sopenharmony_ci * for manipulating the data structures and the TCP timer functions. TCP functions 13195972f6Sopenharmony_ci * related to input and output is found in tcp_in.c and tcp_out.c respectively.\n 14195972f6Sopenharmony_ci * 15195972f6Sopenharmony_ci * TCP connection setup 16195972f6Sopenharmony_ci * -------------------- 17195972f6Sopenharmony_ci * The functions used for setting up connections is similar to that of 18195972f6Sopenharmony_ci * the sequential API and of the BSD socket API. A new TCP connection 19195972f6Sopenharmony_ci * identifier (i.e., a protocol control block - PCB) is created with the 20195972f6Sopenharmony_ci * tcp_new() function. This PCB can then be either set to listen for new 21195972f6Sopenharmony_ci * incoming connections or be explicitly connected to another host. 22195972f6Sopenharmony_ci * - tcp_new() 23195972f6Sopenharmony_ci * - tcp_bind() 24195972f6Sopenharmony_ci * - tcp_listen() and tcp_listen_with_backlog() 25195972f6Sopenharmony_ci * - tcp_accept() 26195972f6Sopenharmony_ci * - tcp_connect() 27195972f6Sopenharmony_ci * 28195972f6Sopenharmony_ci * Sending TCP data 29195972f6Sopenharmony_ci * ---------------- 30195972f6Sopenharmony_ci * TCP data is sent by enqueueing the data with a call to tcp_write() and 31195972f6Sopenharmony_ci * triggering to send by calling tcp_output(). When the data is successfully 32195972f6Sopenharmony_ci * transmitted to the remote host, the application will be notified with a 33195972f6Sopenharmony_ci * call to a specified callback function. 34195972f6Sopenharmony_ci * - tcp_write() 35195972f6Sopenharmony_ci * - tcp_output() 36195972f6Sopenharmony_ci * - tcp_sent() 37195972f6Sopenharmony_ci * 38195972f6Sopenharmony_ci * Receiving TCP data 39195972f6Sopenharmony_ci * ------------------ 40195972f6Sopenharmony_ci * TCP data reception is callback based - an application specified 41195972f6Sopenharmony_ci * callback function is called when new data arrives. When the 42195972f6Sopenharmony_ci * application has taken the data, it has to call the tcp_recved() 43195972f6Sopenharmony_ci * function to indicate that TCP can advertise increase the receive 44195972f6Sopenharmony_ci * window. 45195972f6Sopenharmony_ci * - tcp_recv() 46195972f6Sopenharmony_ci * - tcp_recved() 47195972f6Sopenharmony_ci * 48195972f6Sopenharmony_ci * Application polling 49195972f6Sopenharmony_ci * ------------------- 50195972f6Sopenharmony_ci * When a connection is idle (i.e., no data is either transmitted or 51195972f6Sopenharmony_ci * received), lwIP will repeatedly poll the application by calling a 52195972f6Sopenharmony_ci * specified callback function. This can be used either as a watchdog 53195972f6Sopenharmony_ci * timer for killing connections that have stayed idle for too long, or 54195972f6Sopenharmony_ci * as a method of waiting for memory to become available. For instance, 55195972f6Sopenharmony_ci * if a call to tcp_write() has failed because memory wasn't available, 56195972f6Sopenharmony_ci * the application may use the polling functionality to call tcp_write() 57195972f6Sopenharmony_ci * again when the connection has been idle for a while. 58195972f6Sopenharmony_ci * - tcp_poll() 59195972f6Sopenharmony_ci * 60195972f6Sopenharmony_ci * Closing and aborting connections 61195972f6Sopenharmony_ci * -------------------------------- 62195972f6Sopenharmony_ci * - tcp_close() 63195972f6Sopenharmony_ci * - tcp_abort() 64195972f6Sopenharmony_ci * - tcp_err() 65195972f6Sopenharmony_ci * 66195972f6Sopenharmony_ci */ 67195972f6Sopenharmony_ci 68195972f6Sopenharmony_ci/* 69195972f6Sopenharmony_ci * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 70195972f6Sopenharmony_ci * All rights reserved. 71195972f6Sopenharmony_ci * 72195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 73195972f6Sopenharmony_ci * are permitted provided that the following conditions are met: 74195972f6Sopenharmony_ci * 75195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, 76195972f6Sopenharmony_ci * this list of conditions and the following disclaimer. 77195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, 78195972f6Sopenharmony_ci * this list of conditions and the following disclaimer in the documentation 79195972f6Sopenharmony_ci * and/or other materials provided with the distribution. 80195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products 81195972f6Sopenharmony_ci * derived from this software without specific prior written permission. 82195972f6Sopenharmony_ci * 83195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 84195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 85195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 86195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 87195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 88195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 89195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 90195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 91195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 92195972f6Sopenharmony_ci * OF SUCH DAMAGE. 93195972f6Sopenharmony_ci * 94195972f6Sopenharmony_ci * This file is part of the lwIP TCP/IP stack. 95195972f6Sopenharmony_ci * 96195972f6Sopenharmony_ci * Author: Adam Dunkels <adam@sics.se> 97195972f6Sopenharmony_ci * 98195972f6Sopenharmony_ci */ 99195972f6Sopenharmony_ci 100195972f6Sopenharmony_ci#include "lwip/opt.h" 101195972f6Sopenharmony_ci 102195972f6Sopenharmony_ci#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ 103195972f6Sopenharmony_ci 104195972f6Sopenharmony_ci#include "lwip/def.h" 105195972f6Sopenharmony_ci#include "lwip/mem.h" 106195972f6Sopenharmony_ci#include "lwip/memp.h" 107195972f6Sopenharmony_ci#include "lwip/tcp.h" 108195972f6Sopenharmony_ci#include "lwip/priv/tcp_priv.h" 109195972f6Sopenharmony_ci#include "lwip/debug.h" 110195972f6Sopenharmony_ci#include "lwip/stats.h" 111195972f6Sopenharmony_ci#include "lwip/ip6.h" 112195972f6Sopenharmony_ci#include "lwip/ip6_addr.h" 113195972f6Sopenharmony_ci#include "lwip/nd6.h" 114195972f6Sopenharmony_ci#if LWIP_LOWPOWER 115195972f6Sopenharmony_ci#include "lwip/priv/api_msg.h" 116195972f6Sopenharmony_ci#endif 117195972f6Sopenharmony_ci 118195972f6Sopenharmony_ci#include <string.h> 119195972f6Sopenharmony_ci 120195972f6Sopenharmony_ci#ifdef LWIP_HOOK_FILENAME 121195972f6Sopenharmony_ci#include LWIP_HOOK_FILENAME 122195972f6Sopenharmony_ci#endif 123195972f6Sopenharmony_ci 124195972f6Sopenharmony_ci#ifndef TCP_LOCAL_PORT_RANGE_START 125195972f6Sopenharmony_ci/* From http://www.iana.org/assignments/port-numbers: 126195972f6Sopenharmony_ci "The Dynamic and/or Private Ports are those from 49152 through 65535" */ 127195972f6Sopenharmony_ci#define TCP_LOCAL_PORT_RANGE_START 0xc000 128195972f6Sopenharmony_ci#define TCP_LOCAL_PORT_RANGE_END 0xffff 129195972f6Sopenharmony_ci#define TCP_ENSURE_LOCAL_PORT_RANGE(port) ((u16_t)(((port) & (u16_t)~TCP_LOCAL_PORT_RANGE_START) + TCP_LOCAL_PORT_RANGE_START)) 130195972f6Sopenharmony_ci#endif 131195972f6Sopenharmony_ci 132195972f6Sopenharmony_ci#if LWIP_TCP_KEEPALIVE 133195972f6Sopenharmony_ci#define TCP_KEEP_DUR(pcb) ((pcb)->keep_cnt * (pcb)->keep_intvl) 134195972f6Sopenharmony_ci#define TCP_KEEP_INTVL(pcb) ((pcb)->keep_intvl) 135195972f6Sopenharmony_ci#else /* LWIP_TCP_KEEPALIVE */ 136195972f6Sopenharmony_ci#define TCP_KEEP_DUR(pcb) TCP_MAXIDLE 137195972f6Sopenharmony_ci#define TCP_KEEP_INTVL(pcb) TCP_KEEPINTVL_DEFAULT 138195972f6Sopenharmony_ci#endif /* LWIP_TCP_KEEPALIVE */ 139195972f6Sopenharmony_ci 140195972f6Sopenharmony_ci/* As initial send MSS, we use TCP_MSS but limit it to 536. */ 141195972f6Sopenharmony_ci#if TCP_MSS > 536 142195972f6Sopenharmony_ci#define INITIAL_MSS 536 143195972f6Sopenharmony_ci#else 144195972f6Sopenharmony_ci#define INITIAL_MSS TCP_MSS 145195972f6Sopenharmony_ci#endif 146195972f6Sopenharmony_ci 147195972f6Sopenharmony_cistatic const char *const tcp_state_str[] = { 148195972f6Sopenharmony_ci "CLOSED", 149195972f6Sopenharmony_ci "LISTEN", 150195972f6Sopenharmony_ci "SYN_SENT", 151195972f6Sopenharmony_ci "SYN_RCVD", 152195972f6Sopenharmony_ci "ESTABLISHED", 153195972f6Sopenharmony_ci "FIN_WAIT_1", 154195972f6Sopenharmony_ci "FIN_WAIT_2", 155195972f6Sopenharmony_ci "CLOSE_WAIT", 156195972f6Sopenharmony_ci "CLOSING", 157195972f6Sopenharmony_ci "LAST_ACK", 158195972f6Sopenharmony_ci "TIME_WAIT" 159195972f6Sopenharmony_ci}; 160195972f6Sopenharmony_ci 161195972f6Sopenharmony_ci/* last local TCP port */ 162195972f6Sopenharmony_cistatic volatile u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; 163195972f6Sopenharmony_ci 164195972f6Sopenharmony_ci/* Incremented every coarse grained timer shot (typically every 500 ms). */ 165195972f6Sopenharmony_ciu32_t tcp_ticks; 166195972f6Sopenharmony_cistatic const u8_t tcp_backoff[13] = 167195972f6Sopenharmony_ci{ 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; 168195972f6Sopenharmony_ci/* Times per slowtmr hits */ 169195972f6Sopenharmony_cistatic const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; 170195972f6Sopenharmony_ci 171195972f6Sopenharmony_ci/* The TCP PCB lists. */ 172195972f6Sopenharmony_ci 173195972f6Sopenharmony_ci/** List of all TCP PCBs bound but not yet (connected || listening) */ 174195972f6Sopenharmony_cistruct tcp_pcb *tcp_bound_pcbs; 175195972f6Sopenharmony_ci/** List of all TCP PCBs in LISTEN state */ 176195972f6Sopenharmony_ciunion tcp_listen_pcbs_t tcp_listen_pcbs; 177195972f6Sopenharmony_ci/** List of all TCP PCBs that are in a state in which 178195972f6Sopenharmony_ci * they accept or send data. */ 179195972f6Sopenharmony_cistruct tcp_pcb *tcp_active_pcbs; 180195972f6Sopenharmony_ci/** List of all TCP PCBs in TIME-WAIT state */ 181195972f6Sopenharmony_cistruct tcp_pcb *tcp_tw_pcbs; 182195972f6Sopenharmony_ci 183195972f6Sopenharmony_ci/** An array with all (non-temporary) PCB lists, mainly used for smaller code size */ 184195972f6Sopenharmony_cistruct tcp_pcb **const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs, 185195972f6Sopenharmony_ci &tcp_active_pcbs, &tcp_tw_pcbs 186195972f6Sopenharmony_ci}; 187195972f6Sopenharmony_ci 188195972f6Sopenharmony_ciu8_t tcp_active_pcbs_changed; 189195972f6Sopenharmony_ci 190195972f6Sopenharmony_ci/** Timer counter to handle calling slow-timer from tcp_tmr() */ 191195972f6Sopenharmony_cistatic u8_t tcp_timer; 192195972f6Sopenharmony_cistatic u8_t tcp_timer_ctr; 193195972f6Sopenharmony_cistatic u16_t tcp_new_port(void); 194195972f6Sopenharmony_ci 195195972f6Sopenharmony_cistatic err_t tcp_close_shutdown_fin(struct tcp_pcb *pcb); 196195972f6Sopenharmony_ci#if LWIP_TCP_PCB_NUM_EXT_ARGS 197195972f6Sopenharmony_cistatic void tcp_ext_arg_invoke_callbacks_destroyed(struct tcp_pcb_ext_args *ext_args); 198195972f6Sopenharmony_ci#endif 199195972f6Sopenharmony_ci 200195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 201195972f6Sopenharmony_civoid set_tcp_pcb_net_group(struct tcp_pcb *pcb, struct net_group *group) 202195972f6Sopenharmony_ci{ 203195972f6Sopenharmony_ci set_ippcb_net_group((struct ip_pcb *)pcb, group); 204195972f6Sopenharmony_ci} 205195972f6Sopenharmony_ci 206195972f6Sopenharmony_cistruct net_group *get_net_group_from_tcp_pcb(const struct tcp_pcb *pcb) 207195972f6Sopenharmony_ci{ 208195972f6Sopenharmony_ci return get_net_group_from_ippcb((struct ip_pcb *)pcb); 209195972f6Sopenharmony_ci} 210195972f6Sopenharmony_ci#endif 211195972f6Sopenharmony_ci/** 212195972f6Sopenharmony_ci * Initialize this module. 213195972f6Sopenharmony_ci */ 214195972f6Sopenharmony_civoid 215195972f6Sopenharmony_citcp_init(void) 216195972f6Sopenharmony_ci{ 217195972f6Sopenharmony_ci#ifdef LWIP_RAND 218195972f6Sopenharmony_ci tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); 219195972f6Sopenharmony_ci#endif /* LWIP_RAND */ 220195972f6Sopenharmony_ci} 221195972f6Sopenharmony_ci 222195972f6Sopenharmony_ci/** Free a tcp pcb */ 223195972f6Sopenharmony_civoid 224195972f6Sopenharmony_citcp_free(struct tcp_pcb *pcb) 225195972f6Sopenharmony_ci{ 226195972f6Sopenharmony_ci LWIP_ASSERT("tcp_free: LISTEN", pcb->state != LISTEN); 227195972f6Sopenharmony_ci#if LWIP_TCP_PCB_NUM_EXT_ARGS 228195972f6Sopenharmony_ci tcp_ext_arg_invoke_callbacks_destroyed(pcb->ext_args); 229195972f6Sopenharmony_ci#endif 230195972f6Sopenharmony_ci memp_free(MEMP_TCP_PCB, pcb); 231195972f6Sopenharmony_ci} 232195972f6Sopenharmony_ci 233195972f6Sopenharmony_ci/** Free a tcp listen pcb */ 234195972f6Sopenharmony_cistatic void 235195972f6Sopenharmony_citcp_free_listen(struct tcp_pcb *pcb) 236195972f6Sopenharmony_ci{ 237195972f6Sopenharmony_ci LWIP_ASSERT("tcp_free_listen: !LISTEN", pcb->state != LISTEN); 238195972f6Sopenharmony_ci#if LWIP_TCP_PCB_NUM_EXT_ARGS 239195972f6Sopenharmony_ci tcp_ext_arg_invoke_callbacks_destroyed(pcb->ext_args); 240195972f6Sopenharmony_ci#endif 241195972f6Sopenharmony_ci memp_free(MEMP_TCP_PCB_LISTEN, pcb); 242195972f6Sopenharmony_ci} 243195972f6Sopenharmony_ci 244195972f6Sopenharmony_ci/** 245195972f6Sopenharmony_ci * Called periodically to dispatch TCP timers. 246195972f6Sopenharmony_ci */ 247195972f6Sopenharmony_civoid 248195972f6Sopenharmony_citcp_tmr(void) 249195972f6Sopenharmony_ci{ 250195972f6Sopenharmony_ci /* Call tcp_fasttmr() every 250 ms */ 251195972f6Sopenharmony_ci tcp_fasttmr(); 252195972f6Sopenharmony_ci 253195972f6Sopenharmony_ci if (++tcp_timer & 1) { 254195972f6Sopenharmony_ci /* Call tcp_slowtmr() every 500 ms, i.e., every other timer 255195972f6Sopenharmony_ci tcp_tmr() is called. */ 256195972f6Sopenharmony_ci tcp_slowtmr(); 257195972f6Sopenharmony_ci } 258195972f6Sopenharmony_ci} 259195972f6Sopenharmony_ci 260195972f6Sopenharmony_ci#if LWIP_LOWPOWER 261195972f6Sopenharmony_ci#include "lwip/lowpower.h" 262195972f6Sopenharmony_ci 263195972f6Sopenharmony_cistatic u32_t 264195972f6Sopenharmony_citcp_set_timer_tick_by_persist(struct tcp_pcb *pcb, u32_t tick) 265195972f6Sopenharmony_ci{ 266195972f6Sopenharmony_ci u32_t val; 267195972f6Sopenharmony_ci 268195972f6Sopenharmony_ci if (pcb->persist_backoff > 0) { 269195972f6Sopenharmony_ci u8_t backoff_cnt = tcp_persist_backoff[pcb->persist_backoff - 1]; 270195972f6Sopenharmony_ci SET_TMR_TICK(tick, backoff_cnt); 271195972f6Sopenharmony_ci return tick; 272195972f6Sopenharmony_ci } 273195972f6Sopenharmony_ci 274195972f6Sopenharmony_ci /* timer not running */ 275195972f6Sopenharmony_ci if (pcb->rtime >= 0) { 276195972f6Sopenharmony_ci val = pcb->rto - pcb->rtime; 277195972f6Sopenharmony_ci if (val == 0) { 278195972f6Sopenharmony_ci val = 1; 279195972f6Sopenharmony_ci } 280195972f6Sopenharmony_ci SET_TMR_TICK(tick, val); 281195972f6Sopenharmony_ci } 282195972f6Sopenharmony_ci return tick; 283195972f6Sopenharmony_ci} 284195972f6Sopenharmony_ci 285195972f6Sopenharmony_cistatic u32_t 286195972f6Sopenharmony_citcp_set_timer_tick_by_keepalive(struct tcp_pcb *pcb, u32_t tick) 287195972f6Sopenharmony_ci{ 288195972f6Sopenharmony_ci u32_t val; 289195972f6Sopenharmony_ci 290195972f6Sopenharmony_ci if (ip_get_option(pcb, SOF_KEEPALIVE) && 291195972f6Sopenharmony_ci ((pcb->state == ESTABLISHED) || 292195972f6Sopenharmony_ci (pcb->state == CLOSE_WAIT))) { 293195972f6Sopenharmony_ci u32_t idle = (pcb->keep_idle) / TCP_SLOW_INTERVAL; 294195972f6Sopenharmony_ci if (pcb->keep_cnt_sent == 0) { 295195972f6Sopenharmony_ci val = idle - (tcp_ticks - pcb->tmr); 296195972f6Sopenharmony_ci } else { 297195972f6Sopenharmony_ci val = (tcp_ticks - pcb->tmr) - idle; 298195972f6Sopenharmony_ci idle = (TCP_KEEP_INTVL(pcb) / TCP_SLOW_INTERVAL); 299195972f6Sopenharmony_ci val = idle - (val % idle); 300195972f6Sopenharmony_ci } 301195972f6Sopenharmony_ci /* need add 1 to trig timer */ 302195972f6Sopenharmony_ci val++; 303195972f6Sopenharmony_ci SET_TMR_TICK(tick, val); 304195972f6Sopenharmony_ci } 305195972f6Sopenharmony_ci 306195972f6Sopenharmony_ci return tick; 307195972f6Sopenharmony_ci} 308195972f6Sopenharmony_ci 309195972f6Sopenharmony_cistatic u32_t tcp_set_timer_tick_by_tcp_state(struct tcp_pcb *pcb, u32_t tick) 310195972f6Sopenharmony_ci{ 311195972f6Sopenharmony_ci u32_t val; 312195972f6Sopenharmony_ci 313195972f6Sopenharmony_ci /* Check if this PCB has stayed too long in FIN-WAIT-2 */ 314195972f6Sopenharmony_ci if (pcb->state == FIN_WAIT_2) { 315195972f6Sopenharmony_ci /* If this PCB is in FIN_WAIT_2 because of SHUT_WR don't let it time out. */ 316195972f6Sopenharmony_ci if (pcb->flags & TF_RXCLOSED) { 317195972f6Sopenharmony_ci val = TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL; 318195972f6Sopenharmony_ci SET_TMR_TICK(tick, val); 319195972f6Sopenharmony_ci } 320195972f6Sopenharmony_ci } 321195972f6Sopenharmony_ci 322195972f6Sopenharmony_ci /* Check if this PCB has stayed too long in SYN-RCVD */ 323195972f6Sopenharmony_ci if (pcb->state == SYN_RCVD) { 324195972f6Sopenharmony_ci val = TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL; 325195972f6Sopenharmony_ci SET_TMR_TICK(tick, val); 326195972f6Sopenharmony_ci } 327195972f6Sopenharmony_ci 328195972f6Sopenharmony_ci /* Check if this PCB has stayed too long in LAST-ACK */ 329195972f6Sopenharmony_ci if (pcb->state == LAST_ACK) { 330195972f6Sopenharmony_ci /* 331195972f6Sopenharmony_ci * In a TCP connection the end that performs the active close 332195972f6Sopenharmony_ci * is required to stay in TIME_WAIT state for 2MSL of time 333195972f6Sopenharmony_ci */ 334195972f6Sopenharmony_ci val = (2 * TCP_MSL) / TCP_SLOW_INTERVAL; 335195972f6Sopenharmony_ci SET_TMR_TICK(tick, val); 336195972f6Sopenharmony_ci } 337195972f6Sopenharmony_ci 338195972f6Sopenharmony_ci return tick; 339195972f6Sopenharmony_ci} 340195972f6Sopenharmony_ci 341195972f6Sopenharmony_ciu32_t 342195972f6Sopenharmony_citcp_slow_tmr_tick(void) 343195972f6Sopenharmony_ci{ 344195972f6Sopenharmony_ci struct tcp_pcb *pcb = NULL; 345195972f6Sopenharmony_ci u32_t tick = 0; 346195972f6Sopenharmony_ci 347195972f6Sopenharmony_ci pcb = tcp_active_pcbs; 348195972f6Sopenharmony_ci while (pcb != NULL) { 349195972f6Sopenharmony_ci if (((pcb->state == SYN_SENT) && (pcb->nrtx >= TCP_SYNMAXRTX)) || 350195972f6Sopenharmony_ci ((pcb->state == FIN_WAIT_1) || (pcb->state == CLOSING)) || 351195972f6Sopenharmony_ci (pcb->nrtx >= TCP_MAXRTX)) { 352195972f6Sopenharmony_ci return 1; 353195972f6Sopenharmony_ci } 354195972f6Sopenharmony_ci 355195972f6Sopenharmony_ci tick = tcp_set_timer_tick_by_persist(pcb, tick); 356195972f6Sopenharmony_ci tick = tcp_set_timer_tick_by_keepalive(pcb, tick); 357195972f6Sopenharmony_ci 358195972f6Sopenharmony_ci /* 359195972f6Sopenharmony_ci * If this PCB has queued out of sequence data, but has been 360195972f6Sopenharmony_ci * inactive for too long, will drop the data (it will eventually 361195972f6Sopenharmony_ci * be retransmitted). 362195972f6Sopenharmony_ci */ 363195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ 364195972f6Sopenharmony_ci if (pcb->ooseq != NULL) { 365195972f6Sopenharmony_ci SET_TMR_TICK(tick, 1); 366195972f6Sopenharmony_ci } 367195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ */ 368195972f6Sopenharmony_ci 369195972f6Sopenharmony_ci tick = tcp_set_timer_tick_by_tcp_state(pcb, tick); 370195972f6Sopenharmony_ci 371195972f6Sopenharmony_ci u8_t ret = poll_tcp_needed(pcb->callback_arg, pcb); 372195972f6Sopenharmony_ci if ((pcb->poll != NULL) && (ret != 0)) { 373195972f6Sopenharmony_ci SET_TMR_TICK(tick, 1); 374195972f6Sopenharmony_ci } 375195972f6Sopenharmony_ci pcb = pcb->next; 376195972f6Sopenharmony_ci } 377195972f6Sopenharmony_ci 378195972f6Sopenharmony_ci LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "tcp_slow_tmr_tick", tick)); 379195972f6Sopenharmony_ci return tick; 380195972f6Sopenharmony_ci} 381195972f6Sopenharmony_ci 382195972f6Sopenharmony_ciu32_t 383195972f6Sopenharmony_citcp_fast_tmr_tick(void) 384195972f6Sopenharmony_ci{ 385195972f6Sopenharmony_ci struct tcp_pcb *pcb = NULL; 386195972f6Sopenharmony_ci 387195972f6Sopenharmony_ci pcb = tcp_active_pcbs; 388195972f6Sopenharmony_ci while (pcb != NULL) { 389195972f6Sopenharmony_ci /* send delayed ACKs or send pending FIN */ 390195972f6Sopenharmony_ci if ((pcb->flags & TF_ACK_DELAY) || 391195972f6Sopenharmony_ci (pcb->flags & TF_CLOSEPEND) || 392195972f6Sopenharmony_ci (pcb->refused_data != NULL) 393195972f6Sopenharmony_ci ) { 394195972f6Sopenharmony_ci LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 1\n", "tcp_fast_tmr_tick")); 395195972f6Sopenharmony_ci return 1; 396195972f6Sopenharmony_ci } 397195972f6Sopenharmony_ci pcb = pcb->next; 398195972f6Sopenharmony_ci } 399195972f6Sopenharmony_ci LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 0\n", "tcp_fast_tmr_tick")); 400195972f6Sopenharmony_ci return 0; 401195972f6Sopenharmony_ci} 402195972f6Sopenharmony_ci#endif /* LWIP_LOWPOWER */ 403195972f6Sopenharmony_ci 404195972f6Sopenharmony_ci#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG 405195972f6Sopenharmony_ci/** Called when a listen pcb is closed. Iterates one pcb list and removes the 406195972f6Sopenharmony_ci * closed listener pcb from pcb->listener if matching. 407195972f6Sopenharmony_ci */ 408195972f6Sopenharmony_cistatic void 409195972f6Sopenharmony_citcp_remove_listener(struct tcp_pcb *list, struct tcp_pcb_listen *lpcb) 410195972f6Sopenharmony_ci{ 411195972f6Sopenharmony_ci struct tcp_pcb *pcb; 412195972f6Sopenharmony_ci 413195972f6Sopenharmony_ci LWIP_ASSERT("tcp_remove_listener: invalid listener", lpcb != NULL); 414195972f6Sopenharmony_ci 415195972f6Sopenharmony_ci for (pcb = list; pcb != NULL; pcb = pcb->next) { 416195972f6Sopenharmony_ci if (pcb->listener == lpcb) { 417195972f6Sopenharmony_ci pcb->listener = NULL; 418195972f6Sopenharmony_ci } 419195972f6Sopenharmony_ci } 420195972f6Sopenharmony_ci} 421195972f6Sopenharmony_ci#endif 422195972f6Sopenharmony_ci 423195972f6Sopenharmony_ci/** Called when a listen pcb is closed. Iterates all pcb lists and removes the 424195972f6Sopenharmony_ci * closed listener pcb from pcb->listener if matching. 425195972f6Sopenharmony_ci */ 426195972f6Sopenharmony_cistatic void 427195972f6Sopenharmony_citcp_listen_closed(struct tcp_pcb *pcb) 428195972f6Sopenharmony_ci{ 429195972f6Sopenharmony_ci#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG 430195972f6Sopenharmony_ci size_t i; 431195972f6Sopenharmony_ci LWIP_ASSERT("pcb != NULL", pcb != NULL); 432195972f6Sopenharmony_ci LWIP_ASSERT("pcb->state == LISTEN", pcb->state == LISTEN); 433195972f6Sopenharmony_ci for (i = 1; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) { 434195972f6Sopenharmony_ci tcp_remove_listener(*tcp_pcb_lists[i], (struct tcp_pcb_listen *)pcb); 435195972f6Sopenharmony_ci } 436195972f6Sopenharmony_ci#endif 437195972f6Sopenharmony_ci LWIP_UNUSED_ARG(pcb); 438195972f6Sopenharmony_ci} 439195972f6Sopenharmony_ci 440195972f6Sopenharmony_ci#if TCP_LISTEN_BACKLOG 441195972f6Sopenharmony_ci/** @ingroup tcp_raw 442195972f6Sopenharmony_ci * Delay accepting a connection in respect to the listen backlog: 443195972f6Sopenharmony_ci * the number of outstanding connections is increased until 444195972f6Sopenharmony_ci * tcp_backlog_accepted() is called. 445195972f6Sopenharmony_ci * 446195972f6Sopenharmony_ci * ATTENTION: the caller is responsible for calling tcp_backlog_accepted() 447195972f6Sopenharmony_ci * or else the backlog feature will get out of sync! 448195972f6Sopenharmony_ci * 449195972f6Sopenharmony_ci * @param pcb the connection pcb which is not fully accepted yet 450195972f6Sopenharmony_ci */ 451195972f6Sopenharmony_civoid 452195972f6Sopenharmony_citcp_backlog_delayed(struct tcp_pcb *pcb) 453195972f6Sopenharmony_ci{ 454195972f6Sopenharmony_ci LWIP_ASSERT("pcb != NULL", pcb != NULL); 455195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 456195972f6Sopenharmony_ci if ((pcb->flags & TF_BACKLOGPEND) == 0) { 457195972f6Sopenharmony_ci if (pcb->listener != NULL) { 458195972f6Sopenharmony_ci pcb->listener->accepts_pending++; 459195972f6Sopenharmony_ci LWIP_ASSERT("accepts_pending != 0", pcb->listener->accepts_pending != 0); 460195972f6Sopenharmony_ci tcp_set_flags(pcb, TF_BACKLOGPEND); 461195972f6Sopenharmony_ci } 462195972f6Sopenharmony_ci } 463195972f6Sopenharmony_ci} 464195972f6Sopenharmony_ci 465195972f6Sopenharmony_ci/** @ingroup tcp_raw 466195972f6Sopenharmony_ci * A delayed-accept a connection is accepted (or closed/aborted): decreases 467195972f6Sopenharmony_ci * the number of outstanding connections after calling tcp_backlog_delayed(). 468195972f6Sopenharmony_ci * 469195972f6Sopenharmony_ci * ATTENTION: the caller is responsible for calling tcp_backlog_accepted() 470195972f6Sopenharmony_ci * or else the backlog feature will get out of sync! 471195972f6Sopenharmony_ci * 472195972f6Sopenharmony_ci * @param pcb the connection pcb which is now fully accepted (or closed/aborted) 473195972f6Sopenharmony_ci */ 474195972f6Sopenharmony_civoid 475195972f6Sopenharmony_citcp_backlog_accepted(struct tcp_pcb *pcb) 476195972f6Sopenharmony_ci{ 477195972f6Sopenharmony_ci LWIP_ASSERT("pcb != NULL", pcb != NULL); 478195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 479195972f6Sopenharmony_ci if ((pcb->flags & TF_BACKLOGPEND) != 0) { 480195972f6Sopenharmony_ci if (pcb->listener != NULL) { 481195972f6Sopenharmony_ci LWIP_ASSERT("accepts_pending != 0", pcb->listener->accepts_pending != 0); 482195972f6Sopenharmony_ci pcb->listener->accepts_pending--; 483195972f6Sopenharmony_ci tcp_clear_flags(pcb, TF_BACKLOGPEND); 484195972f6Sopenharmony_ci } 485195972f6Sopenharmony_ci } 486195972f6Sopenharmony_ci} 487195972f6Sopenharmony_ci#endif /* TCP_LISTEN_BACKLOG */ 488195972f6Sopenharmony_ci 489195972f6Sopenharmony_ci/** 490195972f6Sopenharmony_ci * Closes the TX side of a connection held by the PCB. 491195972f6Sopenharmony_ci * For tcp_close(), a RST is sent if the application didn't receive all data 492195972f6Sopenharmony_ci * (tcp_recved() not called for all data passed to recv callback). 493195972f6Sopenharmony_ci * 494195972f6Sopenharmony_ci * Listening pcbs are freed and may not be referenced any more. 495195972f6Sopenharmony_ci * Connection pcbs are freed if not yet connected and may not be referenced 496195972f6Sopenharmony_ci * any more. If a connection is established (at least SYN received or in 497195972f6Sopenharmony_ci * a closing state), the connection is closed, and put in a closing state. 498195972f6Sopenharmony_ci * The pcb is then automatically freed in tcp_slowtmr(). It is therefore 499195972f6Sopenharmony_ci * unsafe to reference it. 500195972f6Sopenharmony_ci * 501195972f6Sopenharmony_ci * @param pcb the tcp_pcb to close 502195972f6Sopenharmony_ci * @return ERR_OK if connection has been closed 503195972f6Sopenharmony_ci * another err_t if closing failed and pcb is not freed 504195972f6Sopenharmony_ci */ 505195972f6Sopenharmony_cistatic err_t 506195972f6Sopenharmony_citcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) 507195972f6Sopenharmony_ci{ 508195972f6Sopenharmony_ci LWIP_ASSERT("tcp_close_shutdown: invalid pcb", pcb != NULL); 509195972f6Sopenharmony_ci 510195972f6Sopenharmony_ci if (rst_on_unacked_data && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) { 511195972f6Sopenharmony_ci if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND_MAX(pcb))) { 512195972f6Sopenharmony_ci /* Not all data received by application, send RST to tell the remote 513195972f6Sopenharmony_ci side about this. */ 514195972f6Sopenharmony_ci LWIP_ASSERT("pcb->flags & TF_RXCLOSED", pcb->flags & TF_RXCLOSED); 515195972f6Sopenharmony_ci 516195972f6Sopenharmony_ci /* don't call tcp_abort here: we must not deallocate the pcb since 517195972f6Sopenharmony_ci that might not be expected when calling tcp_close */ 518195972f6Sopenharmony_ci tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, 519195972f6Sopenharmony_ci pcb->local_port, pcb->remote_port); 520195972f6Sopenharmony_ci 521195972f6Sopenharmony_ci tcp_pcb_purge(pcb); 522195972f6Sopenharmony_ci TCP_RMV_ACTIVE(pcb); 523195972f6Sopenharmony_ci /* Deallocate the pcb since we already sent a RST for it */ 524195972f6Sopenharmony_ci if (tcp_input_pcb == pcb) { 525195972f6Sopenharmony_ci /* prevent using a deallocated pcb: free it from tcp_input later */ 526195972f6Sopenharmony_ci tcp_trigger_input_pcb_close(); 527195972f6Sopenharmony_ci } else { 528195972f6Sopenharmony_ci tcp_free(pcb); 529195972f6Sopenharmony_ci } 530195972f6Sopenharmony_ci return ERR_OK; 531195972f6Sopenharmony_ci } 532195972f6Sopenharmony_ci } 533195972f6Sopenharmony_ci 534195972f6Sopenharmony_ci /* - states which free the pcb are handled here, 535195972f6Sopenharmony_ci - states which send FIN and change state are handled in tcp_close_shutdown_fin() */ 536195972f6Sopenharmony_ci switch (pcb->state) { 537195972f6Sopenharmony_ci case CLOSED: 538195972f6Sopenharmony_ci /* Closing a pcb in the CLOSED state might seem erroneous, 539195972f6Sopenharmony_ci * however, it is in this state once allocated and as yet unused 540195972f6Sopenharmony_ci * and the user needs some way to free it should the need arise. 541195972f6Sopenharmony_ci * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) 542195972f6Sopenharmony_ci * or for a pcb that has been used and then entered the CLOSED state 543195972f6Sopenharmony_ci * is erroneous, but this should never happen as the pcb has in those cases 544195972f6Sopenharmony_ci * been freed, and so any remaining handles are bogus. */ 545195972f6Sopenharmony_ci if (pcb->local_port != 0) { 546195972f6Sopenharmony_ci TCP_RMV(&tcp_bound_pcbs, pcb); 547195972f6Sopenharmony_ci } 548195972f6Sopenharmony_ci tcp_free(pcb); 549195972f6Sopenharmony_ci break; 550195972f6Sopenharmony_ci case LISTEN: 551195972f6Sopenharmony_ci tcp_listen_closed(pcb); 552195972f6Sopenharmony_ci tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb); 553195972f6Sopenharmony_ci tcp_free_listen(pcb); 554195972f6Sopenharmony_ci break; 555195972f6Sopenharmony_ci case SYN_SENT: 556195972f6Sopenharmony_ci TCP_PCB_REMOVE_ACTIVE(pcb); 557195972f6Sopenharmony_ci tcp_free(pcb); 558195972f6Sopenharmony_ci MIB2_STATS_INC(mib2.tcpattemptfails); 559195972f6Sopenharmony_ci break; 560195972f6Sopenharmony_ci default: 561195972f6Sopenharmony_ci return tcp_close_shutdown_fin(pcb); 562195972f6Sopenharmony_ci } 563195972f6Sopenharmony_ci return ERR_OK; 564195972f6Sopenharmony_ci} 565195972f6Sopenharmony_ci 566195972f6Sopenharmony_cistatic err_t 567195972f6Sopenharmony_citcp_close_shutdown_fin(struct tcp_pcb *pcb) 568195972f6Sopenharmony_ci{ 569195972f6Sopenharmony_ci err_t err; 570195972f6Sopenharmony_ci LWIP_ASSERT("pcb != NULL", pcb != NULL); 571195972f6Sopenharmony_ci 572195972f6Sopenharmony_ci switch (pcb->state) { 573195972f6Sopenharmony_ci case SYN_RCVD: 574195972f6Sopenharmony_ci err = tcp_send_fin(pcb); 575195972f6Sopenharmony_ci if (err == ERR_OK) { 576195972f6Sopenharmony_ci tcp_backlog_accepted(pcb); 577195972f6Sopenharmony_ci MIB2_STATS_INC(mib2.tcpattemptfails); 578195972f6Sopenharmony_ci pcb->state = FIN_WAIT_1; 579195972f6Sopenharmony_ci } 580195972f6Sopenharmony_ci break; 581195972f6Sopenharmony_ci case ESTABLISHED: 582195972f6Sopenharmony_ci err = tcp_send_fin(pcb); 583195972f6Sopenharmony_ci if (err == ERR_OK) { 584195972f6Sopenharmony_ci MIB2_STATS_INC(mib2.tcpestabresets); 585195972f6Sopenharmony_ci pcb->state = FIN_WAIT_1; 586195972f6Sopenharmony_ci } 587195972f6Sopenharmony_ci break; 588195972f6Sopenharmony_ci case CLOSE_WAIT: 589195972f6Sopenharmony_ci err = tcp_send_fin(pcb); 590195972f6Sopenharmony_ci if (err == ERR_OK) { 591195972f6Sopenharmony_ci MIB2_STATS_INC(mib2.tcpestabresets); 592195972f6Sopenharmony_ci pcb->state = LAST_ACK; 593195972f6Sopenharmony_ci } 594195972f6Sopenharmony_ci break; 595195972f6Sopenharmony_ci default: 596195972f6Sopenharmony_ci /* Has already been closed, do nothing. */ 597195972f6Sopenharmony_ci return ERR_OK; 598195972f6Sopenharmony_ci } 599195972f6Sopenharmony_ci 600195972f6Sopenharmony_ci if (err == ERR_OK) { 601195972f6Sopenharmony_ci /* To ensure all data has been sent when tcp_close returns, we have 602195972f6Sopenharmony_ci to make sure tcp_output doesn't fail. 603195972f6Sopenharmony_ci Since we don't really have to ensure all data has been sent when tcp_close 604195972f6Sopenharmony_ci returns (unsent data is sent from tcp timer functions, also), we don't care 605195972f6Sopenharmony_ci for the return value of tcp_output for now. */ 606195972f6Sopenharmony_ci tcp_output(pcb); 607195972f6Sopenharmony_ci } else if (err == ERR_MEM) { 608195972f6Sopenharmony_ci /* Mark this pcb for closing. Closing is retried from tcp_tmr. */ 609195972f6Sopenharmony_ci tcp_set_flags(pcb, TF_CLOSEPEND); 610195972f6Sopenharmony_ci /* We have to return ERR_OK from here to indicate to the callers that this 611195972f6Sopenharmony_ci pcb should not be used any more as it will be freed soon via tcp_tmr. 612195972f6Sopenharmony_ci This is OK here since sending FIN does not guarantee a time frime for 613195972f6Sopenharmony_ci actually freeing the pcb, either (it is left in closure states for 614195972f6Sopenharmony_ci remote ACK or timeout) */ 615195972f6Sopenharmony_ci return ERR_OK; 616195972f6Sopenharmony_ci } 617195972f6Sopenharmony_ci return err; 618195972f6Sopenharmony_ci} 619195972f6Sopenharmony_ci 620195972f6Sopenharmony_ci/** 621195972f6Sopenharmony_ci * @ingroup tcp_raw 622195972f6Sopenharmony_ci * Closes the connection held by the PCB. 623195972f6Sopenharmony_ci * 624195972f6Sopenharmony_ci * Listening pcbs are freed and may not be referenced any more. 625195972f6Sopenharmony_ci * Connection pcbs are freed if not yet connected and may not be referenced 626195972f6Sopenharmony_ci * any more. If a connection is established (at least SYN received or in 627195972f6Sopenharmony_ci * a closing state), the connection is closed, and put in a closing state. 628195972f6Sopenharmony_ci * The pcb is then automatically freed in tcp_slowtmr(). It is therefore 629195972f6Sopenharmony_ci * unsafe to reference it (unless an error is returned). 630195972f6Sopenharmony_ci * 631195972f6Sopenharmony_ci * The function may return ERR_MEM if no memory 632195972f6Sopenharmony_ci * was available for closing the connection. If so, the application 633195972f6Sopenharmony_ci * should wait and try again either by using the acknowledgment 634195972f6Sopenharmony_ci * callback or the polling functionality. If the close succeeds, the 635195972f6Sopenharmony_ci * function returns ERR_OK. 636195972f6Sopenharmony_ci * 637195972f6Sopenharmony_ci * @param pcb the tcp_pcb to close 638195972f6Sopenharmony_ci * @return ERR_OK if connection has been closed 639195972f6Sopenharmony_ci * another err_t if closing failed and pcb is not freed 640195972f6Sopenharmony_ci */ 641195972f6Sopenharmony_cierr_t 642195972f6Sopenharmony_citcp_close(struct tcp_pcb *pcb) 643195972f6Sopenharmony_ci{ 644195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 645195972f6Sopenharmony_ci 646195972f6Sopenharmony_ci LWIP_ERROR("tcp_close: invalid pcb", pcb != NULL, return ERR_ARG); 647195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in ")); 648195972f6Sopenharmony_ci 649195972f6Sopenharmony_ci tcp_debug_print_state(pcb->state); 650195972f6Sopenharmony_ci 651195972f6Sopenharmony_ci if (pcb->state != LISTEN) { 652195972f6Sopenharmony_ci /* Set a flag not to receive any more data... */ 653195972f6Sopenharmony_ci tcp_set_flags(pcb, TF_RXCLOSED); 654195972f6Sopenharmony_ci } 655195972f6Sopenharmony_ci /* ... and close */ 656195972f6Sopenharmony_ci return tcp_close_shutdown(pcb, 1); 657195972f6Sopenharmony_ci} 658195972f6Sopenharmony_ci 659195972f6Sopenharmony_ci/** 660195972f6Sopenharmony_ci * @ingroup tcp_raw 661195972f6Sopenharmony_ci * Causes all or part of a full-duplex connection of this PCB to be shut down. 662195972f6Sopenharmony_ci * This doesn't deallocate the PCB unless shutting down both sides! 663195972f6Sopenharmony_ci * Shutting down both sides is the same as calling tcp_close, so if it succeds 664195972f6Sopenharmony_ci * (i.e. returns ER_OK), the PCB must not be referenced any more! 665195972f6Sopenharmony_ci * 666195972f6Sopenharmony_ci * @param pcb PCB to shutdown 667195972f6Sopenharmony_ci * @param shut_rx shut down receive side if this is != 0 668195972f6Sopenharmony_ci * @param shut_tx shut down send side if this is != 0 669195972f6Sopenharmony_ci * @return ERR_OK if shutdown succeeded (or the PCB has already been shut down) 670195972f6Sopenharmony_ci * another err_t on error. 671195972f6Sopenharmony_ci */ 672195972f6Sopenharmony_cierr_t 673195972f6Sopenharmony_citcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx) 674195972f6Sopenharmony_ci{ 675195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 676195972f6Sopenharmony_ci 677195972f6Sopenharmony_ci LWIP_ERROR("tcp_shutdown: invalid pcb", pcb != NULL, return ERR_ARG); 678195972f6Sopenharmony_ci 679195972f6Sopenharmony_ci if (pcb->state == LISTEN) { 680195972f6Sopenharmony_ci return ERR_CONN; 681195972f6Sopenharmony_ci } 682195972f6Sopenharmony_ci if (shut_rx) { 683195972f6Sopenharmony_ci /* shut down the receive side: set a flag not to receive any more data... */ 684195972f6Sopenharmony_ci tcp_set_flags(pcb, TF_RXCLOSED); 685195972f6Sopenharmony_ci if (shut_tx) { 686195972f6Sopenharmony_ci /* shutting down the tx AND rx side is the same as closing for the raw API */ 687195972f6Sopenharmony_ci return tcp_close_shutdown(pcb, 1); 688195972f6Sopenharmony_ci } 689195972f6Sopenharmony_ci /* ... and free buffered data */ 690195972f6Sopenharmony_ci if (pcb->refused_data != NULL) { 691195972f6Sopenharmony_ci pbuf_free(pcb->refused_data); 692195972f6Sopenharmony_ci pcb->refused_data = NULL; 693195972f6Sopenharmony_ci } 694195972f6Sopenharmony_ci } 695195972f6Sopenharmony_ci if (shut_tx) { 696195972f6Sopenharmony_ci /* This can't happen twice since if it succeeds, the pcb's state is changed. 697195972f6Sopenharmony_ci Only close in these states as the others directly deallocate the PCB */ 698195972f6Sopenharmony_ci switch (pcb->state) { 699195972f6Sopenharmony_ci case SYN_RCVD: 700195972f6Sopenharmony_ci case ESTABLISHED: 701195972f6Sopenharmony_ci case CLOSE_WAIT: 702195972f6Sopenharmony_ci return tcp_close_shutdown(pcb, (u8_t)shut_rx); 703195972f6Sopenharmony_ci default: 704195972f6Sopenharmony_ci /* Not (yet?) connected, cannot shutdown the TX side as that would bring us 705195972f6Sopenharmony_ci into CLOSED state, where the PCB is deallocated. */ 706195972f6Sopenharmony_ci return ERR_CONN; 707195972f6Sopenharmony_ci } 708195972f6Sopenharmony_ci } 709195972f6Sopenharmony_ci return ERR_OK; 710195972f6Sopenharmony_ci} 711195972f6Sopenharmony_ci 712195972f6Sopenharmony_ci/** 713195972f6Sopenharmony_ci * Abandons a connection and optionally sends a RST to the remote 714195972f6Sopenharmony_ci * host. Deletes the local protocol control block. This is done when 715195972f6Sopenharmony_ci * a connection is killed because of shortage of memory. 716195972f6Sopenharmony_ci * 717195972f6Sopenharmony_ci * @param pcb the tcp_pcb to abort 718195972f6Sopenharmony_ci * @param reset boolean to indicate whether a reset should be sent 719195972f6Sopenharmony_ci */ 720195972f6Sopenharmony_civoid 721195972f6Sopenharmony_citcp_abandon(struct tcp_pcb *pcb, int reset) 722195972f6Sopenharmony_ci{ 723195972f6Sopenharmony_ci u32_t seqno, ackno; 724195972f6Sopenharmony_ci#if LWIP_CALLBACK_API 725195972f6Sopenharmony_ci tcp_err_fn errf; 726195972f6Sopenharmony_ci#endif /* LWIP_CALLBACK_API */ 727195972f6Sopenharmony_ci void *errf_arg; 728195972f6Sopenharmony_ci 729195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 730195972f6Sopenharmony_ci 731195972f6Sopenharmony_ci LWIP_ERROR("tcp_abandon: invalid pcb", pcb != NULL, return); 732195972f6Sopenharmony_ci 733195972f6Sopenharmony_ci /* pcb->state LISTEN not allowed here */ 734195972f6Sopenharmony_ci LWIP_ASSERT("don't call tcp_abort/tcp_abandon for listen-pcbs", 735195972f6Sopenharmony_ci pcb->state != LISTEN); 736195972f6Sopenharmony_ci /* Figure out on which TCP PCB list we are, and remove us. If we 737195972f6Sopenharmony_ci are in an active state, call the receive function associated with 738195972f6Sopenharmony_ci the PCB with a NULL argument, and send an RST to the remote end. */ 739195972f6Sopenharmony_ci if (pcb->state == TIME_WAIT) { 740195972f6Sopenharmony_ci tcp_pcb_remove(&tcp_tw_pcbs, pcb); 741195972f6Sopenharmony_ci tcp_free(pcb); 742195972f6Sopenharmony_ci } else { 743195972f6Sopenharmony_ci int send_rst = 0; 744195972f6Sopenharmony_ci u16_t local_port = 0; 745195972f6Sopenharmony_ci enum tcp_state last_state; 746195972f6Sopenharmony_ci seqno = pcb->snd_nxt; 747195972f6Sopenharmony_ci ackno = pcb->rcv_nxt; 748195972f6Sopenharmony_ci#if LWIP_CALLBACK_API 749195972f6Sopenharmony_ci errf = pcb->errf; 750195972f6Sopenharmony_ci#endif /* LWIP_CALLBACK_API */ 751195972f6Sopenharmony_ci errf_arg = pcb->callback_arg; 752195972f6Sopenharmony_ci if (pcb->state == CLOSED) { 753195972f6Sopenharmony_ci if (pcb->local_port != 0) { 754195972f6Sopenharmony_ci /* bound, not yet opened */ 755195972f6Sopenharmony_ci TCP_RMV(&tcp_bound_pcbs, pcb); 756195972f6Sopenharmony_ci } 757195972f6Sopenharmony_ci } else { 758195972f6Sopenharmony_ci send_rst = reset; 759195972f6Sopenharmony_ci local_port = pcb->local_port; 760195972f6Sopenharmony_ci TCP_PCB_REMOVE_ACTIVE(pcb); 761195972f6Sopenharmony_ci } 762195972f6Sopenharmony_ci if (pcb->unacked != NULL) { 763195972f6Sopenharmony_ci tcp_segs_free(pcb->unacked); 764195972f6Sopenharmony_ci } 765195972f6Sopenharmony_ci if (pcb->unsent != NULL) { 766195972f6Sopenharmony_ci tcp_segs_free(pcb->unsent); 767195972f6Sopenharmony_ci } 768195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ 769195972f6Sopenharmony_ci if (pcb->ooseq != NULL) { 770195972f6Sopenharmony_ci tcp_segs_free(pcb->ooseq); 771195972f6Sopenharmony_ci } 772195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ */ 773195972f6Sopenharmony_ci tcp_backlog_accepted(pcb); 774195972f6Sopenharmony_ci if (send_rst) { 775195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); 776195972f6Sopenharmony_ci tcp_rst(pcb, seqno, ackno, &pcb->local_ip, &pcb->remote_ip, local_port, pcb->remote_port); 777195972f6Sopenharmony_ci } 778195972f6Sopenharmony_ci last_state = pcb->state; 779195972f6Sopenharmony_ci tcp_free(pcb); 780195972f6Sopenharmony_ci TCP_EVENT_ERR(last_state, errf, errf_arg, ERR_ABRT); 781195972f6Sopenharmony_ci } 782195972f6Sopenharmony_ci} 783195972f6Sopenharmony_ci 784195972f6Sopenharmony_ci/** 785195972f6Sopenharmony_ci * @ingroup tcp_raw 786195972f6Sopenharmony_ci * Aborts the connection by sending a RST (reset) segment to the remote 787195972f6Sopenharmony_ci * host. The pcb is deallocated. This function never fails. 788195972f6Sopenharmony_ci * 789195972f6Sopenharmony_ci * ATTENTION: When calling this from one of the TCP callbacks, make 790195972f6Sopenharmony_ci * sure you always return ERR_ABRT (and never return ERR_ABRT otherwise 791195972f6Sopenharmony_ci * or you will risk accessing deallocated memory or memory leaks! 792195972f6Sopenharmony_ci * 793195972f6Sopenharmony_ci * @param pcb the tcp pcb to abort 794195972f6Sopenharmony_ci */ 795195972f6Sopenharmony_civoid 796195972f6Sopenharmony_citcp_abort(struct tcp_pcb *pcb) 797195972f6Sopenharmony_ci{ 798195972f6Sopenharmony_ci tcp_abandon(pcb, 1); 799195972f6Sopenharmony_ci} 800195972f6Sopenharmony_ci 801195972f6Sopenharmony_ci/** 802195972f6Sopenharmony_ci * @ingroup tcp_raw 803195972f6Sopenharmony_ci * Binds the connection to a local port number and IP address. If the 804195972f6Sopenharmony_ci * IP address is not given (i.e., ipaddr == IP_ANY_TYPE), the connection is 805195972f6Sopenharmony_ci * bound to all local IP addresses. 806195972f6Sopenharmony_ci * If another connection is bound to the same port, the function will 807195972f6Sopenharmony_ci * return ERR_USE, otherwise ERR_OK is returned. 808195972f6Sopenharmony_ci * @see MEMP_NUM_TCP_PCB_LISTEN and MEMP_NUM_TCP_PCB 809195972f6Sopenharmony_ci * 810195972f6Sopenharmony_ci * @param pcb the tcp_pcb to bind (no check is done whether this pcb is 811195972f6Sopenharmony_ci * already bound!) 812195972f6Sopenharmony_ci * @param ipaddr the local ip address to bind to (use IPx_ADDR_ANY to bind 813195972f6Sopenharmony_ci * to any local address 814195972f6Sopenharmony_ci * @param port the local port to bind to 815195972f6Sopenharmony_ci * @return ERR_USE if the port is already in use 816195972f6Sopenharmony_ci * ERR_VAL if bind failed because the PCB is not in a valid state 817195972f6Sopenharmony_ci * ERR_OK if bound 818195972f6Sopenharmony_ci */ 819195972f6Sopenharmony_cierr_t 820195972f6Sopenharmony_citcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) 821195972f6Sopenharmony_ci{ 822195972f6Sopenharmony_ci int i; 823195972f6Sopenharmony_ci int max_pcb_list = NUM_TCP_PCB_LISTS; 824195972f6Sopenharmony_ci struct tcp_pcb *cpcb; 825195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_IPV6_SCOPES 826195972f6Sopenharmony_ci ip_addr_t zoned_ipaddr; 827195972f6Sopenharmony_ci#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ 828195972f6Sopenharmony_ci 829195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 830195972f6Sopenharmony_ci 831195972f6Sopenharmony_ci#if LWIP_IPV4 832195972f6Sopenharmony_ci /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ 833195972f6Sopenharmony_ci if (ipaddr == NULL) { 834195972f6Sopenharmony_ci ipaddr = IP4_ADDR_ANY; 835195972f6Sopenharmony_ci } 836195972f6Sopenharmony_ci#else /* LWIP_IPV4 */ 837195972f6Sopenharmony_ci LWIP_ERROR("tcp_bind: invalid ipaddr", ipaddr != NULL, return ERR_ARG); 838195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 839195972f6Sopenharmony_ci 840195972f6Sopenharmony_ci LWIP_ERROR("tcp_bind: invalid pcb", pcb != NULL, return ERR_ARG); 841195972f6Sopenharmony_ci 842195972f6Sopenharmony_ci LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_VAL); 843195972f6Sopenharmony_ci 844195972f6Sopenharmony_ci#if SO_REUSE 845195972f6Sopenharmony_ci /* Unless the REUSEADDR flag is set, 846195972f6Sopenharmony_ci we have to check the pcbs in TIME-WAIT state, also. 847195972f6Sopenharmony_ci We do not dump TIME_WAIT pcb's; they can still be matched by incoming 848195972f6Sopenharmony_ci packets using both local and remote IP addresses and ports to distinguish. 849195972f6Sopenharmony_ci */ 850195972f6Sopenharmony_ci if (ip_get_option(pcb, SOF_REUSEADDR)) { 851195972f6Sopenharmony_ci max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT; 852195972f6Sopenharmony_ci } 853195972f6Sopenharmony_ci#endif /* SO_REUSE */ 854195972f6Sopenharmony_ci 855195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_IPV6_SCOPES 856195972f6Sopenharmony_ci /* If the given IP address should have a zone but doesn't, assign one now. 857195972f6Sopenharmony_ci * This is legacy support: scope-aware callers should always provide properly 858195972f6Sopenharmony_ci * zoned source addresses. Do the zone selection before the address-in-use 859195972f6Sopenharmony_ci * check below; as such we have to make a temporary copy of the address. */ 860195972f6Sopenharmony_ci if (IP_IS_V6(ipaddr) && ip6_addr_lacks_zone(ip_2_ip6(ipaddr), IP6_UNICAST)) { 861195972f6Sopenharmony_ci ip_addr_copy(zoned_ipaddr, *ipaddr); 862195972f6Sopenharmony_ci ip6_addr_select_zone(ip_2_ip6(&zoned_ipaddr), ip_2_ip6(&zoned_ipaddr)); 863195972f6Sopenharmony_ci ipaddr = &zoned_ipaddr; 864195972f6Sopenharmony_ci } 865195972f6Sopenharmony_ci#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ 866195972f6Sopenharmony_ci 867195972f6Sopenharmony_ci if (port == 0) { 868195972f6Sopenharmony_ci port = tcp_new_port(); 869195972f6Sopenharmony_ci if (port == 0) { 870195972f6Sopenharmony_ci return ERR_BUF; 871195972f6Sopenharmony_ci } 872195972f6Sopenharmony_ci } else { 873195972f6Sopenharmony_ci /* Check if the address already is in use (on all lists) */ 874195972f6Sopenharmony_ci for (i = 0; i < max_pcb_list; i++) { 875195972f6Sopenharmony_ci for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { 876195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 877195972f6Sopenharmony_ci if (cpcb->local_port == port && (get_net_group_from_tcp_pcb(pcb) == get_net_group_from_tcp_pcb(cpcb))) { 878195972f6Sopenharmony_ci#else 879195972f6Sopenharmony_ci if (cpcb->local_port == port) { 880195972f6Sopenharmony_ci#endif 881195972f6Sopenharmony_ci#if SO_REUSE 882195972f6Sopenharmony_ci /* Omit checking for the same port if both pcbs have REUSEADDR set. 883195972f6Sopenharmony_ci For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in 884195972f6Sopenharmony_ci tcp_connect. */ 885195972f6Sopenharmony_ci if (!ip_get_option(pcb, SOF_REUSEADDR) || 886195972f6Sopenharmony_ci !ip_get_option(cpcb, SOF_REUSEADDR)) 887195972f6Sopenharmony_ci#endif /* SO_REUSE */ 888195972f6Sopenharmony_ci { 889195972f6Sopenharmony_ci /* @todo: check accept_any_ip_version */ 890195972f6Sopenharmony_ci if ((IP_IS_V6(ipaddr) == IP_IS_V6_VAL(cpcb->local_ip)) && 891195972f6Sopenharmony_ci (ip_addr_isany(&cpcb->local_ip) || 892195972f6Sopenharmony_ci ip_addr_isany(ipaddr) || 893195972f6Sopenharmony_ci ip_addr_cmp(&cpcb->local_ip, ipaddr))) { 894195972f6Sopenharmony_ci return ERR_USE; 895195972f6Sopenharmony_ci } 896195972f6Sopenharmony_ci } 897195972f6Sopenharmony_ci } 898195972f6Sopenharmony_ci } 899195972f6Sopenharmony_ci } 900195972f6Sopenharmony_ci } 901195972f6Sopenharmony_ci 902195972f6Sopenharmony_ci if (!ip_addr_isany(ipaddr) 903195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 904195972f6Sopenharmony_ci || (IP_GET_TYPE(ipaddr) != IP_GET_TYPE(&pcb->local_ip)) 905195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */ 906195972f6Sopenharmony_ci ) { 907195972f6Sopenharmony_ci ip_addr_set(&pcb->local_ip, ipaddr); 908195972f6Sopenharmony_ci } 909195972f6Sopenharmony_ci pcb->local_port = port; 910195972f6Sopenharmony_ci TCP_REG(&tcp_bound_pcbs, pcb); 911195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port)); 912195972f6Sopenharmony_ci return ERR_OK; 913195972f6Sopenharmony_ci} 914195972f6Sopenharmony_ci 915195972f6Sopenharmony_ci/** 916195972f6Sopenharmony_ci * @ingroup tcp_raw 917195972f6Sopenharmony_ci * Binds the connection to a netif and IP address. 918195972f6Sopenharmony_ci * After calling this function, all packets received via this PCB 919195972f6Sopenharmony_ci * are guaranteed to have come in via the specified netif, and all 920195972f6Sopenharmony_ci * outgoing packets will go out via the specified netif. 921195972f6Sopenharmony_ci * 922195972f6Sopenharmony_ci * @param pcb the tcp_pcb to bind. 923195972f6Sopenharmony_ci * @param netif the netif to bind to. Can be NULL. 924195972f6Sopenharmony_ci */ 925195972f6Sopenharmony_civoid 926195972f6Sopenharmony_citcp_bind_netif(struct tcp_pcb *pcb, const struct netif *netif) 927195972f6Sopenharmony_ci{ 928195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 929195972f6Sopenharmony_ci if (netif != NULL) { 930195972f6Sopenharmony_ci pcb->netif_idx = netif_get_index(netif); 931195972f6Sopenharmony_ci } else { 932195972f6Sopenharmony_ci pcb->netif_idx = NETIF_NO_INDEX; 933195972f6Sopenharmony_ci } 934195972f6Sopenharmony_ci} 935195972f6Sopenharmony_ci 936195972f6Sopenharmony_ci#if LWIP_CALLBACK_API 937195972f6Sopenharmony_ci/** 938195972f6Sopenharmony_ci * Default accept callback if no accept callback is specified by the user. 939195972f6Sopenharmony_ci */ 940195972f6Sopenharmony_cistatic err_t 941195972f6Sopenharmony_citcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err) 942195972f6Sopenharmony_ci{ 943195972f6Sopenharmony_ci LWIP_UNUSED_ARG(arg); 944195972f6Sopenharmony_ci LWIP_UNUSED_ARG(err); 945195972f6Sopenharmony_ci 946195972f6Sopenharmony_ci LWIP_ASSERT("tcp_accept_null: invalid pcb", pcb != NULL); 947195972f6Sopenharmony_ci 948195972f6Sopenharmony_ci tcp_abort(pcb); 949195972f6Sopenharmony_ci 950195972f6Sopenharmony_ci return ERR_ABRT; 951195972f6Sopenharmony_ci} 952195972f6Sopenharmony_ci#endif /* LWIP_CALLBACK_API */ 953195972f6Sopenharmony_ci 954195972f6Sopenharmony_ci/** 955195972f6Sopenharmony_ci * @ingroup tcp_raw 956195972f6Sopenharmony_ci * Set the state of the connection to be LISTEN, which means that it 957195972f6Sopenharmony_ci * is able to accept incoming connections. The protocol control block 958195972f6Sopenharmony_ci * is reallocated in order to consume less memory. Setting the 959195972f6Sopenharmony_ci * connection to LISTEN is an irreversible process. 960195972f6Sopenharmony_ci * When an incoming connection is accepted, the function specified with 961195972f6Sopenharmony_ci * the tcp_accept() function will be called. The pcb has to be bound 962195972f6Sopenharmony_ci * to a local port with the tcp_bind() function. 963195972f6Sopenharmony_ci * 964195972f6Sopenharmony_ci * The tcp_listen() function returns a new connection identifier, and 965195972f6Sopenharmony_ci * the one passed as an argument to the function will be 966195972f6Sopenharmony_ci * deallocated. The reason for this behavior is that less memory is 967195972f6Sopenharmony_ci * needed for a connection that is listening, so tcp_listen() will 968195972f6Sopenharmony_ci * reclaim the memory needed for the original connection and allocate a 969195972f6Sopenharmony_ci * new smaller memory block for the listening connection. 970195972f6Sopenharmony_ci * 971195972f6Sopenharmony_ci * tcp_listen() may return NULL if no memory was available for the 972195972f6Sopenharmony_ci * listening connection. If so, the memory associated with the pcb 973195972f6Sopenharmony_ci * passed as an argument to tcp_listen() will not be deallocated. 974195972f6Sopenharmony_ci * 975195972f6Sopenharmony_ci * The backlog limits the number of outstanding connections 976195972f6Sopenharmony_ci * in the listen queue to the value specified by the backlog argument. 977195972f6Sopenharmony_ci * To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h. 978195972f6Sopenharmony_ci * 979195972f6Sopenharmony_ci * @param pcb the original tcp_pcb 980195972f6Sopenharmony_ci * @param backlog the incoming connections queue limit 981195972f6Sopenharmony_ci * @return tcp_pcb used for listening, consumes less memory. 982195972f6Sopenharmony_ci * 983195972f6Sopenharmony_ci * @note The original tcp_pcb is freed. This function therefore has to be 984195972f6Sopenharmony_ci * called like this: 985195972f6Sopenharmony_ci * tpcb = tcp_listen_with_backlog(tpcb, backlog); 986195972f6Sopenharmony_ci */ 987195972f6Sopenharmony_cistruct tcp_pcb * 988195972f6Sopenharmony_citcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) 989195972f6Sopenharmony_ci{ 990195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 991195972f6Sopenharmony_ci return tcp_listen_with_backlog_and_err(pcb, backlog, NULL); 992195972f6Sopenharmony_ci} 993195972f6Sopenharmony_ci 994195972f6Sopenharmony_ci/** 995195972f6Sopenharmony_ci * @ingroup tcp_raw 996195972f6Sopenharmony_ci * Set the state of the connection to be LISTEN, which means that it 997195972f6Sopenharmony_ci * is able to accept incoming connections. The protocol control block 998195972f6Sopenharmony_ci * is reallocated in order to consume less memory. Setting the 999195972f6Sopenharmony_ci * connection to LISTEN is an irreversible process. 1000195972f6Sopenharmony_ci * 1001195972f6Sopenharmony_ci * @param pcb the original tcp_pcb 1002195972f6Sopenharmony_ci * @param backlog the incoming connections queue limit 1003195972f6Sopenharmony_ci * @param err when NULL is returned, this contains the error reason 1004195972f6Sopenharmony_ci * @return tcp_pcb used for listening, consumes less memory. 1005195972f6Sopenharmony_ci * 1006195972f6Sopenharmony_ci * @note The original tcp_pcb is freed. This function therefore has to be 1007195972f6Sopenharmony_ci * called like this: 1008195972f6Sopenharmony_ci * tpcb = tcp_listen_with_backlog_and_err(tpcb, backlog, &err); 1009195972f6Sopenharmony_ci */ 1010195972f6Sopenharmony_cistruct tcp_pcb * 1011195972f6Sopenharmony_citcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) 1012195972f6Sopenharmony_ci{ 1013195972f6Sopenharmony_ci struct tcp_pcb_listen *lpcb = NULL; 1014195972f6Sopenharmony_ci err_t res; 1015195972f6Sopenharmony_ci 1016195972f6Sopenharmony_ci LWIP_UNUSED_ARG(backlog); 1017195972f6Sopenharmony_ci 1018195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 1019195972f6Sopenharmony_ci 1020195972f6Sopenharmony_ci LWIP_ERROR("tcp_listen_with_backlog_and_err: invalid pcb", pcb != NULL, res = ERR_ARG; goto done); 1021195972f6Sopenharmony_ci LWIP_ERROR("tcp_listen_with_backlog_and_err: pcb already connected", pcb->state == CLOSED, res = ERR_CLSD; goto done); 1022195972f6Sopenharmony_ci 1023195972f6Sopenharmony_ci /* already listening? */ 1024195972f6Sopenharmony_ci if (pcb->state == LISTEN) { 1025195972f6Sopenharmony_ci lpcb = (struct tcp_pcb_listen *)pcb; 1026195972f6Sopenharmony_ci res = ERR_ALREADY; 1027195972f6Sopenharmony_ci goto done; 1028195972f6Sopenharmony_ci } 1029195972f6Sopenharmony_ci#if SO_REUSE 1030195972f6Sopenharmony_ci if (ip_get_option(pcb, SOF_REUSEADDR)) { 1031195972f6Sopenharmony_ci /* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage 1032195972f6Sopenharmony_ci is declared (listen-/connection-pcb), we have to make sure now that 1033195972f6Sopenharmony_ci this port is only used once for every local IP. */ 1034195972f6Sopenharmony_ci for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { 1035195972f6Sopenharmony_ci if ((lpcb->local_port == pcb->local_port) && 1036195972f6Sopenharmony_ci ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) { 1037195972f6Sopenharmony_ci /* this address/port is already used */ 1038195972f6Sopenharmony_ci lpcb = NULL; 1039195972f6Sopenharmony_ci res = ERR_USE; 1040195972f6Sopenharmony_ci goto done; 1041195972f6Sopenharmony_ci } 1042195972f6Sopenharmony_ci } 1043195972f6Sopenharmony_ci } 1044195972f6Sopenharmony_ci#endif /* SO_REUSE */ 1045195972f6Sopenharmony_ci lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN); 1046195972f6Sopenharmony_ci if (lpcb == NULL) { 1047195972f6Sopenharmony_ci res = ERR_MEM; 1048195972f6Sopenharmony_ci goto done; 1049195972f6Sopenharmony_ci } 1050195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 1051195972f6Sopenharmony_ci set_tcp_pcb_net_group((struct tcp_pcb *)lpcb, get_net_group_from_tcp_pcb(pcb)); 1052195972f6Sopenharmony_ci#endif 1053195972f6Sopenharmony_ci lpcb->callback_arg = pcb->callback_arg; 1054195972f6Sopenharmony_ci lpcb->local_port = pcb->local_port; 1055195972f6Sopenharmony_ci lpcb->state = LISTEN; 1056195972f6Sopenharmony_ci lpcb->prio = pcb->prio; 1057195972f6Sopenharmony_ci lpcb->so_options = pcb->so_options; 1058195972f6Sopenharmony_ci lpcb->netif_idx = pcb->netif_idx; 1059195972f6Sopenharmony_ci lpcb->ttl = pcb->ttl; 1060195972f6Sopenharmony_ci lpcb->tos = pcb->tos; 1061195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 1062195972f6Sopenharmony_ci IP_SET_TYPE_VAL(lpcb->remote_ip, pcb->local_ip.type); 1063195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */ 1064195972f6Sopenharmony_ci ip_addr_copy(lpcb->local_ip, pcb->local_ip); 1065195972f6Sopenharmony_ci if (pcb->local_port != 0) { 1066195972f6Sopenharmony_ci TCP_RMV(&tcp_bound_pcbs, pcb); 1067195972f6Sopenharmony_ci } 1068195972f6Sopenharmony_ci#if LWIP_TCP_PCB_NUM_EXT_ARGS 1069195972f6Sopenharmony_ci /* copy over ext_args to listening pcb */ 1070195972f6Sopenharmony_ci memcpy(&lpcb->ext_args, &pcb->ext_args, sizeof(pcb->ext_args)); 1071195972f6Sopenharmony_ci#endif 1072195972f6Sopenharmony_ci tcp_free(pcb); 1073195972f6Sopenharmony_ci#if LWIP_CALLBACK_API 1074195972f6Sopenharmony_ci lpcb->accept = tcp_accept_null; 1075195972f6Sopenharmony_ci#endif /* LWIP_CALLBACK_API */ 1076195972f6Sopenharmony_ci#if TCP_LISTEN_BACKLOG 1077195972f6Sopenharmony_ci lpcb->accepts_pending = 0; 1078195972f6Sopenharmony_ci tcp_backlog_set(lpcb, backlog); 1079195972f6Sopenharmony_ci#endif /* TCP_LISTEN_BACKLOG */ 1080195972f6Sopenharmony_ci TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb); 1081195972f6Sopenharmony_ci res = ERR_OK; 1082195972f6Sopenharmony_cidone: 1083195972f6Sopenharmony_ci if (err != NULL) { 1084195972f6Sopenharmony_ci *err = res; 1085195972f6Sopenharmony_ci } 1086195972f6Sopenharmony_ci return (struct tcp_pcb *)lpcb; 1087195972f6Sopenharmony_ci} 1088195972f6Sopenharmony_ci 1089195972f6Sopenharmony_ci/** 1090195972f6Sopenharmony_ci * Update the state that tracks the available window space to advertise. 1091195972f6Sopenharmony_ci * 1092195972f6Sopenharmony_ci * Returns how much extra window would be advertised if we sent an 1093195972f6Sopenharmony_ci * update now. 1094195972f6Sopenharmony_ci */ 1095195972f6Sopenharmony_ciu32_t 1096195972f6Sopenharmony_citcp_update_rcv_ann_wnd(struct tcp_pcb *pcb) 1097195972f6Sopenharmony_ci{ 1098195972f6Sopenharmony_ci u32_t new_right_edge; 1099195972f6Sopenharmony_ci 1100195972f6Sopenharmony_ci LWIP_ASSERT("tcp_update_rcv_ann_wnd: invalid pcb", pcb != NULL); 1101195972f6Sopenharmony_ci new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd; 1102195972f6Sopenharmony_ci 1103195972f6Sopenharmony_ci if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) { 1104195972f6Sopenharmony_ci /* we can advertise more window */ 1105195972f6Sopenharmony_ci pcb->rcv_ann_wnd = pcb->rcv_wnd; 1106195972f6Sopenharmony_ci return new_right_edge - pcb->rcv_ann_right_edge; 1107195972f6Sopenharmony_ci } else { 1108195972f6Sopenharmony_ci if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) { 1109195972f6Sopenharmony_ci /* Can happen due to other end sending out of advertised window, 1110195972f6Sopenharmony_ci * but within actual available (but not yet advertised) window */ 1111195972f6Sopenharmony_ci pcb->rcv_ann_wnd = 0; 1112195972f6Sopenharmony_ci } else { 1113195972f6Sopenharmony_ci /* keep the right edge of window constant */ 1114195972f6Sopenharmony_ci u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt; 1115195972f6Sopenharmony_ci#if !LWIP_WND_SCALE 1116195972f6Sopenharmony_ci LWIP_ASSERT("new_rcv_ann_wnd <= 0xffff", new_rcv_ann_wnd <= 0xffff); 1117195972f6Sopenharmony_ci#endif 1118195972f6Sopenharmony_ci pcb->rcv_ann_wnd = (tcpwnd_size_t)new_rcv_ann_wnd; 1119195972f6Sopenharmony_ci } 1120195972f6Sopenharmony_ci return 0; 1121195972f6Sopenharmony_ci } 1122195972f6Sopenharmony_ci} 1123195972f6Sopenharmony_ci 1124195972f6Sopenharmony_ci/** 1125195972f6Sopenharmony_ci * @ingroup tcp_raw 1126195972f6Sopenharmony_ci * This function should be called by the application when it has 1127195972f6Sopenharmony_ci * processed the data. The purpose is to advertise a larger window 1128195972f6Sopenharmony_ci * when the data has been processed. 1129195972f6Sopenharmony_ci * 1130195972f6Sopenharmony_ci * @param pcb the tcp_pcb for which data is read 1131195972f6Sopenharmony_ci * @param len the amount of bytes that have been read by the application 1132195972f6Sopenharmony_ci */ 1133195972f6Sopenharmony_civoid 1134195972f6Sopenharmony_citcp_recved(struct tcp_pcb *pcb, u16_t len) 1135195972f6Sopenharmony_ci{ 1136195972f6Sopenharmony_ci u32_t wnd_inflation; 1137195972f6Sopenharmony_ci tcpwnd_size_t rcv_wnd; 1138195972f6Sopenharmony_ci 1139195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 1140195972f6Sopenharmony_ci 1141195972f6Sopenharmony_ci LWIP_ERROR("tcp_recved: invalid pcb", pcb != NULL, return); 1142195972f6Sopenharmony_ci 1143195972f6Sopenharmony_ci /* pcb->state LISTEN not allowed here */ 1144195972f6Sopenharmony_ci LWIP_ASSERT("don't call tcp_recved for listen-pcbs", 1145195972f6Sopenharmony_ci pcb->state != LISTEN); 1146195972f6Sopenharmony_ci 1147195972f6Sopenharmony_ci rcv_wnd = (tcpwnd_size_t)(pcb->rcv_wnd + len); 1148195972f6Sopenharmony_ci if ((rcv_wnd > TCP_WND_MAX(pcb)) || (rcv_wnd < pcb->rcv_wnd)) { 1149195972f6Sopenharmony_ci /* window got too big or tcpwnd_size_t overflow */ 1150195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: window got too big or tcpwnd_size_t overflow\n")); 1151195972f6Sopenharmony_ci pcb->rcv_wnd = TCP_WND_MAX(pcb); 1152195972f6Sopenharmony_ci } else { 1153195972f6Sopenharmony_ci pcb->rcv_wnd = rcv_wnd; 1154195972f6Sopenharmony_ci } 1155195972f6Sopenharmony_ci 1156195972f6Sopenharmony_ci wnd_inflation = tcp_update_rcv_ann_wnd(pcb); 1157195972f6Sopenharmony_ci 1158195972f6Sopenharmony_ci /* If the change in the right edge of window is significant (default 1159195972f6Sopenharmony_ci * watermark is TCP_WND/4), then send an explicit update now. 1160195972f6Sopenharmony_ci * Otherwise wait for a packet to be sent in the normal course of 1161195972f6Sopenharmony_ci * events (or more window to be available later) */ 1162195972f6Sopenharmony_ci if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) { 1163195972f6Sopenharmony_ci tcp_ack_now(pcb); 1164195972f6Sopenharmony_ci tcp_output(pcb); 1165195972f6Sopenharmony_ci } 1166195972f6Sopenharmony_ci 1167195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: received %"U16_F" bytes, wnd %"TCPWNDSIZE_F" (%"TCPWNDSIZE_F").\n", 1168195972f6Sopenharmony_ci len, pcb->rcv_wnd, (u16_t)(TCP_WND_MAX(pcb) - pcb->rcv_wnd))); 1169195972f6Sopenharmony_ci} 1170195972f6Sopenharmony_ci 1171195972f6Sopenharmony_ci/** 1172195972f6Sopenharmony_ci * Allocate a new local TCP port. 1173195972f6Sopenharmony_ci * 1174195972f6Sopenharmony_ci * @return a new (free) local TCP port number 1175195972f6Sopenharmony_ci */ 1176195972f6Sopenharmony_cistatic u16_t 1177195972f6Sopenharmony_citcp_new_port(void) 1178195972f6Sopenharmony_ci{ 1179195972f6Sopenharmony_ci u8_t i; 1180195972f6Sopenharmony_ci u16_t n = 0; 1181195972f6Sopenharmony_ci struct tcp_pcb *pcb; 1182195972f6Sopenharmony_ci 1183195972f6Sopenharmony_ciagain: 1184195972f6Sopenharmony_ci tcp_port++; 1185195972f6Sopenharmony_ci if (tcp_port == TCP_LOCAL_PORT_RANGE_END) { 1186195972f6Sopenharmony_ci tcp_port = TCP_LOCAL_PORT_RANGE_START; 1187195972f6Sopenharmony_ci } 1188195972f6Sopenharmony_ci /* Check all PCB lists. */ 1189195972f6Sopenharmony_ci for (i = 0; i < NUM_TCP_PCB_LISTS; i++) { 1190195972f6Sopenharmony_ci for (pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) { 1191195972f6Sopenharmony_ci if (pcb->local_port == tcp_port) { 1192195972f6Sopenharmony_ci n++; 1193195972f6Sopenharmony_ci if (n > (TCP_LOCAL_PORT_RANGE_END - TCP_LOCAL_PORT_RANGE_START)) { 1194195972f6Sopenharmony_ci return 0; 1195195972f6Sopenharmony_ci } 1196195972f6Sopenharmony_ci goto again; 1197195972f6Sopenharmony_ci } 1198195972f6Sopenharmony_ci } 1199195972f6Sopenharmony_ci } 1200195972f6Sopenharmony_ci return tcp_port; 1201195972f6Sopenharmony_ci} 1202195972f6Sopenharmony_ci 1203195972f6Sopenharmony_ci/** 1204195972f6Sopenharmony_ci * @ingroup tcp_raw 1205195972f6Sopenharmony_ci * Connects to another host. The function given as the "connected" 1206195972f6Sopenharmony_ci * argument will be called when the connection has been established. 1207195972f6Sopenharmony_ci * Sets up the pcb to connect to the remote host and sends the 1208195972f6Sopenharmony_ci * initial SYN segment which opens the connection. 1209195972f6Sopenharmony_ci * 1210195972f6Sopenharmony_ci * The tcp_connect() function returns immediately; it does not wait for 1211195972f6Sopenharmony_ci * the connection to be properly setup. Instead, it will call the 1212195972f6Sopenharmony_ci * function specified as the fourth argument (the "connected" argument) 1213195972f6Sopenharmony_ci * when the connection is established. If the connection could not be 1214195972f6Sopenharmony_ci * properly established, either because the other host refused the 1215195972f6Sopenharmony_ci * connection or because the other host didn't answer, the "err" 1216195972f6Sopenharmony_ci * callback function of this pcb (registered with tcp_err, see below) 1217195972f6Sopenharmony_ci * will be called. 1218195972f6Sopenharmony_ci * 1219195972f6Sopenharmony_ci * The tcp_connect() function can return ERR_MEM if no memory is 1220195972f6Sopenharmony_ci * available for enqueueing the SYN segment. If the SYN indeed was 1221195972f6Sopenharmony_ci * enqueued successfully, the tcp_connect() function returns ERR_OK. 1222195972f6Sopenharmony_ci * 1223195972f6Sopenharmony_ci * @param pcb the tcp_pcb used to establish the connection 1224195972f6Sopenharmony_ci * @param ipaddr the remote ip address to connect to 1225195972f6Sopenharmony_ci * @param port the remote tcp port to connect to 1226195972f6Sopenharmony_ci * @param connected callback function to call when connected (on error, 1227195972f6Sopenharmony_ci the err calback will be called) 1228195972f6Sopenharmony_ci * @return ERR_VAL if invalid arguments are given 1229195972f6Sopenharmony_ci * ERR_OK if connect request has been sent 1230195972f6Sopenharmony_ci * other err_t values if connect request couldn't be sent 1231195972f6Sopenharmony_ci */ 1232195972f6Sopenharmony_cierr_t 1233195972f6Sopenharmony_citcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, 1234195972f6Sopenharmony_ci tcp_connected_fn connected) 1235195972f6Sopenharmony_ci{ 1236195972f6Sopenharmony_ci struct netif *netif = NULL; 1237195972f6Sopenharmony_ci err_t ret; 1238195972f6Sopenharmony_ci u32_t iss; 1239195972f6Sopenharmony_ci u16_t old_local_port; 1240195972f6Sopenharmony_ci 1241195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 1242195972f6Sopenharmony_ci 1243195972f6Sopenharmony_ci LWIP_ERROR("tcp_connect: invalid pcb", pcb != NULL, return ERR_ARG); 1244195972f6Sopenharmony_ci LWIP_ERROR("tcp_connect: invalid ipaddr", ipaddr != NULL, return ERR_ARG); 1245195972f6Sopenharmony_ci 1246195972f6Sopenharmony_ci LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); 1247195972f6Sopenharmony_ci 1248195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 1249195972f6Sopenharmony_ci struct net_group *group = get_net_group_from_tcp_pcb(pcb); 1250195972f6Sopenharmony_ci LWIP_ERROR("tcp_connect: invalid net group", group != NULL, return ERR_RTE); 1251195972f6Sopenharmony_ci#endif 1252195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); 1253195972f6Sopenharmony_ci ip_addr_set(&pcb->remote_ip, ipaddr); 1254195972f6Sopenharmony_ci pcb->remote_port = port; 1255195972f6Sopenharmony_ci 1256195972f6Sopenharmony_ci if (pcb->netif_idx != NETIF_NO_INDEX) { 1257195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 1258195972f6Sopenharmony_ci netif = netif_get_by_index(pcb->netif_idx, group); 1259195972f6Sopenharmony_ci#else 1260195972f6Sopenharmony_ci netif = netif_get_by_index(pcb->netif_idx); 1261195972f6Sopenharmony_ci#endif 1262195972f6Sopenharmony_ci } else { 1263195972f6Sopenharmony_ci /* check if we have a route to the remote host */ 1264195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 1265195972f6Sopenharmony_ci netif = ip_route(&pcb->local_ip, &pcb->remote_ip, group); 1266195972f6Sopenharmony_ci#else 1267195972f6Sopenharmony_ci netif = ip_route(&pcb->local_ip, &pcb->remote_ip); 1268195972f6Sopenharmony_ci#endif 1269195972f6Sopenharmony_ci } 1270195972f6Sopenharmony_ci if (netif == NULL) { 1271195972f6Sopenharmony_ci /* Don't even try to send a SYN packet if we have no route since that will fail. */ 1272195972f6Sopenharmony_ci return ERR_RTE; 1273195972f6Sopenharmony_ci } 1274195972f6Sopenharmony_ci 1275195972f6Sopenharmony_ci /* check if local IP has been assigned to pcb, if not, get one */ 1276195972f6Sopenharmony_ci if (ip_addr_isany(&pcb->local_ip)) { 1277195972f6Sopenharmony_ci const ip_addr_t *local_ip = ip_netif_get_local_ip(netif, ipaddr); 1278195972f6Sopenharmony_ci if (local_ip == NULL) { 1279195972f6Sopenharmony_ci return ERR_RTE; 1280195972f6Sopenharmony_ci } 1281195972f6Sopenharmony_ci ip_addr_copy(pcb->local_ip, *local_ip); 1282195972f6Sopenharmony_ci } 1283195972f6Sopenharmony_ci 1284195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_IPV6_SCOPES 1285195972f6Sopenharmony_ci /* If the given IP address should have a zone but doesn't, assign one now. 1286195972f6Sopenharmony_ci * Given that we already have the target netif, this is easy and cheap. */ 1287195972f6Sopenharmony_ci if (IP_IS_V6(&pcb->remote_ip) && 1288195972f6Sopenharmony_ci ip6_addr_lacks_zone(ip_2_ip6(&pcb->remote_ip), IP6_UNICAST)) { 1289195972f6Sopenharmony_ci ip6_addr_assign_zone(ip_2_ip6(&pcb->remote_ip), IP6_UNICAST, netif); 1290195972f6Sopenharmony_ci } 1291195972f6Sopenharmony_ci#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ 1292195972f6Sopenharmony_ci 1293195972f6Sopenharmony_ci old_local_port = pcb->local_port; 1294195972f6Sopenharmony_ci if (pcb->local_port == 0) { 1295195972f6Sopenharmony_ci pcb->local_port = tcp_new_port(); 1296195972f6Sopenharmony_ci if (pcb->local_port == 0) { 1297195972f6Sopenharmony_ci return ERR_BUF; 1298195972f6Sopenharmony_ci } 1299195972f6Sopenharmony_ci } else { 1300195972f6Sopenharmony_ci#if SO_REUSE 1301195972f6Sopenharmony_ci if (ip_get_option(pcb, SOF_REUSEADDR)) { 1302195972f6Sopenharmony_ci /* Since SOF_REUSEADDR allows reusing a local address, we have to make sure 1303195972f6Sopenharmony_ci now that the 5-tuple is unique. */ 1304195972f6Sopenharmony_ci struct tcp_pcb *cpcb; 1305195972f6Sopenharmony_ci int i; 1306195972f6Sopenharmony_ci /* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */ 1307195972f6Sopenharmony_ci for (i = 2; i < NUM_TCP_PCB_LISTS; i++) { 1308195972f6Sopenharmony_ci for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { 1309195972f6Sopenharmony_ci if ((cpcb->local_port == pcb->local_port) && 1310195972f6Sopenharmony_ci (cpcb->remote_port == port) && 1311195972f6Sopenharmony_ci ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) && 1312195972f6Sopenharmony_ci ip_addr_cmp(&cpcb->remote_ip, ipaddr)) { 1313195972f6Sopenharmony_ci /* linux returns EISCONN here, but ERR_USE should be OK for us */ 1314195972f6Sopenharmony_ci return ERR_USE; 1315195972f6Sopenharmony_ci } 1316195972f6Sopenharmony_ci } 1317195972f6Sopenharmony_ci } 1318195972f6Sopenharmony_ci } 1319195972f6Sopenharmony_ci#endif /* SO_REUSE */ 1320195972f6Sopenharmony_ci } 1321195972f6Sopenharmony_ci 1322195972f6Sopenharmony_ci iss = tcp_next_iss(pcb); 1323195972f6Sopenharmony_ci pcb->rcv_nxt = 0; 1324195972f6Sopenharmony_ci pcb->snd_nxt = iss; 1325195972f6Sopenharmony_ci pcb->lastack = iss - 1; 1326195972f6Sopenharmony_ci pcb->snd_wl2 = iss - 1; 1327195972f6Sopenharmony_ci pcb->snd_lbb = iss - 1; 1328195972f6Sopenharmony_ci /* Start with a window that does not need scaling. When window scaling is 1329195972f6Sopenharmony_ci enabled and used, the window is enlarged when both sides agree on scaling. */ 1330195972f6Sopenharmony_ci pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND); 1331195972f6Sopenharmony_ci pcb->rcv_ann_right_edge = pcb->rcv_nxt; 1332195972f6Sopenharmony_ci pcb->snd_wnd = TCP_WND; 1333195972f6Sopenharmony_ci /* As initial send MSS, we use TCP_MSS but limit it to 536. 1334195972f6Sopenharmony_ci The send MSS is updated when an MSS option is received. */ 1335195972f6Sopenharmony_ci pcb->mss = INITIAL_MSS; 1336195972f6Sopenharmony_ci#if TCP_CALCULATE_EFF_SEND_MSS 1337195972f6Sopenharmony_ci pcb->mss = tcp_eff_send_mss_netif(pcb->mss, netif, &pcb->remote_ip); 1338195972f6Sopenharmony_ci#endif /* TCP_CALCULATE_EFF_SEND_MSS */ 1339195972f6Sopenharmony_ci pcb->cwnd = 1; 1340195972f6Sopenharmony_ci#if LWIP_CALLBACK_API 1341195972f6Sopenharmony_ci pcb->connected = connected; 1342195972f6Sopenharmony_ci#else /* LWIP_CALLBACK_API */ 1343195972f6Sopenharmony_ci LWIP_UNUSED_ARG(connected); 1344195972f6Sopenharmony_ci#endif /* LWIP_CALLBACK_API */ 1345195972f6Sopenharmony_ci 1346195972f6Sopenharmony_ci /* Send a SYN together with the MSS option. */ 1347195972f6Sopenharmony_ci ret = tcp_enqueue_flags(pcb, TCP_SYN); 1348195972f6Sopenharmony_ci if (ret == ERR_OK) { 1349195972f6Sopenharmony_ci /* SYN segment was enqueued, changed the pcbs state now */ 1350195972f6Sopenharmony_ci pcb->state = SYN_SENT; 1351195972f6Sopenharmony_ci if (old_local_port != 0) { 1352195972f6Sopenharmony_ci TCP_RMV(&tcp_bound_pcbs, pcb); 1353195972f6Sopenharmony_ci } 1354195972f6Sopenharmony_ci TCP_REG_ACTIVE(pcb); 1355195972f6Sopenharmony_ci MIB2_STATS_INC(mib2.tcpactiveopens); 1356195972f6Sopenharmony_ci 1357195972f6Sopenharmony_ci tcp_output(pcb); 1358195972f6Sopenharmony_ci } 1359195972f6Sopenharmony_ci return ret; 1360195972f6Sopenharmony_ci} 1361195972f6Sopenharmony_ci 1362195972f6Sopenharmony_ci/** 1363195972f6Sopenharmony_ci * Called every 500 ms and implements the retransmission timer and the timer that 1364195972f6Sopenharmony_ci * removes PCBs that have been in TIME-WAIT for enough time. It also increments 1365195972f6Sopenharmony_ci * various timers such as the inactivity timer in each PCB. 1366195972f6Sopenharmony_ci * 1367195972f6Sopenharmony_ci * Automatically called from tcp_tmr(). 1368195972f6Sopenharmony_ci */ 1369195972f6Sopenharmony_civoid 1370195972f6Sopenharmony_citcp_slowtmr(void) 1371195972f6Sopenharmony_ci{ 1372195972f6Sopenharmony_ci struct tcp_pcb *pcb, *prev; 1373195972f6Sopenharmony_ci tcpwnd_size_t eff_wnd; 1374195972f6Sopenharmony_ci u8_t pcb_remove; /* flag if a PCB should be removed */ 1375195972f6Sopenharmony_ci u8_t pcb_reset; /* flag if a RST should be sent when removing */ 1376195972f6Sopenharmony_ci err_t err; 1377195972f6Sopenharmony_ci 1378195972f6Sopenharmony_ci err = ERR_OK; 1379195972f6Sopenharmony_ci 1380195972f6Sopenharmony_ci ++tcp_ticks; 1381195972f6Sopenharmony_ci ++tcp_timer_ctr; 1382195972f6Sopenharmony_ci 1383195972f6Sopenharmony_citcp_slowtmr_start: 1384195972f6Sopenharmony_ci /* Steps through all of the active PCBs. */ 1385195972f6Sopenharmony_ci prev = NULL; 1386195972f6Sopenharmony_ci pcb = tcp_active_pcbs; 1387195972f6Sopenharmony_ci if (pcb == NULL) { 1388195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n")); 1389195972f6Sopenharmony_ci } 1390195972f6Sopenharmony_ci while (pcb != NULL) { 1391195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n")); 1392195972f6Sopenharmony_ci LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED); 1393195972f6Sopenharmony_ci LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN); 1394195972f6Sopenharmony_ci LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT); 1395195972f6Sopenharmony_ci if (pcb->last_timer == tcp_timer_ctr) { 1396195972f6Sopenharmony_ci /* skip this pcb, we have already processed it */ 1397195972f6Sopenharmony_ci prev = pcb; 1398195972f6Sopenharmony_ci pcb = pcb->next; 1399195972f6Sopenharmony_ci continue; 1400195972f6Sopenharmony_ci } 1401195972f6Sopenharmony_ci pcb->last_timer = tcp_timer_ctr; 1402195972f6Sopenharmony_ci 1403195972f6Sopenharmony_ci pcb_remove = 0; 1404195972f6Sopenharmony_ci pcb_reset = 0; 1405195972f6Sopenharmony_ci 1406195972f6Sopenharmony_ci if (pcb->state == SYN_SENT && pcb->nrtx >= TCP_SYNMAXRTX) { 1407195972f6Sopenharmony_ci ++pcb_remove; 1408195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n")); 1409195972f6Sopenharmony_ci } else if (pcb->nrtx >= TCP_MAXRTX) { 1410195972f6Sopenharmony_ci ++pcb_remove; 1411195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n")); 1412195972f6Sopenharmony_ci } else { 1413195972f6Sopenharmony_ci if (pcb->persist_backoff > 0) { 1414195972f6Sopenharmony_ci LWIP_ASSERT("tcp_slowtimr: persist ticking with in-flight data", pcb->unacked == NULL); 1415195972f6Sopenharmony_ci LWIP_ASSERT("tcp_slowtimr: persist ticking with empty send buffer", pcb->unsent != NULL); 1416195972f6Sopenharmony_ci if (pcb->persist_probe >= TCP_MAXRTX) { 1417195972f6Sopenharmony_ci ++pcb_remove; /* max probes reached */ 1418195972f6Sopenharmony_ci } else { 1419195972f6Sopenharmony_ci u8_t backoff_cnt = tcp_persist_backoff[pcb->persist_backoff - 1]; 1420195972f6Sopenharmony_ci if (pcb->persist_cnt < backoff_cnt) { 1421195972f6Sopenharmony_ci pcb->persist_cnt++; 1422195972f6Sopenharmony_ci } 1423195972f6Sopenharmony_ci if (pcb->persist_cnt >= backoff_cnt) { 1424195972f6Sopenharmony_ci int next_slot = 1; /* increment timer to next slot */ 1425195972f6Sopenharmony_ci /* If snd_wnd is zero, send 1 byte probes */ 1426195972f6Sopenharmony_ci if (pcb->snd_wnd == 0) { 1427195972f6Sopenharmony_ci if (tcp_zero_window_probe(pcb) != ERR_OK) { 1428195972f6Sopenharmony_ci next_slot = 0; /* try probe again with current slot */ 1429195972f6Sopenharmony_ci } 1430195972f6Sopenharmony_ci /* snd_wnd not fully closed, split unsent head and fill window */ 1431195972f6Sopenharmony_ci } else { 1432195972f6Sopenharmony_ci if (tcp_split_unsent_seg(pcb, (u16_t)pcb->snd_wnd) == ERR_OK) { 1433195972f6Sopenharmony_ci if (tcp_output(pcb) == ERR_OK) { 1434195972f6Sopenharmony_ci /* sending will cancel persist timer, else retry with current slot */ 1435195972f6Sopenharmony_ci next_slot = 0; 1436195972f6Sopenharmony_ci } 1437195972f6Sopenharmony_ci } 1438195972f6Sopenharmony_ci } 1439195972f6Sopenharmony_ci if (next_slot) { 1440195972f6Sopenharmony_ci pcb->persist_cnt = 0; 1441195972f6Sopenharmony_ci if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) { 1442195972f6Sopenharmony_ci pcb->persist_backoff++; 1443195972f6Sopenharmony_ci } 1444195972f6Sopenharmony_ci } 1445195972f6Sopenharmony_ci } 1446195972f6Sopenharmony_ci } 1447195972f6Sopenharmony_ci } else { 1448195972f6Sopenharmony_ci /* Increase the retransmission timer if it is running */ 1449195972f6Sopenharmony_ci if ((pcb->rtime >= 0) && (pcb->rtime < 0x7FFF)) { 1450195972f6Sopenharmony_ci ++pcb->rtime; 1451195972f6Sopenharmony_ci } 1452195972f6Sopenharmony_ci 1453195972f6Sopenharmony_ci if (pcb->rtime >= pcb->rto) { 1454195972f6Sopenharmony_ci /* Time for a retransmission. */ 1455195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F 1456195972f6Sopenharmony_ci " pcb->rto %"S16_F"\n", 1457195972f6Sopenharmony_ci pcb->rtime, pcb->rto)); 1458195972f6Sopenharmony_ci /* If prepare phase fails but we have unsent data but no unacked data, 1459195972f6Sopenharmony_ci still execute the backoff calculations below, as this means we somehow 1460195972f6Sopenharmony_ci failed to send segment. */ 1461195972f6Sopenharmony_ci if ((tcp_rexmit_rto_prepare(pcb) == ERR_OK) || ((pcb->unacked == NULL) && (pcb->unsent != NULL))) { 1462195972f6Sopenharmony_ci /* Double retransmission time-out unless we are trying to 1463195972f6Sopenharmony_ci * connect to somebody (i.e., we are in SYN_SENT). */ 1464195972f6Sopenharmony_ci if (pcb->state != SYN_SENT) { 1465195972f6Sopenharmony_ci u8_t backoff_idx = LWIP_MIN(pcb->nrtx, sizeof(tcp_backoff) - 1); 1466195972f6Sopenharmony_ci int calc_rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[backoff_idx]; 1467195972f6Sopenharmony_ci pcb->rto = (s16_t)LWIP_MIN(calc_rto, 0x7FFF); 1468195972f6Sopenharmony_ci } 1469195972f6Sopenharmony_ci 1470195972f6Sopenharmony_ci /* Reset the retransmission timer. */ 1471195972f6Sopenharmony_ci pcb->rtime = 0; 1472195972f6Sopenharmony_ci 1473195972f6Sopenharmony_ci /* Reduce congestion window and ssthresh. */ 1474195972f6Sopenharmony_ci eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd); 1475195972f6Sopenharmony_ci pcb->ssthresh = eff_wnd >> 1; 1476195972f6Sopenharmony_ci if (pcb->ssthresh < (tcpwnd_size_t)(pcb->mss << 1)) { 1477195972f6Sopenharmony_ci pcb->ssthresh = (tcpwnd_size_t)(pcb->mss << 1); 1478195972f6Sopenharmony_ci } 1479195972f6Sopenharmony_ci pcb->cwnd = pcb->mss; 1480195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"TCPWNDSIZE_F 1481195972f6Sopenharmony_ci " ssthresh %"TCPWNDSIZE_F"\n", 1482195972f6Sopenharmony_ci pcb->cwnd, pcb->ssthresh)); 1483195972f6Sopenharmony_ci pcb->bytes_acked = 0; 1484195972f6Sopenharmony_ci 1485195972f6Sopenharmony_ci /* The following needs to be called AFTER cwnd is set to one 1486195972f6Sopenharmony_ci mss - STJ */ 1487195972f6Sopenharmony_ci tcp_rexmit_rto_commit(pcb); 1488195972f6Sopenharmony_ci } 1489195972f6Sopenharmony_ci } 1490195972f6Sopenharmony_ci } 1491195972f6Sopenharmony_ci } 1492195972f6Sopenharmony_ci /* Check if this PCB has stayed too long in FIN-WAIT-2 */ 1493195972f6Sopenharmony_ci if (pcb->state == FIN_WAIT_2) { 1494195972f6Sopenharmony_ci /* If this PCB is in FIN_WAIT_2 because of SHUT_WR don't let it time out. */ 1495195972f6Sopenharmony_ci if (pcb->flags & TF_RXCLOSED) { 1496195972f6Sopenharmony_ci /* PCB was fully closed (either through close() or SHUT_RDWR): 1497195972f6Sopenharmony_ci normal FIN-WAIT timeout handling. */ 1498195972f6Sopenharmony_ci if ((u32_t)(tcp_ticks - pcb->tmr) > 1499195972f6Sopenharmony_ci TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) { 1500195972f6Sopenharmony_ci ++pcb_remove; 1501195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n")); 1502195972f6Sopenharmony_ci } 1503195972f6Sopenharmony_ci } 1504195972f6Sopenharmony_ci } 1505195972f6Sopenharmony_ci 1506195972f6Sopenharmony_ci /* Check if KEEPALIVE should be sent */ 1507195972f6Sopenharmony_ci if (ip_get_option(pcb, SOF_KEEPALIVE) && 1508195972f6Sopenharmony_ci ((pcb->state == ESTABLISHED) || 1509195972f6Sopenharmony_ci (pcb->state == CLOSE_WAIT))) { 1510195972f6Sopenharmony_ci if ((u32_t)(tcp_ticks - pcb->tmr) > 1511195972f6Sopenharmony_ci (pcb->keep_idle + TCP_KEEP_DUR(pcb)) / TCP_SLOW_INTERVAL) { 1512195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to ")); 1513195972f6Sopenharmony_ci ip_addr_debug_print_val(TCP_DEBUG, pcb->remote_ip); 1514195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("\n")); 1515195972f6Sopenharmony_ci 1516195972f6Sopenharmony_ci ++pcb_remove; 1517195972f6Sopenharmony_ci ++pcb_reset; 1518195972f6Sopenharmony_ci } else if ((u32_t)(tcp_ticks - pcb->tmr) > 1519195972f6Sopenharmony_ci (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEP_INTVL(pcb)) 1520195972f6Sopenharmony_ci / TCP_SLOW_INTERVAL) { 1521195972f6Sopenharmony_ci err = tcp_keepalive(pcb); 1522195972f6Sopenharmony_ci if (err == ERR_OK) { 1523195972f6Sopenharmony_ci pcb->keep_cnt_sent++; 1524195972f6Sopenharmony_ci } 1525195972f6Sopenharmony_ci } 1526195972f6Sopenharmony_ci } 1527195972f6Sopenharmony_ci 1528195972f6Sopenharmony_ci /* If this PCB has queued out of sequence data, but has been 1529195972f6Sopenharmony_ci inactive for too long, will drop the data (it will eventually 1530195972f6Sopenharmony_ci be retransmitted). */ 1531195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ 1532195972f6Sopenharmony_ci if (pcb->ooseq != NULL && 1533195972f6Sopenharmony_ci (tcp_ticks - pcb->tmr >= (u32_t)pcb->rto * TCP_OOSEQ_TIMEOUT)) { 1534195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n")); 1535195972f6Sopenharmony_ci tcp_free_ooseq(pcb); 1536195972f6Sopenharmony_ci } 1537195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ */ 1538195972f6Sopenharmony_ci 1539195972f6Sopenharmony_ci /* Check if this PCB has stayed too long in SYN-RCVD */ 1540195972f6Sopenharmony_ci if (pcb->state == SYN_RCVD) { 1541195972f6Sopenharmony_ci if ((u32_t)(tcp_ticks - pcb->tmr) > 1542195972f6Sopenharmony_ci TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) { 1543195972f6Sopenharmony_ci ++pcb_remove; 1544195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n")); 1545195972f6Sopenharmony_ci } 1546195972f6Sopenharmony_ci } 1547195972f6Sopenharmony_ci 1548195972f6Sopenharmony_ci /* Check if this PCB has stayed too long in LAST-ACK */ 1549195972f6Sopenharmony_ci if (pcb->state == LAST_ACK) { 1550195972f6Sopenharmony_ci if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { 1551195972f6Sopenharmony_ci ++pcb_remove; 1552195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n")); 1553195972f6Sopenharmony_ci } 1554195972f6Sopenharmony_ci } 1555195972f6Sopenharmony_ci 1556195972f6Sopenharmony_ci /* If the PCB should be removed, do it. */ 1557195972f6Sopenharmony_ci if (pcb_remove) { 1558195972f6Sopenharmony_ci struct tcp_pcb *pcb2; 1559195972f6Sopenharmony_ci#if LWIP_CALLBACK_API 1560195972f6Sopenharmony_ci tcp_err_fn err_fn = pcb->errf; 1561195972f6Sopenharmony_ci#endif /* LWIP_CALLBACK_API */ 1562195972f6Sopenharmony_ci void *err_arg; 1563195972f6Sopenharmony_ci enum tcp_state last_state; 1564195972f6Sopenharmony_ci tcp_pcb_purge(pcb); 1565195972f6Sopenharmony_ci /* Remove PCB from tcp_active_pcbs list. */ 1566195972f6Sopenharmony_ci if (prev != NULL) { 1567195972f6Sopenharmony_ci LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); 1568195972f6Sopenharmony_ci prev->next = pcb->next; 1569195972f6Sopenharmony_ci } else { 1570195972f6Sopenharmony_ci /* This PCB was the first. */ 1571195972f6Sopenharmony_ci LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); 1572195972f6Sopenharmony_ci tcp_active_pcbs = pcb->next; 1573195972f6Sopenharmony_ci } 1574195972f6Sopenharmony_ci 1575195972f6Sopenharmony_ci if (pcb_reset) { 1576195972f6Sopenharmony_ci tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, 1577195972f6Sopenharmony_ci pcb->local_port, pcb->remote_port); 1578195972f6Sopenharmony_ci } 1579195972f6Sopenharmony_ci 1580195972f6Sopenharmony_ci err_arg = pcb->callback_arg; 1581195972f6Sopenharmony_ci last_state = pcb->state; 1582195972f6Sopenharmony_ci pcb2 = pcb; 1583195972f6Sopenharmony_ci pcb = pcb->next; 1584195972f6Sopenharmony_ci tcp_free(pcb2); 1585195972f6Sopenharmony_ci 1586195972f6Sopenharmony_ci tcp_active_pcbs_changed = 0; 1587195972f6Sopenharmony_ci TCP_EVENT_ERR(last_state, err_fn, err_arg, ERR_ABRT); 1588195972f6Sopenharmony_ci if (tcp_active_pcbs_changed) { 1589195972f6Sopenharmony_ci goto tcp_slowtmr_start; 1590195972f6Sopenharmony_ci } 1591195972f6Sopenharmony_ci } else { 1592195972f6Sopenharmony_ci /* get the 'next' element now and work with 'prev' below (in case of abort) */ 1593195972f6Sopenharmony_ci prev = pcb; 1594195972f6Sopenharmony_ci pcb = pcb->next; 1595195972f6Sopenharmony_ci 1596195972f6Sopenharmony_ci /* We check if we should poll the connection. */ 1597195972f6Sopenharmony_ci ++prev->polltmr; 1598195972f6Sopenharmony_ci if (prev->polltmr >= prev->pollinterval) { 1599195972f6Sopenharmony_ci prev->polltmr = 0; 1600195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n")); 1601195972f6Sopenharmony_ci tcp_active_pcbs_changed = 0; 1602195972f6Sopenharmony_ci TCP_EVENT_POLL(prev, err); 1603195972f6Sopenharmony_ci if (tcp_active_pcbs_changed) { 1604195972f6Sopenharmony_ci goto tcp_slowtmr_start; 1605195972f6Sopenharmony_ci } 1606195972f6Sopenharmony_ci /* if err == ERR_ABRT, 'prev' is already deallocated */ 1607195972f6Sopenharmony_ci if (err == ERR_OK) { 1608195972f6Sopenharmony_ci tcp_output(prev); 1609195972f6Sopenharmony_ci } 1610195972f6Sopenharmony_ci } 1611195972f6Sopenharmony_ci } 1612195972f6Sopenharmony_ci } 1613195972f6Sopenharmony_ci 1614195972f6Sopenharmony_ci 1615195972f6Sopenharmony_ci /* Steps through all of the TIME-WAIT PCBs. */ 1616195972f6Sopenharmony_ci prev = NULL; 1617195972f6Sopenharmony_ci pcb = tcp_tw_pcbs; 1618195972f6Sopenharmony_ci while (pcb != NULL) { 1619195972f6Sopenharmony_ci LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); 1620195972f6Sopenharmony_ci pcb_remove = 0; 1621195972f6Sopenharmony_ci 1622195972f6Sopenharmony_ci /* Check if this PCB has stayed long enough in TIME-WAIT */ 1623195972f6Sopenharmony_ci if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { 1624195972f6Sopenharmony_ci ++pcb_remove; 1625195972f6Sopenharmony_ci } 1626195972f6Sopenharmony_ci 1627195972f6Sopenharmony_ci /* If the PCB should be removed, do it. */ 1628195972f6Sopenharmony_ci if (pcb_remove) { 1629195972f6Sopenharmony_ci struct tcp_pcb *pcb2; 1630195972f6Sopenharmony_ci tcp_pcb_purge(pcb); 1631195972f6Sopenharmony_ci /* Remove PCB from tcp_tw_pcbs list. */ 1632195972f6Sopenharmony_ci if (prev != NULL) { 1633195972f6Sopenharmony_ci LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); 1634195972f6Sopenharmony_ci prev->next = pcb->next; 1635195972f6Sopenharmony_ci } else { 1636195972f6Sopenharmony_ci /* This PCB was the first. */ 1637195972f6Sopenharmony_ci LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); 1638195972f6Sopenharmony_ci tcp_tw_pcbs = pcb->next; 1639195972f6Sopenharmony_ci } 1640195972f6Sopenharmony_ci pcb2 = pcb; 1641195972f6Sopenharmony_ci pcb = pcb->next; 1642195972f6Sopenharmony_ci tcp_free(pcb2); 1643195972f6Sopenharmony_ci } else { 1644195972f6Sopenharmony_ci prev = pcb; 1645195972f6Sopenharmony_ci pcb = pcb->next; 1646195972f6Sopenharmony_ci } 1647195972f6Sopenharmony_ci } 1648195972f6Sopenharmony_ci} 1649195972f6Sopenharmony_ci 1650195972f6Sopenharmony_ci/** 1651195972f6Sopenharmony_ci * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously 1652195972f6Sopenharmony_ci * "refused" by upper layer (application) and sends delayed ACKs or pending FINs. 1653195972f6Sopenharmony_ci * 1654195972f6Sopenharmony_ci * Automatically called from tcp_tmr(). 1655195972f6Sopenharmony_ci */ 1656195972f6Sopenharmony_civoid 1657195972f6Sopenharmony_citcp_fasttmr(void) 1658195972f6Sopenharmony_ci{ 1659195972f6Sopenharmony_ci struct tcp_pcb *pcb; 1660195972f6Sopenharmony_ci 1661195972f6Sopenharmony_ci ++tcp_timer_ctr; 1662195972f6Sopenharmony_ci 1663195972f6Sopenharmony_citcp_fasttmr_start: 1664195972f6Sopenharmony_ci pcb = tcp_active_pcbs; 1665195972f6Sopenharmony_ci 1666195972f6Sopenharmony_ci while (pcb != NULL) { 1667195972f6Sopenharmony_ci if (pcb->last_timer != tcp_timer_ctr) { 1668195972f6Sopenharmony_ci struct tcp_pcb *next; 1669195972f6Sopenharmony_ci pcb->last_timer = tcp_timer_ctr; 1670195972f6Sopenharmony_ci /* send delayed ACKs */ 1671195972f6Sopenharmony_ci if (pcb->flags & TF_ACK_DELAY) { 1672195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); 1673195972f6Sopenharmony_ci tcp_ack_now(pcb); 1674195972f6Sopenharmony_ci tcp_output(pcb); 1675195972f6Sopenharmony_ci tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); 1676195972f6Sopenharmony_ci } 1677195972f6Sopenharmony_ci /* send pending FIN */ 1678195972f6Sopenharmony_ci if (pcb->flags & TF_CLOSEPEND) { 1679195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: pending FIN\n")); 1680195972f6Sopenharmony_ci tcp_clear_flags(pcb, TF_CLOSEPEND); 1681195972f6Sopenharmony_ci tcp_close_shutdown_fin(pcb); 1682195972f6Sopenharmony_ci } 1683195972f6Sopenharmony_ci 1684195972f6Sopenharmony_ci next = pcb->next; 1685195972f6Sopenharmony_ci 1686195972f6Sopenharmony_ci /* If there is data which was previously "refused" by upper layer */ 1687195972f6Sopenharmony_ci if (pcb->refused_data != NULL) { 1688195972f6Sopenharmony_ci tcp_active_pcbs_changed = 0; 1689195972f6Sopenharmony_ci tcp_process_refused_data(pcb); 1690195972f6Sopenharmony_ci if (tcp_active_pcbs_changed) { 1691195972f6Sopenharmony_ci /* application callback has changed the pcb list: restart the loop */ 1692195972f6Sopenharmony_ci goto tcp_fasttmr_start; 1693195972f6Sopenharmony_ci } 1694195972f6Sopenharmony_ci } 1695195972f6Sopenharmony_ci pcb = next; 1696195972f6Sopenharmony_ci } else { 1697195972f6Sopenharmony_ci pcb = pcb->next; 1698195972f6Sopenharmony_ci } 1699195972f6Sopenharmony_ci } 1700195972f6Sopenharmony_ci} 1701195972f6Sopenharmony_ci 1702195972f6Sopenharmony_ci/** Call tcp_output for all active pcbs that have TF_NAGLEMEMERR set */ 1703195972f6Sopenharmony_civoid 1704195972f6Sopenharmony_citcp_txnow(void) 1705195972f6Sopenharmony_ci{ 1706195972f6Sopenharmony_ci struct tcp_pcb *pcb; 1707195972f6Sopenharmony_ci 1708195972f6Sopenharmony_ci for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { 1709195972f6Sopenharmony_ci if (pcb->flags & TF_NAGLEMEMERR) { 1710195972f6Sopenharmony_ci tcp_output(pcb); 1711195972f6Sopenharmony_ci } 1712195972f6Sopenharmony_ci } 1713195972f6Sopenharmony_ci} 1714195972f6Sopenharmony_ci 1715195972f6Sopenharmony_ci/** Pass pcb->refused_data to the recv callback */ 1716195972f6Sopenharmony_cierr_t 1717195972f6Sopenharmony_citcp_process_refused_data(struct tcp_pcb *pcb) 1718195972f6Sopenharmony_ci{ 1719195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE 1720195972f6Sopenharmony_ci struct pbuf *rest; 1721195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ 1722195972f6Sopenharmony_ci 1723195972f6Sopenharmony_ci LWIP_ERROR("tcp_process_refused_data: invalid pcb", pcb != NULL, return ERR_ARG); 1724195972f6Sopenharmony_ci 1725195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE 1726195972f6Sopenharmony_ci while (pcb->refused_data != NULL) 1727195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ 1728195972f6Sopenharmony_ci { 1729195972f6Sopenharmony_ci err_t err; 1730195972f6Sopenharmony_ci u8_t refused_flags = pcb->refused_data->flags; 1731195972f6Sopenharmony_ci /* set pcb->refused_data to NULL in case the callback frees it and then 1732195972f6Sopenharmony_ci closes the pcb */ 1733195972f6Sopenharmony_ci struct pbuf *refused_data = pcb->refused_data; 1734195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE 1735195972f6Sopenharmony_ci pbuf_split_64k(refused_data, &rest); 1736195972f6Sopenharmony_ci pcb->refused_data = rest; 1737195972f6Sopenharmony_ci#else /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ 1738195972f6Sopenharmony_ci pcb->refused_data = NULL; 1739195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ 1740195972f6Sopenharmony_ci /* Notify again application with data previously received. */ 1741195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n")); 1742195972f6Sopenharmony_ci TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err); 1743195972f6Sopenharmony_ci if (err == ERR_OK) { 1744195972f6Sopenharmony_ci /* did refused_data include a FIN? */ 1745195972f6Sopenharmony_ci if ((refused_flags & PBUF_FLAG_TCP_FIN) 1746195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE 1747195972f6Sopenharmony_ci && (rest == NULL) 1748195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ 1749195972f6Sopenharmony_ci ) { 1750195972f6Sopenharmony_ci /* correct rcv_wnd as the application won't call tcp_recved() 1751195972f6Sopenharmony_ci for the FIN's seqno */ 1752195972f6Sopenharmony_ci if (pcb->rcv_wnd != TCP_WND_MAX(pcb)) { 1753195972f6Sopenharmony_ci pcb->rcv_wnd++; 1754195972f6Sopenharmony_ci } 1755195972f6Sopenharmony_ci TCP_EVENT_CLOSED(pcb, err); 1756195972f6Sopenharmony_ci if (err == ERR_ABRT) { 1757195972f6Sopenharmony_ci return ERR_ABRT; 1758195972f6Sopenharmony_ci } 1759195972f6Sopenharmony_ci } 1760195972f6Sopenharmony_ci } else if (err == ERR_ABRT) { 1761195972f6Sopenharmony_ci /* if err == ERR_ABRT, 'pcb' is already deallocated */ 1762195972f6Sopenharmony_ci /* Drop incoming packets because pcb is "full" (only if the incoming 1763195972f6Sopenharmony_ci segment contains data). */ 1764195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); 1765195972f6Sopenharmony_ci return ERR_ABRT; 1766195972f6Sopenharmony_ci } else { 1767195972f6Sopenharmony_ci /* data is still refused, pbuf is still valid (go on for ACK-only packets) */ 1768195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE 1769195972f6Sopenharmony_ci if (rest != NULL) { 1770195972f6Sopenharmony_ci pbuf_cat(refused_data, rest); 1771195972f6Sopenharmony_ci } 1772195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ 1773195972f6Sopenharmony_ci pcb->refused_data = refused_data; 1774195972f6Sopenharmony_ci return ERR_INPROGRESS; 1775195972f6Sopenharmony_ci } 1776195972f6Sopenharmony_ci } 1777195972f6Sopenharmony_ci return ERR_OK; 1778195972f6Sopenharmony_ci} 1779195972f6Sopenharmony_ci 1780195972f6Sopenharmony_ci/** 1781195972f6Sopenharmony_ci * Deallocates a list of TCP segments (tcp_seg structures). 1782195972f6Sopenharmony_ci * 1783195972f6Sopenharmony_ci * @param seg tcp_seg list of TCP segments to free 1784195972f6Sopenharmony_ci */ 1785195972f6Sopenharmony_civoid 1786195972f6Sopenharmony_citcp_segs_free(struct tcp_seg *seg) 1787195972f6Sopenharmony_ci{ 1788195972f6Sopenharmony_ci while (seg != NULL) { 1789195972f6Sopenharmony_ci struct tcp_seg *next = seg->next; 1790195972f6Sopenharmony_ci tcp_seg_free(seg); 1791195972f6Sopenharmony_ci seg = next; 1792195972f6Sopenharmony_ci } 1793195972f6Sopenharmony_ci} 1794195972f6Sopenharmony_ci 1795195972f6Sopenharmony_ci/** 1796195972f6Sopenharmony_ci * Frees a TCP segment (tcp_seg structure). 1797195972f6Sopenharmony_ci * 1798195972f6Sopenharmony_ci * @param seg single tcp_seg to free 1799195972f6Sopenharmony_ci */ 1800195972f6Sopenharmony_civoid 1801195972f6Sopenharmony_citcp_seg_free(struct tcp_seg *seg) 1802195972f6Sopenharmony_ci{ 1803195972f6Sopenharmony_ci if (seg != NULL) { 1804195972f6Sopenharmony_ci if (seg->p != NULL) { 1805195972f6Sopenharmony_ci pbuf_free(seg->p); 1806195972f6Sopenharmony_ci#if TCP_DEBUG 1807195972f6Sopenharmony_ci seg->p = NULL; 1808195972f6Sopenharmony_ci#endif /* TCP_DEBUG */ 1809195972f6Sopenharmony_ci } 1810195972f6Sopenharmony_ci memp_free(MEMP_TCP_SEG, seg); 1811195972f6Sopenharmony_ci } 1812195972f6Sopenharmony_ci} 1813195972f6Sopenharmony_ci 1814195972f6Sopenharmony_ci/** 1815195972f6Sopenharmony_ci * @ingroup tcp 1816195972f6Sopenharmony_ci * Sets the priority of a connection. 1817195972f6Sopenharmony_ci * 1818195972f6Sopenharmony_ci * @param pcb the tcp_pcb to manipulate 1819195972f6Sopenharmony_ci * @param prio new priority 1820195972f6Sopenharmony_ci */ 1821195972f6Sopenharmony_civoid 1822195972f6Sopenharmony_citcp_setprio(struct tcp_pcb *pcb, u8_t prio) 1823195972f6Sopenharmony_ci{ 1824195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 1825195972f6Sopenharmony_ci 1826195972f6Sopenharmony_ci LWIP_ERROR("tcp_setprio: invalid pcb", pcb != NULL, return); 1827195972f6Sopenharmony_ci 1828195972f6Sopenharmony_ci pcb->prio = prio; 1829195972f6Sopenharmony_ci} 1830195972f6Sopenharmony_ci 1831195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ 1832195972f6Sopenharmony_ci/** 1833195972f6Sopenharmony_ci * Returns a copy of the given TCP segment. 1834195972f6Sopenharmony_ci * The pbuf and data are not copied, only the pointers 1835195972f6Sopenharmony_ci * 1836195972f6Sopenharmony_ci * @param seg the old tcp_seg 1837195972f6Sopenharmony_ci * @return a copy of seg 1838195972f6Sopenharmony_ci */ 1839195972f6Sopenharmony_cistruct tcp_seg * 1840195972f6Sopenharmony_citcp_seg_copy(struct tcp_seg *seg) 1841195972f6Sopenharmony_ci{ 1842195972f6Sopenharmony_ci struct tcp_seg *cseg; 1843195972f6Sopenharmony_ci 1844195972f6Sopenharmony_ci LWIP_ASSERT("tcp_seg_copy: invalid seg", seg != NULL); 1845195972f6Sopenharmony_ci 1846195972f6Sopenharmony_ci cseg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG); 1847195972f6Sopenharmony_ci if (cseg == NULL) { 1848195972f6Sopenharmony_ci return NULL; 1849195972f6Sopenharmony_ci } 1850195972f6Sopenharmony_ci SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); 1851195972f6Sopenharmony_ci pbuf_ref(cseg->p); 1852195972f6Sopenharmony_ci return cseg; 1853195972f6Sopenharmony_ci} 1854195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ */ 1855195972f6Sopenharmony_ci 1856195972f6Sopenharmony_ci#if LWIP_CALLBACK_API 1857195972f6Sopenharmony_ci/** 1858195972f6Sopenharmony_ci * Default receive callback that is called if the user didn't register 1859195972f6Sopenharmony_ci * a recv callback for the pcb. 1860195972f6Sopenharmony_ci */ 1861195972f6Sopenharmony_cierr_t 1862195972f6Sopenharmony_citcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) 1863195972f6Sopenharmony_ci{ 1864195972f6Sopenharmony_ci LWIP_UNUSED_ARG(arg); 1865195972f6Sopenharmony_ci 1866195972f6Sopenharmony_ci LWIP_ERROR("tcp_recv_null: invalid pcb", pcb != NULL, return ERR_ARG); 1867195972f6Sopenharmony_ci 1868195972f6Sopenharmony_ci if (p != NULL) { 1869195972f6Sopenharmony_ci tcp_recved(pcb, p->tot_len); 1870195972f6Sopenharmony_ci pbuf_free(p); 1871195972f6Sopenharmony_ci } else if (err == ERR_OK) { 1872195972f6Sopenharmony_ci return tcp_close(pcb); 1873195972f6Sopenharmony_ci } 1874195972f6Sopenharmony_ci return ERR_OK; 1875195972f6Sopenharmony_ci} 1876195972f6Sopenharmony_ci#endif /* LWIP_CALLBACK_API */ 1877195972f6Sopenharmony_ci 1878195972f6Sopenharmony_ci/** 1879195972f6Sopenharmony_ci * Kills the oldest active connection that has a lower priority than 'prio'. 1880195972f6Sopenharmony_ci * 1881195972f6Sopenharmony_ci * @param prio minimum priority 1882195972f6Sopenharmony_ci */ 1883195972f6Sopenharmony_cistatic void 1884195972f6Sopenharmony_citcp_kill_prio(u8_t prio) 1885195972f6Sopenharmony_ci{ 1886195972f6Sopenharmony_ci struct tcp_pcb *pcb, *inactive; 1887195972f6Sopenharmony_ci u32_t inactivity; 1888195972f6Sopenharmony_ci u8_t mprio; 1889195972f6Sopenharmony_ci 1890195972f6Sopenharmony_ci mprio = LWIP_MIN(TCP_PRIO_MAX, prio); 1891195972f6Sopenharmony_ci 1892195972f6Sopenharmony_ci /* We want to kill connections with a lower prio, so bail out if 1893195972f6Sopenharmony_ci * supplied prio is 0 - there can never be a lower prio 1894195972f6Sopenharmony_ci */ 1895195972f6Sopenharmony_ci if (mprio == 0) { 1896195972f6Sopenharmony_ci return; 1897195972f6Sopenharmony_ci } 1898195972f6Sopenharmony_ci 1899195972f6Sopenharmony_ci /* We only want kill connections with a lower prio, so decrement prio by one 1900195972f6Sopenharmony_ci * and start searching for oldest connection with same or lower priority than mprio. 1901195972f6Sopenharmony_ci * We want to find the connections with the lowest possible prio, and among 1902195972f6Sopenharmony_ci * these the one with the longest inactivity time. 1903195972f6Sopenharmony_ci */ 1904195972f6Sopenharmony_ci mprio--; 1905195972f6Sopenharmony_ci 1906195972f6Sopenharmony_ci inactivity = 0; 1907195972f6Sopenharmony_ci inactive = NULL; 1908195972f6Sopenharmony_ci for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { 1909195972f6Sopenharmony_ci /* lower prio is always a kill candidate */ 1910195972f6Sopenharmony_ci if ((pcb->prio < mprio) || 1911195972f6Sopenharmony_ci /* longer inactivity is also a kill candidate */ 1912195972f6Sopenharmony_ci ((pcb->prio == mprio) && ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity))) { 1913195972f6Sopenharmony_ci inactivity = tcp_ticks - pcb->tmr; 1914195972f6Sopenharmony_ci inactive = pcb; 1915195972f6Sopenharmony_ci mprio = pcb->prio; 1916195972f6Sopenharmony_ci } 1917195972f6Sopenharmony_ci } 1918195972f6Sopenharmony_ci if (inactive != NULL) { 1919195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n", 1920195972f6Sopenharmony_ci (void *)inactive, inactivity)); 1921195972f6Sopenharmony_ci tcp_abort(inactive); 1922195972f6Sopenharmony_ci } 1923195972f6Sopenharmony_ci} 1924195972f6Sopenharmony_ci 1925195972f6Sopenharmony_ci/** 1926195972f6Sopenharmony_ci * Kills the oldest connection that is in specific state. 1927195972f6Sopenharmony_ci * Called from tcp_alloc() for LAST_ACK and CLOSING if no more connections are available. 1928195972f6Sopenharmony_ci */ 1929195972f6Sopenharmony_cistatic void 1930195972f6Sopenharmony_citcp_kill_state(enum tcp_state state) 1931195972f6Sopenharmony_ci{ 1932195972f6Sopenharmony_ci struct tcp_pcb *pcb, *inactive; 1933195972f6Sopenharmony_ci u32_t inactivity; 1934195972f6Sopenharmony_ci 1935195972f6Sopenharmony_ci LWIP_ASSERT("invalid state", (state == CLOSING) || (state == LAST_ACK)); 1936195972f6Sopenharmony_ci 1937195972f6Sopenharmony_ci inactivity = 0; 1938195972f6Sopenharmony_ci inactive = NULL; 1939195972f6Sopenharmony_ci /* Go through the list of active pcbs and get the oldest pcb that is in state 1940195972f6Sopenharmony_ci CLOSING/LAST_ACK. */ 1941195972f6Sopenharmony_ci for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { 1942195972f6Sopenharmony_ci if (pcb->state == state) { 1943195972f6Sopenharmony_ci if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { 1944195972f6Sopenharmony_ci inactivity = tcp_ticks - pcb->tmr; 1945195972f6Sopenharmony_ci inactive = pcb; 1946195972f6Sopenharmony_ci } 1947195972f6Sopenharmony_ci } 1948195972f6Sopenharmony_ci } 1949195972f6Sopenharmony_ci if (inactive != NULL) { 1950195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_closing: killing oldest %s PCB %p (%"S32_F")\n", 1951195972f6Sopenharmony_ci tcp_state_str[state], (void *)inactive, inactivity)); 1952195972f6Sopenharmony_ci /* Don't send a RST, since no data is lost. */ 1953195972f6Sopenharmony_ci tcp_abandon(inactive, 0); 1954195972f6Sopenharmony_ci } 1955195972f6Sopenharmony_ci} 1956195972f6Sopenharmony_ci 1957195972f6Sopenharmony_ci/** 1958195972f6Sopenharmony_ci * Kills the oldest connection that is in TIME_WAIT state. 1959195972f6Sopenharmony_ci * Called from tcp_alloc() if no more connections are available. 1960195972f6Sopenharmony_ci */ 1961195972f6Sopenharmony_cistatic void 1962195972f6Sopenharmony_citcp_kill_timewait(void) 1963195972f6Sopenharmony_ci{ 1964195972f6Sopenharmony_ci struct tcp_pcb *pcb, *inactive; 1965195972f6Sopenharmony_ci u32_t inactivity; 1966195972f6Sopenharmony_ci 1967195972f6Sopenharmony_ci inactivity = 0; 1968195972f6Sopenharmony_ci inactive = NULL; 1969195972f6Sopenharmony_ci /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */ 1970195972f6Sopenharmony_ci for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { 1971195972f6Sopenharmony_ci if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { 1972195972f6Sopenharmony_ci inactivity = tcp_ticks - pcb->tmr; 1973195972f6Sopenharmony_ci inactive = pcb; 1974195972f6Sopenharmony_ci } 1975195972f6Sopenharmony_ci } 1976195972f6Sopenharmony_ci if (inactive != NULL) { 1977195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n", 1978195972f6Sopenharmony_ci (void *)inactive, inactivity)); 1979195972f6Sopenharmony_ci tcp_abort(inactive); 1980195972f6Sopenharmony_ci } 1981195972f6Sopenharmony_ci} 1982195972f6Sopenharmony_ci 1983195972f6Sopenharmony_ci/* Called when allocating a pcb fails. 1984195972f6Sopenharmony_ci * In this case, we want to handle all pcbs that want to close first: if we can 1985195972f6Sopenharmony_ci * now send the FIN (which failed before), the pcb might be in a state that is 1986195972f6Sopenharmony_ci * OK for us to now free it. 1987195972f6Sopenharmony_ci */ 1988195972f6Sopenharmony_cistatic void 1989195972f6Sopenharmony_citcp_handle_closepend(void) 1990195972f6Sopenharmony_ci{ 1991195972f6Sopenharmony_ci struct tcp_pcb *pcb = tcp_active_pcbs; 1992195972f6Sopenharmony_ci 1993195972f6Sopenharmony_ci while (pcb != NULL) { 1994195972f6Sopenharmony_ci struct tcp_pcb *next = pcb->next; 1995195972f6Sopenharmony_ci /* send pending FIN */ 1996195972f6Sopenharmony_ci if (pcb->flags & TF_CLOSEPEND) { 1997195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_handle_closepend: pending FIN\n")); 1998195972f6Sopenharmony_ci tcp_clear_flags(pcb, TF_CLOSEPEND); 1999195972f6Sopenharmony_ci tcp_close_shutdown_fin(pcb); 2000195972f6Sopenharmony_ci } 2001195972f6Sopenharmony_ci pcb = next; 2002195972f6Sopenharmony_ci } 2003195972f6Sopenharmony_ci} 2004195972f6Sopenharmony_ci 2005195972f6Sopenharmony_ci/** 2006195972f6Sopenharmony_ci * Allocate a new tcp_pcb structure. 2007195972f6Sopenharmony_ci * 2008195972f6Sopenharmony_ci * @param prio priority for the new pcb 2009195972f6Sopenharmony_ci * @return a new tcp_pcb that initially is in state CLOSED 2010195972f6Sopenharmony_ci */ 2011195972f6Sopenharmony_cistruct tcp_pcb * 2012195972f6Sopenharmony_citcp_alloc(u8_t prio) 2013195972f6Sopenharmony_ci{ 2014195972f6Sopenharmony_ci struct tcp_pcb *pcb; 2015195972f6Sopenharmony_ci 2016195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 2017195972f6Sopenharmony_ci 2018195972f6Sopenharmony_ci pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); 2019195972f6Sopenharmony_ci if (pcb == NULL) { 2020195972f6Sopenharmony_ci /* Try to send FIN for all pcbs stuck in TF_CLOSEPEND first */ 2021195972f6Sopenharmony_ci tcp_handle_closepend(); 2022195972f6Sopenharmony_ci 2023195972f6Sopenharmony_ci /* Try killing oldest connection in TIME-WAIT. */ 2024195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n")); 2025195972f6Sopenharmony_ci tcp_kill_timewait(); 2026195972f6Sopenharmony_ci /* Try to allocate a tcp_pcb again. */ 2027195972f6Sopenharmony_ci pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); 2028195972f6Sopenharmony_ci if (pcb == NULL) { 2029195972f6Sopenharmony_ci /* Try killing oldest connection in LAST-ACK (these wouldn't go to TIME-WAIT). */ 2030195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest LAST-ACK connection\n")); 2031195972f6Sopenharmony_ci tcp_kill_state(LAST_ACK); 2032195972f6Sopenharmony_ci /* Try to allocate a tcp_pcb again. */ 2033195972f6Sopenharmony_ci pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); 2034195972f6Sopenharmony_ci if (pcb == NULL) { 2035195972f6Sopenharmony_ci /* Try killing oldest connection in CLOSING. */ 2036195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest CLOSING connection\n")); 2037195972f6Sopenharmony_ci tcp_kill_state(CLOSING); 2038195972f6Sopenharmony_ci /* Try to allocate a tcp_pcb again. */ 2039195972f6Sopenharmony_ci pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); 2040195972f6Sopenharmony_ci if (pcb == NULL) { 2041195972f6Sopenharmony_ci /* Try killing oldest active connection with lower priority than the new one. */ 2042195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing oldest connection with prio lower than %d\n", prio)); 2043195972f6Sopenharmony_ci tcp_kill_prio(prio); 2044195972f6Sopenharmony_ci /* Try to allocate a tcp_pcb again. */ 2045195972f6Sopenharmony_ci pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); 2046195972f6Sopenharmony_ci if (pcb != NULL) { 2047195972f6Sopenharmony_ci /* adjust err stats: memp_malloc failed multiple times before */ 2048195972f6Sopenharmony_ci MEMP_STATS_DEC(err, MEMP_TCP_PCB); 2049195972f6Sopenharmony_ci } 2050195972f6Sopenharmony_ci } 2051195972f6Sopenharmony_ci if (pcb != NULL) { 2052195972f6Sopenharmony_ci /* adjust err stats: memp_malloc failed multiple times before */ 2053195972f6Sopenharmony_ci MEMP_STATS_DEC(err, MEMP_TCP_PCB); 2054195972f6Sopenharmony_ci } 2055195972f6Sopenharmony_ci } 2056195972f6Sopenharmony_ci if (pcb != NULL) { 2057195972f6Sopenharmony_ci /* adjust err stats: memp_malloc failed multiple times before */ 2058195972f6Sopenharmony_ci MEMP_STATS_DEC(err, MEMP_TCP_PCB); 2059195972f6Sopenharmony_ci } 2060195972f6Sopenharmony_ci } 2061195972f6Sopenharmony_ci if (pcb != NULL) { 2062195972f6Sopenharmony_ci /* adjust err stats: memp_malloc failed above */ 2063195972f6Sopenharmony_ci MEMP_STATS_DEC(err, MEMP_TCP_PCB); 2064195972f6Sopenharmony_ci } 2065195972f6Sopenharmony_ci } 2066195972f6Sopenharmony_ci if (pcb != NULL) { 2067195972f6Sopenharmony_ci /* zero out the whole pcb, so there is no need to initialize members to zero */ 2068195972f6Sopenharmony_ci memset(pcb, 0, sizeof(struct tcp_pcb)); 2069195972f6Sopenharmony_ci pcb->prio = prio; 2070195972f6Sopenharmony_ci pcb->snd_buf = TCP_SND_BUF; 2071195972f6Sopenharmony_ci /* Start with a window that does not need scaling. When window scaling is 2072195972f6Sopenharmony_ci enabled and used, the window is enlarged when both sides agree on scaling. */ 2073195972f6Sopenharmony_ci pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND); 2074195972f6Sopenharmony_ci pcb->ttl = TCP_TTL; 2075195972f6Sopenharmony_ci /* As initial send MSS, we use TCP_MSS but limit it to 536. 2076195972f6Sopenharmony_ci The send MSS is updated when an MSS option is received. */ 2077195972f6Sopenharmony_ci pcb->mss = INITIAL_MSS; 2078195972f6Sopenharmony_ci pcb->rto = 3000 / TCP_SLOW_INTERVAL; 2079195972f6Sopenharmony_ci pcb->sv = 3000 / TCP_SLOW_INTERVAL; 2080195972f6Sopenharmony_ci pcb->rtime = -1; 2081195972f6Sopenharmony_ci pcb->cwnd = 1; 2082195972f6Sopenharmony_ci pcb->tmr = tcp_ticks; 2083195972f6Sopenharmony_ci pcb->last_timer = tcp_timer_ctr; 2084195972f6Sopenharmony_ci 2085195972f6Sopenharmony_ci /* RFC 5681 recommends setting ssthresh abritrarily high and gives an example 2086195972f6Sopenharmony_ci of using the largest advertised receive window. We've seen complications with 2087195972f6Sopenharmony_ci receiving TCPs that use window scaling and/or window auto-tuning where the 2088195972f6Sopenharmony_ci initial advertised window is very small and then grows rapidly once the 2089195972f6Sopenharmony_ci connection is established. To avoid these complications, we set ssthresh to the 2090195972f6Sopenharmony_ci largest effective cwnd (amount of in-flight data) that the sender can have. */ 2091195972f6Sopenharmony_ci pcb->ssthresh = TCP_SND_BUF; 2092195972f6Sopenharmony_ci 2093195972f6Sopenharmony_ci#if LWIP_CALLBACK_API 2094195972f6Sopenharmony_ci pcb->recv = tcp_recv_null; 2095195972f6Sopenharmony_ci#endif /* LWIP_CALLBACK_API */ 2096195972f6Sopenharmony_ci 2097195972f6Sopenharmony_ci /* Init KEEPALIVE timer */ 2098195972f6Sopenharmony_ci pcb->keep_idle = TCP_KEEPIDLE_DEFAULT; 2099195972f6Sopenharmony_ci 2100195972f6Sopenharmony_ci#if LWIP_TCP_KEEPALIVE 2101195972f6Sopenharmony_ci pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT; 2102195972f6Sopenharmony_ci pcb->keep_cnt = TCP_KEEPCNT_DEFAULT; 2103195972f6Sopenharmony_ci#endif /* LWIP_TCP_KEEPALIVE */ 2104195972f6Sopenharmony_ci } 2105195972f6Sopenharmony_ci return pcb; 2106195972f6Sopenharmony_ci} 2107195972f6Sopenharmony_ci 2108195972f6Sopenharmony_ci/** 2109195972f6Sopenharmony_ci * @ingroup tcp_raw 2110195972f6Sopenharmony_ci * Creates a new TCP protocol control block but doesn't place it on 2111195972f6Sopenharmony_ci * any of the TCP PCB lists. 2112195972f6Sopenharmony_ci * The pcb is not put on any list until binding using tcp_bind(). 2113195972f6Sopenharmony_ci * If memory is not available for creating the new pcb, NULL is returned. 2114195972f6Sopenharmony_ci * @see MEMP_NUM_TCP_PCB_LISTEN and MEMP_NUM_TCP_PCB 2115195972f6Sopenharmony_ci * 2116195972f6Sopenharmony_ci * @internal: Maybe there should be a idle TCP PCB list where these 2117195972f6Sopenharmony_ci * PCBs are put on. Port reservation using tcp_bind() is implemented but 2118195972f6Sopenharmony_ci * allocated pcbs that are not bound can't be killed automatically if wanting 2119195972f6Sopenharmony_ci * to allocate a pcb with higher prio (@see tcp_kill_prio()) 2120195972f6Sopenharmony_ci * 2121195972f6Sopenharmony_ci * @return a new tcp_pcb that initially is in state CLOSED 2122195972f6Sopenharmony_ci */ 2123195972f6Sopenharmony_cistruct tcp_pcb * 2124195972f6Sopenharmony_citcp_new(void) 2125195972f6Sopenharmony_ci{ 2126195972f6Sopenharmony_ci return tcp_alloc(TCP_PRIO_NORMAL); 2127195972f6Sopenharmony_ci} 2128195972f6Sopenharmony_ci 2129195972f6Sopenharmony_ci/** 2130195972f6Sopenharmony_ci * @ingroup tcp_raw 2131195972f6Sopenharmony_ci * Creates a new TCP protocol control block but doesn't 2132195972f6Sopenharmony_ci * place it on any of the TCP PCB lists. 2133195972f6Sopenharmony_ci * The pcb is not put on any list until binding using tcp_bind(). 2134195972f6Sopenharmony_ci * @see MEMP_NUM_TCP_PCB_LISTEN and MEMP_NUM_TCP_PCB 2135195972f6Sopenharmony_ci * 2136195972f6Sopenharmony_ci * @param type IP address type, see @ref lwip_ip_addr_type definitions. 2137195972f6Sopenharmony_ci * If you want to listen to IPv4 and IPv6 (dual-stack) connections, 2138195972f6Sopenharmony_ci * supply @ref IPADDR_TYPE_ANY as argument and bind to @ref IP_ANY_TYPE. 2139195972f6Sopenharmony_ci * @return a new tcp_pcb that initially is in state CLOSED 2140195972f6Sopenharmony_ci */ 2141195972f6Sopenharmony_cistruct tcp_pcb * 2142195972f6Sopenharmony_citcp_new_ip_type(u8_t type) 2143195972f6Sopenharmony_ci{ 2144195972f6Sopenharmony_ci struct tcp_pcb *pcb; 2145195972f6Sopenharmony_ci pcb = tcp_alloc(TCP_PRIO_NORMAL); 2146195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 2147195972f6Sopenharmony_ci if (pcb != NULL) { 2148195972f6Sopenharmony_ci IP_SET_TYPE_VAL(pcb->local_ip, type); 2149195972f6Sopenharmony_ci IP_SET_TYPE_VAL(pcb->remote_ip, type); 2150195972f6Sopenharmony_ci } 2151195972f6Sopenharmony_ci#else 2152195972f6Sopenharmony_ci LWIP_UNUSED_ARG(type); 2153195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */ 2154195972f6Sopenharmony_ci return pcb; 2155195972f6Sopenharmony_ci} 2156195972f6Sopenharmony_ci 2157195972f6Sopenharmony_ci/** 2158195972f6Sopenharmony_ci * @ingroup tcp_raw 2159195972f6Sopenharmony_ci * Specifies the program specific state that should be passed to all 2160195972f6Sopenharmony_ci * other callback functions. The "pcb" argument is the current TCP 2161195972f6Sopenharmony_ci * connection control block, and the "arg" argument is the argument 2162195972f6Sopenharmony_ci * that will be passed to the callbacks. 2163195972f6Sopenharmony_ci * 2164195972f6Sopenharmony_ci * @param pcb tcp_pcb to set the callback argument 2165195972f6Sopenharmony_ci * @param arg void pointer argument to pass to callback functions 2166195972f6Sopenharmony_ci */ 2167195972f6Sopenharmony_civoid 2168195972f6Sopenharmony_citcp_arg(struct tcp_pcb *pcb, void *arg) 2169195972f6Sopenharmony_ci{ 2170195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 2171195972f6Sopenharmony_ci /* This function is allowed to be called for both listen pcbs and 2172195972f6Sopenharmony_ci connection pcbs. */ 2173195972f6Sopenharmony_ci if (pcb != NULL) { 2174195972f6Sopenharmony_ci pcb->callback_arg = arg; 2175195972f6Sopenharmony_ci } 2176195972f6Sopenharmony_ci} 2177195972f6Sopenharmony_ci#if LWIP_CALLBACK_API 2178195972f6Sopenharmony_ci 2179195972f6Sopenharmony_ci/** 2180195972f6Sopenharmony_ci * @ingroup tcp_raw 2181195972f6Sopenharmony_ci * Sets the callback function that will be called when new data 2182195972f6Sopenharmony_ci * arrives. The callback function will be passed a NULL pbuf to 2183195972f6Sopenharmony_ci * indicate that the remote host has closed the connection. If the 2184195972f6Sopenharmony_ci * callback function returns ERR_OK or ERR_ABRT it must have 2185195972f6Sopenharmony_ci * freed the pbuf, otherwise it must not have freed it. 2186195972f6Sopenharmony_ci * 2187195972f6Sopenharmony_ci * @param pcb tcp_pcb to set the recv callback 2188195972f6Sopenharmony_ci * @param recv callback function to call for this pcb when data is received 2189195972f6Sopenharmony_ci */ 2190195972f6Sopenharmony_civoid 2191195972f6Sopenharmony_citcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv) 2192195972f6Sopenharmony_ci{ 2193195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 2194195972f6Sopenharmony_ci if (pcb != NULL) { 2195195972f6Sopenharmony_ci LWIP_ASSERT("invalid socket state for recv callback", pcb->state != LISTEN); 2196195972f6Sopenharmony_ci pcb->recv = recv; 2197195972f6Sopenharmony_ci } 2198195972f6Sopenharmony_ci} 2199195972f6Sopenharmony_ci 2200195972f6Sopenharmony_ci/** 2201195972f6Sopenharmony_ci * @ingroup tcp_raw 2202195972f6Sopenharmony_ci * Specifies the callback function that should be called when data has 2203195972f6Sopenharmony_ci * successfully been received (i.e., acknowledged) by the remote 2204195972f6Sopenharmony_ci * host. The len argument passed to the callback function gives the 2205195972f6Sopenharmony_ci * amount bytes that was acknowledged by the last acknowledgment. 2206195972f6Sopenharmony_ci * 2207195972f6Sopenharmony_ci * @param pcb tcp_pcb to set the sent callback 2208195972f6Sopenharmony_ci * @param sent callback function to call for this pcb when data is successfully sent 2209195972f6Sopenharmony_ci */ 2210195972f6Sopenharmony_civoid 2211195972f6Sopenharmony_citcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent) 2212195972f6Sopenharmony_ci{ 2213195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 2214195972f6Sopenharmony_ci if (pcb != NULL) { 2215195972f6Sopenharmony_ci LWIP_ASSERT("invalid socket state for sent callback", pcb->state != LISTEN); 2216195972f6Sopenharmony_ci pcb->sent = sent; 2217195972f6Sopenharmony_ci } 2218195972f6Sopenharmony_ci} 2219195972f6Sopenharmony_ci 2220195972f6Sopenharmony_ci/** 2221195972f6Sopenharmony_ci * @ingroup tcp_raw 2222195972f6Sopenharmony_ci * Used to specify the function that should be called when a fatal error 2223195972f6Sopenharmony_ci * has occurred on the connection. 2224195972f6Sopenharmony_ci * 2225195972f6Sopenharmony_ci * If a connection is aborted because of an error, the application is 2226195972f6Sopenharmony_ci * alerted of this event by the err callback. Errors that might abort a 2227195972f6Sopenharmony_ci * connection are when there is a shortage of memory. The callback 2228195972f6Sopenharmony_ci * function to be called is set using the tcp_err() function. 2229195972f6Sopenharmony_ci * 2230195972f6Sopenharmony_ci * @note The corresponding pcb is already freed when this callback is called! 2231195972f6Sopenharmony_ci * 2232195972f6Sopenharmony_ci * @param pcb tcp_pcb to set the err callback 2233195972f6Sopenharmony_ci * @param err callback function to call for this pcb when a fatal error 2234195972f6Sopenharmony_ci * has occurred on the connection 2235195972f6Sopenharmony_ci */ 2236195972f6Sopenharmony_civoid 2237195972f6Sopenharmony_citcp_err(struct tcp_pcb *pcb, tcp_err_fn err) 2238195972f6Sopenharmony_ci{ 2239195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 2240195972f6Sopenharmony_ci if (pcb != NULL) { 2241195972f6Sopenharmony_ci LWIP_ASSERT("invalid socket state for err callback", pcb->state != LISTEN); 2242195972f6Sopenharmony_ci pcb->errf = err; 2243195972f6Sopenharmony_ci } 2244195972f6Sopenharmony_ci} 2245195972f6Sopenharmony_ci 2246195972f6Sopenharmony_ci/** 2247195972f6Sopenharmony_ci * @ingroup tcp_raw 2248195972f6Sopenharmony_ci * Used for specifying the function that should be called when a 2249195972f6Sopenharmony_ci * LISTENing connection has been connected to another host. 2250195972f6Sopenharmony_ci * @see MEMP_NUM_TCP_PCB_LISTEN and MEMP_NUM_TCP_PCB 2251195972f6Sopenharmony_ci * 2252195972f6Sopenharmony_ci * @param pcb tcp_pcb to set the accept callback 2253195972f6Sopenharmony_ci * @param accept callback function to call for this pcb when LISTENing 2254195972f6Sopenharmony_ci * connection has been connected to another host 2255195972f6Sopenharmony_ci */ 2256195972f6Sopenharmony_civoid 2257195972f6Sopenharmony_citcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept) 2258195972f6Sopenharmony_ci{ 2259195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 2260195972f6Sopenharmony_ci if ((pcb != NULL) && (pcb->state == LISTEN)) { 2261195972f6Sopenharmony_ci struct tcp_pcb_listen *lpcb = (struct tcp_pcb_listen *)pcb; 2262195972f6Sopenharmony_ci lpcb->accept = accept; 2263195972f6Sopenharmony_ci } 2264195972f6Sopenharmony_ci} 2265195972f6Sopenharmony_ci#endif /* LWIP_CALLBACK_API */ 2266195972f6Sopenharmony_ci 2267195972f6Sopenharmony_ci 2268195972f6Sopenharmony_ci/** 2269195972f6Sopenharmony_ci * @ingroup tcp_raw 2270195972f6Sopenharmony_ci * Specifies the polling interval and the callback function that should 2271195972f6Sopenharmony_ci * be called to poll the application. The interval is specified in 2272195972f6Sopenharmony_ci * number of TCP coarse grained timer shots, which typically occurs 2273195972f6Sopenharmony_ci * twice a second. An interval of 10 means that the application would 2274195972f6Sopenharmony_ci * be polled every 5 seconds. 2275195972f6Sopenharmony_ci * 2276195972f6Sopenharmony_ci * When a connection is idle (i.e., no data is either transmitted or 2277195972f6Sopenharmony_ci * received), lwIP will repeatedly poll the application by calling a 2278195972f6Sopenharmony_ci * specified callback function. This can be used either as a watchdog 2279195972f6Sopenharmony_ci * timer for killing connections that have stayed idle for too long, or 2280195972f6Sopenharmony_ci * as a method of waiting for memory to become available. For instance, 2281195972f6Sopenharmony_ci * if a call to tcp_write() has failed because memory wasn't available, 2282195972f6Sopenharmony_ci * the application may use the polling functionality to call tcp_write() 2283195972f6Sopenharmony_ci * again when the connection has been idle for a while. 2284195972f6Sopenharmony_ci */ 2285195972f6Sopenharmony_civoid 2286195972f6Sopenharmony_citcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval) 2287195972f6Sopenharmony_ci{ 2288195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 2289195972f6Sopenharmony_ci 2290195972f6Sopenharmony_ci LWIP_ERROR("tcp_poll: invalid pcb", pcb != NULL, return); 2291195972f6Sopenharmony_ci LWIP_ASSERT("invalid socket state for poll", pcb->state != LISTEN); 2292195972f6Sopenharmony_ci 2293195972f6Sopenharmony_ci#if LWIP_CALLBACK_API 2294195972f6Sopenharmony_ci pcb->poll = poll; 2295195972f6Sopenharmony_ci#else /* LWIP_CALLBACK_API */ 2296195972f6Sopenharmony_ci LWIP_UNUSED_ARG(poll); 2297195972f6Sopenharmony_ci#endif /* LWIP_CALLBACK_API */ 2298195972f6Sopenharmony_ci pcb->pollinterval = interval; 2299195972f6Sopenharmony_ci} 2300195972f6Sopenharmony_ci 2301195972f6Sopenharmony_ci/** 2302195972f6Sopenharmony_ci * Purges a TCP PCB. Removes any buffered data and frees the buffer memory 2303195972f6Sopenharmony_ci * (pcb->ooseq, pcb->unsent and pcb->unacked are freed). 2304195972f6Sopenharmony_ci * 2305195972f6Sopenharmony_ci * @param pcb tcp_pcb to purge. The pcb itself is not deallocated! 2306195972f6Sopenharmony_ci */ 2307195972f6Sopenharmony_civoid 2308195972f6Sopenharmony_citcp_pcb_purge(struct tcp_pcb *pcb) 2309195972f6Sopenharmony_ci{ 2310195972f6Sopenharmony_ci LWIP_ERROR("tcp_pcb_purge: invalid pcb", pcb != NULL, return); 2311195972f6Sopenharmony_ci 2312195972f6Sopenharmony_ci if (pcb->state != CLOSED && 2313195972f6Sopenharmony_ci pcb->state != TIME_WAIT && 2314195972f6Sopenharmony_ci pcb->state != LISTEN) { 2315195972f6Sopenharmony_ci 2316195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n")); 2317195972f6Sopenharmony_ci 2318195972f6Sopenharmony_ci tcp_backlog_accepted(pcb); 2319195972f6Sopenharmony_ci 2320195972f6Sopenharmony_ci if (pcb->refused_data != NULL) { 2321195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n")); 2322195972f6Sopenharmony_ci pbuf_free(pcb->refused_data); 2323195972f6Sopenharmony_ci pcb->refused_data = NULL; 2324195972f6Sopenharmony_ci } 2325195972f6Sopenharmony_ci if (pcb->unsent != NULL) { 2326195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n")); 2327195972f6Sopenharmony_ci } 2328195972f6Sopenharmony_ci if (pcb->unacked != NULL) { 2329195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n")); 2330195972f6Sopenharmony_ci } 2331195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ 2332195972f6Sopenharmony_ci if (pcb->ooseq != NULL) { 2333195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); 2334195972f6Sopenharmony_ci tcp_free_ooseq(pcb); 2335195972f6Sopenharmony_ci } 2336195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ */ 2337195972f6Sopenharmony_ci 2338195972f6Sopenharmony_ci /* Stop the retransmission timer as it will expect data on unacked 2339195972f6Sopenharmony_ci queue if it fires */ 2340195972f6Sopenharmony_ci pcb->rtime = -1; 2341195972f6Sopenharmony_ci 2342195972f6Sopenharmony_ci tcp_segs_free(pcb->unsent); 2343195972f6Sopenharmony_ci tcp_segs_free(pcb->unacked); 2344195972f6Sopenharmony_ci pcb->unacked = pcb->unsent = NULL; 2345195972f6Sopenharmony_ci#if TCP_OVERSIZE 2346195972f6Sopenharmony_ci pcb->unsent_oversize = 0; 2347195972f6Sopenharmony_ci#endif /* TCP_OVERSIZE */ 2348195972f6Sopenharmony_ci } 2349195972f6Sopenharmony_ci} 2350195972f6Sopenharmony_ci 2351195972f6Sopenharmony_ci/** 2352195972f6Sopenharmony_ci * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first. 2353195972f6Sopenharmony_ci * 2354195972f6Sopenharmony_ci * @param pcblist PCB list to purge. 2355195972f6Sopenharmony_ci * @param pcb tcp_pcb to purge. The pcb itself is NOT deallocated! 2356195972f6Sopenharmony_ci */ 2357195972f6Sopenharmony_civoid 2358195972f6Sopenharmony_citcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) 2359195972f6Sopenharmony_ci{ 2360195972f6Sopenharmony_ci LWIP_ASSERT("tcp_pcb_remove: invalid pcb", pcb != NULL); 2361195972f6Sopenharmony_ci LWIP_ASSERT("tcp_pcb_remove: invalid pcblist", pcblist != NULL); 2362195972f6Sopenharmony_ci 2363195972f6Sopenharmony_ci TCP_RMV(pcblist, pcb); 2364195972f6Sopenharmony_ci 2365195972f6Sopenharmony_ci tcp_pcb_purge(pcb); 2366195972f6Sopenharmony_ci 2367195972f6Sopenharmony_ci /* if there is an outstanding delayed ACKs, send it */ 2368195972f6Sopenharmony_ci if ((pcb->state != TIME_WAIT) && 2369195972f6Sopenharmony_ci (pcb->state != LISTEN) && 2370195972f6Sopenharmony_ci (pcb->flags & TF_ACK_DELAY)) { 2371195972f6Sopenharmony_ci tcp_ack_now(pcb); 2372195972f6Sopenharmony_ci tcp_output(pcb); 2373195972f6Sopenharmony_ci } 2374195972f6Sopenharmony_ci 2375195972f6Sopenharmony_ci if (pcb->state != LISTEN) { 2376195972f6Sopenharmony_ci LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL); 2377195972f6Sopenharmony_ci LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL); 2378195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ 2379195972f6Sopenharmony_ci LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL); 2380195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ */ 2381195972f6Sopenharmony_ci } 2382195972f6Sopenharmony_ci 2383195972f6Sopenharmony_ci pcb->state = CLOSED; 2384195972f6Sopenharmony_ci /* reset the local port to prevent the pcb from being 'bound' */ 2385195972f6Sopenharmony_ci pcb->local_port = 0; 2386195972f6Sopenharmony_ci 2387195972f6Sopenharmony_ci LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane()); 2388195972f6Sopenharmony_ci} 2389195972f6Sopenharmony_ci 2390195972f6Sopenharmony_ci/** 2391195972f6Sopenharmony_ci * Calculates a new initial sequence number for new connections. 2392195972f6Sopenharmony_ci * 2393195972f6Sopenharmony_ci * @return u32_t pseudo random sequence number 2394195972f6Sopenharmony_ci */ 2395195972f6Sopenharmony_ciu32_t 2396195972f6Sopenharmony_citcp_next_iss(struct tcp_pcb *pcb) 2397195972f6Sopenharmony_ci{ 2398195972f6Sopenharmony_ci#ifdef LWIP_HOOK_TCP_ISN 2399195972f6Sopenharmony_ci LWIP_ASSERT("tcp_next_iss: invalid pcb", pcb != NULL); 2400195972f6Sopenharmony_ci return LWIP_HOOK_TCP_ISN(&pcb->local_ip, pcb->local_port, &pcb->remote_ip, pcb->remote_port); 2401195972f6Sopenharmony_ci#else /* LWIP_HOOK_TCP_ISN */ 2402195972f6Sopenharmony_ci static u32_t iss = 6510; 2403195972f6Sopenharmony_ci 2404195972f6Sopenharmony_ci LWIP_ASSERT("tcp_next_iss: invalid pcb", pcb != NULL); 2405195972f6Sopenharmony_ci LWIP_UNUSED_ARG(pcb); 2406195972f6Sopenharmony_ci 2407195972f6Sopenharmony_ci iss += tcp_ticks; /* XXX */ 2408195972f6Sopenharmony_ci return iss; 2409195972f6Sopenharmony_ci#endif /* LWIP_HOOK_TCP_ISN */ 2410195972f6Sopenharmony_ci} 2411195972f6Sopenharmony_ci 2412195972f6Sopenharmony_ci#if TCP_CALCULATE_EFF_SEND_MSS 2413195972f6Sopenharmony_ci/** 2414195972f6Sopenharmony_ci * Calculates the effective send mss that can be used for a specific IP address 2415195972f6Sopenharmony_ci * by calculating the minimum of TCP_MSS and the mtu (if set) of the target 2416195972f6Sopenharmony_ci * netif (if not NULL). 2417195972f6Sopenharmony_ci */ 2418195972f6Sopenharmony_ciu16_t 2419195972f6Sopenharmony_citcp_eff_send_mss_netif(u16_t sendmss, struct netif *outif, const ip_addr_t *dest) 2420195972f6Sopenharmony_ci{ 2421195972f6Sopenharmony_ci u16_t mss_s; 2422195972f6Sopenharmony_ci u16_t mtu; 2423195972f6Sopenharmony_ci 2424195972f6Sopenharmony_ci LWIP_UNUSED_ARG(dest); /* in case IPv6 is disabled */ 2425195972f6Sopenharmony_ci 2426195972f6Sopenharmony_ci LWIP_ASSERT("tcp_eff_send_mss_netif: invalid dst_ip", dest != NULL); 2427195972f6Sopenharmony_ci 2428195972f6Sopenharmony_ci#if LWIP_IPV6 2429195972f6Sopenharmony_ci#if LWIP_IPV4 2430195972f6Sopenharmony_ci if (IP_IS_V6(dest)) 2431195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 2432195972f6Sopenharmony_ci { 2433195972f6Sopenharmony_ci /* First look in destination cache, to see if there is a Path MTU. */ 2434195972f6Sopenharmony_ci mtu = nd6_get_destination_mtu(ip_2_ip6(dest), outif); 2435195972f6Sopenharmony_ci } 2436195972f6Sopenharmony_ci#if LWIP_IPV4 2437195972f6Sopenharmony_ci else 2438195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 2439195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */ 2440195972f6Sopenharmony_ci#if LWIP_IPV4 2441195972f6Sopenharmony_ci { 2442195972f6Sopenharmony_ci if (outif == NULL) { 2443195972f6Sopenharmony_ci return sendmss; 2444195972f6Sopenharmony_ci } 2445195972f6Sopenharmony_ci mtu = outif->mtu; 2446195972f6Sopenharmony_ci } 2447195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 2448195972f6Sopenharmony_ci 2449195972f6Sopenharmony_ci if (mtu != 0) { 2450195972f6Sopenharmony_ci u16_t offset; 2451195972f6Sopenharmony_ci#if LWIP_IPV6 2452195972f6Sopenharmony_ci#if LWIP_IPV4 2453195972f6Sopenharmony_ci if (IP_IS_V6(dest)) 2454195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 2455195972f6Sopenharmony_ci { 2456195972f6Sopenharmony_ci offset = IP6_HLEN + TCP_HLEN; 2457195972f6Sopenharmony_ci } 2458195972f6Sopenharmony_ci#if LWIP_IPV4 2459195972f6Sopenharmony_ci else 2460195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 2461195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */ 2462195972f6Sopenharmony_ci#if LWIP_IPV4 2463195972f6Sopenharmony_ci { 2464195972f6Sopenharmony_ci offset = IP_HLEN + TCP_HLEN; 2465195972f6Sopenharmony_ci } 2466195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 2467195972f6Sopenharmony_ci mss_s = (mtu > offset) ? (u16_t)(mtu - offset) : 0; 2468195972f6Sopenharmony_ci /* RFC 1122, chap 4.2.2.6: 2469195972f6Sopenharmony_ci * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize 2470195972f6Sopenharmony_ci * We correct for TCP options in tcp_write(), and don't support IP options. 2471195972f6Sopenharmony_ci */ 2472195972f6Sopenharmony_ci sendmss = LWIP_MIN(sendmss, mss_s); 2473195972f6Sopenharmony_ci } 2474195972f6Sopenharmony_ci return sendmss; 2475195972f6Sopenharmony_ci} 2476195972f6Sopenharmony_ci#endif /* TCP_CALCULATE_EFF_SEND_MSS */ 2477195972f6Sopenharmony_ci 2478195972f6Sopenharmony_ci/** Helper function for tcp_netif_ip_addr_changed() that iterates a pcb list */ 2479195972f6Sopenharmony_cistatic void 2480195972f6Sopenharmony_citcp_netif_ip_addr_changed_pcblist(const ip_addr_t *old_addr, struct tcp_pcb *pcb_list) 2481195972f6Sopenharmony_ci{ 2482195972f6Sopenharmony_ci struct tcp_pcb *pcb; 2483195972f6Sopenharmony_ci pcb = pcb_list; 2484195972f6Sopenharmony_ci 2485195972f6Sopenharmony_ci LWIP_ASSERT("tcp_netif_ip_addr_changed_pcblist: invalid old_addr", old_addr != NULL); 2486195972f6Sopenharmony_ci 2487195972f6Sopenharmony_ci while (pcb != NULL) { 2488195972f6Sopenharmony_ci /* PCB bound to current local interface address? */ 2489195972f6Sopenharmony_ci if (ip_addr_cmp(&pcb->local_ip, old_addr) 2490195972f6Sopenharmony_ci#if LWIP_AUTOIP 2491195972f6Sopenharmony_ci /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ 2492195972f6Sopenharmony_ci && (!IP_IS_V4_VAL(pcb->local_ip) || !ip4_addr_islinklocal(ip_2_ip4(&pcb->local_ip))) 2493195972f6Sopenharmony_ci#endif /* LWIP_AUTOIP */ 2494195972f6Sopenharmony_ci ) { 2495195972f6Sopenharmony_ci /* this connection must be aborted */ 2496195972f6Sopenharmony_ci struct tcp_pcb *next = pcb->next; 2497195972f6Sopenharmony_ci LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb)); 2498195972f6Sopenharmony_ci tcp_abort(pcb); 2499195972f6Sopenharmony_ci pcb = next; 2500195972f6Sopenharmony_ci } else { 2501195972f6Sopenharmony_ci pcb = pcb->next; 2502195972f6Sopenharmony_ci } 2503195972f6Sopenharmony_ci } 2504195972f6Sopenharmony_ci} 2505195972f6Sopenharmony_ci 2506195972f6Sopenharmony_ci/** This function is called from netif.c when address is changed or netif is removed 2507195972f6Sopenharmony_ci * 2508195972f6Sopenharmony_ci * @param old_addr IP address of the netif before change 2509195972f6Sopenharmony_ci * @param new_addr IP address of the netif after change or NULL if netif has been removed 2510195972f6Sopenharmony_ci */ 2511195972f6Sopenharmony_civoid 2512195972f6Sopenharmony_citcp_netif_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_addr) 2513195972f6Sopenharmony_ci{ 2514195972f6Sopenharmony_ci struct tcp_pcb_listen *lpcb; 2515195972f6Sopenharmony_ci 2516195972f6Sopenharmony_ci if (!ip_addr_isany(old_addr)) { 2517195972f6Sopenharmony_ci tcp_netif_ip_addr_changed_pcblist(old_addr, tcp_active_pcbs); 2518195972f6Sopenharmony_ci tcp_netif_ip_addr_changed_pcblist(old_addr, tcp_bound_pcbs); 2519195972f6Sopenharmony_ci 2520195972f6Sopenharmony_ci if (!ip_addr_isany(new_addr)) { 2521195972f6Sopenharmony_ci /* PCB bound to current local interface address? */ 2522195972f6Sopenharmony_ci for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { 2523195972f6Sopenharmony_ci /* PCB bound to current local interface address? */ 2524195972f6Sopenharmony_ci if (ip_addr_cmp(&lpcb->local_ip, old_addr)) { 2525195972f6Sopenharmony_ci /* The PCB is listening to the old ipaddr and 2526195972f6Sopenharmony_ci * is set to listen to the new one instead */ 2527195972f6Sopenharmony_ci ip_addr_copy(lpcb->local_ip, *new_addr); 2528195972f6Sopenharmony_ci } 2529195972f6Sopenharmony_ci } 2530195972f6Sopenharmony_ci } 2531195972f6Sopenharmony_ci } 2532195972f6Sopenharmony_ci} 2533195972f6Sopenharmony_ci 2534195972f6Sopenharmony_ciconst char * 2535195972f6Sopenharmony_citcp_debug_state_str(enum tcp_state s) 2536195972f6Sopenharmony_ci{ 2537195972f6Sopenharmony_ci return tcp_state_str[s]; 2538195972f6Sopenharmony_ci} 2539195972f6Sopenharmony_ci 2540195972f6Sopenharmony_cierr_t 2541195972f6Sopenharmony_citcp_tcp_get_tcp_addrinfo(struct tcp_pcb *pcb, int local, ip_addr_t *addr, u16_t *port) 2542195972f6Sopenharmony_ci{ 2543195972f6Sopenharmony_ci if (pcb) { 2544195972f6Sopenharmony_ci if (local) { 2545195972f6Sopenharmony_ci if (addr) { 2546195972f6Sopenharmony_ci *addr = pcb->local_ip; 2547195972f6Sopenharmony_ci } 2548195972f6Sopenharmony_ci if (port) { 2549195972f6Sopenharmony_ci *port = pcb->local_port; 2550195972f6Sopenharmony_ci } 2551195972f6Sopenharmony_ci } else { 2552195972f6Sopenharmony_ci if (addr) { 2553195972f6Sopenharmony_ci *addr = pcb->remote_ip; 2554195972f6Sopenharmony_ci } 2555195972f6Sopenharmony_ci if (port) { 2556195972f6Sopenharmony_ci *port = pcb->remote_port; 2557195972f6Sopenharmony_ci } 2558195972f6Sopenharmony_ci } 2559195972f6Sopenharmony_ci return ERR_OK; 2560195972f6Sopenharmony_ci } 2561195972f6Sopenharmony_ci return ERR_VAL; 2562195972f6Sopenharmony_ci} 2563195972f6Sopenharmony_ci 2564195972f6Sopenharmony_ci#if TCP_QUEUE_OOSEQ 2565195972f6Sopenharmony_ci/* Free all ooseq pbufs (and possibly reset SACK state) */ 2566195972f6Sopenharmony_civoid 2567195972f6Sopenharmony_citcp_free_ooseq(struct tcp_pcb *pcb) 2568195972f6Sopenharmony_ci{ 2569195972f6Sopenharmony_ci if (pcb->ooseq) { 2570195972f6Sopenharmony_ci tcp_segs_free(pcb->ooseq); 2571195972f6Sopenharmony_ci pcb->ooseq = NULL; 2572195972f6Sopenharmony_ci#if LWIP_TCP_SACK_OUT 2573195972f6Sopenharmony_ci memset(pcb->rcv_sacks, 0, sizeof(pcb->rcv_sacks)); 2574195972f6Sopenharmony_ci#endif /* LWIP_TCP_SACK_OUT */ 2575195972f6Sopenharmony_ci } 2576195972f6Sopenharmony_ci} 2577195972f6Sopenharmony_ci#endif /* TCP_QUEUE_OOSEQ */ 2578195972f6Sopenharmony_ci 2579195972f6Sopenharmony_ci#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG 2580195972f6Sopenharmony_ci/** 2581195972f6Sopenharmony_ci * Print a tcp header for debugging purposes. 2582195972f6Sopenharmony_ci * 2583195972f6Sopenharmony_ci * @param tcphdr pointer to a struct tcp_hdr 2584195972f6Sopenharmony_ci */ 2585195972f6Sopenharmony_civoid 2586195972f6Sopenharmony_citcp_debug_print(struct tcp_hdr *tcphdr) 2587195972f6Sopenharmony_ci{ 2588195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n")); 2589195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); 2590195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", 2591195972f6Sopenharmony_ci lwip_ntohs(tcphdr->src), lwip_ntohs(tcphdr->dest))); 2592195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); 2593195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (seq no)\n", 2594195972f6Sopenharmony_ci lwip_ntohl(tcphdr->seqno))); 2595195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); 2596195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (ack no)\n", 2597195972f6Sopenharmony_ci lwip_ntohl(tcphdr->ackno))); 2598195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); 2599195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" | |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"| %5"U16_F" | (hdrlen, flags (", 2600195972f6Sopenharmony_ci TCPH_HDRLEN(tcphdr), 2601195972f6Sopenharmony_ci (u16_t)(TCPH_FLAGS(tcphdr) >> 5 & 1), 2602195972f6Sopenharmony_ci (u16_t)(TCPH_FLAGS(tcphdr) >> 4 & 1), 2603195972f6Sopenharmony_ci (u16_t)(TCPH_FLAGS(tcphdr) >> 3 & 1), 2604195972f6Sopenharmony_ci (u16_t)(TCPH_FLAGS(tcphdr) >> 2 & 1), 2605195972f6Sopenharmony_ci (u16_t)(TCPH_FLAGS(tcphdr) >> 1 & 1), 2606195972f6Sopenharmony_ci (u16_t)(TCPH_FLAGS(tcphdr) & 1), 2607195972f6Sopenharmony_ci lwip_ntohs(tcphdr->wnd))); 2608195972f6Sopenharmony_ci tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); 2609195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("), win)\n")); 2610195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); 2611195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("| 0x%04"X16_F" | %5"U16_F" | (chksum, urgp)\n", 2612195972f6Sopenharmony_ci lwip_ntohs(tcphdr->chksum), lwip_ntohs(tcphdr->urgp))); 2613195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); 2614195972f6Sopenharmony_ci} 2615195972f6Sopenharmony_ci 2616195972f6Sopenharmony_ci/** 2617195972f6Sopenharmony_ci * Print a tcp state for debugging purposes. 2618195972f6Sopenharmony_ci * 2619195972f6Sopenharmony_ci * @param s enum tcp_state to print 2620195972f6Sopenharmony_ci */ 2621195972f6Sopenharmony_civoid 2622195972f6Sopenharmony_citcp_debug_print_state(enum tcp_state s) 2623195972f6Sopenharmony_ci{ 2624195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("State: %s\n", tcp_state_str[s])); 2625195972f6Sopenharmony_ci} 2626195972f6Sopenharmony_ci 2627195972f6Sopenharmony_ci/** 2628195972f6Sopenharmony_ci * Print tcp flags for debugging purposes. 2629195972f6Sopenharmony_ci * 2630195972f6Sopenharmony_ci * @param flags tcp flags, all active flags are printed 2631195972f6Sopenharmony_ci */ 2632195972f6Sopenharmony_civoid 2633195972f6Sopenharmony_citcp_debug_print_flags(u8_t flags) 2634195972f6Sopenharmony_ci{ 2635195972f6Sopenharmony_ci if (flags & TCP_FIN) { 2636195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("FIN ")); 2637195972f6Sopenharmony_ci } 2638195972f6Sopenharmony_ci if (flags & TCP_SYN) { 2639195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("SYN ")); 2640195972f6Sopenharmony_ci } 2641195972f6Sopenharmony_ci if (flags & TCP_RST) { 2642195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("RST ")); 2643195972f6Sopenharmony_ci } 2644195972f6Sopenharmony_ci if (flags & TCP_PSH) { 2645195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("PSH ")); 2646195972f6Sopenharmony_ci } 2647195972f6Sopenharmony_ci if (flags & TCP_ACK) { 2648195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("ACK ")); 2649195972f6Sopenharmony_ci } 2650195972f6Sopenharmony_ci if (flags & TCP_URG) { 2651195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("URG ")); 2652195972f6Sopenharmony_ci } 2653195972f6Sopenharmony_ci if (flags & TCP_ECE) { 2654195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("ECE ")); 2655195972f6Sopenharmony_ci } 2656195972f6Sopenharmony_ci if (flags & TCP_CWR) { 2657195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("CWR ")); 2658195972f6Sopenharmony_ci } 2659195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("\n")); 2660195972f6Sopenharmony_ci} 2661195972f6Sopenharmony_ci 2662195972f6Sopenharmony_ci/** 2663195972f6Sopenharmony_ci * Print all tcp_pcbs in every list for debugging purposes. 2664195972f6Sopenharmony_ci */ 2665195972f6Sopenharmony_civoid 2666195972f6Sopenharmony_citcp_debug_print_pcbs(void) 2667195972f6Sopenharmony_ci{ 2668195972f6Sopenharmony_ci struct tcp_pcb *pcb; 2669195972f6Sopenharmony_ci struct tcp_pcb_listen *pcbl; 2670195972f6Sopenharmony_ci 2671195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n")); 2672195972f6Sopenharmony_ci for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { 2673195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", 2674195972f6Sopenharmony_ci pcb->local_port, pcb->remote_port, 2675195972f6Sopenharmony_ci pcb->snd_nxt, pcb->rcv_nxt)); 2676195972f6Sopenharmony_ci tcp_debug_print_state(pcb->state); 2677195972f6Sopenharmony_ci } 2678195972f6Sopenharmony_ci 2679195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n")); 2680195972f6Sopenharmony_ci for (pcbl = tcp_listen_pcbs.listen_pcbs; pcbl != NULL; pcbl = pcbl->next) { 2681195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F" ", pcbl->local_port)); 2682195972f6Sopenharmony_ci tcp_debug_print_state(pcbl->state); 2683195972f6Sopenharmony_ci } 2684195972f6Sopenharmony_ci 2685195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n")); 2686195972f6Sopenharmony_ci for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { 2687195972f6Sopenharmony_ci LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", 2688195972f6Sopenharmony_ci pcb->local_port, pcb->remote_port, 2689195972f6Sopenharmony_ci pcb->snd_nxt, pcb->rcv_nxt)); 2690195972f6Sopenharmony_ci tcp_debug_print_state(pcb->state); 2691195972f6Sopenharmony_ci } 2692195972f6Sopenharmony_ci} 2693195972f6Sopenharmony_ci 2694195972f6Sopenharmony_ci/** 2695195972f6Sopenharmony_ci * Check state consistency of the tcp_pcb lists. 2696195972f6Sopenharmony_ci */ 2697195972f6Sopenharmony_cis16_t 2698195972f6Sopenharmony_citcp_pcbs_sane(void) 2699195972f6Sopenharmony_ci{ 2700195972f6Sopenharmony_ci struct tcp_pcb *pcb; 2701195972f6Sopenharmony_ci for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { 2702195972f6Sopenharmony_ci LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED); 2703195972f6Sopenharmony_ci LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN); 2704195972f6Sopenharmony_ci LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); 2705195972f6Sopenharmony_ci } 2706195972f6Sopenharmony_ci for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { 2707195972f6Sopenharmony_ci LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); 2708195972f6Sopenharmony_ci } 2709195972f6Sopenharmony_ci return 1; 2710195972f6Sopenharmony_ci} 2711195972f6Sopenharmony_ci#endif /* TCP_DEBUG */ 2712195972f6Sopenharmony_ci 2713195972f6Sopenharmony_ci#if LWIP_TCP_PCB_NUM_EXT_ARGS 2714195972f6Sopenharmony_ci/** 2715195972f6Sopenharmony_ci * @defgroup tcp_raw_extargs ext arguments 2716195972f6Sopenharmony_ci * @ingroup tcp_raw 2717195972f6Sopenharmony_ci * Additional data storage per tcp pcb\n 2718195972f6Sopenharmony_ci * @see @ref tcp_raw 2719195972f6Sopenharmony_ci * 2720195972f6Sopenharmony_ci * When LWIP_TCP_PCB_NUM_EXT_ARGS is > 0, every tcp pcb (including listen pcb) 2721195972f6Sopenharmony_ci * includes a number of additional argument entries in an array. 2722195972f6Sopenharmony_ci * 2723195972f6Sopenharmony_ci * To support memory management, in addition to a 'void *', callbacks can be 2724195972f6Sopenharmony_ci * provided to manage transition from listening pcbs to connections and to 2725195972f6Sopenharmony_ci * deallocate memory when a pcb is deallocated (see struct @ref tcp_ext_arg_callbacks). 2726195972f6Sopenharmony_ci * 2727195972f6Sopenharmony_ci * After allocating this index, use @ref tcp_ext_arg_set and @ref tcp_ext_arg_get 2728195972f6Sopenharmony_ci * to store and load arguments from this index for a given pcb. 2729195972f6Sopenharmony_ci */ 2730195972f6Sopenharmony_ci 2731195972f6Sopenharmony_cistatic u8_t tcp_ext_arg_id; 2732195972f6Sopenharmony_ci 2733195972f6Sopenharmony_ci/** 2734195972f6Sopenharmony_ci * @ingroup tcp_raw_extargs 2735195972f6Sopenharmony_ci * Allocate an index to store data in ext_args member of struct tcp_pcb. 2736195972f6Sopenharmony_ci * Returned value is an index in mentioned array. 2737195972f6Sopenharmony_ci * The index is *global* over all pcbs! 2738195972f6Sopenharmony_ci * 2739195972f6Sopenharmony_ci * When @ref LWIP_TCP_PCB_NUM_EXT_ARGS is > 0, every tcp pcb (including listen pcb) 2740195972f6Sopenharmony_ci * includes a number of additional argument entries in an array. 2741195972f6Sopenharmony_ci * 2742195972f6Sopenharmony_ci * To support memory management, in addition to a 'void *', callbacks can be 2743195972f6Sopenharmony_ci * provided to manage transition from listening pcbs to connections and to 2744195972f6Sopenharmony_ci * deallocate memory when a pcb is deallocated (see struct @ref tcp_ext_arg_callbacks). 2745195972f6Sopenharmony_ci * 2746195972f6Sopenharmony_ci * After allocating this index, use @ref tcp_ext_arg_set and @ref tcp_ext_arg_get 2747195972f6Sopenharmony_ci * to store and load arguments from this index for a given pcb. 2748195972f6Sopenharmony_ci * 2749195972f6Sopenharmony_ci * @return a unique index into struct tcp_pcb.ext_args 2750195972f6Sopenharmony_ci */ 2751195972f6Sopenharmony_ciu8_t 2752195972f6Sopenharmony_citcp_ext_arg_alloc_id(void) 2753195972f6Sopenharmony_ci{ 2754195972f6Sopenharmony_ci u8_t result = tcp_ext_arg_id; 2755195972f6Sopenharmony_ci tcp_ext_arg_id++; 2756195972f6Sopenharmony_ci 2757195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 2758195972f6Sopenharmony_ci 2759195972f6Sopenharmony_ci#if LWIP_TCP_PCB_NUM_EXT_ARGS >= 255 2760195972f6Sopenharmony_ci#error LWIP_TCP_PCB_NUM_EXT_ARGS 2761195972f6Sopenharmony_ci#endif 2762195972f6Sopenharmony_ci LWIP_ASSERT("Increase LWIP_TCP_PCB_NUM_EXT_ARGS in lwipopts.h", result < LWIP_TCP_PCB_NUM_EXT_ARGS); 2763195972f6Sopenharmony_ci return result; 2764195972f6Sopenharmony_ci} 2765195972f6Sopenharmony_ci 2766195972f6Sopenharmony_ci/** 2767195972f6Sopenharmony_ci * @ingroup tcp_raw_extargs 2768195972f6Sopenharmony_ci * Set callbacks for a given index of ext_args on the specified pcb. 2769195972f6Sopenharmony_ci * 2770195972f6Sopenharmony_ci * @param pcb tcp_pcb for which to set the callback 2771195972f6Sopenharmony_ci * @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id) 2772195972f6Sopenharmony_ci * @param callbacks callback table (const since it is referenced, not copied!) 2773195972f6Sopenharmony_ci */ 2774195972f6Sopenharmony_civoid 2775195972f6Sopenharmony_citcp_ext_arg_set_callbacks(struct tcp_pcb *pcb, uint8_t id, const struct tcp_ext_arg_callbacks * const callbacks) 2776195972f6Sopenharmony_ci{ 2777195972f6Sopenharmony_ci LWIP_ASSERT("pcb != NULL", pcb != NULL); 2778195972f6Sopenharmony_ci LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS); 2779195972f6Sopenharmony_ci LWIP_ASSERT("callbacks != NULL", callbacks != NULL); 2780195972f6Sopenharmony_ci 2781195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 2782195972f6Sopenharmony_ci 2783195972f6Sopenharmony_ci pcb->ext_args[id].callbacks = callbacks; 2784195972f6Sopenharmony_ci} 2785195972f6Sopenharmony_ci 2786195972f6Sopenharmony_ci/** 2787195972f6Sopenharmony_ci * @ingroup tcp_raw_extargs 2788195972f6Sopenharmony_ci * Set data for a given index of ext_args on the specified pcb. 2789195972f6Sopenharmony_ci * 2790195972f6Sopenharmony_ci * @param pcb tcp_pcb for which to set the data 2791195972f6Sopenharmony_ci * @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id) 2792195972f6Sopenharmony_ci * @param arg data pointer to set 2793195972f6Sopenharmony_ci */ 2794195972f6Sopenharmony_civoid tcp_ext_arg_set(struct tcp_pcb *pcb, uint8_t id, void *arg) 2795195972f6Sopenharmony_ci{ 2796195972f6Sopenharmony_ci LWIP_ASSERT("pcb != NULL", pcb != NULL); 2797195972f6Sopenharmony_ci LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS); 2798195972f6Sopenharmony_ci 2799195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 2800195972f6Sopenharmony_ci 2801195972f6Sopenharmony_ci pcb->ext_args[id].data = arg; 2802195972f6Sopenharmony_ci} 2803195972f6Sopenharmony_ci 2804195972f6Sopenharmony_ci/** 2805195972f6Sopenharmony_ci * @ingroup tcp_raw_extargs 2806195972f6Sopenharmony_ci * Set data for a given index of ext_args on the specified pcb. 2807195972f6Sopenharmony_ci * 2808195972f6Sopenharmony_ci * @param pcb tcp_pcb for which to set the data 2809195972f6Sopenharmony_ci * @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id) 2810195972f6Sopenharmony_ci * @return data pointer at the given index 2811195972f6Sopenharmony_ci */ 2812195972f6Sopenharmony_civoid *tcp_ext_arg_get(const struct tcp_pcb *pcb, uint8_t id) 2813195972f6Sopenharmony_ci{ 2814195972f6Sopenharmony_ci LWIP_ASSERT("pcb != NULL", pcb != NULL); 2815195972f6Sopenharmony_ci LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS); 2816195972f6Sopenharmony_ci 2817195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 2818195972f6Sopenharmony_ci 2819195972f6Sopenharmony_ci return pcb->ext_args[id].data; 2820195972f6Sopenharmony_ci} 2821195972f6Sopenharmony_ci 2822195972f6Sopenharmony_ci/** This function calls the "destroy" callback for all ext_args once a pcb is 2823195972f6Sopenharmony_ci * freed. 2824195972f6Sopenharmony_ci */ 2825195972f6Sopenharmony_cistatic void 2826195972f6Sopenharmony_citcp_ext_arg_invoke_callbacks_destroyed(struct tcp_pcb_ext_args *ext_args) 2827195972f6Sopenharmony_ci{ 2828195972f6Sopenharmony_ci int i; 2829195972f6Sopenharmony_ci LWIP_ASSERT("ext_args != NULL", ext_args != NULL); 2830195972f6Sopenharmony_ci 2831195972f6Sopenharmony_ci for (i = 0; i < LWIP_TCP_PCB_NUM_EXT_ARGS; i++) { 2832195972f6Sopenharmony_ci if (ext_args[i].callbacks != NULL) { 2833195972f6Sopenharmony_ci if (ext_args[i].callbacks->destroy != NULL) { 2834195972f6Sopenharmony_ci ext_args[i].callbacks->destroy((u8_t)i, ext_args[i].data); 2835195972f6Sopenharmony_ci } 2836195972f6Sopenharmony_ci } 2837195972f6Sopenharmony_ci } 2838195972f6Sopenharmony_ci} 2839195972f6Sopenharmony_ci 2840195972f6Sopenharmony_ci/** This function calls the "passive_open" callback for all ext_args if a connection 2841195972f6Sopenharmony_ci * is in the process of being accepted. This is called just after the SYN is 2842195972f6Sopenharmony_ci * received and before a SYN/ACK is sent, to allow to modify the very first 2843195972f6Sopenharmony_ci * segment sent even on passive open. Naturally, the "accepted" callback of the 2844195972f6Sopenharmony_ci * pcb has not been called yet! 2845195972f6Sopenharmony_ci */ 2846195972f6Sopenharmony_cierr_t 2847195972f6Sopenharmony_citcp_ext_arg_invoke_callbacks_passive_open(struct tcp_pcb_listen *lpcb, struct tcp_pcb *cpcb) 2848195972f6Sopenharmony_ci{ 2849195972f6Sopenharmony_ci int i; 2850195972f6Sopenharmony_ci LWIP_ASSERT("lpcb != NULL", lpcb != NULL); 2851195972f6Sopenharmony_ci LWIP_ASSERT("cpcb != NULL", cpcb != NULL); 2852195972f6Sopenharmony_ci 2853195972f6Sopenharmony_ci for (i = 0; i < LWIP_TCP_PCB_NUM_EXT_ARGS; i++) { 2854195972f6Sopenharmony_ci if (lpcb->ext_args[i].callbacks != NULL) { 2855195972f6Sopenharmony_ci if (lpcb->ext_args[i].callbacks->passive_open != NULL) { 2856195972f6Sopenharmony_ci err_t err = lpcb->ext_args[i].callbacks->passive_open((u8_t)i, lpcb, cpcb); 2857195972f6Sopenharmony_ci if (err != ERR_OK) { 2858195972f6Sopenharmony_ci return err; 2859195972f6Sopenharmony_ci } 2860195972f6Sopenharmony_ci } 2861195972f6Sopenharmony_ci } 2862195972f6Sopenharmony_ci } 2863195972f6Sopenharmony_ci return ERR_OK; 2864195972f6Sopenharmony_ci} 2865195972f6Sopenharmony_ci#endif /* LWIP_TCP_PCB_NUM_EXT_ARGS */ 2866195972f6Sopenharmony_ci 2867195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 2868