Example program with HTTPServer and sensor data streaming over TCPSockets, using Donatien Garnier's Net APIs and services code on top of LWIP. Files StreamServer.h and .cpp encapsulate streaming over TCPSockets. Broadcast is done by sendToAll(), and all incoming data is echoed back to the client. Echo code can be replaced with some remote control of the streaming interface. See main() that shows how to periodically send some data to all subscribed clients. To subscribe, a client should open a socket at <mbed_ip> port 123. I used few lines in TCL code to set up a quick sink for the data. HTTP files are served on port 80 concurrently to the streaming.

Dependencies:   mbed

Committer:
iva2k
Date:
Sat Jun 12 06:01:50 2010 +0000
Revision:
0:e614f7875b60

        

Who changed what in which revision?

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