diff --git a/.gitignore b/.gitignore index 4095c1a294..8052befe0f 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ core /.config /.config.old /.version +/defconfig /Make.defs /nuttx /nuttx.* diff --git a/include/nuttx/net/netdev.h b/include/nuttx/net/netdev.h index 7c34217ae9..cc6034c472 100644 --- a/include/nuttx/net/netdev.h +++ b/include/nuttx/net/netdev.h @@ -318,12 +318,13 @@ struct net_driver_s * * There are two lists associated with each device: * - * 1) d_pktcb - For connection/port oriented events for certain + * 1) d_conncb - For connection/port oriented events for certain * socket-less packet transfers. There events include: * - * ICMP data receipt: ICMP_NEWDATA, ICMPv6_NEWDATA - * ICMP ECHO replies: ICMP_ECHOREPLY, ICMPv6_ECHOREPLY + * ICMP data receipt: ICMP_NEWDATA, ICMPv6_NEWDATA + * ICMP ECHO replies: ICMP_ECHOREPLY, ICMPv6_ECHOREPLY * Driver Tx poll events: ARP_POLL, ICMP_POLL. ICMPv6_POLL + * IP Forwarding: IPFWD_POLL * * 2) d_devcb - For non-data, device related events that apply to all * transfers or connections involving this device: diff --git a/net/devif/devif.h b/net/devif/devif.h index 99b389c9b1..3a2215bf94 100644 --- a/net/devif/devif.h +++ b/net/devif/devif.h @@ -148,6 +148,14 @@ * is set differently * OUT: Not used * + * IPFWD_POLL IN: Used for polling for forwarded packets layer. This + * is provided periodically from the drivers to support + * to check if there is a packet waiting to be forward + * on the device. This is a device oriented event, + * not associated with a socket. The appdata pointer + * The appdata pointer is not used in this case. + * OUT: Not used + * * ICMP_ECHOREPLY IN: An ICMP Echo Reply has been received. Used to support * ICMP ping from the socket layer. (ICMPv4 only) * OUT: Cleared (only) by the socket layer logic to indicate @@ -164,7 +172,7 @@ * OUT: Not used */ -/* Connection specific events */ +/* Bits 0-9: Connection specific event bits */ #define TCP_ACKDATA (1 << 0) #define TCP_NEWDATA (1 << 1) @@ -178,23 +186,33 @@ #define UDP_POLL TCP_POLL #define PKT_POLL TCP_POLL #define WPAN_POLL TCP_POLL -#define IPFWD_POLL TCP_POLL #define TCP_BACKLOG (1 << 5) #define TCP_CLOSE (1 << 6) #define TCP_ABORT (1 << 7) #define TCP_CONNECTED (1 << 8) #define TCP_TIMEDOUT (1 << 9) -/* Device specific events */ +/* Bits 10-12: Device specific event bits */ #define ICMP_NEWDATA TCP_NEWDATA #define ICMPv6_NEWDATA TCP_NEWDATA -#define ARP_POLL (1 << 10) -#define ICMP_POLL (1 << 11) -#define ICMPv6_POLL (1 << 12) -#define ICMP_ECHOREPLY (1 << 13) -#define ICMPv6_ECHOREPLY (1 << 14) -#define NETDEV_DOWN (1 << 15) +#define ICMP_ECHOREPLY (1 << 10) +#define ICMPv6_ECHOREPLY (1 << 11) +#define NETDEV_DOWN (1 << 12) + +/* Bits 13-15: Encoded device specific poll events. Unlike connection + * oriented poll events, device related poll events must distinguish + * between what is being polled for since the callbacks all reside in + * the same list in the network device structure. + */ + +#define DEVPOLL_SHIFT (13) +#define DEVPOLL_MASK (7 << DEVPOLL_SHIFT) +# define DEVPOLL_NONE (0 << DEVPOLL_SHIFT) +# define ARP_POLL (1 << DEVPOLL_SHIFT) +# define ICMP_POLL (2 << DEVPOLL_SHIFT) +# define ICMPv6_POLL (3 << DEVPOLL_SHIFT) +# define IPFWD_POLL (4 << DEVPOLL_SHIFT) /* The set of events that and implications to the TCP connection state */ diff --git a/net/devif/devif_callback.c b/net/devif/devif_callback.c index bb8867b73f..c88dda744c 100644 --- a/net/devif/devif_callback.c +++ b/net/devif/devif_callback.c @@ -41,6 +41,7 @@ #if defined(CONFIG_NET) #include +#include #include #include #include @@ -162,6 +163,45 @@ static void devif_callback_free(FAR struct net_driver_s *dev, } } +/**************************************************************************** + * Name: devif_event_trigger + * + * Description: + * Return true if the current set of events should trigger a callback to + * occur. + * + * Input paramters: + * events - The set of events that has occurred. + * triggers - The set of events that will trigger a callback. + * + ****************************************************************************/ + +static bool devif_event_trigger(uint16_t events, uint16_t triggers) +{ + /* The events are divided into a set of individual bits that may be ORed + * together PLUS a field that encodes a single poll event. + * + * First check if any of the individual event bits will trigger the + * callback. + */ + + if ((events & triggers & ~DEVPOLL_MASK) != 0) + { + return true; + } + + /* No... check the encoded device event. */ + + if ((events & DEVPOLL_MASK) == (triggers & DEVPOLL_MASK)) + { + return true; + } + + /* No.. this event set will not generate the callback */ + + return false; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -335,7 +375,7 @@ void devif_dev_callback_free(FAR struct net_driver_s *dev, * was allocated and the time when the callback was freed. */ - if (dev && netdev_verify(dev)) + if (dev != NULL && netdev_verify(dev)) { /* The device reference is valid.. the use the list pointer in the * device structure as well. @@ -400,7 +440,7 @@ uint16_t devif_conn_event(FAR struct net_driver_s *dev, void *pvconn, /* Check if this callback handles any of the events in the flag set */ - if (list->event && (flags & list->flags) != 0) + if (list->event != NULL && devif_event_trigger(flags, list->flags)) { /* Yes.. perform the callback. Actions perform by the callback * may delete the current list entry or add a new list entry to @@ -464,7 +504,7 @@ uint16_t devif_dev_event(FAR struct net_driver_s *dev, void *pvconn, /* Check if this callback handles any of the events in the flag set */ - if (cb->event && (flags & cb->flags) != 0) + if (cb->event != NULL && devif_event_trigger(flags, cb->flags)) { /* Yes.. perform the callback. Actions perform by the callback * may delete the current list entry or add a new list entry to diff --git a/net/devif/devif_poll.c b/net/devif/devif_poll.c index 73c5050f58..6f37768d6b 100644 --- a/net/devif/devif_poll.c +++ b/net/devif/devif_poll.c @@ -56,6 +56,7 @@ #include "icmp/icmp.h" #include "icmpv6/icmpv6.h" #include "igmp/igmp.h" +#include "ipforward/ipforward.h" #include "sixlowpan/sixlowpan.h" /**************************************************************************** @@ -166,8 +167,8 @@ static void devif_packet_conversion(FAR struct net_driver_s *dev, * Poll all packet connections for available packets to send. * * Assumptions: - * This function is called from the MAC device driver and may be called - * from the timer interrupt/watchdog handle level. + * This function is called from the MAC device driver with the network + * locked. * ****************************************************************************/ @@ -259,13 +260,18 @@ static inline int devif_poll_icmpv6(FAR struct net_driver_s *dev, * ****************************************************************************/ -#if defined(CONFIG_NET_IPFORWARD) || defined(CONFIG_NETDEV_MULTINIC) +#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NETDEV_MULTINIC) static inline int devif_poll_forward(FAR struct net_driver_s *dev, devif_poll_callback_t callback) { - /* Perform the ICMPv6 poll */ + /* Perform the forwarding poll */ - devif_dev_event(dev, NULL, IPFWD_POLL); + ipfwd_poll(dev); + + /* NOTE: that 6LoWPAN packet conversions are handled differently for + * forwarded packets. That is because we don't know what the packet + * type is at this point; not within peeking into the device's d_buf. + */ /* Call back into the driver */ @@ -280,8 +286,8 @@ static inline int devif_poll_forward(FAR struct net_driver_s *dev, * Poll all IGMP connections for available packets to send. * * Assumptions: - * This function is called from the MAC device driver and may be called - * from the timer interrupt/watchdog handle level. + * This function is called from the MAC device driver with the network + * locked. * ****************************************************************************/ @@ -310,8 +316,8 @@ static inline int devif_poll_igmp(FAR struct net_driver_s *dev, * Poll all UDP connections for available packets to send. * * Assumptions: - * This function is called from the MAC device driver and may be called - * from the timer interrupt/watchdog handle level. + * This function is called from the MAC device driver with the network + * locked. * ****************************************************************************/ @@ -350,8 +356,8 @@ static int devif_poll_udp_connections(FAR struct net_driver_s *dev, * Poll all UDP connections for available packets to send. * * Assumptions: - * This function is called from the MAC device driver and may be called - * from the timer interrupt/watchdog handle level. + * This function is called from the MAC device driver with the network + * locked. * ****************************************************************************/ @@ -393,8 +399,8 @@ static inline int devif_poll_tcp_connections(FAR struct net_driver_s *dev, * TCP connection. * * Assumptions: - * This function is called from the MAC device driver and may be called - * from the timer interrupt/watchdog handle level. + * This function is called from the MAC device driver with the network + * locked. * ****************************************************************************/ @@ -453,8 +459,8 @@ static inline int devif_poll_tcp_timer(FAR struct net_driver_s *dev, * out the packet. * * Assumptions: - * This function is called from the MAC device driver and may be called - * from the timer interrupt/watchdog handle level. + * This function is called from the MAC device driver with the network + * locked. * ****************************************************************************/ @@ -530,7 +536,7 @@ int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback) if (!bstop) #endif -#if defined(CONFIG_NET_IPFORWARD) || defined(CONFIG_NETDEV_MULTINIC) +#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NETDEV_MULTINIC) { /* Traverse all of the tasks waiting to forward a packet to this device. */ @@ -565,8 +571,8 @@ int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback) * out the packet. * * Assumptions: - * This function is called from the MAC device driver and may be called from - * the timer interrupt/watchdog handle level. + * This function is called from the MAC device driver with the network + * locked. * ****************************************************************************/ diff --git a/net/ipforward/Make.defs b/net/ipforward/Make.defs index cc46826da5..c8ad408c56 100644 --- a/net/ipforward/Make.defs +++ b/net/ipforward/Make.defs @@ -37,8 +37,6 @@ ifeq ($(CONFIG_NET_IPFORWARD),y) -NET_CSRCS += ipfwd_forward.c - ifeq ($(CONFIG_NET_IPv4),y) NET_CSRCS += ipv4_forward.c endif @@ -48,7 +46,7 @@ NET_CSRCS += ipv6_forward.c endif ifeq ($(CONFIG_NETDEV_MULTINIC),y) -NET_CSRCS += ipfwd_alloc.c +NET_CSRCS += ipfwd_alloc.c ipfwd_forward.c ipfwd_poll.c endif ifeq ($(CONFIG_NET_STATISTICS),y) diff --git a/net/ipforward/ipforward.h b/net/ipforward/ipforward.h index a267c1f901..e88c23a659 100644 --- a/net/ipforward/ipforward.h +++ b/net/ipforward/ipforward.h @@ -63,6 +63,11 @@ # define CONFIG_NET_IPFORWARD_NSTRUCT 4 #endif +/* Allocate a new IP forwarding data callback */ + +#define ipfwd_callback_alloc(dev) devif_callback_alloc(dev, &(dev)->d_conncb) +#define ipfwd_callback_free(dev,cb) devif_dev_callback_free(dev, cb) + /**************************************************************************** * Public Types ****************************************************************************/ @@ -240,6 +245,20 @@ void devif_forward(FAR struct forward_s *fwd); int ipfwd_forward(FAR struct forward_s *fwd); +/**************************************************************************** + * Name: ipfwd_poll + * + * Description: + * Poll all pending transfer for ARP requests to send. + * + * Assumptions: + * This function is called from the MAC device driver indirectly through + * devif_poll() and devif_timer(). + * + ****************************************************************************/ + +void ipfwd_poll(FAR struct net_driver_s *dev); + #endif /* CONFIG_NETDEV_MULTINIC */ /**************************************************************************** diff --git a/net/ipforward/ipfwd_forward.c b/net/ipforward/ipfwd_forward.c index 962713425e..9899fadcc7 100644 --- a/net/ipforward/ipfwd_forward.c +++ b/net/ipforward/ipfwd_forward.c @@ -264,6 +264,7 @@ static uint16_t ipfwd_interrupt(FAR struct net_driver_s *dev, FAR void *conn, /* Copy the user data into d_appdata and send it. */ devif_forward(fwd); + flags &= ~DEVPOLL_MASK; /* Check if the destination IP address is in the ARP or Neighbor * table. If not, then the send won't actually make it out... it @@ -282,7 +283,7 @@ static uint16_t ipfwd_interrupt(FAR struct net_driver_s *dev, FAR void *conn, fwd->f_cb->priv = NULL; fwd->f_cb->event = NULL; - devif_conn_callback_free(dev, fwd->f_cb, NULL); + ipfwd_callback_free(dev, fwd->f_cb); /* Free any IOBs */ @@ -332,7 +333,7 @@ int ipfwd_forward(FAR struct forward_s *fwd) /* Set up the callback in the connection */ - fwd->f_cb = devif_callback_alloc(fwd->f_dev, NULL); + fwd->f_cb = ipfwd_callback_alloc(fwd->f_dev); if (fwd->f_cb != NULL) { fwd->f_cb->flags = (IPFWD_POLL | NETDEV_DOWN); diff --git a/net/ipforward/ipfwd_poll.c b/net/ipforward/ipfwd_poll.c new file mode 100644 index 0000000000..e9ba676c21 --- /dev/null +++ b/net/ipforward/ipfwd_poll.c @@ -0,0 +1,206 @@ +/**************************************************************************** + * net/ipforward/ipfwd_poll.c + * + * Copyright (C) 2017 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 + +#include + +#include + +#include "devif/devif.h" +#include "ipforward/ipforward.h" + +#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NETDEV_MULTINIC) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ipfwd_packet_proto + * + * Description: + * Generic output conversion hook. Only needed for IEEE802.15.4 for now + * but this is a point where support for other conversions may be + * provided. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_6LOWPAN +static int ipfwd_packet_proto(FAR struct net_driver_s *dev) +{ + FAR struct ipv6_hdr_s *ipv6; + int llhdrlen = NET_LL_HDRLEN(dev); + + /* Make sure the there is something in buffer that is at least as large as + * the IPv6_HDR. + */ + + if (dev->d_len > (IPv6_HDRLEN + llhdrlen)) + { +#ifdef CONFIG_NET_MULTILINK + /* Handle the case where multiple link layer protocols are supported */ + + if (dev->d_lltype == NET_LL_IEEE802154) +#endif + { + /* There should be an IPv6 packet in the at the beginning of the debugger */ + + ipv6 = (FAR struct ipv6_hdr_s *)&dev->d_buf[llhdrlen]; + if ((ipv6->vtc & IP_VERSION_MASK) == IPv6_VERSION) + { + /* Yes.. return the L2 protocol of the packet */ + + return ipv6->proto; + } + } + } + + return -EPROTO; +} +#endif /* CONFIG_NET_6LOWPAN */ + +/**************************************************************************** + * Name: ipfwd_packet_conversion + * + * Description: + * Generic output conversion hook. Only needed for IEEE802.15.4 for now + * but this is a point where support for other conversions may be + * provided. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_6LOWPAN +static void ipfwd_packet_conversion(FAR struct net_driver_s *dev, int proto) +{ +#ifdef CONFIG_NET_MULTILINK + /* Handle the case where multiple link layer protocols are supported */ + + if (dev->d_len > 0 && dev->d_lltype == NET_LL_IEEE802154) +#else + if (dev->d_len > 0) +#endif + { +#ifdef CONFIG_NET_TCP + if (proto == IP_PROTO_TCP) + { + /* Let 6LoWPAN convert IPv6 TCP output into IEEE802.15.4 frames. */ + + sixlowpan_tcp_send(dev, dev, ipv6); + } + else +#endif +#ifdef CONFIG_NET_UDP + if (proto == IP_PROTO_UDP) + { + /* Let 6LoWPAN convert IPv6 UDP output into IEEE802.15.4 frames. */ + + sixlowpan_udp_send(dev, dev, ipv6); + } + else +#endif +#ifdef CONFIG_NET_ICMPv6 + if (proto == IP_PROTO_ICMP6) + { + /* Let 6LoWPAN convert IPv6 UDP output into IEEE802.15.4 frames. */ + + nwerr("ERROR: Missing support for ICMPv6 packet forwarding\n"); + } + else +#endif + { + nwarn("WARNING: Non-TCP packet dropped. Packet type: %u\n", proto); + } + + dev->d_len = 0; + } +} +#endif /* CONFIG_NET_6LOWPAN */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ipfwd_poll + * + * Description: + * Poll all pending transfer for ARP requests to send. + * + * Assumptions: + * This function is called from the MAC device driver indirectly through + * devif_poll() and devif_timer(). + * + ****************************************************************************/ + +void ipfwd_poll(FAR struct net_driver_s *dev) +{ + uint16_t flags; + + /* Setup for the callback (most of these do not apply) */ + + dev->d_appdata = NULL; + dev->d_len = 0; + dev->d_sndlen = 0; + + /* Perform the forwarding callbacks. Returns the new set of flags. If + * the packet was fowarded, then the new set will be zero. + */ + + flags = devif_conn_event(dev, NULL, IPFWD_POLL, dev->d_conncb); + +#ifdef CONFIG_NET_6LOWPAN + if ((flags & DEVPOLL_MASK) == 0) + { + /* Get the L2 protocol of packet in the device's d_buf */ + + int proto = ipfwd_packet_proto(dev); + if (proto >= 0) + { + /* Perform any necessary conversions on the forwarded packet */ + + ipfwd_packet_conversion(dev, proto); + } + } +#else + UNUSED(flags); +#endif +} + +#endif /* CONFIG_NET_ARP_SEND && CONFIG_NETDEV_MULTINIC */