Used in Live Traffic Update Nokia LCD Display Project

Fork of NetServices by Segundo Equipo

Committer:
rrajan8
Date:
Wed Mar 06 19:07:23 2013 +0000
Revision:
8:92b57208ab99
Parent:
0:ac1725ba162c
This project utilizes mbed's networking features to display live traffic updates on the Nokia LCD using the MapQuest API's Traffic Web Service.

Who changed what in which revision?

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