From 17edc87d5eadbdcd81add3cd4ff8941fee253e14 Mon Sep 17 00:00:00 2001 From: patacongo Date: Mon, 1 Sep 2008 13:59:54 +0000 Subject: Add uIP support more multi-threaded socket access git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@858 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/net/uip/Make.defs | 2 +- nuttx/net/uip/uip-callback.c | 252 ++++++++++++++++++++++++++++++++++++++++ nuttx/net/uip/uip-initialize.c | 6 +- nuttx/net/uip/uip-internal.h | 22 ++-- nuttx/net/uip/uip-tcpappsend.c | 12 +- nuttx/net/uip/uip-tcpcallback.c | 107 ++++++++++------- nuttx/net/uip/uip-tcpinput.c | 2 +- nuttx/net/uip/uip-tcpsend.c | 2 +- nuttx/net/uip/uip-udpcallback.c | 8 +- 9 files changed, 347 insertions(+), 66 deletions(-) create mode 100644 nuttx/net/uip/uip-callback.c (limited to 'nuttx/net/uip') diff --git a/nuttx/net/uip/Make.defs b/nuttx/net/uip/Make.defs index 4512e11c3..71fcdf67c 100644 --- a/nuttx/net/uip/Make.defs +++ b/nuttx/net/uip/Make.defs @@ -41,7 +41,7 @@ ifeq ($(CONFIG_NET),y) # Common IP source files UIP_CSRCS += uip-initialize.c uip-setipid.c uip-arp.c uip-input.c uip-send.c \ - uip-poll.c uip-chksum.c + uip-poll.c uip-chksum.c uip-callback.c ifeq ($(CONFIG_NET_IPv6),y) UIP_CSRCS += uip-neighbor.c diff --git a/nuttx/net/uip/uip-callback.c b/nuttx/net/uip/uip-callback.c new file mode 100644 index 000000000..22755a43a --- /dev/null +++ b/nuttx/net/uip/uip-callback.c @@ -0,0 +1,252 @@ +/**************************************************************************** + * net/uip/uip-callback.c + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * + * 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 NuttX 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) + +#include +#include +#include + +#include +#include +#include + +#include "uip-internal.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct uip_callback_s g_cbprealloc[CONFIG_NET_NACTIVESOCKETS]; +static FAR struct uip_callback_s *g_cbfreelist = NULL; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: uip_callbackinit + * + * Description: + * Configure the pre-allocated callaback structures into a free list. + * This is called internally as part of uIP initialization and should not + * be accessed from the application or socket layer. + * + * Assumptions: + * This function is called with interrupts disabled. + * + ****************************************************************************/ + +void uip_callbackinit(void) +{ + int i; + for (i = 0; i < CONFIG_NET_NACTIVESOCKETS; i++) + { + g_cbprealloc[i].flink = g_cbfreelist; + g_cbfreelist = &g_cbprealloc[i]; + } +} + +/**************************************************************************** + * Function: uip_callbackalloc + * + * Description: + * Allocate a callback container from the free list. + * This is called internally as part of uIP initialization and should not + * be accessed from the application or socket layer. + * + * Assumptions: + * This function is called with interrupts disabled. + * + ****************************************************************************/ + +FAR struct uip_callback_s *uip_callbackalloc(FAR struct uip_callback_s **list) +{ + struct uip_callback_s *ret; + irqstate_t save; + + /* Check the head of the free list */ + + save = irqsave(); + ret = g_cbfreelist; + if (ret) + { + /* Remove the next instance from the head of the free list */ + + g_cbfreelist = ret->flink; + memset(ret, 0, sizeof(struct uip_callback_s)); + + /* Add the newly allocated instance to the head of the specified list */ + + if (list) + { + ret->flink = *list; + *list = ret; + } + else + { + ret->flink = NULL; + } + } +#ifdef CONFIG_DEBUG + else + { + dbg("Failed to allocate callback\n"); + } +#endif + + irqrestore(save); + return ret; +} + +/**************************************************************************** + * Function: uip_callbackfree + * + * Description: + * Return a callback container to the free list. + * This is called internally as part of uIP initialization and should not + * be accessed from the application or socket layer. + * + * Assumptions: + * This function is called with interrupts disabled. + * + ****************************************************************************/ + +void uip_callbackfree(FAR struct uip_callback_s *cb, FAR struct uip_callback_s **list) +{ + FAR struct uip_callback_s *prev; + FAR struct uip_callback_s *curr; + irqstate_t save; + + if (cb) + { + /* Find the callback structure in the connection's list */ + + save = irqsave(); + if (list) + { + for (prev = NULL, curr = *list; + curr && curr != cb; + prev = curr, curr = curr->flink); + + /* Remove the structure from the connection's list */ + + if (curr) + { + if (prev) + { + prev->flink = cb->flink; + } + else + { + *list = cb->flink; + } + } + } + + /* Put the structure into the free list */ + + cb->flink = g_cbfreelist; + g_cbfreelist = cb; + irqrestore(save); + } +} + +/**************************************************************************** + * Function: uip_callbackexecute + * + * Description: + * Execute a list of callbacks. + * This is called internally as part of uIP initialization and should not + * be accessed from the application or socket layer. + * + * Assumptions: + * This function is called with interrupts disabled. + * + ****************************************************************************/ + +uint16 uip_callbackexecute(FAR struct uip_driver_s *dev, void *pvconn, uint16 flags, + FAR struct uip_callback_s *list) +{ + FAR struct uip_callback_s *next; + irqstate_t save; + + /* Loop for each callback in the list and while there are still events + * set in the flags set. + */ + + save = irqsave(); + while (list && flags) + { + /* Save the pointer to the next callback in the lists. This is done + * because the callback action might delete the entry pointed to by + * list. + */ + + next = list->flink; + + /* Check if this callback handles any of the events in the flag set */ + + if (list->event && (flags & list->flags) != 0) + { + /* Yes.. perform the callback. Actions perform by the callback + * may delete the current list entry or add a new list entry to + * beginning of the list (which will be ignored on this pass) + */ + + vdbg("Call event=%p with flags=%04x\n", list->event, flags); + flags = list->event(dev, pvconn, list->private, flags); + } + + /* Set up for the next time through the loop */ + + list = next; + } + + irqrestore(save); + return flags; +} + +#endif /* CONFIG_NET */ diff --git a/nuttx/net/uip/uip-initialize.c b/nuttx/net/uip/uip-initialize.c index 9b51e1735..c2ea121ec 100644 --- a/nuttx/net/uip/uip-initialize.c +++ b/nuttx/net/uip/uip-initialize.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/uip/uip-initialize.c * - * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Adapted for NuttX from logic in uIP which also has a BSD-like license: @@ -114,6 +114,10 @@ uint8 uip_reasstmr; void uip_initialize(void) { + /* Initialize callback support */ + + uip_callbackinit(); + /* Initialize the listening port structures */ #ifdef CONFIG_NET_TCP diff --git a/nuttx/net/uip/uip-internal.h b/nuttx/net/uip/uip-internal.h index 2aab6fbe3..e408a66b3 100644 --- a/nuttx/net/uip/uip-internal.h +++ b/nuttx/net/uip/uip-internal.h @@ -118,6 +118,14 @@ extern "C" { #define EXTERN extern #endif +/* Defined in uip_callback.c ************************************************/ + +EXTERN void uip_callbackinit(void); +EXTERN FAR struct uip_callback_s *uip_callbackalloc(struct uip_callback_s **list); +EXTERN void uip_callbackfree(FAR struct uip_callback_s *cb, struct uip_callback_s **list); +EXTERN uint16 uip_callbackexecute(FAR struct uip_driver_s *dev, void *pvconn, + uint16 flags, FAR struct uip_callback_s *list); + #ifdef CONFIG_NET_TCP /* Defined in uip_tcpconn.c *************************************************/ @@ -145,7 +153,7 @@ EXTERN int uip_accept(struct uip_conn *conn, uint16 portno); /* Defined in uip-tcpsend.c *************************************************/ EXTERN void uip_tcpsend(struct uip_driver_s *dev, struct uip_conn *conn, - uint8 flags, uint16 len); + uint16 flags, uint16 len); EXTERN void uip_tcpreset(struct uip_driver_s *dev); EXTERN void uip_tcpack(struct uip_driver_s *dev, struct uip_conn *conn, uint8 ack); @@ -153,9 +161,9 @@ EXTERN void uip_tcpack(struct uip_driver_s *dev, struct uip_conn *conn, /* Defined in uip-tcpappsend.c **********************************************/ EXTERN void uip_tcpappsend(struct uip_driver_s *dev, struct uip_conn *conn, - uint8 result); + uint16 result); EXTERN void uip_tcprexmit(struct uip_driver_s *dev, struct uip_conn *conn, - uint8 result); + uint16 result); /* Defined in uip-tcpinput.c ************************************************/ @@ -163,8 +171,8 @@ EXTERN void uip_tcpinput(struct uip_driver_s *dev); /* Defined in uip_tcpcallback.c *********************************************/ -EXTERN uint8 uip_tcpcallback(struct uip_driver_s *dev, - struct uip_conn *conn, uint8 flags); +EXTERN uint16 uip_tcpcallback(struct uip_driver_s *dev, + struct uip_conn *conn, uint16 flags); /* Defined in uip-tcpreadahead.c ********************************************/ @@ -195,10 +203,10 @@ EXTERN void uip_udpsend(struct uip_driver_s *dev, struct uip_udp_conn *conn); EXTERN void uip_udpinput(struct uip_driver_s *dev); -/* Defined in uip_uipcallback.c *********************************************/ +/* Defined in uip_udpcallback.c *********************************************/ EXTERN void uip_udpcallback(struct uip_driver_s *dev, - struct uip_udp_conn *conn, uint8 flags); + struct uip_udp_conn *conn, uint16 flags); #endif /* CONFIG_NET_UDP */ #ifdef CONFIG_NET_ICMP diff --git a/nuttx/net/uip/uip-tcpappsend.c b/nuttx/net/uip/uip-tcpappsend.c index 2ef57004b..93f840b02 100644 --- a/nuttx/net/uip/uip-tcpappsend.c +++ b/nuttx/net/uip/uip-tcpappsend.c @@ -94,11 +94,11 @@ * ****************************************************************************/ -void uip_tcpappsend(struct uip_driver_s *dev, struct uip_conn *conn, uint8 result) +void uip_tcpappsend(struct uip_driver_s *dev, struct uip_conn *conn, uint16 result) { /* Handle the result based on the application response */ - nvdbg("result: %02x\n", result); + nvdbg("result: %04x\n", result); /* Check for connection aborted */ @@ -202,9 +202,9 @@ void uip_tcpappsend(struct uip_driver_s *dev, struct uip_conn *conn, uint8 resul * ****************************************************************************/ -void uip_tcprexmit(struct uip_driver_s *dev, struct uip_conn *conn, uint8 result) +void uip_tcprexmit(struct uip_driver_s *dev, struct uip_conn *conn, uint16 result) { - nvdbg("result: %02x\n", result); + nvdbg("result: %04x\n", result); dev->d_appdata = dev->d_snddata; @@ -221,9 +221,9 @@ void uip_tcprexmit(struct uip_driver_s *dev, struct uip_conn *conn, uint8 result uip_tcpsend(dev, conn, TCP_ACK | TCP_PSH, conn->len + UIP_TCPIP_HLEN); } - /* If there is no data to send, just send out a pure ACK if there is newdata. */ + /* If there is no data to send, just send out a pure ACK if one is requested`. */ - else if (result & UIP_NEWDATA) + else if (result & UIP_SNDACK) { uip_tcpsend(dev, conn, TCP_ACK, UIP_TCPIP_HLEN); } diff --git a/nuttx/net/uip/uip-tcpcallback.c b/nuttx/net/uip/uip-tcpcallback.c index 7c7fb2209..b99e41f9f 100644 --- a/nuttx/net/uip/uip-tcpcallback.c +++ b/nuttx/net/uip/uip-tcpcallback.c @@ -102,24 +102,32 @@ static int uip_readahead(struct uip_readahead_s *readahead, uint8 *buf, int len) * Function: uip_dataevent * * Description: - * This is the default data_event handler that is called when there is no - * use data handler in place + * This is the default data event handler that is called when there is no + * user data handler in place * * Assumptions: - * This function is called at the interrupt level with interrupts disabled. + * - The called has checked that UIP_NEWDATA is set in flags and that is no + * other handler available to process the incoming data. + * - This function is called at the interrupt level with interrupts disabled. * ****************************************************************************/ -static inline uint8 -uip_dataevent(struct uip_driver_s *dev, struct uip_conn *conn, uint8 flags) +static inline uint16 +uip_dataevent(struct uip_driver_s *dev, struct uip_conn *conn, uint16 flags) { - uint8 ret = flags; + uint16 ret; + + /* Assume that we will ACK the data. The data will be ACKed if it is + * placed in the read-ahead buffer -OR- if it zero length + */ + + ret = (flags & ~UIP_NEWDATA) | UIP_SNDACK; /* Is there new data? With non-zero length? (Certain connection events * can have zero-length with UIP_NEWDATA set just to cause an ACK). */ - if ((flags & UIP_NEWDATA) != 0 && dev->d_len > 0) + if (dev->d_len > 0) { #if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0 struct uip_readahead_s *readahead1; @@ -127,7 +135,11 @@ uip_dataevent(struct uip_driver_s *dev, struct uip_conn *conn, uint8 flags) uint16 recvlen = 0; uint8 *buf = dev->d_appdata; int buflen = dev->d_len; +#endif + nvdbg("No listener on connection\n"); + +#if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0 /* First, we need to determine if we have space to buffer the data. This * needs to be verified before we actually begin buffering the data. We * will use any remaining space in the last allocated readahead buffer @@ -169,28 +181,30 @@ uip_dataevent(struct uip_driver_s *dev, struct uip_conn *conn, uint8 flags) sq_addlast(&readahead2->rh_node, &conn->readahead); } - /* Indicate that all of the data in the buffer has been consumed */ - nvdbg("Buffered %d bytes\n", dev->d_len); - dev->d_len = 0; } else #endif { /* There is no handler to receive new data and there are no free - * read-ahead buffers to retain the data. In this case, clear the - * UIP_NEWDATA bit so that no ACK will be sent and drop the packet. + * read-ahead buffers to retain the data -- drop the packet. */ -#ifdef CONFIG_NET_STATISTICS + nvdbg("Dropped %d bytes\n", dev->d_len); + + #ifdef CONFIG_NET_STATISTICS uip_stat.tcp.syndrop++; uip_stat.tcp.drop++; #endif - ret &= ~UIP_NEWDATA; - dev->d_len = 0; + /* Clear the UIP_SNDACK bit so that no ACK will be sent */ + + ret &= ~UIP_SNDACK; } } + /* In any event, the new data has now been handled */ + + dev->d_len = 0; return ret; } @@ -209,7 +223,7 @@ uip_dataevent(struct uip_driver_s *dev, struct uip_conn *conn, uint8 flags) * ****************************************************************************/ -uint8 uip_tcpcallback(struct uip_driver_s *dev, struct uip_conn *conn, uint8 flags) +uint16 uip_tcpcallback(struct uip_driver_s *dev, struct uip_conn *conn, uint16 flags) { /* Preserve the UIP_ACKDATA, UIP_CLOSE, and UIP_ABORT in the response. * These is needed by uIP to handle responses and buffer state. The @@ -217,39 +231,42 @@ uint8 uip_tcpcallback(struct uip_driver_s *dev, struct uip_conn *conn, uint8 fla * explicitly set in the callback. */ - uint8 ret = flags; - - nvdbg("flags: %02x\n", flags); - - /* Check if there is a data callback */ - - if (conn->data_event) - { - /* Perform the callback. Callback function normally returns the input flags, - * however, the implementation may set one of the following: - * - * UIP_CLOSE - Gracefully close the current connection - * UIP_ABORT - Abort (reset) the current connection on an error that - * prevents UIP_CLOSE from working. - * - * Or clear the following: - * - * UIP_NEWDATA - May be cleared to suppress returning the ACK response. - * (dev->d_len should also be set to zero in this case). - */ - - ret = conn->data_event(dev, conn, flags); - } - - /* If there is no data callback -OR- if the data callback does not handle the - * newdata event, then there is no handler in place to handle new incoming data. + uint16 ret = flags; + + nvdbg("flags: %04x\n", flags); + + /* Perform the data callback. When a data callback is executed from 'list', + * the input flags are normally returned, however, the implementation + * may set one of the following: + * + * UIP_CLOSE - Gracefully close the current connection + * UIP_ABORT - Abort (reset) the current connection on an error that + * prevents UIP_CLOSE from working. + * + * And/Or set/clear the following: + * + * UIP_NEWDATA - May be cleared to indicate that the data was consumed + * and that no further process of the new data should be + * attempted. + * UIP_SNDACK - If UIP_NEWDATA is cleared, then UIP_SNDACK may be set + * to indicate that an ACK should be included in the response. + * (In UIP_NEWDATA is cleared bu UIP_SNDACK is not set, then + * dev->d_len should also be cleared). + */ + + ret = uip_callbackexecute(dev, conn, flags, conn->list); + + /* There may be no new data handler in place at them moment that the new + * incoming data is received. If the new incoming data was not handled, then + * either (1) put the unhandled incoming data in the read-ahead buffer (if + * enabled) or (2) suppress the ACK to the data in the hope that it will + * be re-transmitted at a better time. */ - if (!conn->data_event || (conn->data_flags & UIP_NEWDATA) == 0) + if ((ret & UIP_NEWDATA) != 0) { - /* In either case, we will take a default newdata action */ + /* Data was not handled.. dispose of it appropriately */ - nvdbg("No listener on connection\n"); ret = uip_dataevent(dev, conn, ret); } diff --git a/nuttx/net/uip/uip-tcpinput.c b/nuttx/net/uip/uip-tcpinput.c index 73eb73592..5a7b5b923 100644 --- a/nuttx/net/uip/uip-tcpinput.c +++ b/nuttx/net/uip/uip-tcpinput.c @@ -98,8 +98,8 @@ void uip_tcpinput(struct uip_driver_s *dev) { struct uip_conn *conn = NULL; uint16 tmp16; + uint16 flags; uint8 opt; - uint8 flags; uint8 result; int len; int i; diff --git a/nuttx/net/uip/uip-tcpsend.c b/nuttx/net/uip/uip-tcpsend.c index b68788b93..17cc6fc92 100644 --- a/nuttx/net/uip/uip-tcpsend.c +++ b/nuttx/net/uip/uip-tcpsend.c @@ -228,7 +228,7 @@ static void uip_tcpsendcommon(struct uip_driver_s *dev, struct uip_conn *conn) * ****************************************************************************/ -void uip_tcpsend(struct uip_driver_s *dev, struct uip_conn *conn, uint8 flags, uint16 len) +void uip_tcpsend(struct uip_driver_s *dev, struct uip_conn *conn, uint16 flags, uint16 len) { BUF->flags = flags; dev->d_len = len; diff --git a/nuttx/net/uip/uip-udpcallback.c b/nuttx/net/uip/uip-udpcallback.c index ae5187913..6c7fecef3 100644 --- a/nuttx/net/uip/uip-udpcallback.c +++ b/nuttx/net/uip/uip-udpcallback.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/uip/uip-udpcallback.c * - * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * @@ -74,9 +74,9 @@ ****************************************************************************/ void uip_udpcallback(struct uip_driver_s *dev, struct uip_udp_conn *conn, - uint8 flags) + uint16 flags) { - nvdbg("flags: %02x\n", flags); + nvdbg("flags: %04x\n", flags); /* Some sanity checking */ @@ -84,7 +84,7 @@ void uip_udpcallback(struct uip_driver_s *dev, struct uip_udp_conn *conn, { /* Perform the callback */ - conn->event(dev, conn, flags); + flags = uip_callbackexecute(dev, conn, flags, conn->list); } } -- cgit v1.2.3