summaryrefslogtreecommitdiff
path: root/nuttx/net/uip/uip-tcpconn.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/net/uip/uip-tcpconn.c')
-rw-r--r--nuttx/net/uip/uip-tcpconn.c405
1 files changed, 405 insertions, 0 deletions
diff --git a/nuttx/net/uip/uip-tcpconn.c b/nuttx/net/uip/uip-tcpconn.c
new file mode 100644
index 000000000..c877de2c4
--- /dev/null
+++ b/nuttx/net/uip/uip-tcpconn.c
@@ -0,0 +1,405 @@
+/****************************************************************************
+ * uip_tcpbind.c
+ *
+ * Copyright (C) 2007 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * 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 and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name Gregory Nutt nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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
+ * COPYRIGHT OWNER OR CONTRIBUTORS 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Compilation Switches
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#ifdef CONFIG_NET
+
+#include <sys/types.h>
+#include <string.h>
+#include <arch/irq.h>
+
+#include <net/uip/uipopt.h>
+#include <net/uip/uip.h>
+#include <net/uip/uip-arch.h>
+
+#include "uip-internal.h"
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* g_tcp_sequence[] is used to generate TCP sequence numbers */
+
+uint8 g_tcp_sequence[4];
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* The array containing all uIP connections. */
+
+static struct uip_conn g_tcp_connections[UIP_CONNS];
+
+/* Last port used by a TCP connection connection. */
+
+static uint16 g_last_tcp_port;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* Given a port number, find the socket bound to the port number.
+ * Primary use: to determine if a port number is available.
+ */
+
+static struct uip_conn *uip_find_conn(uint16 portno)
+{
+ struct uip_conn *conn;
+ int i;
+
+ /* Check if this port number is already in use, and if so try to find
+ * another one.
+ */
+
+ for (i = 0; i < UIP_CONNS; i++)
+ {
+ conn = &g_tcp_connections[i];
+ if (conn->tcpstateflags != UIP_CLOSED && conn->lport == htons(g_last_tcp_port))
+ {
+ /* The portnumber is in use */
+
+ return conn;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: uip_tcpinit()
+ *
+ * Description:
+ * Initialize the TCP/IP connection structures. Called only from the UIP
+ * layer.
+ *
+ ****************************************************************************/
+
+void uip_tcpinit(void)
+{
+ int i;
+ for (i = 0; i < UIP_CONNS; i++)
+ {
+ g_tcp_connections[i].tcpstateflags = UIP_CLOSED;
+ }
+
+ g_last_tcp_port = 1024;
+}
+
+/****************************************************************************
+ * Name: uip_tcpalloc()
+ *
+ * Description:
+ * Find a free TCP/IP connection structure and allocate it
+ * for use. This is normally something done by the implementation of the
+ * socket() API but is also called from the interrupt level when a TCP
+ * packet is received while "listening"
+ *
+ ****************************************************************************/
+
+struct uip_conn *uip_tcpalloc(void)
+{
+#if 0 /* Revisit */
+ struct uip_conn *oldest = NULL;
+#endif
+ irqstate_t flags;
+ unsigned int i;
+
+ /* Because this routine is called from both interrupt level and
+ * and from user level, we have not option but to disable interrupts
+ * while accessing g_tcp_connections[];
+ */
+
+ flags = irqsave();
+
+ /* Check if there are any available connections. */
+
+ for (i = 0; i < UIP_CONNS; i++)
+ {
+ /* First, check if any connections structures are marked as
+ * CLOSED in the table of pre-allocated connection structures.
+ */
+
+ if (g_tcp_connections[i].tcpstateflags == UIP_CLOSED)
+ {
+ /* We found an unused structure. Mark as allocated, but not
+ * initialized.
+ */
+
+ memset(&g_tcp_connections[i], 0, sizeof(struct uip_conn));
+ g_tcp_connections[i].tcpstateflags = UIP_ALLOCATED;
+
+ irqrestore(flags);
+ return &g_tcp_connections[i];
+ }
+
+#if 0 /* Revisit */
+ /* As a fallback, check for connection structures in the TIME_WAIT
+ * state. If no CLOSED connections are found, then take the oldest
+ */
+
+ if (g_tcp_connections[i].tcpstateflags == UIP_TIME_WAIT)
+ {
+ if (!oldest || g_tcp_connections[i].timer > oldest->timer)
+ {
+ oldest = &g_tcp_connections[i];
+ }
+ }
+ }
+ return oldest;
+#else
+ }
+
+ irqrestore(flags);
+ return NULL;
+#endif
+}
+
+/****************************************************************************
+ * Name: uip_tcpfree()
+ *
+ * Description:
+ * Free a connection structure that is no longer in use. This should be
+ * done by the implementation of close()
+ *
+ ****************************************************************************/
+
+void uip_tcpfree(struct uip_conn *conn)
+{
+ /* this action is atomic and should require no special protetion */
+
+ conn->tcpstateflags = UIP_CLOSED;
+}
+
+/****************************************************************************
+ * Name: uip_tcpactive()
+ *
+ * Description:
+ * Find a connection structure that is the appropriate
+ * connection to be used withi the provided TCP/IP header
+ *
+ * Assumptions:
+ * This function is called from UIP logic at interrupt level
+ *
+ ****************************************************************************/
+
+struct uip_conn *uip_tcpactive(struct uip_tcpip_hdr *buf)
+{
+ struct uip_conn *conn;
+ for (conn = g_tcp_connections; conn <= &g_tcp_connections[UIP_CONNS - 1]; conn++)
+ {
+ /* Find an open connection matching the tcp input */
+
+ if (conn->tcpstateflags != UIP_CLOSED &&
+ buf->destport == conn->lport && buf->srcport == conn->rport &&
+ uip_ipaddr_cmp(buf->srcipaddr, conn->ripaddr))
+ {
+ return conn;
+ }
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ * Name: uip_tcppoll()
+ *
+ * Description:
+ * Periodic processing for a connection identified by its number.
+ * This function does the necessary periodic processing (timers,
+ * polling) for a uIP TCP conneciton, and should be called by the UIP
+ * device driver when the periodic uIP timer goes off. It should be
+ * called for every connection, regardless of whether they are open of
+ * closed.
+ *
+ * Assumptions:
+ * This function is called from the CAN device driver may be called from
+ * the timer interrupt/watchdog handle level.
+ *
+ ****************************************************************************/
+
+void uip_tcppoll(unsigned int conn)
+{
+ uip_conn = &g_tcp_connections[conn];
+ uip_interrupt(UIP_TIMER);
+}
+
+/****************************************************************************
+ * Name: uip_tcpactive()
+ *
+ * Description:
+ * Increment the TCP/IP sequence number
+ *
+ * Assumptions:
+ * This function is called from the interrupt level
+ *
+ ****************************************************************************/
+
+void uip_tcpnextsequence(void)
+{
+ /* This inplements a byte-by-byte big-endian increment */
+
+ if (++g_tcp_sequence[3] == 0)
+ {
+ if (++g_tcp_sequence[2] == 0)
+ {
+ if (++g_tcp_sequence[1] == 0)
+ {
+ ++g_tcp_sequence[0];
+ }
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: uip_tcpbind()
+ *
+ * Description:
+ * This function implements the UIP specific parts of the standard TCP
+ * bind() operation.
+ *
+ * Assumptions:
+ * This function is called from normal user level code.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+int uip_tcpbind(struct uip_conn *conn, const struct sockaddr_in6 *addr)
+#else
+int uip_tcpbind(struct uip_conn *conn, const struct sockaddr_in *addr)
+#endif
+{
+#warning "Need to implement bind logic"
+ return ERROR;
+}
+
+/****************************************************************************
+ * Name: uip_tcpbind()
+ *
+ * Description:
+ * This function implements the UIP specific parts of the standard
+ * TCP connect() operation: It connects to a remote host using TCP.
+ *
+ * This function is used to start a new connection to the specified
+ * port on the specied host. It uses the connection structure that was
+ * allocated by a preceding socket() call. It sets the connection to
+ * the SYN_SENT state and sets the retransmission timer to 0. This will
+ * cause a TCP SYN segment to be sent out the next time this connection
+ * is periodically processed, which usually is done within 0.5 seconds
+ * after the call to uip_tcpconnect().
+ *
+ * Assumptions:
+ * This function is called from normal user level code.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+int uip_tcpconnect(struct uip_conn *conn, const struct sockaddr_in6 *addr )
+#else
+int uip_tcpconnect(struct uip_conn *conn, const struct sockaddr_in *addr )
+#endif
+{
+ uint16 port;
+ int i;
+
+ /* If the TCP port has not alread been bound to a local port, then select
+ * one now.
+ */
+
+ port = ntohs(conn->lport);
+ if (port == 0)
+ {
+ /* No local port assigned. Loop until we find a valid listen port number\
+ * that is not being used by any other connection.
+ */
+
+ do
+ {
+ /* Guess that the next available port number will be the one after
+ * the last port number assigned.
+ */
+#warning "This need protection from other threads and from interrupts"
+ port = ++g_last_tcp_port;
+
+ /* Make sure that the port number is within range */
+
+ if (g_last_tcp_port >= 32000)
+ {
+ g_last_tcp_port = 4096;
+ }
+ }
+ while (uip_find_conn(g_last_tcp_port));
+ }
+
+ /* Initialize and return the connection structure, bind it to the port number */
+
+ conn->tcpstateflags = UIP_SYN_SENT;
+
+ conn->snd_nxt[0] = g_tcp_sequence[0];
+ conn->snd_nxt[1] = g_tcp_sequence[1];
+ conn->snd_nxt[2] = g_tcp_sequence[2];
+ conn->snd_nxt[3] = g_tcp_sequence[3];
+
+ conn->initialmss = conn->mss = UIP_TCP_MSS;
+
+ conn->len = 1; /* TCP length of the SYN is one. */
+ conn->nrtx = 0;
+ conn->timer = 1; /* Send the SYN next time around. */
+ conn->rto = UIP_RTO;
+ conn->sa = 0;
+ conn->sv = 16; /* Initial value of the RTT variance. */
+ conn->lport = htons(port);
+
+ /* The sockaddr port is 16 bits and already in network order */
+
+ conn->rport = addr->sin_port;
+
+ /* The sockaddr address is 32-bits in network order. */
+
+ uip_ipaddr_copy(&conn->ripaddr, addr->sin_addr.s_addr);
+ return OK;
+}
+
+#endif /* CONFIG_NET */