aboutsummaryrefslogtreecommitdiff
path: root/nuttx/net/uip/uip_udpconn.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/net/uip/uip_udpconn.c')
-rw-r--r--nuttx/net/uip/uip_udpconn.c492
1 files changed, 492 insertions, 0 deletions
diff --git a/nuttx/net/uip/uip_udpconn.c b/nuttx/net/uip/uip_udpconn.c
new file mode 100644
index 000000000..3c4ee5add
--- /dev/null
+++ b/nuttx/net/uip/uip_udpconn.c
@@ -0,0 +1,492 @@
+/****************************************************************************
+ * net/uip/uip_udpconn.c
+ *
+ * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Large parts of this file were leveraged from uIP logic:
+ *
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * 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 and/or other materials provided with the distribution.
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Compilation Switches
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#if defined(CONFIG_NET) && defined(CONFIG_NET_UDP)
+
+#include <stdint.h>
+#include <string.h>
+#include <semaphore.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include <nuttx/net/uip/uipopt.h>
+#include <nuttx/net/uip/uip.h>
+#include <nuttx/net/uip/uip-arch.h>
+
+#include "uip_internal.h"
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* The array containing all uIP UDP connections. */
+
+struct uip_udp_conn g_udp_connections[CONFIG_NET_UDP_CONNS];
+
+/* A list of all free UDP connections */
+
+static dq_queue_t g_free_udp_connections;
+static sem_t g_free_sem;
+
+/* A list of all allocated UDP connections */
+
+static dq_queue_t g_active_udp_connections;
+
+/* Last port used by a UDP connection connection. */
+
+static uint16_t g_last_udp_port;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: _uip_semtake() and _uip_semgive()
+ *
+ * Description:
+ * Take/give semaphore
+ *
+ ****************************************************************************/
+
+static inline void _uip_semtake(sem_t *sem)
+{
+ /* Take the semaphore (perhaps waiting) */
+
+ while (uip_lockedwait(sem) != 0)
+ {
+ /* The only case that an error should occur here is if
+ * the wait was awakened by a signal.
+ */
+
+ ASSERT(*get_errno_ptr() == EINTR);
+ }
+}
+
+#define _uip_semgive(sem) sem_post(sem)
+
+/****************************************************************************
+ * Name: uip_find_conn()
+ *
+ * Description:
+ * Find the UDP connection that uses this local port number. Called only
+ * from user user level code, but with interrupts disabled.
+ *
+ ****************************************************************************/
+
+static struct uip_udp_conn *uip_find_conn(uint16_t portno)
+{
+ int i;
+
+ /* Now search each connection structure.*/
+
+ for (i = 0; i < CONFIG_NET_UDP_CONNS; i++)
+ {
+ if (g_udp_connections[ i ].lport == portno)
+ {
+ return &g_udp_connections[ i ];
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ * Name: uip_selectport()
+ *
+ * Description:
+ * Select an unused port number.
+ *
+ * NOTE that in prinicple this function could fail if there is no available
+ * port number. There is no check for that case and it would actually
+ * in an infinite loop if that were the case. In this simple, small UDP
+ * implementation, it is reasonable to assume that that error cannot happen
+ * and that a port number will always be available.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Return:
+ * Next available port number
+ *
+ ****************************************************************************/
+
+static uint16_t uip_selectport(void)
+{
+ uint16_t portno;
+
+ /* Find an unused local port number. Loop until we find a valid
+ * listen port number that is not being used by any other connection.
+ */
+
+ uip_lock_t flags = uip_lock();
+ do
+ {
+ /* Guess that the next available port number will be the one after
+ * the last port number assigned.
+ */
+
+ ++g_last_udp_port;
+
+ /* Make sure that the port number is within range */
+
+ if (g_last_udp_port >= 32000)
+ {
+ g_last_udp_port = 4096;
+ }
+ }
+ while (uip_find_conn(htons(g_last_udp_port)));
+
+ /* Initialize and return the connection structure, bind it to the
+ * port number
+ */
+
+ portno = g_last_udp_port;
+ uip_unlock(flags);
+
+ return portno;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: uip_udpinit()
+ *
+ * Description:
+ * Initialize the UDP connection structures. Called once and only from
+ * the UIP layer.
+ *
+ ****************************************************************************/
+
+void uip_udpinit(void)
+{
+ int i;
+
+ /* Initialize the queues */
+
+ dq_init(&g_free_udp_connections);
+ dq_init(&g_active_udp_connections);
+ sem_init(&g_free_sem, 0, 1);
+
+ for (i = 0; i < CONFIG_NET_UDP_CONNS; i++)
+ {
+ /* Mark the connection closed and move it to the free list */
+
+ g_udp_connections[i].lport = 0;
+ dq_addlast(&g_udp_connections[i].node, &g_free_udp_connections);
+ }
+
+ g_last_udp_port = 1024;
+}
+
+/****************************************************************************
+ * Name: uip_udpalloc()
+ *
+ * Description:
+ * Alloc a new, uninitialized UDP connection structure.
+ *
+ ****************************************************************************/
+
+struct uip_udp_conn *uip_udpalloc(void)
+{
+ struct uip_udp_conn *conn;
+
+ /* The free list is only accessed from user, non-interrupt level and
+ * is protected by a semaphore (that behaves like a mutex).
+ */
+
+ _uip_semtake(&g_free_sem);
+ conn = (struct uip_udp_conn *)dq_remfirst(&g_free_udp_connections);
+ if (conn)
+ {
+ /* Make sure that the connection is marked as uninitialized */
+
+ conn->lport = 0;
+ }
+ _uip_semgive(&g_free_sem);
+ return conn;
+}
+
+/****************************************************************************
+ * Name: uip_udpfree()
+ *
+ * Description:
+ * Free a UDP connection structure that is no longer in use. This should be
+ * done by the implementation of close(). uip_udpdisable must have been
+ * previously called.
+ *
+ ****************************************************************************/
+
+void uip_udpfree(struct uip_udp_conn *conn)
+{
+ /* The free list is only accessed from user, non-interrupt level and
+ * is protected by a semaphore (that behaves like a mutex).
+ */
+
+ DEBUGASSERT(conn->crefs == 0);
+
+ _uip_semtake(&g_free_sem);
+ conn->lport = 0;
+ dq_addlast(&conn->node, &g_free_udp_connections);
+ _uip_semgive(&g_free_sem);
+}
+
+/****************************************************************************
+ * Name: uip_udpactive()
+ *
+ * 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_udp_conn *uip_udpactive(struct uip_udpip_hdr *buf)
+{
+ struct uip_udp_conn *conn = (struct uip_udp_conn *)g_active_udp_connections.head;
+
+ while (conn)
+ {
+ /* If the local UDP port is non-zero, the connection is considered
+ * to be used. If so, the local port number is checked against the
+ * destination port number in the received packet. If the two port
+ * numbers match, the remote port number is checked if the
+ * connection is bound to a remote port. Finally, if the
+ * connection is bound to a remote IP address, the source IP
+ * address of the packet is checked.
+ */
+
+ if (conn->lport != 0 && buf->destport == conn->lport &&
+ (conn->rport == 0 || buf->srcport == conn->rport) &&
+ (uip_ipaddr_cmp(conn->ripaddr, g_allzeroaddr) ||
+ uip_ipaddr_cmp(conn->ripaddr, g_alloneaddr) ||
+ uiphdr_ipaddr_cmp(buf->srcipaddr, &conn->ripaddr)))
+ {
+ /* Matching connection found.. return a reference to it */
+
+ break;
+ }
+
+ /* Look at the next active connection */
+
+ conn = (struct uip_udp_conn *)conn->node.flink;
+ }
+
+ return conn;
+}
+
+/****************************************************************************
+ * Name: uip_nextudpconn()
+ *
+ * Description:
+ * Traverse the list of allocated UDP connections
+ *
+ * Assumptions:
+ * This function is called from UIP logic at interrupt level (or with
+ * interrupts disabled).
+ *
+ ****************************************************************************/
+
+struct uip_udp_conn *uip_nextudpconn(struct uip_udp_conn *conn)
+{
+ if (!conn)
+ {
+ return (struct uip_udp_conn *)g_active_udp_connections.head;
+ }
+ else
+ {
+ return (struct uip_udp_conn *)conn->node.flink;
+ }
+}
+
+/****************************************************************************
+ * Name: uip_udpbind()
+ *
+ * Description:
+ * This function implements the UIP specific parts of the standard UDP
+ * bind() operation.
+ *
+ * Assumptions:
+ * This function is called from normal user level code.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+int uip_udpbind(struct uip_udp_conn *conn, const struct sockaddr_in6 *addr)
+#else
+int uip_udpbind(struct uip_udp_conn *conn, const struct sockaddr_in *addr)
+#endif
+{
+ int ret = -EADDRINUSE;
+ uip_lock_t flags;
+
+ /* Is the user requesting to bind to any port? */
+
+ if (!addr->sin_port)
+ {
+ /* Yes.. Find an unused local port number */
+
+ conn->lport = htons(uip_selectport());
+ ret = OK;
+ }
+ else
+ {
+ /* Interrupts must be disabled while access the UDP connection list */
+
+ flags = uip_lock();
+
+ /* Is any other UDP connection bound to this port? */
+
+ if (!uip_find_conn(addr->sin_port))
+ {
+ /* No.. then bind the socket to the port */
+
+ conn->lport = addr->sin_port;
+ ret = OK;
+ }
+
+ uip_unlock(flags);
+ }
+ return ret;
+}
+
+/****************************************************************************
+ * Name: uip_udpconnect()
+ *
+ * Description:
+ * This function sets up a new UDP connection. The function will
+ * automatically allocate an unused local port for the new
+ * connection. However, another port can be chosen by using the
+ * uip_udpbind() call, after the uip_udpconnect() function has been
+ * called.
+ *
+ * uip_udpenable() must be called before the connection is made active (i.e.,
+ * is eligible for callbacks.
+ *
+ * addr The address of the remote host.
+ *
+ * Assumptions:
+ * This function is called user code. Interrupts may be enabled.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+int uip_udpconnect(struct uip_udp_conn *conn, const struct sockaddr_in6 *addr)
+#else
+int uip_udpconnect(struct uip_udp_conn *conn, const struct sockaddr_in *addr)
+#endif
+{
+ /* Has this address already been bound to a local port (lport)? */
+
+ if (!conn->lport)
+ {
+ /* No.. Find an unused local port number and bind it to the
+ * connection structure.
+ */
+
+ conn->lport = htons(uip_selectport());
+ }
+
+ /* Is there a remote port (rport) */
+
+ if (addr)
+ {
+ conn->rport = addr->sin_port;
+ uip_ipaddr_copy(conn->ripaddr, addr->sin_addr.s_addr);
+ }
+ else
+ {
+ conn->rport = 0;
+ uip_ipaddr_copy(conn->ripaddr, g_allzeroaddr);
+ }
+
+ conn->ttl = UIP_TTL;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: uip_udpenable() uip_udpdisable.
+ *
+ * Description:
+ * Enable/disable callbacks for the specified connection
+ *
+ * Assumptions:
+ * This function is called user code. Interrupts may be enabled.
+ *
+ ****************************************************************************/
+
+void uip_udpenable(struct uip_udp_conn *conn)
+{
+ /* Add the connection structure to the active connectionlist. This list
+ * is modifiable from interrupt level, we we must disable interrupts to
+ * access it safely.
+ */
+
+ uip_lock_t flags = uip_lock();
+ dq_addlast(&conn->node, &g_active_udp_connections);
+ uip_unlock(flags);
+}
+
+void uip_udpdisable(struct uip_udp_conn *conn)
+{
+ /* Remove the connection structure from the active connectionlist. This list
+ * is modifiable from interrupt level, we we must disable interrupts to
+ * access it safely.
+ */
+
+ uip_lock_t flags = uip_lock();
+ dq_rem(&conn->node, &g_active_udp_connections);
+ uip_unlock(flags);
+}
+
+#endif /* CONFIG_NET && CONFIG_NET_UDP */