/**
* @file
*
* Transmission Control Protocol for IP
*
* This file contains common functions for the TCP implementation, such as functinos
* for manipulating the data structures and the TCP timer functions. TCP functions
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include <string.h>
#if LWIP_TCP
/* Incremented every coarse grained timer shot (typically every 500 ms). */
{ 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};
/* The TCP PCB lists. */
/** List of all TCP PCBs in LISTEN state */
/** List of all TCP PCBs that are in a state in which
* they accept or send data. */
/** List of all TCP PCBs in TIME-WAIT state */
static u16_t tcp_new_port(void);
/**
* Initializes the TCP layer.
*/
void
tcp_init(void)
{
/* Clear globals. */
tcp_tw_pcbs = NULL;
tcp_tmp_pcb = NULL;
/* initialize timer */
tcp_ticks = 0;
tcp_timer = 0;
}
/**
* Called periodically to dispatch TCP timers.
*
*/
void
tcp_tmr(void)
{
/* Call tcp_fasttmr() every 250 ms */
tcp_fasttmr();
if (++tcp_timer & 1) {
/* Call tcp_tmr() every 500 ms, i.e., every other timer
tcp_tmr() is called. */
tcp_slowtmr();
}
}
/**
* Closes the connection held by the PCB.
*
*/
{
#if TCP_DEBUG
#endif /* TCP_DEBUG */
case CLOSED:
/* Closing a pcb in the CLOSED state might seem erroneous,
* however, it is in this state once allocated and as yet unused
* and the user needs some way to free it should the need arise.
* Calling tcp_close() with a pcb that has already been closed, (i.e. twice)
* or for a pcb that has been used and then entered the CLOSED state
* is erroneous, but this should never happen as the pcb has in those cases
* been freed, and so any remaining handles are bogus. */
break;
case LISTEN:
break;
case SYN_SENT:
break;
case SYN_RCVD:
}
break;
case ESTABLISHED:
}
break;
case CLOSE_WAIT:
}
break;
default:
/* Has already been closed, do nothing. */
break;
}
}
return err;
}
/**
* Aborts a connection by sending a RST to the remote host and deletes
* the local protocol control block. This is done when a connection is
* killed because of shortage of memory.
*
*/
void
{
#endif /* LWIP_CALLBACK_API */
void *errf_arg;
/* Figure out on which TCP PCB list we are, and remove us. If we
are in an active state, call the receive function associated with
the PCB with a NULL argument, and send an RST to the remote end. */
} else {
#endif /* LWIP_CALLBACK_API */
}
}
#if TCP_QUEUE_OOSEQ
}
#endif /* TCP_QUEUE_OOSEQ */
}
}
/**
* Binds the connection to a local portnumber and IP address. If the
* IP address is not given (i.e., ipaddr == NULL), the IP address of
* the outgoing network interface is used instead.
*
*/
{
if (port == 0) {
port = tcp_new_port();
}
/* Check if the address already is in use. */
ip_addr_isany(ipaddr) ||
return ERR_USE;
}
}
}
for(cpcb = tcp_active_pcbs;
ip_addr_isany(ipaddr) ||
return ERR_USE;
}
}
}
if (!ip_addr_isany(ipaddr)) {
}
return ERR_OK;
}
static err_t
{
(void)arg;
(void)pcb;
(void)err;
return ERR_ABRT;
}
#endif /* LWIP_CALLBACK_API */
/**
* Set the state of the connection to be LISTEN, which means that it
* is able to accept incoming connections. The protocol control block
* is reallocated in order to consume less memory. Setting the
* connection to LISTEN is an irreversible process.
*
*/
struct tcp_pcb *
{
/* already listening? */
return pcb;
}
return NULL;
}
#endif /* LWIP_CALLBACK_API */
}
/**
* This function should be called by the application when it has
* processed the data. The purpose is to advertise a larger window
* when the data has been processed.
*
*/
void
{
} else {
}
/*
* We send an ACK here (if one is not already pending, hence
* the above tests) as tcp_recved() implies that the application
* has processed some data, and so we can open the receiver's
* window to allow more to be transmitted. This could result in
* two ACKs being sent for each received packet in some limited cases
* (where the application is only receiving data, and is slow to
* process it) but it is necessary to guarantee that the sender can
* continue to transmit.
*/
}
/* If we can send a window update such that there is a full
* segment available in the window, do so now. This is sort of
* nagle-like in its goals, and tries to hit a compromise between
* sending acks each time the window is updated, and only sending
* window updates when a timer expires. The "threshold" used
* above (currently TCP_WND/2) can be tuned to be more or less
* aggressive */
}
}
/**
* A nastly hack featuring 'goto' statements that allocates a
* new TCP local port.
*/
static u16_t
tcp_new_port(void)
{
#ifndef TCP_LOCAL_PORT_RANGE_START
#endif
if (++port > TCP_LOCAL_PORT_RANGE_END) {
}
goto again;
}
}
goto again;
}
}
goto again;
}
}
return port;
}
/**
* Connects to another host. The function given as the "connected"
* argument will be called when the connection has been established.
*
*/
{
} else {
return ERR_VAL;
}
if (pcb->local_port == 0) {
}
iss = tcp_next_iss();
#endif /* LWIP_CALLBACK_API */
/* Build an MSS option */
}
return ret;
}
/**
* Called every 500 ms and implements the retransmission timer and the timer that
* removes PCBs that have been in TIME-WAIT for enough time. It also increments
* various timers such as the inactivity timer in each PCB.
*/
void
tcp_slowtmr(void)
{
++tcp_ticks;
/* Steps through all of the active PCBs. */
}
pcb_remove = 0;
++pcb_remove;
}
++pcb_remove;
} else {
/* Time for a retransmission. */
/* Double retransmission time-out unless we are trying to
* connect to somebody (i.e., we are in SYN_SENT). */
}
/* Reduce congestion window and ssthresh. */
}
/* The following needs to be called AFTER cwnd is set to one mss - STJ */
}
}
/* Check if this PCB has stayed too long in FIN-WAIT-2 */
++pcb_remove;
}
}
/* Check if KEEPALIVE should be sent */
if((pcb->so_options & SOF_KEEPALIVE) && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",
}
else if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + pcb->keep_cnt * TCP_KEEPINTVL) / TCP_SLOW_INTERVAL) {
}
}
/* If this PCB has queued out of sequence data, but has been
inactive for too long, will drop the data (it will eventually
be retransmitted). */
#if TCP_QUEUE_OOSEQ
}
#endif /* TCP_QUEUE_OOSEQ */
/* Check if this PCB has stayed too long in SYN-RCVD */
++pcb_remove;
}
}
/* Check if this PCB has stayed too long in LAST-ACK */
++pcb_remove;
}
}
/* If the PCB should be removed, do it. */
if (pcb_remove) {
/* Remove PCB from tcp_active_pcbs list. */
} else {
/* This PCB was the first. */
}
} else {
/* We check if we should poll the connection. */
}
}
}
}
/* Steps through all of the TIME-WAIT PCBs. */
pcb = tcp_tw_pcbs;
pcb_remove = 0;
/* Check if this PCB has stayed long enough in TIME-WAIT */
++pcb_remove;
}
/* If the PCB should be removed, do it. */
if (pcb_remove) {
/* Remove PCB from tcp_tw_pcbs list. */
} else {
/* This PCB was the first. */
}
} else {
}
}
}
/**
* Is called every TCP_FAST_INTERVAL (250 ms) and sends delayed ACKs.
*/
void
tcp_fasttmr(void)
{
/* send delayed ACKs */
}
}
}
/**
* Deallocates a list of TCP segments (tcp_seg structures).
*
*/
{
}
return count;
}
/**
* Frees a TCP segment.
*
*/
{
#if TCP_DEBUG
#endif /* TCP_DEBUG */
}
}
return count;
}
/**
* Sets the priority of a connection.
*
*/
void
{
}
#if TCP_QUEUE_OOSEQ
/**
* Returns a copy of the given TCP segment.
*
*/
struct tcp_seg *
{
return NULL;
}
return cseg;
}
#endif
static err_t
{
if (p != NULL) {
pbuf_free(p);
}
return ERR_OK;
}
#endif /* LWIP_CALLBACK_API */
static void
{
/* We kill the oldest active connection that has lower priority than
prio. */
inactivity = 0;
}
}
(void *)inactive, inactivity));
}
}
static void
tcp_kill_timewait(void)
{
inactivity = 0;
}
}
(void *)inactive, inactivity));
}
}
struct tcp_pcb *
{
/* Try killing oldest connection in TIME-WAIT. */
}
}
pcb->snd_queuelen = 0;
iss = tcp_next_iss();
#endif /* LWIP_CALLBACK_API */
/* Init KEEPALIVE timer */
}
return pcb;
}
/**
* Creates a new TCP protocol control block but doesn't place it on
* any of the TCP PCB lists.
*
* @internal: Maybe there should be a idle TCP PCB list where these
* PCBs are put on. We can then implement port reservation using
* tcp_bind(). Currently, we lack this (BSD socket type of) feature.
*/
struct tcp_pcb *
tcp_new(void)
{
return tcp_alloc(TCP_PRIO_NORMAL);
}
/*
* tcp_arg():
*
* Used to specify the argument that should be passed callback
* functions.
*
*/
void
{
}
/**
* Used to specify the function that should be called when a TCP
* connection receives data.
*
*/
void
{
}
/**
* Used to specify the function that should be called when TCP data
* has been successfully delivered to the remote host.
*
*/
void
{
}
/**
* Used to specify the function that should be called when a fatal error
* has occured on the connection.
*
*/
void
{
}
/**
* Used for specifying the function that should be called when a
* LISTENing connection has been connected to another host.
*
*/
void
{
}
#endif /* LWIP_CALLBACK_API */
/**
* Used to specify the function that should be called periodically
* from TCP. The interval is specified in terms of the TCP coarse
* timer interval, which is called twice a second.
*
*/
void
{
#endif /* LWIP_CALLBACK_API */
}
/**
* Purges a TCP PCB. Removes any buffered data and frees the buffer memory.
*
*/
void
{
}
}
#if TCP_QUEUE_OOSEQ /* LW */
}
#endif /* TCP_QUEUE_OOSEQ */
}
}
/**
* Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.
*
*/
void
{
/* if there is an outstanding delayed ACKs, send it */
}
}
/**
* Calculates a new initial sequence number for new connections.
*
*/
tcp_next_iss(void)
{
return iss;
}
void
{
LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" | |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"| %5"U16_F" | (hdrlen, flags (",
}
void
{
switch (s) {
case CLOSED:
break;
case LISTEN:
break;
case SYN_SENT:
break;
case SYN_RCVD:
break;
case ESTABLISHED:
break;
case FIN_WAIT_1:
break;
case FIN_WAIT_2:
break;
case CLOSE_WAIT:
break;
case CLOSING:
break;
case LAST_ACK:
break;
case TIME_WAIT:
break;
}
}
void
{
}
}
}
}
}
}
}
}
}
void
tcp_debug_print_pcbs(void)
{
LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
}
LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
}
LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
}
}
tcp_pcbs_sane(void)
{
}
}
return 1;
}
#endif /* TCP_DEBUG */
#endif /* LWIP_TCP */