My fork of the HTTPServer (working)

Dependents:   DGWWebServer LAN2

Committer:
screamer
Date:
Mon Aug 06 09:23:14 2012 +0000
Revision:
0:7a64fbb4069d
[mbed] converted /DGWWebServer/HTTPServer

Who changed what in which revision?

UserRevisionLine numberNew contents of line
screamer 0:7a64fbb4069d 1 /**
screamer 0:7a64fbb4069d 2 * @file
screamer 0:7a64fbb4069d 3 * Transmission Control Protocol for IP
screamer 0:7a64fbb4069d 4 *
screamer 0:7a64fbb4069d 5 * This file contains common functions for the TCP implementation, such as functinos
screamer 0:7a64fbb4069d 6 * for manipulating the data structures and the TCP timer functions. TCP functions
screamer 0:7a64fbb4069d 7 * related to input and output is found in tcp_in.c and tcp_out.c respectively.
screamer 0:7a64fbb4069d 8 *
screamer 0:7a64fbb4069d 9 */
screamer 0:7a64fbb4069d 10
screamer 0:7a64fbb4069d 11 /*
screamer 0:7a64fbb4069d 12 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
screamer 0:7a64fbb4069d 13 * All rights reserved.
screamer 0:7a64fbb4069d 14 *
screamer 0:7a64fbb4069d 15 * Redistribution and use in source and binary forms, with or without modification,
screamer 0:7a64fbb4069d 16 * are permitted provided that the following conditions are met:
screamer 0:7a64fbb4069d 17 *
screamer 0:7a64fbb4069d 18 * 1. Redistributions of source code must retain the above copyright notice,
screamer 0:7a64fbb4069d 19 * this list of conditions and the following disclaimer.
screamer 0:7a64fbb4069d 20 * 2. Redistributions in binary form must reproduce the above copyright notice,
screamer 0:7a64fbb4069d 21 * this list of conditions and the following disclaimer in the documentation
screamer 0:7a64fbb4069d 22 * and/or other materials provided with the distribution.
screamer 0:7a64fbb4069d 23 * 3. The name of the author may not be used to endorse or promote products
screamer 0:7a64fbb4069d 24 * derived from this software without specific prior written permission.
screamer 0:7a64fbb4069d 25 *
screamer 0:7a64fbb4069d 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
screamer 0:7a64fbb4069d 27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
screamer 0:7a64fbb4069d 28 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
screamer 0:7a64fbb4069d 29 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
screamer 0:7a64fbb4069d 30 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
screamer 0:7a64fbb4069d 31 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
screamer 0:7a64fbb4069d 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
screamer 0:7a64fbb4069d 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
screamer 0:7a64fbb4069d 34 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
screamer 0:7a64fbb4069d 35 * OF SUCH DAMAGE.
screamer 0:7a64fbb4069d 36 *
screamer 0:7a64fbb4069d 37 * This file is part of the lwIP TCP/IP stack.
screamer 0:7a64fbb4069d 38 *
screamer 0:7a64fbb4069d 39 * Author: Adam Dunkels <adam@sics.se>
screamer 0:7a64fbb4069d 40 *
screamer 0:7a64fbb4069d 41 */
screamer 0:7a64fbb4069d 42
screamer 0:7a64fbb4069d 43 #include "lwip/opt.h"
screamer 0:7a64fbb4069d 44
screamer 0:7a64fbb4069d 45 #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
screamer 0:7a64fbb4069d 46
screamer 0:7a64fbb4069d 47 #include "lwip/def.h"
screamer 0:7a64fbb4069d 48 #include "lwip/mem.h"
screamer 0:7a64fbb4069d 49 #include "lwip/memp.h"
screamer 0:7a64fbb4069d 50 #include "lwip/snmp.h"
screamer 0:7a64fbb4069d 51 #include "lwip/tcp.h"
screamer 0:7a64fbb4069d 52
screamer 0:7a64fbb4069d 53 #include <string.h>
screamer 0:7a64fbb4069d 54
screamer 0:7a64fbb4069d 55 /* Incremented every coarse grained timer shot (typically every 500 ms). */
screamer 0:7a64fbb4069d 56 u32_t tcp_ticks;
screamer 0:7a64fbb4069d 57 const u8_t tcp_backoff[13] =
screamer 0:7a64fbb4069d 58 { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};
screamer 0:7a64fbb4069d 59 /* Times per slowtmr hits */
screamer 0:7a64fbb4069d 60 const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 };
screamer 0:7a64fbb4069d 61
screamer 0:7a64fbb4069d 62 /* The TCP PCB lists. */
screamer 0:7a64fbb4069d 63
screamer 0:7a64fbb4069d 64 /** List of all TCP PCBs bound but not yet (connected || listening) */
screamer 0:7a64fbb4069d 65 struct tcp_pcb *tcp_bound_pcbs;
screamer 0:7a64fbb4069d 66 /** List of all TCP PCBs in LISTEN state */
screamer 0:7a64fbb4069d 67 union tcp_listen_pcbs_t tcp_listen_pcbs;
screamer 0:7a64fbb4069d 68 /** List of all TCP PCBs that are in a state in which
screamer 0:7a64fbb4069d 69 * they accept or send data. */
screamer 0:7a64fbb4069d 70 struct tcp_pcb *tcp_active_pcbs;
screamer 0:7a64fbb4069d 71 /** List of all TCP PCBs in TIME-WAIT state */
screamer 0:7a64fbb4069d 72 struct tcp_pcb *tcp_tw_pcbs;
screamer 0:7a64fbb4069d 73
screamer 0:7a64fbb4069d 74 struct tcp_pcb *tcp_tmp_pcb;
screamer 0:7a64fbb4069d 75
screamer 0:7a64fbb4069d 76 static u8_t tcp_timer;
screamer 0:7a64fbb4069d 77 static u16_t tcp_new_port(void);
screamer 0:7a64fbb4069d 78
screamer 0:7a64fbb4069d 79 /**
screamer 0:7a64fbb4069d 80 * Called periodically to dispatch TCP timers.
screamer 0:7a64fbb4069d 81 *
screamer 0:7a64fbb4069d 82 */
screamer 0:7a64fbb4069d 83 void
screamer 0:7a64fbb4069d 84 tcp_tmr(void)
screamer 0:7a64fbb4069d 85 {
screamer 0:7a64fbb4069d 86 /* Call tcp_fasttmr() every 250 ms */
screamer 0:7a64fbb4069d 87 tcp_fasttmr();
screamer 0:7a64fbb4069d 88
screamer 0:7a64fbb4069d 89 if (++tcp_timer & 1) {
screamer 0:7a64fbb4069d 90 /* Call tcp_tmr() every 500 ms, i.e., every other timer
screamer 0:7a64fbb4069d 91 tcp_tmr() is called. */
screamer 0:7a64fbb4069d 92 tcp_slowtmr();
screamer 0:7a64fbb4069d 93 }
screamer 0:7a64fbb4069d 94 }
screamer 0:7a64fbb4069d 95
screamer 0:7a64fbb4069d 96 /**
screamer 0:7a64fbb4069d 97 * Closes the connection held by the PCB.
screamer 0:7a64fbb4069d 98 *
screamer 0:7a64fbb4069d 99 * Listening pcbs are freed and may not be referenced any more.
screamer 0:7a64fbb4069d 100 * Connection pcbs are freed if not yet connected and may not be referenced
screamer 0:7a64fbb4069d 101 * any more. If a connection is established (at least SYN received or in
screamer 0:7a64fbb4069d 102 * a closing state), the connection is closed, and put in a closing state.
screamer 0:7a64fbb4069d 103 * The pcb is then automatically freed in tcp_slowtmr(). It is therefore
screamer 0:7a64fbb4069d 104 * unsafe to reference it.
screamer 0:7a64fbb4069d 105 *
screamer 0:7a64fbb4069d 106 * @param pcb the tcp_pcb to close
screamer 0:7a64fbb4069d 107 * @return ERR_OK if connection has been closed
screamer 0:7a64fbb4069d 108 * another err_t if closing failed and pcb is not freed
screamer 0:7a64fbb4069d 109 */
screamer 0:7a64fbb4069d 110 err_t
screamer 0:7a64fbb4069d 111 tcp_close(struct tcp_pcb *pcb)
screamer 0:7a64fbb4069d 112 {
screamer 0:7a64fbb4069d 113 err_t err;
screamer 0:7a64fbb4069d 114
screamer 0:7a64fbb4069d 115 #if TCP_DEBUG
screamer 0:7a64fbb4069d 116 LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in "));
screamer 0:7a64fbb4069d 117 tcp_debug_print_state(pcb->state);
screamer 0:7a64fbb4069d 118 #endif /* TCP_DEBUG */
screamer 0:7a64fbb4069d 119
screamer 0:7a64fbb4069d 120 switch (pcb->state) {
screamer 0:7a64fbb4069d 121 case CLOSED:
screamer 0:7a64fbb4069d 122 /* Closing a pcb in the CLOSED state might seem erroneous,
screamer 0:7a64fbb4069d 123 * however, it is in this state once allocated and as yet unused
screamer 0:7a64fbb4069d 124 * and the user needs some way to free it should the need arise.
screamer 0:7a64fbb4069d 125 * Calling tcp_close() with a pcb that has already been closed, (i.e. twice)
screamer 0:7a64fbb4069d 126 * or for a pcb that has been used and then entered the CLOSED state
screamer 0:7a64fbb4069d 127 * is erroneous, but this should never happen as the pcb has in those cases
screamer 0:7a64fbb4069d 128 * been freed, and so any remaining handles are bogus. */
screamer 0:7a64fbb4069d 129 err = ERR_OK;
screamer 0:7a64fbb4069d 130 TCP_RMV(&tcp_bound_pcbs, pcb);
screamer 0:7a64fbb4069d 131 memp_free(MEMP_TCP_PCB, pcb);
screamer 0:7a64fbb4069d 132 pcb = NULL;
screamer 0:7a64fbb4069d 133 break;
screamer 0:7a64fbb4069d 134 case LISTEN:
screamer 0:7a64fbb4069d 135 err = ERR_OK;
screamer 0:7a64fbb4069d 136 tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb);
screamer 0:7a64fbb4069d 137 memp_free(MEMP_TCP_PCB_LISTEN, pcb);
screamer 0:7a64fbb4069d 138 pcb = NULL;
screamer 0:7a64fbb4069d 139 break;
screamer 0:7a64fbb4069d 140 case SYN_SENT:
screamer 0:7a64fbb4069d 141 err = ERR_OK;
screamer 0:7a64fbb4069d 142 tcp_pcb_remove(&tcp_active_pcbs, pcb);
screamer 0:7a64fbb4069d 143 memp_free(MEMP_TCP_PCB, pcb);
screamer 0:7a64fbb4069d 144 pcb = NULL;
screamer 0:7a64fbb4069d 145 snmp_inc_tcpattemptfails();
screamer 0:7a64fbb4069d 146 break;
screamer 0:7a64fbb4069d 147 case SYN_RCVD:
screamer 0:7a64fbb4069d 148 err = tcp_send_ctrl(pcb, TCP_FIN);
screamer 0:7a64fbb4069d 149 if (err == ERR_OK) {
screamer 0:7a64fbb4069d 150 snmp_inc_tcpattemptfails();
screamer 0:7a64fbb4069d 151 pcb->state = FIN_WAIT_1;
screamer 0:7a64fbb4069d 152 }
screamer 0:7a64fbb4069d 153 break;
screamer 0:7a64fbb4069d 154 case ESTABLISHED:
screamer 0:7a64fbb4069d 155 err = tcp_send_ctrl(pcb, TCP_FIN);
screamer 0:7a64fbb4069d 156 if (err == ERR_OK) {
screamer 0:7a64fbb4069d 157 snmp_inc_tcpestabresets();
screamer 0:7a64fbb4069d 158 pcb->state = FIN_WAIT_1;
screamer 0:7a64fbb4069d 159 }
screamer 0:7a64fbb4069d 160 break;
screamer 0:7a64fbb4069d 161 case CLOSE_WAIT:
screamer 0:7a64fbb4069d 162 err = tcp_send_ctrl(pcb, TCP_FIN);
screamer 0:7a64fbb4069d 163 if (err == ERR_OK) {
screamer 0:7a64fbb4069d 164 snmp_inc_tcpestabresets();
screamer 0:7a64fbb4069d 165 pcb->state = LAST_ACK;
screamer 0:7a64fbb4069d 166 }
screamer 0:7a64fbb4069d 167 break;
screamer 0:7a64fbb4069d 168 default:
screamer 0:7a64fbb4069d 169 /* Has already been closed, do nothing. */
screamer 0:7a64fbb4069d 170 err = ERR_OK;
screamer 0:7a64fbb4069d 171 pcb = NULL;
screamer 0:7a64fbb4069d 172 break;
screamer 0:7a64fbb4069d 173 }
screamer 0:7a64fbb4069d 174
screamer 0:7a64fbb4069d 175 if (pcb != NULL && err == ERR_OK) {
screamer 0:7a64fbb4069d 176 /* To ensure all data has been sent when tcp_close returns, we have
screamer 0:7a64fbb4069d 177 to make sure tcp_output doesn't fail.
screamer 0:7a64fbb4069d 178 Since we don't really have to ensure all data has been sent when tcp_close
screamer 0:7a64fbb4069d 179 returns (unsent data is sent from tcp timer functions, also), we don't care
screamer 0:7a64fbb4069d 180 for the return value of tcp_output for now. */
screamer 0:7a64fbb4069d 181 /* @todo: When implementing SO_LINGER, this must be changed somehow:
screamer 0:7a64fbb4069d 182 If SOF_LINGER is set, the data should be sent when tcp_close returns. */
screamer 0:7a64fbb4069d 183 tcp_output(pcb);
screamer 0:7a64fbb4069d 184 }
screamer 0:7a64fbb4069d 185 return err;
screamer 0:7a64fbb4069d 186 }
screamer 0:7a64fbb4069d 187
screamer 0:7a64fbb4069d 188 /**
screamer 0:7a64fbb4069d 189 * Abandons a connection and optionally sends a RST to the remote
screamer 0:7a64fbb4069d 190 * host. Deletes the local protocol control block. This is done when
screamer 0:7a64fbb4069d 191 * a connection is killed because of shortage of memory.
screamer 0:7a64fbb4069d 192 *
screamer 0:7a64fbb4069d 193 * @param pcb the tcp_pcb to abort
screamer 0:7a64fbb4069d 194 * @param reset boolean to indicate whether a reset should be sent
screamer 0:7a64fbb4069d 195 */
screamer 0:7a64fbb4069d 196 void
screamer 0:7a64fbb4069d 197 tcp_abandon(struct tcp_pcb *pcb, int reset)
screamer 0:7a64fbb4069d 198 {
screamer 0:7a64fbb4069d 199 u32_t seqno, ackno;
screamer 0:7a64fbb4069d 200 u16_t remote_port, local_port;
screamer 0:7a64fbb4069d 201 struct ip_addr remote_ip, local_ip;
screamer 0:7a64fbb4069d 202 #if LWIP_CALLBACK_API
screamer 0:7a64fbb4069d 203 void (* errf)(void *arg, err_t err);
screamer 0:7a64fbb4069d 204 #endif /* LWIP_CALLBACK_API */
screamer 0:7a64fbb4069d 205 void *errf_arg;
screamer 0:7a64fbb4069d 206
screamer 0:7a64fbb4069d 207
screamer 0:7a64fbb4069d 208 /* Figure out on which TCP PCB list we are, and remove us. If we
screamer 0:7a64fbb4069d 209 are in an active state, call the receive function associated with
screamer 0:7a64fbb4069d 210 the PCB with a NULL argument, and send an RST to the remote end. */
screamer 0:7a64fbb4069d 211 if (pcb->state == TIME_WAIT) {
screamer 0:7a64fbb4069d 212 tcp_pcb_remove(&tcp_tw_pcbs, pcb);
screamer 0:7a64fbb4069d 213 memp_free(MEMP_TCP_PCB, pcb);
screamer 0:7a64fbb4069d 214 } else {
screamer 0:7a64fbb4069d 215 seqno = pcb->snd_nxt;
screamer 0:7a64fbb4069d 216 ackno = pcb->rcv_nxt;
screamer 0:7a64fbb4069d 217 ip_addr_set(&local_ip, &(pcb->local_ip));
screamer 0:7a64fbb4069d 218 ip_addr_set(&remote_ip, &(pcb->remote_ip));
screamer 0:7a64fbb4069d 219 local_port = pcb->local_port;
screamer 0:7a64fbb4069d 220 remote_port = pcb->remote_port;
screamer 0:7a64fbb4069d 221 #if LWIP_CALLBACK_API
screamer 0:7a64fbb4069d 222 errf = pcb->errf;
screamer 0:7a64fbb4069d 223 #endif /* LWIP_CALLBACK_API */
screamer 0:7a64fbb4069d 224 errf_arg = pcb->callback_arg;
screamer 0:7a64fbb4069d 225 tcp_pcb_remove(&tcp_active_pcbs, pcb);
screamer 0:7a64fbb4069d 226 if (pcb->unacked != NULL) {
screamer 0:7a64fbb4069d 227 tcp_segs_free(pcb->unacked);
screamer 0:7a64fbb4069d 228 }
screamer 0:7a64fbb4069d 229 if (pcb->unsent != NULL) {
screamer 0:7a64fbb4069d 230 tcp_segs_free(pcb->unsent);
screamer 0:7a64fbb4069d 231 }
screamer 0:7a64fbb4069d 232 #if TCP_QUEUE_OOSEQ
screamer 0:7a64fbb4069d 233 if (pcb->ooseq != NULL) {
screamer 0:7a64fbb4069d 234 tcp_segs_free(pcb->ooseq);
screamer 0:7a64fbb4069d 235 }
screamer 0:7a64fbb4069d 236 #endif /* TCP_QUEUE_OOSEQ */
screamer 0:7a64fbb4069d 237 memp_free(MEMP_TCP_PCB, pcb);
screamer 0:7a64fbb4069d 238 TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
screamer 0:7a64fbb4069d 239 if (reset) {
screamer 0:7a64fbb4069d 240 LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));
screamer 0:7a64fbb4069d 241 tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);
screamer 0:7a64fbb4069d 242 }
screamer 0:7a64fbb4069d 243 }
screamer 0:7a64fbb4069d 244 }
screamer 0:7a64fbb4069d 245
screamer 0:7a64fbb4069d 246 /**
screamer 0:7a64fbb4069d 247 * Binds the connection to a local portnumber and IP address. If the
screamer 0:7a64fbb4069d 248 * IP address is not given (i.e., ipaddr == NULL), the IP address of
screamer 0:7a64fbb4069d 249 * the outgoing network interface is used instead.
screamer 0:7a64fbb4069d 250 *
screamer 0:7a64fbb4069d 251 * @param pcb the tcp_pcb to bind (no check is done whether this pcb is
screamer 0:7a64fbb4069d 252 * already bound!)
screamer 0:7a64fbb4069d 253 * @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind
screamer 0:7a64fbb4069d 254 * to any local address
screamer 0:7a64fbb4069d 255 * @param port the local port to bind to
screamer 0:7a64fbb4069d 256 * @return ERR_USE if the port is already in use
screamer 0:7a64fbb4069d 257 * ERR_OK if bound
screamer 0:7a64fbb4069d 258 */
screamer 0:7a64fbb4069d 259 err_t
screamer 0:7a64fbb4069d 260 tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
screamer 0:7a64fbb4069d 261 {
screamer 0:7a64fbb4069d 262 struct tcp_pcb *cpcb;
screamer 0:7a64fbb4069d 263
screamer 0:7a64fbb4069d 264 LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
screamer 0:7a64fbb4069d 265
screamer 0:7a64fbb4069d 266 if (port == 0) {
screamer 0:7a64fbb4069d 267 port = tcp_new_port();
screamer 0:7a64fbb4069d 268 }
screamer 0:7a64fbb4069d 269 /* Check if the address already is in use. */
screamer 0:7a64fbb4069d 270 /* Check the listen pcbs. */
screamer 0:7a64fbb4069d 271 for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs;
screamer 0:7a64fbb4069d 272 cpcb != NULL; cpcb = cpcb->next) {
screamer 0:7a64fbb4069d 273 if (cpcb->local_port == port) {
screamer 0:7a64fbb4069d 274 if (ip_addr_isany(&(cpcb->local_ip)) ||
screamer 0:7a64fbb4069d 275 ip_addr_isany(ipaddr) ||
screamer 0:7a64fbb4069d 276 ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
screamer 0:7a64fbb4069d 277 return ERR_USE;
screamer 0:7a64fbb4069d 278 }
screamer 0:7a64fbb4069d 279 }
screamer 0:7a64fbb4069d 280 }
screamer 0:7a64fbb4069d 281 /* Check the connected pcbs. */
screamer 0:7a64fbb4069d 282 for(cpcb = tcp_active_pcbs;
screamer 0:7a64fbb4069d 283 cpcb != NULL; cpcb = cpcb->next) {
screamer 0:7a64fbb4069d 284 if (cpcb->local_port == port) {
screamer 0:7a64fbb4069d 285 if (ip_addr_isany(&(cpcb->local_ip)) ||
screamer 0:7a64fbb4069d 286 ip_addr_isany(ipaddr) ||
screamer 0:7a64fbb4069d 287 ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
screamer 0:7a64fbb4069d 288 return ERR_USE;
screamer 0:7a64fbb4069d 289 }
screamer 0:7a64fbb4069d 290 }
screamer 0:7a64fbb4069d 291 }
screamer 0:7a64fbb4069d 292 /* Check the bound, not yet connected pcbs. */
screamer 0:7a64fbb4069d 293 for(cpcb = tcp_bound_pcbs; cpcb != NULL; cpcb = cpcb->next) {
screamer 0:7a64fbb4069d 294 if (cpcb->local_port == port) {
screamer 0:7a64fbb4069d 295 if (ip_addr_isany(&(cpcb->local_ip)) ||
screamer 0:7a64fbb4069d 296 ip_addr_isany(ipaddr) ||
screamer 0:7a64fbb4069d 297 ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
screamer 0:7a64fbb4069d 298 return ERR_USE;
screamer 0:7a64fbb4069d 299 }
screamer 0:7a64fbb4069d 300 }
screamer 0:7a64fbb4069d 301 }
screamer 0:7a64fbb4069d 302 /* @todo: until SO_REUSEADDR is implemented (see task #6995 on savannah),
screamer 0:7a64fbb4069d 303 * we have to check the pcbs in TIME-WAIT state, also: */
screamer 0:7a64fbb4069d 304 for(cpcb = tcp_tw_pcbs; cpcb != NULL; cpcb = cpcb->next) {
screamer 0:7a64fbb4069d 305 if (cpcb->local_port == port) {
screamer 0:7a64fbb4069d 306 if (ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
screamer 0:7a64fbb4069d 307 return ERR_USE;
screamer 0:7a64fbb4069d 308 }
screamer 0:7a64fbb4069d 309 }
screamer 0:7a64fbb4069d 310 }
screamer 0:7a64fbb4069d 311
screamer 0:7a64fbb4069d 312 if (!ip_addr_isany(ipaddr)) {
screamer 0:7a64fbb4069d 313 pcb->local_ip = *ipaddr;
screamer 0:7a64fbb4069d 314 }
screamer 0:7a64fbb4069d 315 pcb->local_port = port;
screamer 0:7a64fbb4069d 316 TCP_REG(&tcp_bound_pcbs, pcb);
screamer 0:7a64fbb4069d 317 LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port));
screamer 0:7a64fbb4069d 318 return ERR_OK;
screamer 0:7a64fbb4069d 319 }
screamer 0:7a64fbb4069d 320 #if LWIP_CALLBACK_API
screamer 0:7a64fbb4069d 321 /**
screamer 0:7a64fbb4069d 322 * Default accept callback if no accept callback is specified by the user.
screamer 0:7a64fbb4069d 323 */
screamer 0:7a64fbb4069d 324 static err_t
screamer 0:7a64fbb4069d 325 tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)
screamer 0:7a64fbb4069d 326 {
screamer 0:7a64fbb4069d 327 LWIP_UNUSED_ARG(arg);
screamer 0:7a64fbb4069d 328 LWIP_UNUSED_ARG(pcb);
screamer 0:7a64fbb4069d 329 LWIP_UNUSED_ARG(err);
screamer 0:7a64fbb4069d 330
screamer 0:7a64fbb4069d 331 return ERR_ABRT;
screamer 0:7a64fbb4069d 332 }
screamer 0:7a64fbb4069d 333 #endif /* LWIP_CALLBACK_API */
screamer 0:7a64fbb4069d 334
screamer 0:7a64fbb4069d 335 /**
screamer 0:7a64fbb4069d 336 * Set the state of the connection to be LISTEN, which means that it
screamer 0:7a64fbb4069d 337 * is able to accept incoming connections. The protocol control block
screamer 0:7a64fbb4069d 338 * is reallocated in order to consume less memory. Setting the
screamer 0:7a64fbb4069d 339 * connection to LISTEN is an irreversible process.
screamer 0:7a64fbb4069d 340 *
screamer 0:7a64fbb4069d 341 * @param pcb the original tcp_pcb
screamer 0:7a64fbb4069d 342 * @param backlog the incoming connections queue limit
screamer 0:7a64fbb4069d 343 * @return tcp_pcb used for listening, consumes less memory.
screamer 0:7a64fbb4069d 344 *
screamer 0:7a64fbb4069d 345 * @note The original tcp_pcb is freed. This function therefore has to be
screamer 0:7a64fbb4069d 346 * called like this:
screamer 0:7a64fbb4069d 347 * tpcb = tcp_listen(tpcb);
screamer 0:7a64fbb4069d 348 */
screamer 0:7a64fbb4069d 349 struct tcp_pcb *
screamer 0:7a64fbb4069d 350 tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
screamer 0:7a64fbb4069d 351 {
screamer 0:7a64fbb4069d 352 struct tcp_pcb_listen *lpcb;
screamer 0:7a64fbb4069d 353
screamer 0:7a64fbb4069d 354 LWIP_UNUSED_ARG(backlog);
screamer 0:7a64fbb4069d 355 LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL);
screamer 0:7a64fbb4069d 356
screamer 0:7a64fbb4069d 357 /* already listening? */
screamer 0:7a64fbb4069d 358 if (pcb->state == LISTEN) {
screamer 0:7a64fbb4069d 359 return pcb;
screamer 0:7a64fbb4069d 360 }
screamer 0:7a64fbb4069d 361 lpcb = (struct tcp_pcb_listen *)(memp_malloc(MEMP_TCP_PCB_LISTEN)); // static_cast<struct tcp_pcb_listen *>(x)
screamer 0:7a64fbb4069d 362 if (lpcb == NULL) {
screamer 0:7a64fbb4069d 363 return NULL;
screamer 0:7a64fbb4069d 364 }
screamer 0:7a64fbb4069d 365 lpcb->callback_arg = pcb->callback_arg;
screamer 0:7a64fbb4069d 366 lpcb->local_port = pcb->local_port;
screamer 0:7a64fbb4069d 367 lpcb->state = LISTEN;
screamer 0:7a64fbb4069d 368 lpcb->so_options = pcb->so_options;
screamer 0:7a64fbb4069d 369 lpcb->so_options |= SOF_ACCEPTCONN;
screamer 0:7a64fbb4069d 370 lpcb->ttl = pcb->ttl;
screamer 0:7a64fbb4069d 371 lpcb->tos = pcb->tos;
screamer 0:7a64fbb4069d 372 ip_addr_set(&lpcb->local_ip, &pcb->local_ip);
screamer 0:7a64fbb4069d 373 TCP_RMV(&tcp_bound_pcbs, pcb);
screamer 0:7a64fbb4069d 374 memp_free(MEMP_TCP_PCB, pcb);
screamer 0:7a64fbb4069d 375 #if LWIP_CALLBACK_API
screamer 0:7a64fbb4069d 376 lpcb->accept = tcp_accept_null;
screamer 0:7a64fbb4069d 377 #endif /* LWIP_CALLBACK_API */
screamer 0:7a64fbb4069d 378 #if TCP_LISTEN_BACKLOG
screamer 0:7a64fbb4069d 379 lpcb->accepts_pending = 0;
screamer 0:7a64fbb4069d 380 lpcb->backlog = (backlog ? backlog : 1);
screamer 0:7a64fbb4069d 381 #endif /* TCP_LISTEN_BACKLOG */
screamer 0:7a64fbb4069d 382 TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb);
screamer 0:7a64fbb4069d 383 return (struct tcp_pcb *)lpcb;
screamer 0:7a64fbb4069d 384 }
screamer 0:7a64fbb4069d 385
screamer 0:7a64fbb4069d 386 /**
screamer 0:7a64fbb4069d 387 * Update the state that tracks the available window space to advertise.
screamer 0:7a64fbb4069d 388 *
screamer 0:7a64fbb4069d 389 * Returns how much extra window would be advertised if we sent an
screamer 0:7a64fbb4069d 390 * update now.
screamer 0:7a64fbb4069d 391 */
screamer 0:7a64fbb4069d 392 u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)
screamer 0:7a64fbb4069d 393 {
screamer 0:7a64fbb4069d 394 u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd;
screamer 0:7a64fbb4069d 395
screamer 0:7a64fbb4069d 396 if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + pcb->mss)) {
screamer 0:7a64fbb4069d 397 /* we can advertise more window */
screamer 0:7a64fbb4069d 398 pcb->rcv_ann_wnd = pcb->rcv_wnd;
screamer 0:7a64fbb4069d 399 return new_right_edge - pcb->rcv_ann_right_edge;
screamer 0:7a64fbb4069d 400 } else {
screamer 0:7a64fbb4069d 401 if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) {
screamer 0:7a64fbb4069d 402 /* Can happen due to other end sending out of advertised window,
screamer 0:7a64fbb4069d 403 * but within actual available (but not yet advertised) window */
screamer 0:7a64fbb4069d 404 pcb->rcv_ann_wnd = 0;
screamer 0:7a64fbb4069d 405 } else {
screamer 0:7a64fbb4069d 406 /* keep the right edge of window constant */
screamer 0:7a64fbb4069d 407 pcb->rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt;
screamer 0:7a64fbb4069d 408 }
screamer 0:7a64fbb4069d 409 return 0;
screamer 0:7a64fbb4069d 410 }
screamer 0:7a64fbb4069d 411 }
screamer 0:7a64fbb4069d 412
screamer 0:7a64fbb4069d 413 /**
screamer 0:7a64fbb4069d 414 * This function should be called by the application when it has
screamer 0:7a64fbb4069d 415 * processed the data. The purpose is to advertise a larger window
screamer 0:7a64fbb4069d 416 * when the data has been processed.
screamer 0:7a64fbb4069d 417 *
screamer 0:7a64fbb4069d 418 * @param pcb the tcp_pcb for which data is read
screamer 0:7a64fbb4069d 419 * @param len the amount of bytes that have been read by the application
screamer 0:7a64fbb4069d 420 */
screamer 0:7a64fbb4069d 421 void
screamer 0:7a64fbb4069d 422 tcp_recved(struct tcp_pcb *pcb, u16_t len)
screamer 0:7a64fbb4069d 423 {
screamer 0:7a64fbb4069d 424 int wnd_inflation;
screamer 0:7a64fbb4069d 425
screamer 0:7a64fbb4069d 426 pcb->rcv_wnd += len;
screamer 0:7a64fbb4069d 427 if (pcb->rcv_wnd > TCP_WND)
screamer 0:7a64fbb4069d 428 pcb->rcv_wnd = TCP_WND;
screamer 0:7a64fbb4069d 429
screamer 0:7a64fbb4069d 430 wnd_inflation = tcp_update_rcv_ann_wnd(pcb);
screamer 0:7a64fbb4069d 431
screamer 0:7a64fbb4069d 432 /* If the change in the right edge of window is significant (default
screamer 0:7a64fbb4069d 433 * watermark is TCP_WND/2), then send an explicit update now.
screamer 0:7a64fbb4069d 434 * Otherwise wait for a packet to be sent in the normal course of
screamer 0:7a64fbb4069d 435 * events (or more window to be available later) */
screamer 0:7a64fbb4069d 436 if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD)
screamer 0:7a64fbb4069d 437 tcp_ack_now(pcb);
screamer 0:7a64fbb4069d 438
screamer 0:7a64fbb4069d 439 LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n",
screamer 0:7a64fbb4069d 440 len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));
screamer 0:7a64fbb4069d 441 }
screamer 0:7a64fbb4069d 442
screamer 0:7a64fbb4069d 443 /**
screamer 0:7a64fbb4069d 444 * A nastly hack featuring 'goto' statements that allocates a
screamer 0:7a64fbb4069d 445 * new TCP local port.
screamer 0:7a64fbb4069d 446 *
screamer 0:7a64fbb4069d 447 * @return a new (free) local TCP port number
screamer 0:7a64fbb4069d 448 */
screamer 0:7a64fbb4069d 449 static u16_t
screamer 0:7a64fbb4069d 450 tcp_new_port(void)
screamer 0:7a64fbb4069d 451 {
screamer 0:7a64fbb4069d 452 struct tcp_pcb *pcb;
screamer 0:7a64fbb4069d 453 #ifndef TCP_LOCAL_PORT_RANGE_START
screamer 0:7a64fbb4069d 454 #define TCP_LOCAL_PORT_RANGE_START 4096
screamer 0:7a64fbb4069d 455 #define TCP_LOCAL_PORT_RANGE_END 0x7fff
screamer 0:7a64fbb4069d 456 #endif
screamer 0:7a64fbb4069d 457 static u16_t port = TCP_LOCAL_PORT_RANGE_START;
screamer 0:7a64fbb4069d 458
screamer 0:7a64fbb4069d 459 again:
screamer 0:7a64fbb4069d 460 if (++port > TCP_LOCAL_PORT_RANGE_END) {
screamer 0:7a64fbb4069d 461 port = TCP_LOCAL_PORT_RANGE_START;
screamer 0:7a64fbb4069d 462 }
screamer 0:7a64fbb4069d 463
screamer 0:7a64fbb4069d 464 for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
screamer 0:7a64fbb4069d 465 if (pcb->local_port == port) {
screamer 0:7a64fbb4069d 466 goto again;
screamer 0:7a64fbb4069d 467 }
screamer 0:7a64fbb4069d 468 }
screamer 0:7a64fbb4069d 469 for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
screamer 0:7a64fbb4069d 470 if (pcb->local_port == port) {
screamer 0:7a64fbb4069d 471 goto again;
screamer 0:7a64fbb4069d 472 }
screamer 0:7a64fbb4069d 473 }
screamer 0:7a64fbb4069d 474 for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
screamer 0:7a64fbb4069d 475 if (pcb->local_port == port) {
screamer 0:7a64fbb4069d 476 goto again;
screamer 0:7a64fbb4069d 477 }
screamer 0:7a64fbb4069d 478 }
screamer 0:7a64fbb4069d 479 return port;
screamer 0:7a64fbb4069d 480 }
screamer 0:7a64fbb4069d 481
screamer 0:7a64fbb4069d 482 /**
screamer 0:7a64fbb4069d 483 * Connects to another host. The function given as the "connected"
screamer 0:7a64fbb4069d 484 * argument will be called when the connection has been established.
screamer 0:7a64fbb4069d 485 *
screamer 0:7a64fbb4069d 486 * @param pcb the tcp_pcb used to establish the connection
screamer 0:7a64fbb4069d 487 * @param ipaddr the remote ip address to connect to
screamer 0:7a64fbb4069d 488 * @param port the remote tcp port to connect to
screamer 0:7a64fbb4069d 489 * @param connected callback function to call when connected (or on error)
screamer 0:7a64fbb4069d 490 * @return ERR_VAL if invalid arguments are given
screamer 0:7a64fbb4069d 491 * ERR_OK if connect request has been sent
screamer 0:7a64fbb4069d 492 * other err_t values if connect request couldn't be sent
screamer 0:7a64fbb4069d 493 */
screamer 0:7a64fbb4069d 494 err_t
screamer 0:7a64fbb4069d 495 tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,
screamer 0:7a64fbb4069d 496 err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))
screamer 0:7a64fbb4069d 497 {
screamer 0:7a64fbb4069d 498 err_t ret;
screamer 0:7a64fbb4069d 499 u32_t iss;
screamer 0:7a64fbb4069d 500
screamer 0:7a64fbb4069d 501 LWIP_ERROR("tcp_connect: can only connected from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
screamer 0:7a64fbb4069d 502
screamer 0:7a64fbb4069d 503 LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));
screamer 0:7a64fbb4069d 504 if (ipaddr != NULL) {
screamer 0:7a64fbb4069d 505 pcb->remote_ip = *ipaddr;
screamer 0:7a64fbb4069d 506 } else {
screamer 0:7a64fbb4069d 507 return ERR_VAL;
screamer 0:7a64fbb4069d 508 }
screamer 0:7a64fbb4069d 509 pcb->remote_port = port;
screamer 0:7a64fbb4069d 510 if (pcb->local_port == 0) {
screamer 0:7a64fbb4069d 511 pcb->local_port = tcp_new_port();
screamer 0:7a64fbb4069d 512 }
screamer 0:7a64fbb4069d 513 iss = tcp_next_iss();
screamer 0:7a64fbb4069d 514 pcb->rcv_nxt = 0;
screamer 0:7a64fbb4069d 515 pcb->snd_nxt = iss;
screamer 0:7a64fbb4069d 516 pcb->lastack = iss - 1;
screamer 0:7a64fbb4069d 517 pcb->snd_lbb = iss - 1;
screamer 0:7a64fbb4069d 518 pcb->rcv_wnd = TCP_WND;
screamer 0:7a64fbb4069d 519 pcb->rcv_ann_wnd = TCP_WND;
screamer 0:7a64fbb4069d 520 pcb->rcv_ann_right_edge = pcb->rcv_nxt;
screamer 0:7a64fbb4069d 521 pcb->snd_wnd = TCP_WND;
screamer 0:7a64fbb4069d 522 /* As initial send MSS, we use TCP_MSS but limit it to 536.
screamer 0:7a64fbb4069d 523 The send MSS is updated when an MSS option is received. */
screamer 0:7a64fbb4069d 524 pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;
screamer 0:7a64fbb4069d 525 #if TCP_CALCULATE_EFF_SEND_MSS
screamer 0:7a64fbb4069d 526 pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr);
screamer 0:7a64fbb4069d 527 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
screamer 0:7a64fbb4069d 528 pcb->cwnd = 1;
screamer 0:7a64fbb4069d 529 pcb->ssthresh = pcb->mss * 10;
screamer 0:7a64fbb4069d 530 pcb->state = SYN_SENT;
screamer 0:7a64fbb4069d 531 #if LWIP_CALLBACK_API
screamer 0:7a64fbb4069d 532 pcb->connected = connected;
screamer 0:7a64fbb4069d 533 #endif /* LWIP_CALLBACK_API */
screamer 0:7a64fbb4069d 534 TCP_RMV(&tcp_bound_pcbs, pcb);
screamer 0:7a64fbb4069d 535 TCP_REG(&tcp_active_pcbs, pcb);
screamer 0:7a64fbb4069d 536
screamer 0:7a64fbb4069d 537 snmp_inc_tcpactiveopens();
screamer 0:7a64fbb4069d 538
screamer 0:7a64fbb4069d 539 ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, TF_SEG_OPTS_MSS
screamer 0:7a64fbb4069d 540 #if LWIP_TCP_TIMESTAMPS
screamer 0:7a64fbb4069d 541 | TF_SEG_OPTS_TS
screamer 0:7a64fbb4069d 542 #endif
screamer 0:7a64fbb4069d 543 );
screamer 0:7a64fbb4069d 544 if (ret == ERR_OK) {
screamer 0:7a64fbb4069d 545 tcp_output(pcb);
screamer 0:7a64fbb4069d 546 }
screamer 0:7a64fbb4069d 547 return ret;
screamer 0:7a64fbb4069d 548 }
screamer 0:7a64fbb4069d 549
screamer 0:7a64fbb4069d 550 /**
screamer 0:7a64fbb4069d 551 * Called every 500 ms and implements the retransmission timer and the timer that
screamer 0:7a64fbb4069d 552 * removes PCBs that have been in TIME-WAIT for enough time. It also increments
screamer 0:7a64fbb4069d 553 * various timers such as the inactivity timer in each PCB.
screamer 0:7a64fbb4069d 554 *
screamer 0:7a64fbb4069d 555 * Automatically called from tcp_tmr().
screamer 0:7a64fbb4069d 556 */
screamer 0:7a64fbb4069d 557 void
screamer 0:7a64fbb4069d 558 tcp_slowtmr(void)
screamer 0:7a64fbb4069d 559 {
screamer 0:7a64fbb4069d 560 struct tcp_pcb *pcb, *pcb2, *prev;
screamer 0:7a64fbb4069d 561 u16_t eff_wnd;
screamer 0:7a64fbb4069d 562 u8_t pcb_remove; /* flag if a PCB should be removed */
screamer 0:7a64fbb4069d 563 err_t err;
screamer 0:7a64fbb4069d 564
screamer 0:7a64fbb4069d 565 err = ERR_OK;
screamer 0:7a64fbb4069d 566
screamer 0:7a64fbb4069d 567 ++tcp_ticks;
screamer 0:7a64fbb4069d 568
screamer 0:7a64fbb4069d 569 /* Steps through all of the active PCBs. */
screamer 0:7a64fbb4069d 570 prev = NULL;
screamer 0:7a64fbb4069d 571 pcb = tcp_active_pcbs;
screamer 0:7a64fbb4069d 572 if (pcb == NULL) {
screamer 0:7a64fbb4069d 573 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));
screamer 0:7a64fbb4069d 574 }
screamer 0:7a64fbb4069d 575 while (pcb != NULL) {
screamer 0:7a64fbb4069d 576 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n"));
screamer 0:7a64fbb4069d 577 LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);
screamer 0:7a64fbb4069d 578 LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN);
screamer 0:7a64fbb4069d 579 LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);
screamer 0:7a64fbb4069d 580
screamer 0:7a64fbb4069d 581 pcb_remove = 0;
screamer 0:7a64fbb4069d 582
screamer 0:7a64fbb4069d 583 if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {
screamer 0:7a64fbb4069d 584 ++pcb_remove;
screamer 0:7a64fbb4069d 585 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n"));
screamer 0:7a64fbb4069d 586 }
screamer 0:7a64fbb4069d 587 else if (pcb->nrtx == TCP_MAXRTX) {
screamer 0:7a64fbb4069d 588 ++pcb_remove;
screamer 0:7a64fbb4069d 589 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));
screamer 0:7a64fbb4069d 590 } else {
screamer 0:7a64fbb4069d 591 if (pcb->persist_backoff > 0) {
screamer 0:7a64fbb4069d 592 /* If snd_wnd is zero, use persist timer to send 1 byte probes
screamer 0:7a64fbb4069d 593 * instead of using the standard retransmission mechanism. */
screamer 0:7a64fbb4069d 594 pcb->persist_cnt++;
screamer 0:7a64fbb4069d 595 if (pcb->persist_cnt >= tcp_persist_backoff[pcb->persist_backoff-1]) {
screamer 0:7a64fbb4069d 596 pcb->persist_cnt = 0;
screamer 0:7a64fbb4069d 597 if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) {
screamer 0:7a64fbb4069d 598 pcb->persist_backoff++;
screamer 0:7a64fbb4069d 599 }
screamer 0:7a64fbb4069d 600 tcp_zero_window_probe(pcb);
screamer 0:7a64fbb4069d 601 }
screamer 0:7a64fbb4069d 602 } else {
screamer 0:7a64fbb4069d 603 /* Increase the retransmission timer if it is running */
screamer 0:7a64fbb4069d 604 if(pcb->rtime >= 0)
screamer 0:7a64fbb4069d 605 ++pcb->rtime;
screamer 0:7a64fbb4069d 606
screamer 0:7a64fbb4069d 607 if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {
screamer 0:7a64fbb4069d 608 /* Time for a retransmission. */
screamer 0:7a64fbb4069d 609 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F
screamer 0:7a64fbb4069d 610 " pcb->rto %"S16_F"\n",
screamer 0:7a64fbb4069d 611 pcb->rtime, pcb->rto));
screamer 0:7a64fbb4069d 612
screamer 0:7a64fbb4069d 613 /* Double retransmission time-out unless we are trying to
screamer 0:7a64fbb4069d 614 * connect to somebody (i.e., we are in SYN_SENT). */
screamer 0:7a64fbb4069d 615 if (pcb->state != SYN_SENT) {
screamer 0:7a64fbb4069d 616 pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];
screamer 0:7a64fbb4069d 617 }
screamer 0:7a64fbb4069d 618
screamer 0:7a64fbb4069d 619 /* Reset the retransmission timer. */
screamer 0:7a64fbb4069d 620 pcb->rtime = 0;
screamer 0:7a64fbb4069d 621
screamer 0:7a64fbb4069d 622 /* Reduce congestion window and ssthresh. */
screamer 0:7a64fbb4069d 623 eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);
screamer 0:7a64fbb4069d 624 pcb->ssthresh = eff_wnd >> 1;
screamer 0:7a64fbb4069d 625 if (pcb->ssthresh < pcb->mss) {
screamer 0:7a64fbb4069d 626 pcb->ssthresh = pcb->mss * 2;
screamer 0:7a64fbb4069d 627 }
screamer 0:7a64fbb4069d 628 pcb->cwnd = pcb->mss;
screamer 0:7a64fbb4069d 629 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F
screamer 0:7a64fbb4069d 630 " ssthresh %"U16_F"\n",
screamer 0:7a64fbb4069d 631 pcb->cwnd, pcb->ssthresh));
screamer 0:7a64fbb4069d 632
screamer 0:7a64fbb4069d 633 /* The following needs to be called AFTER cwnd is set to one
screamer 0:7a64fbb4069d 634 mss - STJ */
screamer 0:7a64fbb4069d 635 tcp_rexmit_rto(pcb);
screamer 0:7a64fbb4069d 636 }
screamer 0:7a64fbb4069d 637 }
screamer 0:7a64fbb4069d 638 }
screamer 0:7a64fbb4069d 639 /* Check if this PCB has stayed too long in FIN-WAIT-2 */
screamer 0:7a64fbb4069d 640 if (pcb->state == FIN_WAIT_2) {
screamer 0:7a64fbb4069d 641 if ((u32_t)(tcp_ticks - pcb->tmr) >
screamer 0:7a64fbb4069d 642 TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {
screamer 0:7a64fbb4069d 643 ++pcb_remove;
screamer 0:7a64fbb4069d 644 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));
screamer 0:7a64fbb4069d 645 }
screamer 0:7a64fbb4069d 646 }
screamer 0:7a64fbb4069d 647
screamer 0:7a64fbb4069d 648 /* Check if KEEPALIVE should be sent */
screamer 0:7a64fbb4069d 649 if((pcb->so_options & SOF_KEEPALIVE) &&
screamer 0:7a64fbb4069d 650 ((pcb->state == ESTABLISHED) ||
screamer 0:7a64fbb4069d 651 (pcb->state == CLOSE_WAIT))) {
screamer 0:7a64fbb4069d 652 #if LWIP_TCP_KEEPALIVE
screamer 0:7a64fbb4069d 653 if((u32_t)(tcp_ticks - pcb->tmr) >
screamer 0:7a64fbb4069d 654 (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl))
screamer 0:7a64fbb4069d 655 / TCP_SLOW_INTERVAL)
screamer 0:7a64fbb4069d 656 #else
screamer 0:7a64fbb4069d 657 if((u32_t)(tcp_ticks - pcb->tmr) >
screamer 0:7a64fbb4069d 658 (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)
screamer 0:7a64fbb4069d 659 #endif /* LWIP_TCP_KEEPALIVE */
screamer 0:7a64fbb4069d 660 {
screamer 0:7a64fbb4069d 661 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",
screamer 0:7a64fbb4069d 662 ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
screamer 0:7a64fbb4069d 663 ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));
screamer 0:7a64fbb4069d 664
screamer 0:7a64fbb4069d 665 tcp_abort(pcb);
screamer 0:7a64fbb4069d 666 }
screamer 0:7a64fbb4069d 667 #if LWIP_TCP_KEEPALIVE
screamer 0:7a64fbb4069d 668 else if((u32_t)(tcp_ticks - pcb->tmr) >
screamer 0:7a64fbb4069d 669 (pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl)
screamer 0:7a64fbb4069d 670 / TCP_SLOW_INTERVAL)
screamer 0:7a64fbb4069d 671 #else
screamer 0:7a64fbb4069d 672 else if((u32_t)(tcp_ticks - pcb->tmr) >
screamer 0:7a64fbb4069d 673 (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT)
screamer 0:7a64fbb4069d 674 / TCP_SLOW_INTERVAL)
screamer 0:7a64fbb4069d 675 #endif /* LWIP_TCP_KEEPALIVE */
screamer 0:7a64fbb4069d 676 {
screamer 0:7a64fbb4069d 677 tcp_keepalive(pcb);
screamer 0:7a64fbb4069d 678 pcb->keep_cnt_sent++;
screamer 0:7a64fbb4069d 679 }
screamer 0:7a64fbb4069d 680 }
screamer 0:7a64fbb4069d 681
screamer 0:7a64fbb4069d 682 /* If this PCB has queued out of sequence data, but has been
screamer 0:7a64fbb4069d 683 inactive for too long, will drop the data (it will eventually
screamer 0:7a64fbb4069d 684 be retransmitted). */
screamer 0:7a64fbb4069d 685 #if TCP_QUEUE_OOSEQ
screamer 0:7a64fbb4069d 686 if (pcb->ooseq != NULL &&
screamer 0:7a64fbb4069d 687 (u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) {
screamer 0:7a64fbb4069d 688 tcp_segs_free(pcb->ooseq);
screamer 0:7a64fbb4069d 689 pcb->ooseq = NULL;
screamer 0:7a64fbb4069d 690 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n"));
screamer 0:7a64fbb4069d 691 }
screamer 0:7a64fbb4069d 692 #endif /* TCP_QUEUE_OOSEQ */
screamer 0:7a64fbb4069d 693
screamer 0:7a64fbb4069d 694 /* Check if this PCB has stayed too long in SYN-RCVD */
screamer 0:7a64fbb4069d 695 if (pcb->state == SYN_RCVD) {
screamer 0:7a64fbb4069d 696 if ((u32_t)(tcp_ticks - pcb->tmr) >
screamer 0:7a64fbb4069d 697 TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) {
screamer 0:7a64fbb4069d 698 ++pcb_remove;
screamer 0:7a64fbb4069d 699 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n"));
screamer 0:7a64fbb4069d 700 }
screamer 0:7a64fbb4069d 701 }
screamer 0:7a64fbb4069d 702
screamer 0:7a64fbb4069d 703 /* Check if this PCB has stayed too long in LAST-ACK */
screamer 0:7a64fbb4069d 704 if (pcb->state == LAST_ACK) {
screamer 0:7a64fbb4069d 705 if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {
screamer 0:7a64fbb4069d 706 ++pcb_remove;
screamer 0:7a64fbb4069d 707 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n"));
screamer 0:7a64fbb4069d 708 }
screamer 0:7a64fbb4069d 709 }
screamer 0:7a64fbb4069d 710
screamer 0:7a64fbb4069d 711 /* If the PCB should be removed, do it. */
screamer 0:7a64fbb4069d 712 if (pcb_remove) {
screamer 0:7a64fbb4069d 713 tcp_pcb_purge(pcb);
screamer 0:7a64fbb4069d 714 /* Remove PCB from tcp_active_pcbs list. */
screamer 0:7a64fbb4069d 715 if (prev != NULL) {
screamer 0:7a64fbb4069d 716 LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);
screamer 0:7a64fbb4069d 717 prev->next = pcb->next;
screamer 0:7a64fbb4069d 718 } else {
screamer 0:7a64fbb4069d 719 /* This PCB was the first. */
screamer 0:7a64fbb4069d 720 LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb);
screamer 0:7a64fbb4069d 721 tcp_active_pcbs = pcb->next;
screamer 0:7a64fbb4069d 722 }
screamer 0:7a64fbb4069d 723
screamer 0:7a64fbb4069d 724 TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);
screamer 0:7a64fbb4069d 725
screamer 0:7a64fbb4069d 726 pcb2 = pcb->next;
screamer 0:7a64fbb4069d 727 memp_free(MEMP_TCP_PCB, pcb);
screamer 0:7a64fbb4069d 728 pcb = pcb2;
screamer 0:7a64fbb4069d 729 } else {
screamer 0:7a64fbb4069d 730
screamer 0:7a64fbb4069d 731 /* We check if we should poll the connection. */
screamer 0:7a64fbb4069d 732 ++pcb->polltmr;
screamer 0:7a64fbb4069d 733 if (pcb->polltmr >= pcb->pollinterval) {
screamer 0:7a64fbb4069d 734 pcb->polltmr = 0;
screamer 0:7a64fbb4069d 735 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));
screamer 0:7a64fbb4069d 736 TCP_EVENT_POLL(pcb, err);
screamer 0:7a64fbb4069d 737 if (err == ERR_OK) {
screamer 0:7a64fbb4069d 738 tcp_output(pcb);
screamer 0:7a64fbb4069d 739 }
screamer 0:7a64fbb4069d 740 }
screamer 0:7a64fbb4069d 741
screamer 0:7a64fbb4069d 742 prev = pcb;
screamer 0:7a64fbb4069d 743 pcb = pcb->next;
screamer 0:7a64fbb4069d 744 }
screamer 0:7a64fbb4069d 745 }
screamer 0:7a64fbb4069d 746
screamer 0:7a64fbb4069d 747
screamer 0:7a64fbb4069d 748 /* Steps through all of the TIME-WAIT PCBs. */
screamer 0:7a64fbb4069d 749 prev = NULL;
screamer 0:7a64fbb4069d 750 pcb = tcp_tw_pcbs;
screamer 0:7a64fbb4069d 751 while (pcb != NULL) {
screamer 0:7a64fbb4069d 752 LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
screamer 0:7a64fbb4069d 753 pcb_remove = 0;
screamer 0:7a64fbb4069d 754
screamer 0:7a64fbb4069d 755 /* Check if this PCB has stayed long enough in TIME-WAIT */
screamer 0:7a64fbb4069d 756 if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {
screamer 0:7a64fbb4069d 757 ++pcb_remove;
screamer 0:7a64fbb4069d 758 }
screamer 0:7a64fbb4069d 759
screamer 0:7a64fbb4069d 760
screamer 0:7a64fbb4069d 761
screamer 0:7a64fbb4069d 762 /* If the PCB should be removed, do it. */
screamer 0:7a64fbb4069d 763 if (pcb_remove) {
screamer 0:7a64fbb4069d 764 tcp_pcb_purge(pcb);
screamer 0:7a64fbb4069d 765 /* Remove PCB from tcp_tw_pcbs list. */
screamer 0:7a64fbb4069d 766 if (prev != NULL) {
screamer 0:7a64fbb4069d 767 LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);
screamer 0:7a64fbb4069d 768 prev->next = pcb->next;
screamer 0:7a64fbb4069d 769 } else {
screamer 0:7a64fbb4069d 770 /* This PCB was the first. */
screamer 0:7a64fbb4069d 771 LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);
screamer 0:7a64fbb4069d 772 tcp_tw_pcbs = pcb->next;
screamer 0:7a64fbb4069d 773 }
screamer 0:7a64fbb4069d 774 pcb2 = pcb->next;
screamer 0:7a64fbb4069d 775 memp_free(MEMP_TCP_PCB, pcb);
screamer 0:7a64fbb4069d 776 pcb = pcb2;
screamer 0:7a64fbb4069d 777 } else {
screamer 0:7a64fbb4069d 778 prev = pcb;
screamer 0:7a64fbb4069d 779 pcb = pcb->next;
screamer 0:7a64fbb4069d 780 }
screamer 0:7a64fbb4069d 781 }
screamer 0:7a64fbb4069d 782 }
screamer 0:7a64fbb4069d 783
screamer 0:7a64fbb4069d 784 /**
screamer 0:7a64fbb4069d 785 * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously
screamer 0:7a64fbb4069d 786 * "refused" by upper layer (application) and sends delayed ACKs.
screamer 0:7a64fbb4069d 787 *
screamer 0:7a64fbb4069d 788 * Automatically called from tcp_tmr().
screamer 0:7a64fbb4069d 789 */
screamer 0:7a64fbb4069d 790 void
screamer 0:7a64fbb4069d 791 tcp_fasttmr(void)
screamer 0:7a64fbb4069d 792 {
screamer 0:7a64fbb4069d 793 struct tcp_pcb *pcb;
screamer 0:7a64fbb4069d 794
screamer 0:7a64fbb4069d 795 for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
screamer 0:7a64fbb4069d 796 /* If there is data which was previously "refused" by upper layer */
screamer 0:7a64fbb4069d 797 if (pcb->refused_data != NULL) {
screamer 0:7a64fbb4069d 798 /* Notify again application with data previously received. */
screamer 0:7a64fbb4069d 799 err_t err;
screamer 0:7a64fbb4069d 800 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n"));
screamer 0:7a64fbb4069d 801 TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
screamer 0:7a64fbb4069d 802 if (err == ERR_OK) {
screamer 0:7a64fbb4069d 803 pcb->refused_data = NULL;
screamer 0:7a64fbb4069d 804 }
screamer 0:7a64fbb4069d 805 }
screamer 0:7a64fbb4069d 806
screamer 0:7a64fbb4069d 807 /* send delayed ACKs */
screamer 0:7a64fbb4069d 808 if (pcb->flags & TF_ACK_DELAY) {
screamer 0:7a64fbb4069d 809 LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));
screamer 0:7a64fbb4069d 810 tcp_ack_now(pcb);
screamer 0:7a64fbb4069d 811 pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
screamer 0:7a64fbb4069d 812 }
screamer 0:7a64fbb4069d 813 }
screamer 0:7a64fbb4069d 814 }
screamer 0:7a64fbb4069d 815
screamer 0:7a64fbb4069d 816 /**
screamer 0:7a64fbb4069d 817 * Deallocates a list of TCP segments (tcp_seg structures).
screamer 0:7a64fbb4069d 818 *
screamer 0:7a64fbb4069d 819 * @param seg tcp_seg list of TCP segments to free
screamer 0:7a64fbb4069d 820 * @return the number of pbufs that were deallocated
screamer 0:7a64fbb4069d 821 */
screamer 0:7a64fbb4069d 822 u8_t
screamer 0:7a64fbb4069d 823 tcp_segs_free(struct tcp_seg *seg)
screamer 0:7a64fbb4069d 824 {
screamer 0:7a64fbb4069d 825 u8_t count = 0;
screamer 0:7a64fbb4069d 826 struct tcp_seg *next;
screamer 0:7a64fbb4069d 827 while (seg != NULL) {
screamer 0:7a64fbb4069d 828 next = seg->next;
screamer 0:7a64fbb4069d 829 count += tcp_seg_free(seg);
screamer 0:7a64fbb4069d 830 seg = next;
screamer 0:7a64fbb4069d 831 }
screamer 0:7a64fbb4069d 832 return count;
screamer 0:7a64fbb4069d 833 }
screamer 0:7a64fbb4069d 834
screamer 0:7a64fbb4069d 835 /**
screamer 0:7a64fbb4069d 836 * Frees a TCP segment (tcp_seg structure).
screamer 0:7a64fbb4069d 837 *
screamer 0:7a64fbb4069d 838 * @param seg single tcp_seg to free
screamer 0:7a64fbb4069d 839 * @return the number of pbufs that were deallocated
screamer 0:7a64fbb4069d 840 */
screamer 0:7a64fbb4069d 841 u8_t
screamer 0:7a64fbb4069d 842 tcp_seg_free(struct tcp_seg *seg)
screamer 0:7a64fbb4069d 843 {
screamer 0:7a64fbb4069d 844 u8_t count = 0;
screamer 0:7a64fbb4069d 845
screamer 0:7a64fbb4069d 846 if (seg != NULL) {
screamer 0:7a64fbb4069d 847 if (seg->p != NULL) {
screamer 0:7a64fbb4069d 848 count = pbuf_free(seg->p);
screamer 0:7a64fbb4069d 849 #if TCP_DEBUG
screamer 0:7a64fbb4069d 850 seg->p = NULL;
screamer 0:7a64fbb4069d 851 #endif /* TCP_DEBUG */
screamer 0:7a64fbb4069d 852 }
screamer 0:7a64fbb4069d 853 memp_free(MEMP_TCP_SEG, seg);
screamer 0:7a64fbb4069d 854 }
screamer 0:7a64fbb4069d 855 return count;
screamer 0:7a64fbb4069d 856 }
screamer 0:7a64fbb4069d 857
screamer 0:7a64fbb4069d 858 /**
screamer 0:7a64fbb4069d 859 * Sets the priority of a connection.
screamer 0:7a64fbb4069d 860 *
screamer 0:7a64fbb4069d 861 * @param pcb the tcp_pcb to manipulate
screamer 0:7a64fbb4069d 862 * @param prio new priority
screamer 0:7a64fbb4069d 863 */
screamer 0:7a64fbb4069d 864 void
screamer 0:7a64fbb4069d 865 tcp_setprio(struct tcp_pcb *pcb, u8_t prio)
screamer 0:7a64fbb4069d 866 {
screamer 0:7a64fbb4069d 867 pcb->prio = prio;
screamer 0:7a64fbb4069d 868 }
screamer 0:7a64fbb4069d 869 #if TCP_QUEUE_OOSEQ
screamer 0:7a64fbb4069d 870
screamer 0:7a64fbb4069d 871 /**
screamer 0:7a64fbb4069d 872 * Returns a copy of the given TCP segment.
screamer 0:7a64fbb4069d 873 * The pbuf and data are not copied, only the pointers
screamer 0:7a64fbb4069d 874 *
screamer 0:7a64fbb4069d 875 * @param seg the old tcp_seg
screamer 0:7a64fbb4069d 876 * @return a copy of seg
screamer 0:7a64fbb4069d 877 */
screamer 0:7a64fbb4069d 878 struct tcp_seg *
screamer 0:7a64fbb4069d 879 tcp_seg_copy(struct tcp_seg *seg)
screamer 0:7a64fbb4069d 880 {
screamer 0:7a64fbb4069d 881 struct tcp_seg *cseg;
screamer 0:7a64fbb4069d 882
screamer 0:7a64fbb4069d 883 cseg = (struct tcp_seg *)(memp_malloc(MEMP_TCP_SEG)); // static_cast<struct tcp_seg *>(x)
screamer 0:7a64fbb4069d 884 if (cseg == NULL) {
screamer 0:7a64fbb4069d 885 return NULL;
screamer 0:7a64fbb4069d 886 }
screamer 0:7a64fbb4069d 887 SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg));
screamer 0:7a64fbb4069d 888 pbuf_ref(cseg->p);
screamer 0:7a64fbb4069d 889 return cseg;
screamer 0:7a64fbb4069d 890 }
screamer 0:7a64fbb4069d 891 #endif
screamer 0:7a64fbb4069d 892
screamer 0:7a64fbb4069d 893 #if LWIP_CALLBACK_API
screamer 0:7a64fbb4069d 894 /**
screamer 0:7a64fbb4069d 895 * Default receive callback that is called if the user didn't register
screamer 0:7a64fbb4069d 896 * a recv callback for the pcb.
screamer 0:7a64fbb4069d 897 */
screamer 0:7a64fbb4069d 898 static err_t
screamer 0:7a64fbb4069d 899 tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
screamer 0:7a64fbb4069d 900 {
screamer 0:7a64fbb4069d 901 arg = arg;
screamer 0:7a64fbb4069d 902 if (p != NULL) {
screamer 0:7a64fbb4069d 903 pbuf_free(p);
screamer 0:7a64fbb4069d 904 } else if (err == ERR_OK) {
screamer 0:7a64fbb4069d 905 return tcp_close(pcb);
screamer 0:7a64fbb4069d 906 }
screamer 0:7a64fbb4069d 907 return ERR_OK;
screamer 0:7a64fbb4069d 908 }
screamer 0:7a64fbb4069d 909 #endif /* LWIP_CALLBACK_API */
screamer 0:7a64fbb4069d 910
screamer 0:7a64fbb4069d 911 /**
screamer 0:7a64fbb4069d 912 * Kills the oldest active connection that has lower priority than prio.
screamer 0:7a64fbb4069d 913 *
screamer 0:7a64fbb4069d 914 * @param prio minimum priority
screamer 0:7a64fbb4069d 915 */
screamer 0:7a64fbb4069d 916 static void
screamer 0:7a64fbb4069d 917 tcp_kill_prio(u8_t prio)
screamer 0:7a64fbb4069d 918 {
screamer 0:7a64fbb4069d 919 struct tcp_pcb *pcb, *inactive;
screamer 0:7a64fbb4069d 920 u32_t inactivity;
screamer 0:7a64fbb4069d 921 u8_t mprio;
screamer 0:7a64fbb4069d 922
screamer 0:7a64fbb4069d 923
screamer 0:7a64fbb4069d 924 mprio = TCP_PRIO_MAX;
screamer 0:7a64fbb4069d 925
screamer 0:7a64fbb4069d 926 /* We kill the oldest active connection that has lower priority than prio. */
screamer 0:7a64fbb4069d 927 inactivity = 0;
screamer 0:7a64fbb4069d 928 inactive = NULL;
screamer 0:7a64fbb4069d 929 for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
screamer 0:7a64fbb4069d 930 if (pcb->prio <= prio &&
screamer 0:7a64fbb4069d 931 pcb->prio <= mprio &&
screamer 0:7a64fbb4069d 932 (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {
screamer 0:7a64fbb4069d 933 inactivity = tcp_ticks - pcb->tmr;
screamer 0:7a64fbb4069d 934 inactive = pcb;
screamer 0:7a64fbb4069d 935 mprio = pcb->prio;
screamer 0:7a64fbb4069d 936 }
screamer 0:7a64fbb4069d 937 }
screamer 0:7a64fbb4069d 938 if (inactive != NULL) {
screamer 0:7a64fbb4069d 939 LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n",
screamer 0:7a64fbb4069d 940 (void *)inactive, inactivity));
screamer 0:7a64fbb4069d 941 tcp_abort(inactive);
screamer 0:7a64fbb4069d 942 }
screamer 0:7a64fbb4069d 943 }
screamer 0:7a64fbb4069d 944
screamer 0:7a64fbb4069d 945 /**
screamer 0:7a64fbb4069d 946 * Kills the oldest connection that is in TIME_WAIT state.
screamer 0:7a64fbb4069d 947 * Called from tcp_alloc() if no more connections are available.
screamer 0:7a64fbb4069d 948 */
screamer 0:7a64fbb4069d 949 static void
screamer 0:7a64fbb4069d 950 tcp_kill_timewait(void)
screamer 0:7a64fbb4069d 951 {
screamer 0:7a64fbb4069d 952 struct tcp_pcb *pcb, *inactive;
screamer 0:7a64fbb4069d 953 u32_t inactivity;
screamer 0:7a64fbb4069d 954
screamer 0:7a64fbb4069d 955 inactivity = 0;
screamer 0:7a64fbb4069d 956 inactive = NULL;
screamer 0:7a64fbb4069d 957 /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */
screamer 0:7a64fbb4069d 958 for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
screamer 0:7a64fbb4069d 959 if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {
screamer 0:7a64fbb4069d 960 inactivity = tcp_ticks - pcb->tmr;
screamer 0:7a64fbb4069d 961 inactive = pcb;
screamer 0:7a64fbb4069d 962 }
screamer 0:7a64fbb4069d 963 }
screamer 0:7a64fbb4069d 964 if (inactive != NULL) {
screamer 0:7a64fbb4069d 965 LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n",
screamer 0:7a64fbb4069d 966 (void *)inactive, inactivity));
screamer 0:7a64fbb4069d 967 tcp_abort(inactive);
screamer 0:7a64fbb4069d 968 }
screamer 0:7a64fbb4069d 969 }
screamer 0:7a64fbb4069d 970
screamer 0:7a64fbb4069d 971 /**
screamer 0:7a64fbb4069d 972 * Allocate a new tcp_pcb structure.
screamer 0:7a64fbb4069d 973 *
screamer 0:7a64fbb4069d 974 * @param prio priority for the new pcb
screamer 0:7a64fbb4069d 975 * @return a new tcp_pcb that initially is in state CLOSED
screamer 0:7a64fbb4069d 976 */
screamer 0:7a64fbb4069d 977 struct tcp_pcb *
screamer 0:7a64fbb4069d 978 tcp_alloc(u8_t prio)
screamer 0:7a64fbb4069d 979 {
screamer 0:7a64fbb4069d 980 struct tcp_pcb *pcb;
screamer 0:7a64fbb4069d 981 u32_t iss;
screamer 0:7a64fbb4069d 982
screamer 0:7a64fbb4069d 983 pcb = (struct tcp_pcb *)(memp_malloc(MEMP_TCP_PCB)); // static_cast<struct tcp_pcb *>(x)
screamer 0:7a64fbb4069d 984 if (pcb == NULL) {
screamer 0:7a64fbb4069d 985 /* Try killing oldest connection in TIME-WAIT. */
screamer 0:7a64fbb4069d 986 LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n"));
screamer 0:7a64fbb4069d 987 tcp_kill_timewait();
screamer 0:7a64fbb4069d 988 /* Try to allocate a tcp_pcb again. */
screamer 0:7a64fbb4069d 989 pcb = (struct tcp_pcb *)(memp_malloc(MEMP_TCP_PCB)); // static_cast<struct tcp_pcb *>(x)
screamer 0:7a64fbb4069d 990 if (pcb == NULL) {
screamer 0:7a64fbb4069d 991 /* Try killing active connections with lower priority than the new one. */
screamer 0:7a64fbb4069d 992 tcp_kill_prio(prio);
screamer 0:7a64fbb4069d 993 /* Try to allocate a tcp_pcb again. */
screamer 0:7a64fbb4069d 994 pcb = (struct tcp_pcb *)(memp_malloc(MEMP_TCP_PCB)); // static_cast<struct tcp_pcb *>(x)
screamer 0:7a64fbb4069d 995 }
screamer 0:7a64fbb4069d 996 }
screamer 0:7a64fbb4069d 997 if (pcb != NULL) {
screamer 0:7a64fbb4069d 998 memset(pcb, 0, sizeof(struct tcp_pcb));
screamer 0:7a64fbb4069d 999 pcb->prio = TCP_PRIO_NORMAL;
screamer 0:7a64fbb4069d 1000 pcb->snd_buf = TCP_SND_BUF;
screamer 0:7a64fbb4069d 1001 pcb->snd_queuelen = 0;
screamer 0:7a64fbb4069d 1002 pcb->rcv_wnd = TCP_WND;
screamer 0:7a64fbb4069d 1003 pcb->rcv_ann_wnd = TCP_WND;
screamer 0:7a64fbb4069d 1004 pcb->tos = 0;
screamer 0:7a64fbb4069d 1005 pcb->ttl = TCP_TTL;
screamer 0:7a64fbb4069d 1006 /* As initial send MSS, we use TCP_MSS but limit it to 536.
screamer 0:7a64fbb4069d 1007 The send MSS is updated when an MSS option is received. */
screamer 0:7a64fbb4069d 1008 pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;
screamer 0:7a64fbb4069d 1009 pcb->rto = 3000 / TCP_SLOW_INTERVAL;
screamer 0:7a64fbb4069d 1010 pcb->sa = 0;
screamer 0:7a64fbb4069d 1011 pcb->sv = 3000 / TCP_SLOW_INTERVAL;
screamer 0:7a64fbb4069d 1012 pcb->rtime = -1;
screamer 0:7a64fbb4069d 1013 pcb->cwnd = 1;
screamer 0:7a64fbb4069d 1014 iss = tcp_next_iss();
screamer 0:7a64fbb4069d 1015 pcb->snd_wl2 = iss;
screamer 0:7a64fbb4069d 1016 pcb->snd_nxt = iss;
screamer 0:7a64fbb4069d 1017 pcb->snd_max = iss;
screamer 0:7a64fbb4069d 1018 pcb->lastack = iss;
screamer 0:7a64fbb4069d 1019 pcb->snd_lbb = iss;
screamer 0:7a64fbb4069d 1020 pcb->tmr = tcp_ticks;
screamer 0:7a64fbb4069d 1021
screamer 0:7a64fbb4069d 1022 pcb->polltmr = 0;
screamer 0:7a64fbb4069d 1023
screamer 0:7a64fbb4069d 1024 #if LWIP_CALLBACK_API
screamer 0:7a64fbb4069d 1025 pcb->recv = tcp_recv_null;
screamer 0:7a64fbb4069d 1026 #endif /* LWIP_CALLBACK_API */
screamer 0:7a64fbb4069d 1027
screamer 0:7a64fbb4069d 1028 /* Init KEEPALIVE timer */
screamer 0:7a64fbb4069d 1029 pcb->keep_idle = TCP_KEEPIDLE_DEFAULT;
screamer 0:7a64fbb4069d 1030
screamer 0:7a64fbb4069d 1031 #if LWIP_TCP_KEEPALIVE
screamer 0:7a64fbb4069d 1032 pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT;
screamer 0:7a64fbb4069d 1033 pcb->keep_cnt = TCP_KEEPCNT_DEFAULT;
screamer 0:7a64fbb4069d 1034 #endif /* LWIP_TCP_KEEPALIVE */
screamer 0:7a64fbb4069d 1035
screamer 0:7a64fbb4069d 1036 pcb->keep_cnt_sent = 0;
screamer 0:7a64fbb4069d 1037 }
screamer 0:7a64fbb4069d 1038 return pcb;
screamer 0:7a64fbb4069d 1039 }
screamer 0:7a64fbb4069d 1040
screamer 0:7a64fbb4069d 1041 /**
screamer 0:7a64fbb4069d 1042 * Creates a new TCP protocol control block but doesn't place it on
screamer 0:7a64fbb4069d 1043 * any of the TCP PCB lists.
screamer 0:7a64fbb4069d 1044 * The pcb is not put on any list until binding using tcp_bind().
screamer 0:7a64fbb4069d 1045 *
screamer 0:7a64fbb4069d 1046 * @internal: Maybe there should be a idle TCP PCB list where these
screamer 0:7a64fbb4069d 1047 * PCBs are put on. Port reservation using tcp_bind() is implemented but
screamer 0:7a64fbb4069d 1048 * allocated pcbs that are not bound can't be killed automatically if wanting
screamer 0:7a64fbb4069d 1049 * to allocate a pcb with higher prio (@see tcp_kill_prio())
screamer 0:7a64fbb4069d 1050 *
screamer 0:7a64fbb4069d 1051 * @return a new tcp_pcb that initially is in state CLOSED
screamer 0:7a64fbb4069d 1052 */
screamer 0:7a64fbb4069d 1053 struct tcp_pcb *
screamer 0:7a64fbb4069d 1054 tcp_new(void)
screamer 0:7a64fbb4069d 1055 {
screamer 0:7a64fbb4069d 1056 return tcp_alloc(TCP_PRIO_NORMAL);
screamer 0:7a64fbb4069d 1057 }
screamer 0:7a64fbb4069d 1058
screamer 0:7a64fbb4069d 1059 /**
screamer 0:7a64fbb4069d 1060 * Used to specify the argument that should be passed callback
screamer 0:7a64fbb4069d 1061 * functions.
screamer 0:7a64fbb4069d 1062 *
screamer 0:7a64fbb4069d 1063 * @param pcb tcp_pcb to set the callback argument
screamer 0:7a64fbb4069d 1064 * @param arg void pointer argument to pass to callback functions
screamer 0:7a64fbb4069d 1065 */
screamer 0:7a64fbb4069d 1066 void
screamer 0:7a64fbb4069d 1067 tcp_arg(struct tcp_pcb *pcb, void *arg)
screamer 0:7a64fbb4069d 1068 {
screamer 0:7a64fbb4069d 1069 pcb->callback_arg = arg;
screamer 0:7a64fbb4069d 1070 }
screamer 0:7a64fbb4069d 1071 #if LWIP_CALLBACK_API
screamer 0:7a64fbb4069d 1072
screamer 0:7a64fbb4069d 1073 /**
screamer 0:7a64fbb4069d 1074 * Used to specify the function that should be called when a TCP
screamer 0:7a64fbb4069d 1075 * connection receives data.
screamer 0:7a64fbb4069d 1076 *
screamer 0:7a64fbb4069d 1077 * @param pcb tcp_pcb to set the recv callback
screamer 0:7a64fbb4069d 1078 * @param recv callback function to call for this pcb when data is received
screamer 0:7a64fbb4069d 1079 */
screamer 0:7a64fbb4069d 1080 void
screamer 0:7a64fbb4069d 1081 tcp_recv(struct tcp_pcb *pcb,
screamer 0:7a64fbb4069d 1082 err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err))
screamer 0:7a64fbb4069d 1083 {
screamer 0:7a64fbb4069d 1084 pcb->recv = recv;
screamer 0:7a64fbb4069d 1085 }
screamer 0:7a64fbb4069d 1086
screamer 0:7a64fbb4069d 1087 /**
screamer 0:7a64fbb4069d 1088 * Used to specify the function that should be called when TCP data
screamer 0:7a64fbb4069d 1089 * has been successfully delivered to the remote host.
screamer 0:7a64fbb4069d 1090 *
screamer 0:7a64fbb4069d 1091 * @param pcb tcp_pcb to set the sent callback
screamer 0:7a64fbb4069d 1092 * @param sent callback function to call for this pcb when data is successfully sent
screamer 0:7a64fbb4069d 1093 */
screamer 0:7a64fbb4069d 1094 void
screamer 0:7a64fbb4069d 1095 tcp_sent(struct tcp_pcb *pcb,
screamer 0:7a64fbb4069d 1096 err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len))
screamer 0:7a64fbb4069d 1097 {
screamer 0:7a64fbb4069d 1098 pcb->sent = sent;
screamer 0:7a64fbb4069d 1099 }
screamer 0:7a64fbb4069d 1100
screamer 0:7a64fbb4069d 1101 /**
screamer 0:7a64fbb4069d 1102 * Used to specify the function that should be called when a fatal error
screamer 0:7a64fbb4069d 1103 * has occured on the connection.
screamer 0:7a64fbb4069d 1104 *
screamer 0:7a64fbb4069d 1105 * @param pcb tcp_pcb to set the err callback
screamer 0:7a64fbb4069d 1106 * @param errf callback function to call for this pcb when a fatal error
screamer 0:7a64fbb4069d 1107 * has occured on the connection
screamer 0:7a64fbb4069d 1108 */
screamer 0:7a64fbb4069d 1109 void
screamer 0:7a64fbb4069d 1110 tcp_err(struct tcp_pcb *pcb,
screamer 0:7a64fbb4069d 1111 void (* errf)(void *arg, err_t err))
screamer 0:7a64fbb4069d 1112 {
screamer 0:7a64fbb4069d 1113 pcb->errf = errf;
screamer 0:7a64fbb4069d 1114 }
screamer 0:7a64fbb4069d 1115
screamer 0:7a64fbb4069d 1116 /**
screamer 0:7a64fbb4069d 1117 * Used for specifying the function that should be called when a
screamer 0:7a64fbb4069d 1118 * LISTENing connection has been connected to another host.
screamer 0:7a64fbb4069d 1119 *
screamer 0:7a64fbb4069d 1120 * @param pcb tcp_pcb to set the accept callback
screamer 0:7a64fbb4069d 1121 * @param accept callback function to call for this pcb when LISTENing
screamer 0:7a64fbb4069d 1122 * connection has been connected to another host
screamer 0:7a64fbb4069d 1123 */
screamer 0:7a64fbb4069d 1124 void
screamer 0:7a64fbb4069d 1125 tcp_accept(struct tcp_pcb *pcb,
screamer 0:7a64fbb4069d 1126 err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))
screamer 0:7a64fbb4069d 1127 {
screamer 0:7a64fbb4069d 1128 pcb->accept = accept;
screamer 0:7a64fbb4069d 1129 }
screamer 0:7a64fbb4069d 1130 #endif /* LWIP_CALLBACK_API */
screamer 0:7a64fbb4069d 1131
screamer 0:7a64fbb4069d 1132
screamer 0:7a64fbb4069d 1133 /**
screamer 0:7a64fbb4069d 1134 * Used to specify the function that should be called periodically
screamer 0:7a64fbb4069d 1135 * from TCP. The interval is specified in terms of the TCP coarse
screamer 0:7a64fbb4069d 1136 * timer interval, which is called twice a second.
screamer 0:7a64fbb4069d 1137 *
screamer 0:7a64fbb4069d 1138 */
screamer 0:7a64fbb4069d 1139 void
screamer 0:7a64fbb4069d 1140 tcp_poll(struct tcp_pcb *pcb,
screamer 0:7a64fbb4069d 1141 err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval)
screamer 0:7a64fbb4069d 1142 {
screamer 0:7a64fbb4069d 1143 #if LWIP_CALLBACK_API
screamer 0:7a64fbb4069d 1144 pcb->poll = poll;
screamer 0:7a64fbb4069d 1145 #endif /* LWIP_CALLBACK_API */
screamer 0:7a64fbb4069d 1146 pcb->pollinterval = interval;
screamer 0:7a64fbb4069d 1147 }
screamer 0:7a64fbb4069d 1148
screamer 0:7a64fbb4069d 1149 /**
screamer 0:7a64fbb4069d 1150 * Purges a TCP PCB. Removes any buffered data and frees the buffer memory
screamer 0:7a64fbb4069d 1151 * (pcb->ooseq, pcb->unsent and pcb->unacked are freed).
screamer 0:7a64fbb4069d 1152 *
screamer 0:7a64fbb4069d 1153 * @param pcb tcp_pcb to purge. The pcb itself is not deallocated!
screamer 0:7a64fbb4069d 1154 */
screamer 0:7a64fbb4069d 1155 void
screamer 0:7a64fbb4069d 1156 tcp_pcb_purge(struct tcp_pcb *pcb)
screamer 0:7a64fbb4069d 1157 {
screamer 0:7a64fbb4069d 1158 if (pcb->state != CLOSED &&
screamer 0:7a64fbb4069d 1159 pcb->state != TIME_WAIT &&
screamer 0:7a64fbb4069d 1160 pcb->state != LISTEN) {
screamer 0:7a64fbb4069d 1161
screamer 0:7a64fbb4069d 1162 LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));
screamer 0:7a64fbb4069d 1163
screamer 0:7a64fbb4069d 1164 #if TCP_LISTEN_BACKLOG
screamer 0:7a64fbb4069d 1165 if (pcb->state == SYN_RCVD) {
screamer 0:7a64fbb4069d 1166 /* Need to find the corresponding listen_pcb and decrease its accepts_pending */
screamer 0:7a64fbb4069d 1167 struct tcp_pcb_listen *lpcb;
screamer 0:7a64fbb4069d 1168 LWIP_ASSERT("tcp_pcb_purge: pcb->state == SYN_RCVD but tcp_listen_pcbs is NULL",
screamer 0:7a64fbb4069d 1169 tcp_listen_pcbs.listen_pcbs != NULL);
screamer 0:7a64fbb4069d 1170 for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
screamer 0:7a64fbb4069d 1171 if ((lpcb->local_port == pcb->local_port) &&
screamer 0:7a64fbb4069d 1172 (ip_addr_isany(&lpcb->local_ip) ||
screamer 0:7a64fbb4069d 1173 ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) {
screamer 0:7a64fbb4069d 1174 /* port and address of the listen pcb match the timed-out pcb */
screamer 0:7a64fbb4069d 1175 LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending",
screamer 0:7a64fbb4069d 1176 lpcb->accepts_pending > 0);
screamer 0:7a64fbb4069d 1177 lpcb->accepts_pending--;
screamer 0:7a64fbb4069d 1178 break;
screamer 0:7a64fbb4069d 1179 }
screamer 0:7a64fbb4069d 1180 }
screamer 0:7a64fbb4069d 1181 }
screamer 0:7a64fbb4069d 1182 #endif /* TCP_LISTEN_BACKLOG */
screamer 0:7a64fbb4069d 1183
screamer 0:7a64fbb4069d 1184
screamer 0:7a64fbb4069d 1185 if (pcb->refused_data != NULL) {
screamer 0:7a64fbb4069d 1186 LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n"));
screamer 0:7a64fbb4069d 1187 pbuf_free(pcb->refused_data);
screamer 0:7a64fbb4069d 1188 pcb->refused_data = NULL;
screamer 0:7a64fbb4069d 1189 }
screamer 0:7a64fbb4069d 1190 if (pcb->unsent != NULL) {
screamer 0:7a64fbb4069d 1191 LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n"));
screamer 0:7a64fbb4069d 1192 }
screamer 0:7a64fbb4069d 1193 if (pcb->unacked != NULL) {
screamer 0:7a64fbb4069d 1194 LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n"));
screamer 0:7a64fbb4069d 1195 }
screamer 0:7a64fbb4069d 1196 #if TCP_QUEUE_OOSEQ /* LW */
screamer 0:7a64fbb4069d 1197 if (pcb->ooseq != NULL) {
screamer 0:7a64fbb4069d 1198 LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));
screamer 0:7a64fbb4069d 1199 }
screamer 0:7a64fbb4069d 1200
screamer 0:7a64fbb4069d 1201 /* Stop the retransmission timer as it will expect data on unacked
screamer 0:7a64fbb4069d 1202 queue if it fires */
screamer 0:7a64fbb4069d 1203 pcb->rtime = -1;
screamer 0:7a64fbb4069d 1204
screamer 0:7a64fbb4069d 1205 tcp_segs_free(pcb->ooseq);
screamer 0:7a64fbb4069d 1206 pcb->ooseq = NULL;
screamer 0:7a64fbb4069d 1207 #endif /* TCP_QUEUE_OOSEQ */
screamer 0:7a64fbb4069d 1208 tcp_segs_free(pcb->unsent);
screamer 0:7a64fbb4069d 1209 tcp_segs_free(pcb->unacked);
screamer 0:7a64fbb4069d 1210 pcb->unacked = pcb->unsent = NULL;
screamer 0:7a64fbb4069d 1211 }
screamer 0:7a64fbb4069d 1212 }
screamer 0:7a64fbb4069d 1213
screamer 0:7a64fbb4069d 1214 /**
screamer 0:7a64fbb4069d 1215 * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.
screamer 0:7a64fbb4069d 1216 *
screamer 0:7a64fbb4069d 1217 * @param pcblist PCB list to purge.
screamer 0:7a64fbb4069d 1218 * @param pcb tcp_pcb to purge. The pcb itself is also deallocated!
screamer 0:7a64fbb4069d 1219 */
screamer 0:7a64fbb4069d 1220 void
screamer 0:7a64fbb4069d 1221 tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)
screamer 0:7a64fbb4069d 1222 {
screamer 0:7a64fbb4069d 1223 TCP_RMV(pcblist, pcb);
screamer 0:7a64fbb4069d 1224
screamer 0:7a64fbb4069d 1225 tcp_pcb_purge(pcb);
screamer 0:7a64fbb4069d 1226
screamer 0:7a64fbb4069d 1227 /* if there is an outstanding delayed ACKs, send it */
screamer 0:7a64fbb4069d 1228 if (pcb->state != TIME_WAIT &&
screamer 0:7a64fbb4069d 1229 pcb->state != LISTEN &&
screamer 0:7a64fbb4069d 1230 pcb->flags & TF_ACK_DELAY) {
screamer 0:7a64fbb4069d 1231 pcb->flags |= TF_ACK_NOW;
screamer 0:7a64fbb4069d 1232 tcp_output(pcb);
screamer 0:7a64fbb4069d 1233 }
screamer 0:7a64fbb4069d 1234
screamer 0:7a64fbb4069d 1235 if (pcb->state != LISTEN) {
screamer 0:7a64fbb4069d 1236 LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL);
screamer 0:7a64fbb4069d 1237 LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL);
screamer 0:7a64fbb4069d 1238 #if TCP_QUEUE_OOSEQ
screamer 0:7a64fbb4069d 1239 LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL);
screamer 0:7a64fbb4069d 1240 #endif /* TCP_QUEUE_OOSEQ */
screamer 0:7a64fbb4069d 1241 }
screamer 0:7a64fbb4069d 1242
screamer 0:7a64fbb4069d 1243 pcb->state = CLOSED;
screamer 0:7a64fbb4069d 1244
screamer 0:7a64fbb4069d 1245 LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());
screamer 0:7a64fbb4069d 1246 }
screamer 0:7a64fbb4069d 1247
screamer 0:7a64fbb4069d 1248 /**
screamer 0:7a64fbb4069d 1249 * Calculates a new initial sequence number for new connections.
screamer 0:7a64fbb4069d 1250 *
screamer 0:7a64fbb4069d 1251 * @return u32_t pseudo random sequence number
screamer 0:7a64fbb4069d 1252 */
screamer 0:7a64fbb4069d 1253 u32_t
screamer 0:7a64fbb4069d 1254 tcp_next_iss(void)
screamer 0:7a64fbb4069d 1255 {
screamer 0:7a64fbb4069d 1256 static u32_t iss = 6510;
screamer 0:7a64fbb4069d 1257
screamer 0:7a64fbb4069d 1258 iss += tcp_ticks; /* XXX */
screamer 0:7a64fbb4069d 1259 return iss;
screamer 0:7a64fbb4069d 1260 }
screamer 0:7a64fbb4069d 1261
screamer 0:7a64fbb4069d 1262 #if TCP_CALCULATE_EFF_SEND_MSS
screamer 0:7a64fbb4069d 1263 /**
screamer 0:7a64fbb4069d 1264 * Calcluates the effective send mss that can be used for a specific IP address
screamer 0:7a64fbb4069d 1265 * by using ip_route to determin the netif used to send to the address and
screamer 0:7a64fbb4069d 1266 * calculating the minimum of TCP_MSS and that netif's mtu (if set).
screamer 0:7a64fbb4069d 1267 */
screamer 0:7a64fbb4069d 1268 u16_t
screamer 0:7a64fbb4069d 1269 tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr)
screamer 0:7a64fbb4069d 1270 {
screamer 0:7a64fbb4069d 1271 u16_t mss_s;
screamer 0:7a64fbb4069d 1272 struct netif *outif;
screamer 0:7a64fbb4069d 1273
screamer 0:7a64fbb4069d 1274 outif = ip_route(addr);
screamer 0:7a64fbb4069d 1275 if ((outif != NULL) && (outif->mtu != 0)) {
screamer 0:7a64fbb4069d 1276 mss_s = outif->mtu - IP_HLEN - TCP_HLEN;
screamer 0:7a64fbb4069d 1277 /* RFC 1122, chap 4.2.2.6:
screamer 0:7a64fbb4069d 1278 * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize
screamer 0:7a64fbb4069d 1279 * We correct for TCP options in tcp_enqueue(), and don't support
screamer 0:7a64fbb4069d 1280 * IP options
screamer 0:7a64fbb4069d 1281 */
screamer 0:7a64fbb4069d 1282 sendmss = LWIP_MIN(sendmss, mss_s);
screamer 0:7a64fbb4069d 1283 }
screamer 0:7a64fbb4069d 1284 return sendmss;
screamer 0:7a64fbb4069d 1285 }
screamer 0:7a64fbb4069d 1286 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
screamer 0:7a64fbb4069d 1287
screamer 0:7a64fbb4069d 1288 #if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
screamer 0:7a64fbb4069d 1289 /**
screamer 0:7a64fbb4069d 1290 * Print a tcp header for debugging purposes.
screamer 0:7a64fbb4069d 1291 *
screamer 0:7a64fbb4069d 1292 * @param tcphdr pointer to a struct tcp_hdr
screamer 0:7a64fbb4069d 1293 */
screamer 0:7a64fbb4069d 1294 void
screamer 0:7a64fbb4069d 1295 tcp_debug_print(struct tcp_hdr *tcphdr)
screamer 0:7a64fbb4069d 1296 {
screamer 0:7a64fbb4069d 1297 LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n"));
screamer 0:7a64fbb4069d 1298 LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
screamer 0:7a64fbb4069d 1299 LWIP_DEBUGF(TCP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n",
screamer 0:7a64fbb4069d 1300 ntohs(tcphdr->src), ntohs(tcphdr->dest)));
screamer 0:7a64fbb4069d 1301 LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
screamer 0:7a64fbb4069d 1302 LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (seq no)\n",
screamer 0:7a64fbb4069d 1303 ntohl(tcphdr->seqno)));
screamer 0:7a64fbb4069d 1304 LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
screamer 0:7a64fbb4069d 1305 LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (ack no)\n",
screamer 0:7a64fbb4069d 1306 ntohl(tcphdr->ackno)));
screamer 0:7a64fbb4069d 1307 LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
screamer 0:7a64fbb4069d 1308 LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" | |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"| %5"U16_F" | (hdrlen, flags (",
screamer 0:7a64fbb4069d 1309 TCPH_HDRLEN(tcphdr),
screamer 0:7a64fbb4069d 1310 TCPH_FLAGS(tcphdr) >> 5 & 1,
screamer 0:7a64fbb4069d 1311 TCPH_FLAGS(tcphdr) >> 4 & 1,
screamer 0:7a64fbb4069d 1312 TCPH_FLAGS(tcphdr) >> 3 & 1,
screamer 0:7a64fbb4069d 1313 TCPH_FLAGS(tcphdr) >> 2 & 1,
screamer 0:7a64fbb4069d 1314 TCPH_FLAGS(tcphdr) >> 1 & 1,
screamer 0:7a64fbb4069d 1315 TCPH_FLAGS(tcphdr) & 1,
screamer 0:7a64fbb4069d 1316 ntohs(tcphdr->wnd)));
screamer 0:7a64fbb4069d 1317 tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
screamer 0:7a64fbb4069d 1318 LWIP_DEBUGF(TCP_DEBUG, ("), win)\n"));
screamer 0:7a64fbb4069d 1319 LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
screamer 0:7a64fbb4069d 1320 LWIP_DEBUGF(TCP_DEBUG, ("| 0x%04"X16_F" | %5"U16_F" | (chksum, urgp)\n",
screamer 0:7a64fbb4069d 1321 ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));
screamer 0:7a64fbb4069d 1322 LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
screamer 0:7a64fbb4069d 1323 }
screamer 0:7a64fbb4069d 1324
screamer 0:7a64fbb4069d 1325 /**
screamer 0:7a64fbb4069d 1326 * Print a tcp state for debugging purposes.
screamer 0:7a64fbb4069d 1327 *
screamer 0:7a64fbb4069d 1328 * @param s enum tcp_state to print
screamer 0:7a64fbb4069d 1329 */
screamer 0:7a64fbb4069d 1330 void
screamer 0:7a64fbb4069d 1331 tcp_debug_print_state(enum tcp_state s)
screamer 0:7a64fbb4069d 1332 {
screamer 0:7a64fbb4069d 1333 LWIP_DEBUGF(TCP_DEBUG, ("State: "));
screamer 0:7a64fbb4069d 1334 switch (s) {
screamer 0:7a64fbb4069d 1335 case CLOSED:
screamer 0:7a64fbb4069d 1336 LWIP_DEBUGF(TCP_DEBUG, ("CLOSED\n"));
screamer 0:7a64fbb4069d 1337 break;
screamer 0:7a64fbb4069d 1338 case LISTEN:
screamer 0:7a64fbb4069d 1339 LWIP_DEBUGF(TCP_DEBUG, ("LISTEN\n"));
screamer 0:7a64fbb4069d 1340 break;
screamer 0:7a64fbb4069d 1341 case SYN_SENT:
screamer 0:7a64fbb4069d 1342 LWIP_DEBUGF(TCP_DEBUG, ("SYN_SENT\n"));
screamer 0:7a64fbb4069d 1343 break;
screamer 0:7a64fbb4069d 1344 case SYN_RCVD:
screamer 0:7a64fbb4069d 1345 LWIP_DEBUGF(TCP_DEBUG, ("SYN_RCVD\n"));
screamer 0:7a64fbb4069d 1346 break;
screamer 0:7a64fbb4069d 1347 case ESTABLISHED:
screamer 0:7a64fbb4069d 1348 LWIP_DEBUGF(TCP_DEBUG, ("ESTABLISHED\n"));
screamer 0:7a64fbb4069d 1349 break;
screamer 0:7a64fbb4069d 1350 case FIN_WAIT_1:
screamer 0:7a64fbb4069d 1351 LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_1\n"));
screamer 0:7a64fbb4069d 1352 break;
screamer 0:7a64fbb4069d 1353 case FIN_WAIT_2:
screamer 0:7a64fbb4069d 1354 LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_2\n"));
screamer 0:7a64fbb4069d 1355 break;
screamer 0:7a64fbb4069d 1356 case CLOSE_WAIT:
screamer 0:7a64fbb4069d 1357 LWIP_DEBUGF(TCP_DEBUG, ("CLOSE_WAIT\n"));
screamer 0:7a64fbb4069d 1358 break;
screamer 0:7a64fbb4069d 1359 case CLOSING:
screamer 0:7a64fbb4069d 1360 LWIP_DEBUGF(TCP_DEBUG, ("CLOSING\n"));
screamer 0:7a64fbb4069d 1361 break;
screamer 0:7a64fbb4069d 1362 case LAST_ACK:
screamer 0:7a64fbb4069d 1363 LWIP_DEBUGF(TCP_DEBUG, ("LAST_ACK\n"));
screamer 0:7a64fbb4069d 1364 break;
screamer 0:7a64fbb4069d 1365 case TIME_WAIT:
screamer 0:7a64fbb4069d 1366 LWIP_DEBUGF(TCP_DEBUG, ("TIME_WAIT\n"));
screamer 0:7a64fbb4069d 1367 break;
screamer 0:7a64fbb4069d 1368 }
screamer 0:7a64fbb4069d 1369 }
screamer 0:7a64fbb4069d 1370
screamer 0:7a64fbb4069d 1371 /**
screamer 0:7a64fbb4069d 1372 * Print tcp flags for debugging purposes.
screamer 0:7a64fbb4069d 1373 *
screamer 0:7a64fbb4069d 1374 * @param flags tcp flags, all active flags are printed
screamer 0:7a64fbb4069d 1375 */
screamer 0:7a64fbb4069d 1376 void
screamer 0:7a64fbb4069d 1377 tcp_debug_print_flags(u8_t flags)
screamer 0:7a64fbb4069d 1378 {
screamer 0:7a64fbb4069d 1379 if (flags & TCP_FIN) {
screamer 0:7a64fbb4069d 1380 LWIP_DEBUGF(TCP_DEBUG, ("FIN "));
screamer 0:7a64fbb4069d 1381 }
screamer 0:7a64fbb4069d 1382 if (flags & TCP_SYN) {
screamer 0:7a64fbb4069d 1383 LWIP_DEBUGF(TCP_DEBUG, ("SYN "));
screamer 0:7a64fbb4069d 1384 }
screamer 0:7a64fbb4069d 1385 if (flags & TCP_RST) {
screamer 0:7a64fbb4069d 1386 LWIP_DEBUGF(TCP_DEBUG, ("RST "));
screamer 0:7a64fbb4069d 1387 }
screamer 0:7a64fbb4069d 1388 if (flags & TCP_PSH) {
screamer 0:7a64fbb4069d 1389 LWIP_DEBUGF(TCP_DEBUG, ("PSH "));
screamer 0:7a64fbb4069d 1390 }
screamer 0:7a64fbb4069d 1391 if (flags & TCP_ACK) {
screamer 0:7a64fbb4069d 1392 LWIP_DEBUGF(TCP_DEBUG, ("ACK "));
screamer 0:7a64fbb4069d 1393 }
screamer 0:7a64fbb4069d 1394 if (flags & TCP_URG) {
screamer 0:7a64fbb4069d 1395 LWIP_DEBUGF(TCP_DEBUG, ("URG "));
screamer 0:7a64fbb4069d 1396 }
screamer 0:7a64fbb4069d 1397 if (flags & TCP_ECE) {
screamer 0:7a64fbb4069d 1398 LWIP_DEBUGF(TCP_DEBUG, ("ECE "));
screamer 0:7a64fbb4069d 1399 }
screamer 0:7a64fbb4069d 1400 if (flags & TCP_CWR) {
screamer 0:7a64fbb4069d 1401 LWIP_DEBUGF(TCP_DEBUG, ("CWR "));
screamer 0:7a64fbb4069d 1402 }
screamer 0:7a64fbb4069d 1403 }
screamer 0:7a64fbb4069d 1404
screamer 0:7a64fbb4069d 1405 /**
screamer 0:7a64fbb4069d 1406 * Print all tcp_pcbs in every list for debugging purposes.
screamer 0:7a64fbb4069d 1407 */
screamer 0:7a64fbb4069d 1408 void
screamer 0:7a64fbb4069d 1409 tcp_debug_print_pcbs(void)
screamer 0:7a64fbb4069d 1410 {
screamer 0:7a64fbb4069d 1411 struct tcp_pcb *pcb;
screamer 0:7a64fbb4069d 1412 LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n"));
screamer 0:7a64fbb4069d 1413 for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
screamer 0:7a64fbb4069d 1414 LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
screamer 0:7a64fbb4069d 1415 pcb->local_port, pcb->remote_port,
screamer 0:7a64fbb4069d 1416 pcb->snd_nxt, pcb->rcv_nxt));
screamer 0:7a64fbb4069d 1417 tcp_debug_print_state(pcb->state);
screamer 0:7a64fbb4069d 1418 }
screamer 0:7a64fbb4069d 1419 LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n"));
screamer 0:7a64fbb4069d 1420 for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
screamer 0:7a64fbb4069d 1421 LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
screamer 0:7a64fbb4069d 1422 pcb->local_port, pcb->remote_port,
screamer 0:7a64fbb4069d 1423 pcb->snd_nxt, pcb->rcv_nxt));
screamer 0:7a64fbb4069d 1424 tcp_debug_print_state(pcb->state);
screamer 0:7a64fbb4069d 1425 }
screamer 0:7a64fbb4069d 1426 LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n"));
screamer 0:7a64fbb4069d 1427 for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
screamer 0:7a64fbb4069d 1428 LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
screamer 0:7a64fbb4069d 1429 pcb->local_port, pcb->remote_port,
screamer 0:7a64fbb4069d 1430 pcb->snd_nxt, pcb->rcv_nxt));
screamer 0:7a64fbb4069d 1431 tcp_debug_print_state(pcb->state);
screamer 0:7a64fbb4069d 1432 }
screamer 0:7a64fbb4069d 1433 }
screamer 0:7a64fbb4069d 1434
screamer 0:7a64fbb4069d 1435 /**
screamer 0:7a64fbb4069d 1436 * Check state consistency of the tcp_pcb lists.
screamer 0:7a64fbb4069d 1437 */
screamer 0:7a64fbb4069d 1438 s16_t
screamer 0:7a64fbb4069d 1439 tcp_pcbs_sane(void)
screamer 0:7a64fbb4069d 1440 {
screamer 0:7a64fbb4069d 1441 struct tcp_pcb *pcb;
screamer 0:7a64fbb4069d 1442 for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
screamer 0:7a64fbb4069d 1443 LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED);
screamer 0:7a64fbb4069d 1444 LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN);
screamer 0:7a64fbb4069d 1445 LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
screamer 0:7a64fbb4069d 1446 }
screamer 0:7a64fbb4069d 1447 for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
screamer 0:7a64fbb4069d 1448 LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
screamer 0:7a64fbb4069d 1449 }
screamer 0:7a64fbb4069d 1450 return 1;
screamer 0:7a64fbb4069d 1451 }
screamer 0:7a64fbb4069d 1452 #endif /* TCP_DEBUG */
screamer 0:7a64fbb4069d 1453
screamer 0:7a64fbb4069d 1454 #endif /* LWIP_TCP */