Blame src/vma/lwip/tcp.c

Packit Service aa3af4
/**
Packit Service aa3af4
 * @file
Packit Service aa3af4
 * Transmission Control Protocol for IP
Packit Service aa3af4
 *
Packit Service aa3af4
 * This file contains common functions for the TCP implementation, such as functinos
Packit Service aa3af4
 * for manipulating the data structures and the TCP timer functions. TCP functions
Packit Service aa3af4
 * related to input and output is found in tcp_in.c and tcp_out.c respectively.
Packit Service aa3af4
 *
Packit Service aa3af4
 */
Packit Service aa3af4
Packit Service aa3af4
/*
Packit Service aa3af4
 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
Packit Service aa3af4
 * All rights reserved. 
Packit Service aa3af4
 * 
Packit Service aa3af4
 * Redistribution and use in source and binary forms, with or without modification, 
Packit Service aa3af4
 * are permitted provided that the following conditions are met:
Packit Service aa3af4
 *
Packit Service aa3af4
 * 1. Redistributions of source code must retain the above copyright notice,
Packit Service aa3af4
 *    this list of conditions and the following disclaimer.
Packit Service aa3af4
 * 2. Redistributions in binary form must reproduce the above copyright notice,
Packit Service aa3af4
 *    this list of conditions and the following disclaimer in the documentation
Packit Service aa3af4
 *    and/or other materials provided with the distribution.
Packit Service aa3af4
 * 3. The name of the author may not be used to endorse or promote products
Packit Service aa3af4
 *    derived from this software without specific prior written permission. 
Packit Service aa3af4
 *
Packit Service aa3af4
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
Packit Service aa3af4
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
Packit Service aa3af4
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
Packit Service aa3af4
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
Packit Service aa3af4
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
Packit Service aa3af4
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
Packit Service aa3af4
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
Packit Service aa3af4
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
Packit Service aa3af4
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
Packit Service aa3af4
 * OF SUCH DAMAGE.
Packit Service aa3af4
 *
Packit Service aa3af4
 * This file is part of the lwIP TCP/IP stack.
Packit Service aa3af4
 * 
Packit Service aa3af4
 * Author: Adam Dunkels <adam@sics.se>
Packit Service aa3af4
 *
Packit Service aa3af4
 */
Packit Service aa3af4
Packit Service aa3af4
#include "vma/lwip/opt.h"
Packit Service aa3af4
Packit Service aa3af4
#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
Packit Service aa3af4
#include "vma/lwip/cc.h"
Packit Service aa3af4
#include "vma/lwip/tcp.h"
Packit Service aa3af4
#include "vma/lwip/tcp_impl.h"
Packit Service aa3af4
#include "vma/lwip/stats.h"
Packit Service aa3af4
Packit Service aa3af4
#include <string.h>
Packit Service aa3af4
#include <sys/types.h>
Packit Service aa3af4
#include <unistd.h>
Packit Service aa3af4
Packit Service aa3af4
#if LWIP_3RD_PARTY_BUFS
Packit Service aa3af4
tcp_tx_pbuf_alloc_fn external_tcp_tx_pbuf_alloc;
Packit Service aa3af4
Packit Service aa3af4
void register_tcp_tx_pbuf_alloc(tcp_tx_pbuf_alloc_fn fn)
Packit Service aa3af4
{
Packit Service aa3af4
    external_tcp_tx_pbuf_alloc = fn;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
tcp_tx_pbuf_free_fn external_tcp_tx_pbuf_free;
Packit Service aa3af4
Packit Service aa3af4
void register_tcp_tx_pbuf_free(tcp_tx_pbuf_free_fn fn)
Packit Service aa3af4
{
Packit Service aa3af4
    external_tcp_tx_pbuf_free = fn;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
tcp_seg_alloc_fn external_tcp_seg_alloc;
Packit Service aa3af4
Packit Service aa3af4
void register_tcp_seg_alloc(tcp_seg_alloc_fn fn)
Packit Service aa3af4
{
Packit Service aa3af4
    external_tcp_seg_alloc = fn;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
tcp_seg_free_fn external_tcp_seg_free;
Packit Service aa3af4
Packit Service aa3af4
void register_tcp_seg_free(tcp_seg_free_fn fn)
Packit Service aa3af4
{
Packit Service aa3af4
    external_tcp_seg_free = fn;
Packit Service aa3af4
}
Packit Service aa3af4
#endif
Packit Service aa3af4
Packit Service aa3af4
/* allow user to be notified upon tcp_state changes */
Packit Service aa3af4
tcp_state_observer_fn external_tcp_state_observer;
Packit Service aa3af4
Packit Service aa3af4
void register_tcp_state_observer(tcp_state_observer_fn fn)
Packit Service aa3af4
{
Packit Service aa3af4
	external_tcp_state_observer = fn;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
Packit Service aa3af4
enum cc_algo_mod lwip_cc_algo_module = CC_MOD_LWIP;
Packit Service aa3af4
Packit Service aa3af4
u16_t lwip_tcp_mss = CONST_TCP_MSS;
Packit Service aa3af4
Packit Service aa3af4
u8_t enable_ts_option = 0;
Packit Service aa3af4
/* slow timer value */
Packit Service aa3af4
static u32_t slow_tmr_interval;
Packit Service aa3af4
/* Incremented every coarse grained timer shot (typically every slow_tmr_interval ms). */
Packit Service aa3af4
u32_t tcp_ticks = 0;
Packit Service aa3af4
const u8_t tcp_backoff[13] =
Packit Service aa3af4
    { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};
Packit Service aa3af4
 /* Times per slowtmr hits */
Packit Service aa3af4
const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 };
Packit Service aa3af4
Packit Service aa3af4
/** Only used for temporary storage. */
Packit Service aa3af4
struct tcp_pcb *tcp_tmp_pcb;
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param v value to set
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
set_tmr_resolution(u32_t v)
Packit Service aa3af4
{
Packit Service aa3af4
	slow_tmr_interval = v * 2;
Packit Service aa3af4
}
Packit Service aa3af4
/**
Packit Service aa3af4
 * Called periodically to dispatch TCP timers.
Packit Service aa3af4
 *
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_tmr(struct tcp_pcb* pcb)
Packit Service aa3af4
{
Packit Service aa3af4
  /* Call tcp_fasttmr() every (slow_tmr_interval / 2) ms */
Packit Service aa3af4
  tcp_fasttmr(pcb);
Packit Service aa3af4
Packit Service aa3af4
  if (++(pcb->tcp_timer) & 1) {
Packit Service aa3af4
    /* Call tcp_tmr() every slow_tmr_interval ms, i.e., every other timer
Packit Service aa3af4
       tcp_tmr() is called. */
Packit Service aa3af4
    tcp_slowtmr(pcb);
Packit Service aa3af4
  }
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Closes the TX side of a connection held by the PCB.
Packit Service aa3af4
 * For tcp_close(), a RST is sent if the application didn't receive all data
Packit Service aa3af4
 * (tcp_recved() not called for all data passed to recv callback).
Packit Service aa3af4
 *
Packit Service aa3af4
 * Listening pcbs are freed and may not be referenced any more.
Packit Service aa3af4
 * Connection pcbs are freed if not yet connected and may not be referenced
Packit Service aa3af4
 * any more. If a connection is established (at least SYN received or in
Packit Service aa3af4
 * a closing state), the connection is closed, and put in a closing state.
Packit Service aa3af4
 * The pcb is then automatically freed in tcp_slowtmr(). It is therefore
Packit Service aa3af4
 * unsafe to reference it.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcb the tcp_pcb to close
Packit Service aa3af4
 * @return ERR_OK if connection has been closed
Packit Service aa3af4
 *         another err_t if closing failed and pcb is not freed
Packit Service aa3af4
 */
Packit Service aa3af4
static err_t
Packit Service aa3af4
tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
Packit Service aa3af4
{
Packit Service aa3af4
  err_t err;
Packit Service aa3af4
Packit Service aa3af4
  if (rst_on_unacked_data && ((get_tcp_state(pcb) == ESTABLISHED) || (get_tcp_state(pcb) == CLOSE_WAIT))) {
Packit Service aa3af4
    if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != pcb->rcv_wnd_max)) {
Packit Service aa3af4
      /* Not all data received by application, send RST to tell the remote
Packit Service aa3af4
         side about this. */
Packit Service aa3af4
      LWIP_ASSERT("pcb->flags & TF_RXCLOSED", pcb->flags & TF_RXCLOSED);
Packit Service aa3af4
Packit Service aa3af4
      /* don't call tcp_abort here: we must not deallocate the pcb since
Packit Service aa3af4
         that might not be expected when calling tcp_close */
Packit Service aa3af4
      tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, pcb->local_port, pcb->remote_port, pcb);
Packit Service aa3af4
Packit Service aa3af4
      tcp_pcb_purge(pcb);
Packit Service aa3af4
Packit Service aa3af4
      if (get_tcp_state(pcb) == ESTABLISHED) {
Packit Service aa3af4
              /* move to TIME_WAIT since we close actively */
Packit Service aa3af4
    	  set_tcp_state(pcb, TIME_WAIT);
Packit Service aa3af4
      } else {
Packit Service aa3af4
              /* CLOSE_WAIT: deallocate the pcb since we already sent a RST for it */
Packit Service aa3af4
      }
Packit Service aa3af4
Packit Service aa3af4
      return ERR_OK;
Packit Service aa3af4
    }
Packit Service aa3af4
  }
Packit Service aa3af4
Packit Service aa3af4
  switch (get_tcp_state(pcb)) {
Packit Service aa3af4
  case CLOSED:
Packit Service aa3af4
    /* Closing a pcb in the CLOSED state might seem erroneous,
Packit Service aa3af4
     * however, it is in this state once allocated and as yet unused
Packit Service aa3af4
     * and the user needs some way to free it should the need arise.
Packit Service aa3af4
     * Calling tcp_close() with a pcb that has already been closed, (i.e. twice)
Packit Service aa3af4
     * or for a pcb that has been used and then entered the CLOSED state 
Packit Service aa3af4
     * is erroneous, but this should never happen as the pcb has in those cases
Packit Service aa3af4
     * been freed, and so any remaining handles are bogus. */
Packit Service aa3af4
    err = ERR_OK;
Packit Service aa3af4
    pcb = NULL;
Packit Service aa3af4
    break;
Packit Service aa3af4
  case LISTEN:
Packit Service aa3af4
    err = ERR_OK;
Packit Service aa3af4
    tcp_pcb_remove(pcb);
Packit Service aa3af4
    pcb = NULL;
Packit Service aa3af4
    break;
Packit Service aa3af4
  case SYN_SENT:
Packit Service aa3af4
    err = ERR_OK;
Packit Service aa3af4
    tcp_pcb_remove(pcb);
Packit Service aa3af4
    pcb = NULL;
Packit Service aa3af4
    break;
Packit Service aa3af4
  case SYN_RCVD:
Packit Service aa3af4
    err = tcp_send_fin(pcb);
Packit Service aa3af4
    if (err == ERR_OK) {
Packit Service aa3af4
      set_tcp_state(pcb, FIN_WAIT_1);
Packit Service aa3af4
    }
Packit Service aa3af4
    break;
Packit Service aa3af4
  case ESTABLISHED:
Packit Service aa3af4
    err = tcp_send_fin(pcb);
Packit Service aa3af4
    if (err == ERR_OK) {
Packit Service aa3af4
      set_tcp_state(pcb, FIN_WAIT_1);
Packit Service aa3af4
    }
Packit Service aa3af4
    break;
Packit Service aa3af4
  case CLOSE_WAIT:
Packit Service aa3af4
    err = tcp_send_fin(pcb);
Packit Service aa3af4
    if (err == ERR_OK) {
Packit Service aa3af4
      set_tcp_state(pcb, LAST_ACK);
Packit Service aa3af4
    }
Packit Service aa3af4
    break;
Packit Service aa3af4
  default:
Packit Service aa3af4
    /* Has already been closed, do nothing. */
Packit Service aa3af4
    err = ERR_OK;
Packit Service aa3af4
    pcb = NULL;
Packit Service aa3af4
    break;
Packit Service aa3af4
  }
Packit Service aa3af4
Packit Service aa3af4
  if (pcb != NULL && err == ERR_OK) {
Packit Service aa3af4
    /* To ensure all data has been sent when tcp_close returns, we have
Packit Service aa3af4
       to make sure tcp_output doesn't fail.
Packit Service aa3af4
       Since we don't really have to ensure all data has been sent when tcp_close
Packit Service aa3af4
       returns (unsent data is sent from tcp timer functions, also), we don't care
Packit Service aa3af4
       for the return value of tcp_output for now. */
Packit Service aa3af4
    /* @todo: When implementing SO_LINGER, this must be changed somehow:
Packit Service aa3af4
       If SOF_LINGER is set, the data should be sent and acked before close returns.
Packit Service aa3af4
       This can only be valid for sequential APIs, not for the raw API. */
Packit Service aa3af4
    tcp_output(pcb);
Packit Service aa3af4
  }
Packit Service aa3af4
  return err;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Closes the connection held by the PCB.
Packit Service aa3af4
 *
Packit Service aa3af4
 * Listening pcbs are freed and may not be referenced any more.
Packit Service aa3af4
 * Connection pcbs are freed if not yet connected and may not be referenced
Packit Service aa3af4
 * any more. If a connection is established (at least SYN received or in
Packit Service aa3af4
 * a closing state), the connection is closed, and put in a closing state.
Packit Service aa3af4
 * The pcb is then automatically freed in tcp_slowtmr(). It is therefore
Packit Service aa3af4
 * unsafe to reference it (unless an error is returned).
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcb the tcp_pcb to close
Packit Service aa3af4
 * @return ERR_OK if connection has been closed
Packit Service aa3af4
 *         another err_t if closing failed and pcb is not freed
Packit Service aa3af4
 */
Packit Service aa3af4
err_t
Packit Service aa3af4
tcp_close(struct tcp_pcb *pcb)
Packit Service aa3af4
{
Packit Service aa3af4
#if TCP_DEBUG
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in "));
Packit Service aa3af4
  tcp_debug_print_state(get_tcp_state(pcb));
Packit Service aa3af4
#endif /* TCP_DEBUG */
Packit Service aa3af4
Packit Service aa3af4
  if (get_tcp_state(pcb) != LISTEN) {
Packit Service aa3af4
    /* Set a flag not to receive any more data... */
Packit Service aa3af4
    pcb->flags |= TF_RXCLOSED;
Packit Service aa3af4
  }
Packit Service aa3af4
  /* ... and close */
Packit Service aa3af4
  return tcp_close_shutdown(pcb, 1);
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Causes all or part of a full-duplex connection of this PCB to be shut down.
Packit Service aa3af4
 * This doesn't deallocate the PCB!
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcb PCB to shutdown
Packit Service aa3af4
 * @param shut_rx shut down receive side if this is != 0
Packit Service aa3af4
 * @param shut_tx shut down send side if this is != 0
Packit Service aa3af4
 * @return ERR_OK if shutdown succeeded (or the PCB has already been shut down)
Packit Service aa3af4
 *         another err_t on error.
Packit Service aa3af4
 */
Packit Service aa3af4
err_t
Packit Service aa3af4
tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx)
Packit Service aa3af4
{
Packit Service aa3af4
  if (get_tcp_state(pcb) == LISTEN) {
Packit Service aa3af4
    return ERR_CONN;
Packit Service aa3af4
  }
Packit Service aa3af4
  if (shut_rx) {
Packit Service aa3af4
    /* shut down the receive side: set a flag not to receive any more data... */
Packit Service aa3af4
    pcb->flags |= TF_RXCLOSED;
Packit Service aa3af4
    if (shut_tx) {
Packit Service aa3af4
      /* shutting down the tx AND rx side is the same as closing for the raw API */
Packit Service aa3af4
      return tcp_close_shutdown(pcb, 1);
Packit Service aa3af4
    }
Packit Service aa3af4
    /* ... and free buffered data */
Packit Service aa3af4
    if (pcb->refused_data != NULL) {
Packit Service aa3af4
      pbuf_free(pcb->refused_data);
Packit Service aa3af4
      pcb->refused_data = NULL;
Packit Service aa3af4
    }
Packit Service aa3af4
  }
Packit Service aa3af4
  if (shut_tx) {
Packit Service aa3af4
    /* This can't happen twice since if it succeeds, the pcb's state is changed.
Packit Service aa3af4
       Only close in these states as the others directly deallocate the PCB */
Packit Service aa3af4
    switch (get_tcp_state(pcb)) {
Packit Service aa3af4
  case SYN_RCVD:
Packit Service aa3af4
  case ESTABLISHED:
Packit Service aa3af4
  case CLOSE_WAIT:
Packit Service aa3af4
    return tcp_close_shutdown(pcb, 0);
Packit Service aa3af4
  default:
Packit Service aa3af4
      /* Not (yet?) connected, cannot shutdown the TX side as that would bring us
Packit Service aa3af4
	into CLOSED state, where the PCB is deallocated. */
Packit Service aa3af4
      return ERR_CONN;
Packit Service aa3af4
    }
Packit Service aa3af4
  }
Packit Service aa3af4
  /* @todo: return another err_t if not in correct state or already shut? */
Packit Service aa3af4
  return ERR_OK;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Abandons a connection and optionally sends a RST to the remote
Packit Service aa3af4
 * host.  Deletes the local protocol control block. This is done when
Packit Service aa3af4
 * a connection is killed because of shortage of memory.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcb the tcp_pcb to abort
Packit Service aa3af4
 * @param reset boolean to indicate whether a reset should be sent
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_abandon(struct tcp_pcb *pcb, int reset)
Packit Service aa3af4
{
Packit Service aa3af4
  u32_t seqno, ackno;
Packit Service aa3af4
  u16_t remote_port, local_port;
Packit Service aa3af4
  ip_addr_t remote_ip, local_ip;
Packit Service aa3af4
#if LWIP_CALLBACK_API  
Packit Service aa3af4
  tcp_err_fn errf;
Packit Service aa3af4
#endif /* LWIP_CALLBACK_API */
Packit Service aa3af4
  void *errf_arg;
Packit Service aa3af4
Packit Service aa3af4
  /* get_tcp_state(pcb) LISTEN not allowed here */
Packit Service aa3af4
  LWIP_ASSERT("don't call tcp_abort/tcp_abandon for listen-pcbs",
Packit Service aa3af4
		  get_tcp_state(pcb) != LISTEN);
Packit Service aa3af4
  /* Figure out on which TCP PCB list we are, and remove us. If we
Packit Service aa3af4
     are in an active state, call the receive function associated with
Packit Service aa3af4
     the PCB with a NULL argument, and send an RST to the remote end. */
Packit Service aa3af4
  if (get_tcp_state(pcb) == TIME_WAIT) {
Packit Service aa3af4
    tcp_pcb_remove(pcb);
Packit Service aa3af4
  } else {
Packit Service aa3af4
    int send_rst = reset && (get_tcp_state(pcb) != CLOSED);
Packit Service aa3af4
    seqno = pcb->snd_nxt;
Packit Service aa3af4
    ackno = pcb->rcv_nxt;
Packit Service aa3af4
    ip_addr_copy(local_ip, pcb->local_ip);
Packit Service aa3af4
    ip_addr_copy(remote_ip, pcb->remote_ip);
Packit Service aa3af4
    local_port = pcb->local_port;
Packit Service aa3af4
    remote_port = pcb->remote_port;
Packit Service aa3af4
#if LWIP_CALLBACK_API
Packit Service aa3af4
    errf = pcb->errf;
Packit Service aa3af4
#endif /* LWIP_CALLBACK_API */
Packit Service aa3af4
    errf_arg = pcb->my_container;
Packit Service aa3af4
    tcp_pcb_remove(pcb);
Packit Service aa3af4
    if (pcb->unacked != NULL) {
Packit Service aa3af4
      tcp_tx_segs_free(pcb, pcb->unacked);
Packit Service aa3af4
      pcb->unacked = NULL;
Packit Service aa3af4
    }
Packit Service aa3af4
    if (pcb->unsent != NULL) {
Packit Service aa3af4
      tcp_tx_segs_free(pcb, pcb->unsent);
Packit Service aa3af4
      pcb->unsent = NULL;
Packit Service aa3af4
    }
Packit Service aa3af4
#if TCP_QUEUE_OOSEQ    
Packit Service aa3af4
    if (pcb->ooseq != NULL) {
Packit Service aa3af4
      tcp_segs_free(pcb, pcb->ooseq);
Packit Service aa3af4
    }
Packit Service aa3af4
#endif /* TCP_QUEUE_OOSEQ */
Packit Service aa3af4
    TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
Packit Service aa3af4
    if (send_rst) {
Packit Service aa3af4
      LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));
Packit Service aa3af4
      tcp_rst(seqno, ackno, local_port, remote_port, pcb);
Packit Service aa3af4
    }
Packit Service aa3af4
  }
Packit Service aa3af4
  (void)local_ip;  /* Fix warning -Wunused-but-set-variable */
Packit Service aa3af4
  (void)remote_ip; /* Fix warning -Wunused-but-set-variable */
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Aborts the connection by sending a RST (reset) segment to the remote
Packit Service aa3af4
 * host. The pcb is deallocated. This function never fails.
Packit Service aa3af4
 *
Packit Service aa3af4
 * ATTENTION: When calling this from one of the TCP callbacks, make
Packit Service aa3af4
 * sure you always return ERR_ABRT (and never return ERR_ABRT otherwise
Packit Service aa3af4
 * or you will risk accessing deallocated memory or memory leaks!
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcb the tcp pcb to abort
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_abort(struct tcp_pcb *pcb)
Packit Service aa3af4
{
Packit Service aa3af4
  tcp_abandon(pcb, 1);
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Binds the connection to a local portnumber and IP address. If the
Packit Service aa3af4
 * IP address is not given (i.e., ipaddr == NULL), the IP address of
Packit Service aa3af4
 * the outgoing network interface is used instead.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcb the tcp_pcb to bind (no check is done whether this pcb is
Packit Service aa3af4
 *        already bound!)
Packit Service aa3af4
 * @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind
Packit Service aa3af4
 *        to any local address
Packit Service aa3af4
 * @param port the local port to bind to
Packit Service aa3af4
 * @return ERR_USE if the port is already in use
Packit Service aa3af4
 *         ERR_OK if bound
Packit Service aa3af4
 */
Packit Service aa3af4
err_t
Packit Service aa3af4
tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
Packit Service aa3af4
{
Packit Service aa3af4
  LWIP_ERROR("tcp_bind: can only bind in state CLOSED", get_tcp_state(pcb) == CLOSED, return ERR_ISCONN);
Packit Service aa3af4
Packit Service aa3af4
 if (!ip_addr_isany(ipaddr)) {
Packit Service aa3af4
    pcb->local_ip = *ipaddr;
Packit Service aa3af4
  }
Packit Service aa3af4
  pcb->local_port = port;
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port));
Packit Service aa3af4
Packit Service aa3af4
  return ERR_OK;
Packit Service aa3af4
}
Packit Service aa3af4
#if LWIP_CALLBACK_API
Packit Service aa3af4
/**
Packit Service aa3af4
 * Default accept callback if no accept callback is specified by the user.
Packit Service aa3af4
 */
Packit Service aa3af4
static err_t
Packit Service aa3af4
tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)
Packit Service aa3af4
{
Packit Service aa3af4
  LWIP_UNUSED_ARG(arg);
Packit Service aa3af4
  LWIP_UNUSED_ARG(pcb);
Packit Service aa3af4
  LWIP_UNUSED_ARG(err);
Packit Service aa3af4
Packit Service aa3af4
  return ERR_ABRT;
Packit Service aa3af4
}
Packit Service aa3af4
#endif /* LWIP_CALLBACK_API */
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Set the state of the connection to be LISTEN, which means that it
Packit Service aa3af4
 * is able to accept incoming connections.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param listen_pcb used for listening
Packit Service aa3af4
 * @param pcb the original tcp_pcb
Packit Service aa3af4
 * @return ERR_ISCONN if the conn_pcb is already in LISTEN state
Packit Service aa3af4
 * and ERR_OK on success
Packit Service aa3af4
 *
Packit Service aa3af4
 */
Packit Service aa3af4
err_t
Packit Service aa3af4
tcp_listen(struct tcp_pcb_listen *listen_pcb, struct tcp_pcb *pcb)
Packit Service aa3af4
{
Packit Service aa3af4
  /*
Packit Service aa3af4
  * LWIP_ERROR("tcp_listen: conn_pcb already connected", get_tcp_state(pcb) == CLOSED, ERR_ISCONN);
Packit Service aa3af4
  */
Packit Service aa3af4
Packit Service aa3af4
  /* already listening? */
Packit Service aa3af4
  if (!listen_pcb || (!pcb || get_tcp_state(pcb) == LISTEN)) {
Packit Service aa3af4
    return ERR_ISCONN;
Packit Service aa3af4
  }
Packit Service aa3af4
  listen_pcb->callback_arg = pcb->callback_arg;
Packit Service aa3af4
  listen_pcb->local_port = pcb->local_port;
Packit Service aa3af4
  set_tcp_state(listen_pcb, LISTEN);
Packit Service aa3af4
  listen_pcb->prio = pcb->prio;
Packit Service aa3af4
  listen_pcb->so_options = pcb->so_options;
Packit Service aa3af4
  listen_pcb->so_options |= SOF_ACCEPTCONN;
Packit Service aa3af4
  listen_pcb->ttl = pcb->ttl;
Packit Service aa3af4
  listen_pcb->tos = pcb->tos;
Packit Service aa3af4
  ip_addr_copy(listen_pcb->local_ip, pcb->local_ip);
Packit Service aa3af4
#if LWIP_CALLBACK_API
Packit Service aa3af4
  listen_pcb->accept = tcp_accept_null;
Packit Service aa3af4
#endif /* LWIP_CALLBACK_API */
Packit Service aa3af4
  return ERR_OK;
Packit Service aa3af4
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/** 
Packit Service aa3af4
 * Update the state that tracks the available window space to advertise.
Packit Service aa3af4
 *
Packit Service aa3af4
 * Returns how much extra window would be advertised if we sent an
Packit Service aa3af4
 * update now.
Packit Service aa3af4
 */
Packit Service aa3af4
u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)
Packit Service aa3af4
{
Packit Service aa3af4
  u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd;
Packit Service aa3af4
Packit Service aa3af4
  if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((pcb->rcv_wnd_max / 2), pcb->mss))) {
Packit Service aa3af4
    /* we can advertise more window */
Packit Service aa3af4
    pcb->rcv_ann_wnd = pcb->rcv_wnd;
Packit Service aa3af4
    return new_right_edge - pcb->rcv_ann_right_edge;
Packit Service aa3af4
  } else {
Packit Service aa3af4
    if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) {
Packit Service aa3af4
      /* Can happen due to other end sending out of advertised window,
Packit Service aa3af4
       * but within actual available (but not yet advertised) window */
Packit Service aa3af4
      pcb->rcv_ann_wnd = 0;
Packit Service aa3af4
    } else {
Packit Service aa3af4
      /* keep the right edge of window constant */
Packit Service aa3af4
      u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt;
Packit Service aa3af4
      LWIP_ASSERT("new_rcv_ann_wnd <= 0xffff00", new_rcv_ann_wnd <= 0xffff00);
Packit Service aa3af4
      pcb->rcv_ann_wnd = new_rcv_ann_wnd;
Packit Service aa3af4
    }
Packit Service aa3af4
    return 0;
Packit Service aa3af4
  }
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * This function should be called by the application when it has
Packit Service aa3af4
 * processed the data. The purpose is to advertise a larger window
Packit Service aa3af4
 * when the data has been processed.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcb the tcp_pcb for which data is read
Packit Service aa3af4
 * @param len the amount of bytes that have been read by the application
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_recved(struct tcp_pcb *pcb, u32_t len)
Packit Service aa3af4
{
Packit Service aa3af4
  u32_t wnd_inflation;
Packit Service aa3af4
Packit Service aa3af4
  LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n",
Packit Service aa3af4
              len <= 0xffffffffU - pcb->rcv_wnd );
Packit Service aa3af4
Packit Service aa3af4
  pcb->rcv_wnd += len;
Packit Service aa3af4
  if (pcb->rcv_wnd > pcb->rcv_wnd_max) {
Packit Service aa3af4
    pcb->rcv_wnd = pcb->rcv_wnd_max;
Packit Service aa3af4
  } else if(pcb->rcv_wnd == 0) {
Packit Service aa3af4
  /* rcv_wnd overflowed */
Packit Service aa3af4
    if ((get_tcp_state(pcb) == CLOSE_WAIT) || (get_tcp_state(pcb) == LAST_ACK)) {
Packit Service aa3af4
      /* In passive close, we allow this, since the FIN bit is added to rcv_wnd
Packit Service aa3af4
         by the stack itself, since it is not mandatory for an application
Packit Service aa3af4
         to call tcp_recved() for the FIN bit, but e.g. the netconn API does so. */
Packit Service aa3af4
      pcb->rcv_wnd = pcb->rcv_wnd_max;
Packit Service aa3af4
    } else {
Packit Service aa3af4
      LWIP_ASSERT("tcp_recved: len wrapped rcv_wnd\n", 0);
Packit Service aa3af4
    }
Packit Service aa3af4
  }
Packit Service aa3af4
Packit Service aa3af4
  wnd_inflation = tcp_update_rcv_ann_wnd(pcb);
Packit Service aa3af4
Packit Service aa3af4
  /* If the change in the right edge of window is significant (default
Packit Service aa3af4
   * watermark is TCP_WND/4), then send an explicit update now.
Packit Service aa3af4
   * Otherwise wait for a packet to be sent in the normal course of
Packit Service aa3af4
   * events (or more window to be available later) */
Packit Service aa3af4
  if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) {
Packit Service aa3af4
    tcp_ack_now(pcb);
Packit Service aa3af4
    tcp_output(pcb);
Packit Service aa3af4
  }
Packit Service aa3af4
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n",
Packit Service aa3af4
         len, pcb->rcv_wnd, TCP_WND_SCALED(pcb) - pcb->rcv_wnd));
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Connects to another host. The function given as the "connected"
Packit Service aa3af4
 * argument will be called when the connection has been established.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcb the tcp_pcb used to establish the connection
Packit Service aa3af4
 * @param ipaddr the remote ip address to connect to
Packit Service aa3af4
 * @param port the remote tcp port to connect to
Packit Service aa3af4
 * @param connected callback function to call when connected (or on error)
Packit Service aa3af4
 * @return ERR_VAL if invalid arguments are given
Packit Service aa3af4
 *         ERR_OK if connect request has been sent
Packit Service aa3af4
 *         other err_t values if connect request couldn't be sent
Packit Service aa3af4
 */
Packit Service aa3af4
err_t
Packit Service aa3af4
tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
Packit Service aa3af4
      tcp_connected_fn connected)
Packit Service aa3af4
{
Packit Service aa3af4
  err_t ret;
Packit Service aa3af4
  u32_t iss;
Packit Service aa3af4
Packit Service aa3af4
  LWIP_ERROR("tcp_connect: can only connected from state CLOSED", get_tcp_state(pcb) == CLOSED, return ERR_ISCONN);
Packit Service aa3af4
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));
Packit Service aa3af4
  if (ipaddr != NULL) {
Packit Service aa3af4
    pcb->remote_ip = *ipaddr;
Packit Service aa3af4
  } else {
Packit Service aa3af4
    return ERR_VAL;
Packit Service aa3af4
  }
Packit Service aa3af4
  pcb->remote_port = port;
Packit Service aa3af4
Packit Service aa3af4
  /* check if we have a route to the remote host */
Packit Service aa3af4
  if (ip_addr_isany(&(pcb->local_ip))) {
Packit Service aa3af4
	  LWIP_ASSERT("tcp_connect: need to find route to host", 0);
Packit Service aa3af4
  }
Packit Service aa3af4
Packit Service aa3af4
  if (pcb->local_port == 0) {
Packit Service aa3af4
    return ERR_VAL;
Packit Service aa3af4
  }
Packit Service aa3af4
  iss = tcp_next_iss();
Packit Service aa3af4
  pcb->rcv_nxt = 0;
Packit Service aa3af4
  pcb->snd_nxt = iss;
Packit Service aa3af4
  pcb->lastack = iss - 1;
Packit Service aa3af4
  pcb->snd_lbb = iss - 1;
Packit Service aa3af4
  pcb->rcv_ann_right_edge = pcb->rcv_nxt;
Packit Service aa3af4
  pcb->snd_wnd = TCP_WND;
Packit Service aa3af4
  /* 
Packit Service aa3af4
   * For effective and advertized MSS without MTU consideration:
Packit Service aa3af4
   * If MSS is configured - do not accept a higher value than 536 
Packit Service aa3af4
   * If MSS is not configured assume minimum value of 536 
Packit Service aa3af4
   * The send MSS is updated when an MSS option is received 
Packit Service aa3af4
   */
Packit Service aa3af4
  u16_t snd_mss = pcb->advtsd_mss = (LWIP_TCP_MSS) ? ((LWIP_TCP_MSS > 536) ? 536 : LWIP_TCP_MSS) : 536;
Packit Service aa3af4
  UPDATE_PCB_BY_MSS(pcb, snd_mss); 
Packit Service aa3af4
#if TCP_CALCULATE_EFF_SEND_MSS
Packit Service aa3af4
  /* 
Packit Service aa3af4
   * For advertized MSS with MTU knowledge - it is highly likely that it can be derived from the MTU towards the remote IP address. 
Packit Service aa3af4
   * Otherwise (if unlikely MTU==0)
Packit Service aa3af4
   * If LWIP_TCP_MSS>0 use it as MSS 
Packit Service aa3af4
   * If LWIP_TCP_MSS==0 set advertized MSS value to default 536
Packit Service aa3af4
   */
Packit Service aa3af4
  pcb->advtsd_mss = (LWIP_TCP_MSS > 0) ? tcp_eff_send_mss(LWIP_TCP_MSS, pcb) : tcp_mss_follow_mtu_with_default(536, pcb);
Packit Service aa3af4
  /* 
Packit Service aa3af4
   * For effective MSS with MTU knowledge - get the minimum between pcb->mss and the MSS derived from the 
Packit Service aa3af4
   * MTU towards the remote IP address 
Packit Service aa3af4
   * */
Packit Service aa3af4
  u16_t eff_mss = tcp_eff_send_mss(pcb->mss, pcb);
Packit Service aa3af4
  UPDATE_PCB_BY_MSS(pcb, eff_mss);
Packit Service aa3af4
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
Packit Service aa3af4
  pcb->cwnd = 1;
Packit Service aa3af4
  pcb->ssthresh = pcb->mss * 10;
Packit Service aa3af4
  pcb->connected = connected;
Packit Service aa3af4
Packit Service aa3af4
  /* Send a SYN together with the MSS option. */
Packit Service aa3af4
  ret = tcp_enqueue_flags(pcb, TCP_SYN);
Packit Service aa3af4
  if (ret == ERR_OK) {
Packit Service aa3af4
    /* SYN segment was enqueued, changed the pcbs state now */
Packit Service aa3af4
	  set_tcp_state(pcb, SYN_SENT);
Packit Service aa3af4
Packit Service aa3af4
    tcp_output(pcb);
Packit Service aa3af4
  }
Packit Service aa3af4
  return ret;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Called every slow_tmr_interval ms and implements the retransmission timer and the timer that
Packit Service aa3af4
 * closes the psb if it in TIME_WAIT state for enough time. It also increments
Packit Service aa3af4
 * various timers such as the inactivity timer in PCB.
Packit Service aa3af4
 *
Packit Service aa3af4
 * Automatically called from tcp_tmr().
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_slowtmr(struct tcp_pcb* pcb)
Packit Service aa3af4
{
Packit Service aa3af4
#if !TCP_CC_ALGO_MOD
Packit Service aa3af4
  u32_t eff_wnd;
Packit Service aa3af4
#endif //!TCP_CC_ALGO_MOD
Packit Service aa3af4
  u8_t pcb_remove;      /* flag if a PCB should be removed */
Packit Service aa3af4
  u8_t pcb_reset;       /* flag if a RST should be sent when removing */
Packit Service aa3af4
  err_t err;
Packit Service aa3af4
Packit Service aa3af4
  err = ERR_OK;
Packit Service aa3af4
Packit Service aa3af4
  if (pcb == NULL) {
Packit Service aa3af4
	LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));
Packit Service aa3af4
  }
Packit Service aa3af4
Packit Service aa3af4
  if (pcb && PCB_IN_ACTIVE_STATE(pcb)) {
Packit Service aa3af4
	LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n"));
Packit Service aa3af4
	LWIP_ASSERT("tcp_slowtmr: active get_tcp_state(pcb) != CLOSED\n", get_tcp_state(pcb) != CLOSED);
Packit Service aa3af4
	LWIP_ASSERT("tcp_slowtmr: active get_tcp_state(pcb) != LISTEN\n", get_tcp_state(pcb) != LISTEN);
Packit Service aa3af4
	LWIP_ASSERT("tcp_slowtmr: active get_tcp_state(pcb) != TIME-WAIT\n", get_tcp_state(pcb) != TIME_WAIT);
Packit Service aa3af4
Packit Service aa3af4
	pcb_remove = 0;
Packit Service aa3af4
	pcb_reset = 0;
Packit Service aa3af4
Packit Service aa3af4
	if (get_tcp_state(pcb) == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {
Packit Service aa3af4
	  ++pcb_remove;
Packit Service aa3af4
	  err = ERR_TIMEOUT;
Packit Service aa3af4
	  LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n"));
Packit Service aa3af4
	}
Packit Service aa3af4
	else if (pcb->nrtx == TCP_MAXRTX) {
Packit Service aa3af4
	  ++pcb_remove;
Packit Service aa3af4
	  err = ERR_ABRT;
Packit Service aa3af4
	  LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));
Packit Service aa3af4
	} else {
Packit Service aa3af4
	  if (pcb->persist_backoff > 0) {
Packit Service aa3af4
		/* If snd_wnd is zero and pcb->unacked is NULL , use persist timer to send 1 byte probes
Packit Service aa3af4
		 * instead of using the standard retransmission mechanism. */
Packit Service aa3af4
		pcb->persist_cnt++;
Packit Service aa3af4
		if (pcb->persist_cnt >= tcp_persist_backoff[pcb->persist_backoff-1]) {
Packit Service aa3af4
		  pcb->persist_cnt = 0;
Packit Service aa3af4
		  if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) {
Packit Service aa3af4
			pcb->persist_backoff++;
Packit Service aa3af4
		  }
Packit Service aa3af4
		  /* Use tcp_keepalive() instead of tcp_zero_window_probe() to probe for window update
Packit Service aa3af4
		   * without sending any data (which will force us to split the segment).
Packit Service aa3af4
		   * tcp_zero_window_probe(pcb); */
Packit Service aa3af4
		  tcp_keepalive(pcb);
Packit Service aa3af4
		}
Packit Service aa3af4
	  } else {
Packit Service aa3af4
		/* Increase the retransmission timer if it is running */
Packit Service aa3af4
		if(pcb->rtime >= 0)
Packit Service aa3af4
		  ++pcb->rtime;
Packit Service aa3af4
Packit Service aa3af4
		if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {
Packit Service aa3af4
		  /* Time for a retransmission. */
Packit Service aa3af4
		  LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F
Packit Service aa3af4
									  " pcb->rto %"S16_F"\n",
Packit Service aa3af4
									  pcb->rtime, pcb->rto));
Packit Service aa3af4
Packit Service aa3af4
		  /* Double retransmission time-out unless we are trying to
Packit Service aa3af4
		   * connect to somebody (i.e., we are in SYN_SENT). */
Packit Service aa3af4
		  if (get_tcp_state(pcb) != SYN_SENT) {
Packit Service aa3af4
			pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];
Packit Service aa3af4
		  }
Packit Service aa3af4
Packit Service aa3af4
		  /* Reset the retransmission timer. */
Packit Service aa3af4
		  pcb->rtime = 0;
Packit Service aa3af4
Packit Service aa3af4
#if TCP_CC_ALGO_MOD
Packit Service aa3af4
		  cc_cong_signal(pcb, CC_RTO);
Packit Service aa3af4
#else
Packit Service aa3af4
		  /* Reduce congestion window and ssthresh. */
Packit Service aa3af4
		  eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);
Packit Service aa3af4
		  pcb->ssthresh = eff_wnd >> 1;
Packit Service aa3af4
		  if (pcb->ssthresh < (u32_t)(pcb->mss << 1)) {
Packit Service aa3af4
			pcb->ssthresh = (pcb->mss << 1);
Packit Service aa3af4
		  }
Packit Service aa3af4
		  pcb->cwnd = pcb->mss;
Packit Service aa3af4
#endif
Packit Service aa3af4
		  LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F
Packit Service aa3af4
									   " ssthresh %"U16_F"\n",
Packit Service aa3af4
									   pcb->cwnd, pcb->ssthresh));
Packit Service aa3af4
Packit Service aa3af4
		  /* The following needs to be called AFTER cwnd is set to one
Packit Service aa3af4
			 mss - STJ */
Packit Service aa3af4
		  tcp_rexmit_rto(pcb);
Packit Service aa3af4
		}
Packit Service aa3af4
	  }
Packit Service aa3af4
	}
Packit Service aa3af4
	/* Check if this PCB has stayed too long in FIN-WAIT-2 */
Packit Service aa3af4
	if (get_tcp_state(pcb) == FIN_WAIT_2) {
Packit Service aa3af4
		/* If this PCB is in FIN_WAIT_2 because of SHUT_WR don't let it time out. */
Packit Service aa3af4
		if (pcb->flags & TF_RXCLOSED) {
Packit Service aa3af4
			/* PCB was fully closed (either through close() or SHUT_RDWR):
Packit Service aa3af4
	   	   	   normal FIN-WAIT timeout handling. */
Packit Service aa3af4
			if ((u32_t)(tcp_ticks - pcb->tmr) >
Packit Service aa3af4
			TCP_FIN_WAIT_TIMEOUT / slow_tmr_interval) {
Packit Service aa3af4
				++pcb_remove;
Packit Service aa3af4
				err = ERR_ABRT;
Packit Service aa3af4
				LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));
Packit Service aa3af4
			}
Packit Service aa3af4
		}
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	/* Check if KEEPALIVE should be sent */
Packit Service aa3af4
	if((pcb->so_options & SOF_KEEPALIVE) &&
Packit Service aa3af4
	   ((get_tcp_state(pcb) == ESTABLISHED) ||
Packit Service aa3af4
		(get_tcp_state(pcb) == CLOSE_WAIT))) {
Packit Service aa3af4
#if LWIP_TCP_KEEPALIVE
Packit Service aa3af4
	  if((u32_t)(tcp_ticks - pcb->tmr) >
Packit Service aa3af4
		 (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl))
Packit Service aa3af4
		 / slow_tmr_interval)
Packit Service aa3af4
#else
Packit Service aa3af4
	  if((u32_t)(tcp_ticks - pcb->tmr) >
Packit Service aa3af4
		 (pcb->keep_idle + TCP_MAXIDLE) / slow_tmr_interval)
Packit Service aa3af4
#endif /* LWIP_TCP_KEEPALIVE */
Packit Service aa3af4
	  {
Packit Service aa3af4
		LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",
Packit Service aa3af4
								ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
Packit Service aa3af4
								ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
Packit Service aa3af4
Packit Service aa3af4
		++pcb_remove;
Packit Service aa3af4
		err = ERR_ABRT;
Packit Service aa3af4
		++pcb_reset;
Packit Service aa3af4
	  }
Packit Service aa3af4
#if LWIP_TCP_KEEPALIVE
Packit Service aa3af4
	  else if((u32_t)(tcp_ticks - pcb->tmr) >
Packit Service aa3af4
			  (pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl)
Packit Service aa3af4
			  / slow_tmr_interval)
Packit Service aa3af4
#else
Packit Service aa3af4
	  else if((u32_t)(tcp_ticks - pcb->tmr) >
Packit Service aa3af4
			  (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT)
Packit Service aa3af4
			  / slow_tmr_interval)
Packit Service aa3af4
#endif /* LWIP_TCP_KEEPALIVE */
Packit Service aa3af4
	  {
Packit Service aa3af4
		tcp_keepalive(pcb);
Packit Service aa3af4
		pcb->keep_cnt_sent++;
Packit Service aa3af4
	  }
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	/* If this PCB has queued out of sequence data, but has been
Packit Service aa3af4
	   inactive for too long, will drop the data (it will eventually
Packit Service aa3af4
	   be retransmitted). */
Packit Service aa3af4
#if TCP_QUEUE_OOSEQ
Packit Service aa3af4
	if (pcb->ooseq != NULL &&
Packit Service aa3af4
		(u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) {
Packit Service aa3af4
	  tcp_segs_free(pcb, pcb->ooseq);
Packit Service aa3af4
	  pcb->ooseq = NULL;
Packit Service aa3af4
	  LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n"));
Packit Service aa3af4
	}
Packit Service aa3af4
#endif /* TCP_QUEUE_OOSEQ */
Packit Service aa3af4
Packit Service aa3af4
	/* Check if this PCB has stayed too long in SYN-RCVD */
Packit Service aa3af4
	if (get_tcp_state(pcb) == SYN_RCVD) {
Packit Service aa3af4
	  if ((u32_t)(tcp_ticks - pcb->tmr) >
Packit Service aa3af4
		  TCP_SYN_RCVD_TIMEOUT / slow_tmr_interval) {
Packit Service aa3af4
		++pcb_remove;
Packit Service aa3af4
		err = ERR_ABRT;
Packit Service aa3af4
		LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n"));
Packit Service aa3af4
	  }
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	/* Check if this PCB has stayed too long in LAST-ACK */
Packit Service aa3af4
	if (get_tcp_state(pcb) == LAST_ACK) {
Packit Service aa3af4
	  if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / slow_tmr_interval) {
Packit Service aa3af4
		++pcb_remove;
Packit Service aa3af4
		err = ERR_ABRT;
Packit Service aa3af4
		LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n"));
Packit Service aa3af4
	  }
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	/* If the PCB should be removed, do it. */
Packit Service aa3af4
	if (pcb_remove) {
Packit Service aa3af4
	  tcp_pcb_purge(pcb);
Packit Service aa3af4
Packit Service aa3af4
	  TCP_EVENT_ERR(pcb->errf, pcb->my_container, err);
Packit Service aa3af4
Packit Service aa3af4
	  if (pcb_reset) {
Packit Service aa3af4
		tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, pcb->local_port, pcb->remote_port, pcb);
Packit Service aa3af4
	  }
Packit Service aa3af4
	  set_tcp_state(pcb, CLOSED);
Packit Service aa3af4
	} else {
Packit Service aa3af4
	   /* We check if we should poll the connection. */
Packit Service aa3af4
	  ++pcb->polltmr;
Packit Service aa3af4
	  if (pcb->polltmr >= pcb->pollinterval) {
Packit Service aa3af4
		  pcb->polltmr = 0;
Packit Service aa3af4
		LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));
Packit Service aa3af4
		TCP_EVENT_POLL(pcb, err);
Packit Service aa3af4
		/* if err == ERR_ABRT, 'prev' is already deallocated */
Packit Service aa3af4
		if (err == ERR_OK) {
Packit Service aa3af4
		  tcp_output(pcb);
Packit Service aa3af4
		}
Packit Service aa3af4
	  }
Packit Service aa3af4
	}
Packit Service aa3af4
  }
Packit Service aa3af4
Packit Service aa3af4
Packit Service aa3af4
  if (pcb && PCB_IN_TIME_WAIT_STATE(pcb)) {
Packit Service aa3af4
	LWIP_ASSERT("tcp_slowtmr: TIME-WAIT get_tcp_state(pcb) == TIME-WAIT", get_tcp_state(pcb) == TIME_WAIT);
Packit Service aa3af4
	pcb_remove = 0;
Packit Service aa3af4
Packit Service aa3af4
	/* Check if this PCB has stayed long enough in TIME-WAIT */
Packit Service aa3af4
	if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / slow_tmr_interval) {
Packit Service aa3af4
	  ++pcb_remove;
Packit Service aa3af4
	  /* err = ERR_ABRT; */ /* Note: suppress warning 'err' is never read */
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	/* If the PCB should be removed, do it. */
Packit Service aa3af4
	if (pcb_remove) {
Packit Service aa3af4
	  tcp_pcb_purge(pcb);
Packit Service aa3af4
Packit Service aa3af4
	  set_tcp_state(pcb, CLOSED);
Packit Service aa3af4
	}
Packit Service aa3af4
  }
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Is called every slow_tmr_interval and process data previously
Packit Service aa3af4
 * "refused" by upper layer (application) and sends delayed ACKs.
Packit Service aa3af4
 *
Packit Service aa3af4
 * Automatically called from tcp_tmr().
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_fasttmr(struct tcp_pcb* pcb)
Packit Service aa3af4
{
Packit Service aa3af4
  if(pcb != NULL && PCB_IN_ACTIVE_STATE(pcb)) {
Packit Service aa3af4
    /* If there is data which was previously "refused" by upper layer */
Packit Service aa3af4
	  while (pcb->refused_data != NULL) { // 'while' instead of 'if' because windows scale uses large pbuf
Packit Service aa3af4
		  struct pbuf *rest;
Packit Service aa3af4
		  /* Notify again application with data previously received. */
Packit Service aa3af4
		  err_t err;
Packit Service aa3af4
		  pbuf_split_64k(pcb->refused_data, &rest);
Packit Service aa3af4
		  LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n"));
Packit Service aa3af4
		  TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
Packit Service aa3af4
		  if (err == ERR_OK) {
Packit Service aa3af4
			  pcb->refused_data = rest;
Packit Service aa3af4
		  } else {
Packit Service aa3af4
			  if (rest) {
Packit Service aa3af4
				  pbuf_cat(pcb->refused_data, rest); /* undo splitting */
Packit Service aa3af4
			  }
Packit Service aa3af4
			  if (err == ERR_ABRT) {
Packit Service aa3af4
				  /* if err == ERR_ABRT, 'pcb' is already deallocated */
Packit Service aa3af4
				  pcb = NULL;
Packit Service aa3af4
			  }
Packit Service aa3af4
			  break;
Packit Service aa3af4
		  }
Packit Service aa3af4
    }
Packit Service aa3af4
Packit Service aa3af4
    /* send delayed ACKs */
Packit Service aa3af4
    if (pcb && (pcb->flags & TF_ACK_DELAY)) {
Packit Service aa3af4
      LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));
Packit Service aa3af4
      tcp_ack_now(pcb);
Packit Service aa3af4
      tcp_output(pcb);
Packit Service aa3af4
      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
Packit Service aa3af4
    }
Packit Service aa3af4
  }
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Deallocates a list of TCP segments (tcp_seg structures).
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param seg tcp_seg list of TCP segments to free
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_segs_free(struct tcp_pcb *pcb, struct tcp_seg *seg)
Packit Service aa3af4
{
Packit Service aa3af4
  while (seg != NULL) {
Packit Service aa3af4
    struct tcp_seg *next = seg->next;
Packit Service aa3af4
    seg->next = NULL;
Packit Service aa3af4
    tcp_seg_free(pcb, seg);
Packit Service aa3af4
    seg = next;
Packit Service aa3af4
  }
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Frees a TCP segment (tcp_seg structure).
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param seg single tcp_seg to free
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_seg_free(struct tcp_pcb *pcb, struct tcp_seg *seg)
Packit Service aa3af4
{
Packit Service aa3af4
  if (seg != NULL) {
Packit Service aa3af4
    if (seg->p != NULL) {
Packit Service aa3af4
      pbuf_free(seg->p);
Packit Service aa3af4
#if TCP_DEBUG
Packit Service aa3af4
      seg->p = NULL;
Packit Service aa3af4
#endif /* TCP_DEBUG */
Packit Service aa3af4
    }
Packit Service aa3af4
    external_tcp_seg_free(pcb, seg);
Packit Service aa3af4
  }
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Deallocates a list of TCP segments (tcp_seg structures).
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param seg tcp_seg list of TCP segments to free
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_tx_segs_free(struct tcp_pcb * pcb, struct tcp_seg *seg)
Packit Service aa3af4
{
Packit Service aa3af4
  while (seg != NULL) {
Packit Service aa3af4
    struct tcp_seg *next = seg->next;
Packit Service aa3af4
    seg->next = NULL;
Packit Service aa3af4
    tcp_tx_seg_free(pcb, seg);
Packit Service aa3af4
    seg = next;
Packit Service aa3af4
  }
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Frees a TCP segment (tcp_seg structure).
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param seg single tcp_seg to free
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_tx_seg_free(struct tcp_pcb * pcb, struct tcp_seg *seg)
Packit Service aa3af4
{
Packit Service aa3af4
  if (seg != NULL) {
Packit Service aa3af4
    if (seg->p != NULL) {
Packit Service aa3af4
      tcp_tx_pbuf_free(pcb, seg->p);
Packit Service aa3af4
    }
Packit Service aa3af4
    external_tcp_seg_free(pcb, seg);
Packit Service aa3af4
  }
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
#if TCP_QUEUE_OOSEQ
Packit Service aa3af4
/**
Packit Service aa3af4
 * Returns a copy of the given TCP segment.
Packit Service aa3af4
 * The pbuf and data are not copied, only the pointers
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param seg the old tcp_seg
Packit Service aa3af4
 * @return a copy of seg
Packit Service aa3af4
 */ 
Packit Service aa3af4
struct tcp_seg *
Packit Service aa3af4
tcp_seg_copy(struct tcp_pcb* pcb, struct tcp_seg *seg)
Packit Service aa3af4
{
Packit Service aa3af4
  struct tcp_seg *cseg;
Packit Service aa3af4
Packit Service aa3af4
  cseg = external_tcp_seg_alloc(pcb);
Packit Service aa3af4
  if (cseg == NULL) {
Packit Service aa3af4
    return NULL;
Packit Service aa3af4
  }
Packit Service aa3af4
  SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); 
Packit Service aa3af4
  pbuf_ref(cseg->p);
Packit Service aa3af4
  return cseg;
Packit Service aa3af4
}
Packit Service aa3af4
#endif /* TCP_QUEUE_OOSEQ */
Packit Service aa3af4
Packit Service aa3af4
#if LWIP_CALLBACK_API
Packit Service aa3af4
/**
Packit Service aa3af4
 * Default receive callback that is called if the user didn't register
Packit Service aa3af4
 * a recv callback for the pcb.
Packit Service aa3af4
 */
Packit Service aa3af4
err_t
Packit Service aa3af4
tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
Packit Service aa3af4
{
Packit Service aa3af4
  LWIP_UNUSED_ARG(arg);
Packit Service aa3af4
  if (p != NULL) {
Packit Service aa3af4
    tcp_recved(pcb, (u32_t)p->tot_len);
Packit Service aa3af4
    pbuf_free(p);
Packit Service aa3af4
  } else if (err == ERR_OK) {
Packit Service aa3af4
    return tcp_close(pcb);
Packit Service aa3af4
  }
Packit Service aa3af4
  return ERR_OK;
Packit Service aa3af4
}
Packit Service aa3af4
#endif /* LWIP_CALLBACK_API */
Packit Service aa3af4
Packit Service aa3af4
void tcp_pcb_init (struct tcp_pcb* pcb, u8_t prio)
Packit Service aa3af4
{
Packit Service aa3af4
	u32_t iss;
Packit Service aa3af4
Packit Service aa3af4
	memset(pcb, 0, sizeof(*pcb));
Packit Service aa3af4
	pcb->max_snd_buff = TCP_SND_BUF;
Packit Service aa3af4
	pcb->prio = prio;
Packit Service aa3af4
	pcb->snd_buf = pcb->max_snd_buff;
Packit Service aa3af4
	pcb->snd_queuelen = 0;
Packit Service aa3af4
	pcb->snd_scale = 0;
Packit Service aa3af4
	pcb->rcv_scale = 0;
Packit Service aa3af4
	pcb->rcv_wnd = TCP_WND_SCALED(pcb);
Packit Service aa3af4
	pcb->rcv_ann_wnd = TCP_WND_SCALED(pcb);
Packit Service aa3af4
	pcb->rcv_wnd_max = TCP_WND_SCALED(pcb);
Packit Service aa3af4
	pcb->rcv_wnd_max_desired = TCP_WND_SCALED(pcb);
Packit Service aa3af4
	pcb->tos = 0;
Packit Service aa3af4
	pcb->ttl = TCP_TTL;
Packit Service aa3af4
	/* As initial send MSS, we use TCP_MSS but limit it to 536.
Packit Service aa3af4
	   The send MSS is updated when an MSS option is received. */
Packit Service aa3af4
	u16_t snd_mss = pcb->advtsd_mss = (LWIP_TCP_MSS) ? ((LWIP_TCP_MSS > 536) ? 536 : LWIP_TCP_MSS) : 536;
Packit Service aa3af4
	UPDATE_PCB_BY_MSS(pcb, snd_mss);
Packit Service aa3af4
	pcb->max_unsent_len = pcb->max_tcp_snd_queuelen;
Packit Service aa3af4
	pcb->rto = 3000 / slow_tmr_interval;
Packit Service aa3af4
	pcb->sa = 0;
Packit Service aa3af4
	pcb->sv = 3000 / slow_tmr_interval;
Packit Service aa3af4
	pcb->rtime = -1;
Packit Service aa3af4
#if TCP_CC_ALGO_MOD
Packit Service aa3af4
	switch (lwip_cc_algo_module) {
Packit Service aa3af4
	case CC_MOD_CUBIC:
Packit Service aa3af4
		pcb->cc_algo = &cubic_cc_algo;
Packit Service aa3af4
		break;
Packit Service aa3af4
	case CC_MOD_NONE:
Packit Service aa3af4
		pcb->cc_algo = &none_cc_algo;
Packit Service aa3af4
		break;
Packit Service aa3af4
	case CC_MOD_LWIP:
Packit Service aa3af4
	default:
Packit Service aa3af4
		pcb->cc_algo = &lwip_cc_algo;
Packit Service aa3af4
		break;
Packit Service aa3af4
	}
Packit Service aa3af4
	cc_init(pcb);
Packit Service aa3af4
#endif
Packit Service aa3af4
	pcb->cwnd = 1;
Packit Service aa3af4
	iss = tcp_next_iss();
Packit Service aa3af4
	pcb->snd_wl2 = iss;
Packit Service aa3af4
	pcb->snd_nxt = iss;
Packit Service aa3af4
	pcb->lastack = iss;
Packit Service aa3af4
	pcb->snd_lbb = iss;
Packit Service aa3af4
	pcb->tmr = tcp_ticks;
Packit Service aa3af4
	pcb->snd_sml_snt = 0;
Packit Service aa3af4
	pcb->snd_sml_add = 0;
Packit Service aa3af4
Packit Service aa3af4
	pcb->polltmr = 0;
Packit Service aa3af4
	pcb->tcp_timer = 0;
Packit Service aa3af4
#if LWIP_CALLBACK_API
Packit Service aa3af4
	pcb->recv = tcp_recv_null;
Packit Service aa3af4
#endif /* LWIP_CALLBACK_API */
Packit Service aa3af4
Packit Service aa3af4
	/* Init KEEPALIVE timer */
Packit Service aa3af4
	pcb->keep_idle  = TCP_KEEPIDLE_DEFAULT;
Packit Service aa3af4
Packit Service aa3af4
#if LWIP_TCP_KEEPALIVE
Packit Service aa3af4
	pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT;
Packit Service aa3af4
	pcb->keep_cnt   = TCP_KEEPCNT_DEFAULT;
Packit Service aa3af4
#endif /* LWIP_TCP_KEEPALIVE */
Packit Service aa3af4
Packit Service aa3af4
	pcb->keep_cnt_sent = 0;
Packit Service aa3af4
	pcb->quickack = 0;
Packit Service aa3af4
	pcb->enable_ts_opt = enable_ts_option;
Packit Service aa3af4
	pcb->seg_alloc = NULL;
Packit Service aa3af4
	pcb->pbuf_alloc = NULL;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
struct pbuf *
Packit Service aa3af4
tcp_tx_pbuf_alloc(struct tcp_pcb * pcb, u16_t length, pbuf_type type)
Packit Service aa3af4
{
Packit Service aa3af4
	struct pbuf * p;
Packit Service aa3af4
Packit Service aa3af4
	if (!pcb->pbuf_alloc) {
Packit Service aa3af4
Packit Service aa3af4
		// pbuf_alloc is not valid, we should allocate a new pbuf.
Packit Service aa3af4
		p = external_tcp_tx_pbuf_alloc(pcb);
Packit Service aa3af4
		if (!p) return NULL;
Packit Service aa3af4
Packit Service aa3af4
		p->next = NULL;
Packit Service aa3af4
		p->type = type;
Packit Service aa3af4
		/* set reference count */
Packit Service aa3af4
		p->ref = 1;
Packit Service aa3af4
		/* set flags */
Packit Service aa3af4
		p->flags = 0;
Packit Service aa3af4
	} else {
Packit Service aa3af4
		// pbuf_alloc is valid, we dont need to allocate a new pbuf element.
Packit Service aa3af4
		p = pcb->pbuf_alloc;
Packit Service aa3af4
		pcb->pbuf_alloc = NULL;
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	/* Set up internal structure of the pbuf. */
Packit Service aa3af4
	p->len = p->tot_len = length;
Packit Service aa3af4
Packit Service aa3af4
	return p;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
// Release preallocated buffers
Packit Service aa3af4
void tcp_tx_preallocted_buffers_free(struct tcp_pcb * pcb)
Packit Service aa3af4
{
Packit Service aa3af4
	if (pcb->seg_alloc) {
Packit Service aa3af4
		tcp_tx_seg_free(pcb, pcb->seg_alloc);
Packit Service aa3af4
		pcb->seg_alloc = NULL;
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	if (pcb->pbuf_alloc) {
Packit Service aa3af4
		tcp_tx_pbuf_free(pcb, pcb->pbuf_alloc);
Packit Service aa3af4
		pcb->pbuf_alloc = NULL;
Packit Service aa3af4
	}
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
void
Packit Service aa3af4
tcp_tx_pbuf_free(struct tcp_pcb * pcb, struct pbuf * p)
Packit Service aa3af4
{
Packit Service aa3af4
	struct pbuf * p_next = NULL;
Packit Service aa3af4
	while (p) {
Packit Service aa3af4
		p_next = p->next;
Packit Service aa3af4
		p->next = NULL;
Packit Service aa3af4
		if (p->type  == PBUF_RAM) {
Packit Service aa3af4
			external_tcp_tx_pbuf_free(pcb, p);
Packit Service aa3af4
		} else {
Packit Service aa3af4
			pbuf_free(p);
Packit Service aa3af4
		}
Packit Service aa3af4
		p = p_next;
Packit Service aa3af4
	}
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Used to specify the argument that should be passed callback
Packit Service aa3af4
 * functions.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcb tcp_pcb to set the callback argument
Packit Service aa3af4
 * @param arg void pointer argument to pass to callback functions
Packit Service aa3af4
 */ 
Packit Service aa3af4
void
Packit Service aa3af4
tcp_arg(struct tcp_pcb *pcb, void *arg)
Packit Service aa3af4
{  
Packit Service aa3af4
  pcb->callback_arg = arg;
Packit Service aa3af4
}
Packit Service aa3af4
#if LWIP_CALLBACK_API
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Used to specify the function that should be called when a TCP
Packit Service aa3af4
 * connection receives data.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcb tcp_pcb to set the recv callback
Packit Service aa3af4
 * @param recv callback function to call for this pcb when data is received
Packit Service aa3af4
 */ 
Packit Service aa3af4
void
Packit Service aa3af4
tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv)
Packit Service aa3af4
{
Packit Service aa3af4
  pcb->recv = recv;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Used to specify the function that should be called when TCP data
Packit Service aa3af4
 * has been successfully delivered to the remote host.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcb tcp_pcb to set the sent callback
Packit Service aa3af4
 * @param sent callback function to call for this pcb when data is successfully sent
Packit Service aa3af4
 */ 
Packit Service aa3af4
void
Packit Service aa3af4
tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent)
Packit Service aa3af4
{
Packit Service aa3af4
  pcb->sent = sent;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Used to specify the function that should be called when a fatal error
Packit Service aa3af4
 * has occured on the connection.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcb tcp_pcb to set the err callback
Packit Service aa3af4
 * @param err callback function to call for this pcb when a fatal error
Packit Service aa3af4
 *        has occured on the connection
Packit Service aa3af4
 */ 
Packit Service aa3af4
void
Packit Service aa3af4
tcp_err(struct tcp_pcb *pcb, tcp_err_fn err)
Packit Service aa3af4
{
Packit Service aa3af4
  pcb->errf = err;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Used for specifying the function that should be called when a
Packit Service aa3af4
 * LISTENing connection has been connected to another host.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcb tcp_pcb to set the accept callback
Packit Service aa3af4
 * @param accept callback function to call for this pcb when LISTENing
Packit Service aa3af4
 *        connection has been connected to another host
Packit Service aa3af4
 */ 
Packit Service aa3af4
void
Packit Service aa3af4
tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept)
Packit Service aa3af4
{
Packit Service aa3af4
  pcb->accept = accept;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Used for specifying the function that should be called 
Packit Service aa3af4
 * for sending packets.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcb tcp_pcb to set the outputcallback
Packit Service aa3af4
 * @param output callback function
Packit Service aa3af4
 */ 
Packit Service aa3af4
void
Packit Service aa3af4
tcp_ip_output(struct tcp_pcb *pcb, ip_output_fn ip_output)
Packit Service aa3af4
{
Packit Service aa3af4
  pcb->ip_output = ip_output;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Used for specifying the function that should be called when a
Packit Service aa3af4
 * SYN was received.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcb tcp_pcb to set the accept callback
Packit Service aa3af4
 * @param accept callback function to call for this pcb when SYN
Packit Service aa3af4
 *        is received
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_syn_handled(struct tcp_pcb_listen *pcb, tcp_syn_handled_fn syn_handled)
Packit Service aa3af4
{
Packit Service aa3af4
  pcb->syn_handled_cb = syn_handled;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Used for specifying the function that should be called to clone pcb
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param listen pcb to clone
Packit Service aa3af4
 * @param clone callback function to call in order to clone the pcb
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_clone_conn(struct tcp_pcb_listen *pcb, tcp_clone_conn_fn clone_conn)
Packit Service aa3af4
{
Packit Service aa3af4
  pcb->clone_conn = clone_conn;
Packit Service aa3af4
}
Packit Service aa3af4
#endif /* LWIP_CALLBACK_API */
Packit Service aa3af4
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Used to specify the function that should be called periodically
Packit Service aa3af4
 * from TCP. The interval is specified in terms of the TCP coarse
Packit Service aa3af4
 * timer interval, which is called twice a second.
Packit Service aa3af4
 *
Packit Service aa3af4
 */ 
Packit Service aa3af4
void
Packit Service aa3af4
tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval)
Packit Service aa3af4
{
Packit Service aa3af4
#if LWIP_CALLBACK_API
Packit Service aa3af4
  pcb->poll = poll;
Packit Service aa3af4
#else /* LWIP_CALLBACK_API */  
Packit Service aa3af4
  LWIP_UNUSED_ARG(poll);
Packit Service aa3af4
#endif /* LWIP_CALLBACK_API */  
Packit Service aa3af4
  pcb->pollinterval = interval;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Purges a TCP PCB. Removes any buffered data and frees the buffer memory
Packit Service aa3af4
 * (pcb->ooseq, pcb->unsent and pcb->unacked are freed).
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcb tcp_pcb to purge. The pcb itself is not deallocated!
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_pcb_purge(struct tcp_pcb *pcb)
Packit Service aa3af4
{
Packit Service aa3af4
  if (get_tcp_state(pcb) != CLOSED &&
Packit Service aa3af4
     get_tcp_state(pcb) != TIME_WAIT &&
Packit Service aa3af4
     get_tcp_state(pcb) != LISTEN) {
Packit Service aa3af4
Packit Service aa3af4
    LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));
Packit Service aa3af4
Packit Service aa3af4
    if (pcb->refused_data != NULL) {
Packit Service aa3af4
      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n"));
Packit Service aa3af4
      pbuf_free(pcb->refused_data);
Packit Service aa3af4
      pcb->refused_data = NULL;
Packit Service aa3af4
    }
Packit Service aa3af4
    if (pcb->unsent != NULL) {
Packit Service aa3af4
      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n"));
Packit Service aa3af4
    }
Packit Service aa3af4
    if (pcb->unacked != NULL) {
Packit Service aa3af4
      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n"));
Packit Service aa3af4
    }
Packit Service aa3af4
#if TCP_QUEUE_OOSEQ
Packit Service aa3af4
    if (pcb->ooseq != NULL) {
Packit Service aa3af4
      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));
Packit Service aa3af4
    }
Packit Service aa3af4
    tcp_segs_free(pcb, pcb->ooseq);
Packit Service aa3af4
    pcb->ooseq = NULL;
Packit Service aa3af4
#endif /* TCP_QUEUE_OOSEQ */
Packit Service aa3af4
Packit Service aa3af4
    /* Stop the retransmission timer as it will expect data on unacked
Packit Service aa3af4
       queue if it fires */
Packit Service aa3af4
    pcb->rtime = -1;
Packit Service aa3af4
Packit Service aa3af4
    tcp_tx_segs_free(pcb, pcb->unsent);
Packit Service aa3af4
    tcp_tx_segs_free(pcb, pcb->unacked);
Packit Service aa3af4
    pcb->unacked = pcb->unsent = NULL;
Packit Service aa3af4
#if TCP_OVERSIZE
Packit Service aa3af4
    pcb->unsent_oversize = 0;
Packit Service aa3af4
#endif /* TCP_OVERSIZE */
Packit Service aa3af4
#if TCP_CC_ALGO_MOD
Packit Service aa3af4
    cc_destroy(pcb);
Packit Service aa3af4
#endif
Packit Service aa3af4
  }
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param pcblist PCB list to purge.
Packit Service aa3af4
 * @param pcb tcp_pcb to purge. The pcb itself is NOT deallocated!
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_pcb_remove(struct tcp_pcb *pcb)
Packit Service aa3af4
{
Packit Service aa3af4
  tcp_pcb_purge(pcb);
Packit Service aa3af4
  
Packit Service aa3af4
  /* if there is an outstanding delayed ACKs, send it */
Packit Service aa3af4
  if (get_tcp_state(pcb) != TIME_WAIT &&
Packit Service aa3af4
		  get_tcp_state(pcb) != LISTEN &&
Packit Service aa3af4
     pcb->flags & TF_ACK_DELAY) {
Packit Service aa3af4
    pcb->flags |= TF_ACK_NOW;
Packit Service aa3af4
    tcp_output(pcb);
Packit Service aa3af4
  }
Packit Service aa3af4
Packit Service aa3af4
  if (get_tcp_state(pcb) != LISTEN) {
Packit Service aa3af4
    LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL);
Packit Service aa3af4
    LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL);
Packit Service aa3af4
#if TCP_QUEUE_OOSEQ
Packit Service aa3af4
    LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL);
Packit Service aa3af4
#endif /* TCP_QUEUE_OOSEQ */
Packit Service aa3af4
  }
Packit Service aa3af4
Packit Service aa3af4
  set_tcp_state(pcb, CLOSED);
Packit Service aa3af4
Packit Service aa3af4
  LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Calculates a new initial sequence number for new connections.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @return u32_t pseudo random sequence number
Packit Service aa3af4
 */
Packit Service aa3af4
u32_t
Packit Service aa3af4
tcp_next_iss(void)
Packit Service aa3af4
{
Packit Service aa3af4
  static u32_t iss = 6510;
Packit Service aa3af4
  
Packit Service aa3af4
  iss += tcp_ticks;       /* XXX */
Packit Service aa3af4
  return iss;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
#if TCP_CALCULATE_EFF_SEND_MSS
Packit Service aa3af4
/**
Packit Service aa3af4
 * Calcluates the effective send mss that can be used for a specific IP address
Packit Service aa3af4
 * by using ip_route to determine the netif used to send to the address and
Packit Service aa3af4
 * calculating the minimum of TCP_MSS and that netif's mtu (if set).
Packit Service aa3af4
 */
Packit Service aa3af4
u16_t
Packit Service aa3af4
tcp_eff_send_mss(u16_t sendmss, struct tcp_pcb *pcb)
Packit Service aa3af4
{
Packit Service aa3af4
  u16_t mtu;
Packit Service aa3af4
Packit Service aa3af4
  mtu = external_ip_route_mtu(pcb);
Packit Service aa3af4
  if (mtu != 0) {
Packit Service aa3af4
    sendmss = LWIP_MIN(sendmss, mtu - IP_HLEN - TCP_HLEN);
Packit Service aa3af4
  }
Packit Service aa3af4
  return sendmss;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Calcluates the send mss that can be used for a specific IP address
Packit Service aa3af4
 * by using ip_route to determine the netif used to send to the address. 
Packit Service aa3af4
 * In case MTU is unkonw - return the default MSS 
Packit Service aa3af4
 */
Packit Service aa3af4
u16_t
Packit Service aa3af4
tcp_mss_follow_mtu_with_default(u16_t defsendmss, struct tcp_pcb *pcb)
Packit Service aa3af4
{
Packit Service aa3af4
  u16_t mtu;
Packit Service aa3af4
Packit Service aa3af4
  mtu = external_ip_route_mtu(pcb);
Packit Service aa3af4
  if (mtu != 0) {
Packit Service aa3af4
    defsendmss = mtu - IP_HLEN - TCP_HLEN;
Packit Service aa3af4
    defsendmss = LWIP_MAX(defsendmss, 1); /* MSS must be a positive number */
Packit Service aa3af4
  }
Packit Service aa3af4
  return defsendmss;
Packit Service aa3af4
}
Packit Service aa3af4
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
Packit Service aa3af4
Packit Service aa3af4
#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
Packit Service aa3af4
/**
Packit Service aa3af4
 * Print a tcp header for debugging purposes.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param tcphdr pointer to a struct tcp_hdr
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_debug_print(struct tcp_hdr *tcphdr)
Packit Service aa3af4
{
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n"));
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("|    %5"U16_F"      |    %5"U16_F"      | (src port, dest port)\n",
Packit Service aa3af4
         ntohs(tcphdr->src), ntohs(tcphdr->dest)));
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (seq no)\n",
Packit Service aa3af4
          ntohl(tcphdr->seqno)));
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (ack no)\n",
Packit Service aa3af4
         ntohl(tcphdr->ackno)));
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" |   |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"|     %5"U16_F"     | (hdrlen, flags (",
Packit Service aa3af4
       TCPH_HDRLEN(tcphdr),
Packit Service aa3af4
         TCPH_FLAGS(tcphdr) >> 5 & 1,
Packit Service aa3af4
         TCPH_FLAGS(tcphdr) >> 4 & 1,
Packit Service aa3af4
         TCPH_FLAGS(tcphdr) >> 3 & 1,
Packit Service aa3af4
         TCPH_FLAGS(tcphdr) >> 2 & 1,
Packit Service aa3af4
         TCPH_FLAGS(tcphdr) >> 1 & 1,
Packit Service aa3af4
         TCPH_FLAGS(tcphdr) & 1,
Packit Service aa3af4
         ntohs(tcphdr->wnd)));
Packit Service aa3af4
  tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("), win)\n"));
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("|    0x%04"X16_F"     |     %5"U16_F"     | (chksum, urgp)\n",
Packit Service aa3af4
         ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Print a tcp state for debugging purposes.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param s enum tcp_state to print
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_debug_print_state(enum tcp_state s)
Packit Service aa3af4
{
Packit Service aa3af4
  LWIP_UNUSED_ARG(s);
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("State: %s\n", tcp_state_str[s]));
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Print tcp flags for debugging purposes.
Packit Service aa3af4
 *
Packit Service aa3af4
 * @param flags tcp flags, all active flags are printed
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_debug_print_flags(u8_t flags)
Packit Service aa3af4
{
Packit Service aa3af4
  if (flags & TCP_FIN) {
Packit Service aa3af4
    LWIP_DEBUGF(TCP_DEBUG, ("FIN "));
Packit Service aa3af4
  }
Packit Service aa3af4
  if (flags & TCP_SYN) {
Packit Service aa3af4
    LWIP_DEBUGF(TCP_DEBUG, ("SYN "));
Packit Service aa3af4
  }
Packit Service aa3af4
  if (flags & TCP_RST) {
Packit Service aa3af4
    LWIP_DEBUGF(TCP_DEBUG, ("RST "));
Packit Service aa3af4
  }
Packit Service aa3af4
  if (flags & TCP_PSH) {
Packit Service aa3af4
    LWIP_DEBUGF(TCP_DEBUG, ("PSH "));
Packit Service aa3af4
  }
Packit Service aa3af4
  if (flags & TCP_ACK) {
Packit Service aa3af4
    LWIP_DEBUGF(TCP_DEBUG, ("ACK "));
Packit Service aa3af4
  }
Packit Service aa3af4
  if (flags & TCP_URG) {
Packit Service aa3af4
    LWIP_DEBUGF(TCP_DEBUG, ("URG "));
Packit Service aa3af4
  }
Packit Service aa3af4
  if (flags & TCP_ECE) {
Packit Service aa3af4
    LWIP_DEBUGF(TCP_DEBUG, ("ECE "));
Packit Service aa3af4
  }
Packit Service aa3af4
  if (flags & TCP_CWR) {
Packit Service aa3af4
    LWIP_DEBUGF(TCP_DEBUG, ("CWR "));
Packit Service aa3af4
  }
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("\n"));
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 * Print all tcp_pcbs in every list for debugging purposes.
Packit Service aa3af4
 */
Packit Service aa3af4
void
Packit Service aa3af4
tcp_debug_print_pcbs(void)
Packit Service aa3af4
{
Packit Service aa3af4
  LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states: REMOVED\n"));
Packit Service aa3af4
}
Packit Service aa3af4
#endif /* TCP_DEBUG */
Packit Service aa3af4
Packit Service aa3af4
#endif /* LWIP_TCP */