1
0
Fork 0
forked from nuttx/nuttx-update

IP forwarding: Two bugfixes (1) IPFWD poll event must be unique and different from other device poll events otherwise, some other waiting task might get the poll, (2) Add logic necessary to forward 6LoWPAN packets.

This commit is contained in:
Gregory Nutt 2017-07-08 09:56:08 -06:00
parent 25abbf7b17
commit bea75baaab
9 changed files with 328 additions and 38 deletions

1
.gitignore vendored
View file

@ -13,6 +13,7 @@ core
/.config
/.config.old
/.version
/defconfig
/Make.defs
/nuttx
/nuttx.*

View file

@ -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:

View file

@ -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 */

View file

@ -41,6 +41,7 @@
#if defined(CONFIG_NET)
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <debug.h>
#include <assert.h>
@ -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

View file

@ -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.
*
****************************************************************************/

View file

@ -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)

View file

@ -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 */
/****************************************************************************

View file

@ -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);

206
net/ipforward/ipfwd_poll.c Normal file
View file

@ -0,0 +1,206 @@
/****************************************************************************
* net/ipforward/ipfwd_poll.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#include <stdint.h>
#include <nuttx/net/netdev.h>
#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 */