diff --git a/include/nuttx/net/icmp.h b/include/nuttx/net/icmp.h index 875deaae42..33c38f2cf6 100644 --- a/include/nuttx/net/icmp.h +++ b/include/nuttx/net/icmp.h @@ -99,7 +99,26 @@ * Public Type Definitions ****************************************************************************/ -/* The ICMP and IP headers */ +struct icmp_hdr_s +{ + /* ICMP header */ + + uint8_t type; /* Defines the format of the ICMP message */ + uint8_t icode; /* Further qualifies the ICMP messsage */ + uint16_t icmpchksum; /* Checksum of ICMP header and data */ + + /* All ICMP packets have an 8-byte header and variable-sized data section. + * The first 4 bytes of the header have fixed format, while the last 4 bytes + * depend on the type/code of that ICMP packet. + */ + + /* ICMP_ECHO_REQUEST and ICMP_ECHO_REPLY data */ + + uint16_t id; /* Used to match requests with replies */ + uint16_t seqno; /* " " "" " " " " " " " " */ +}; + +/* The ICMP and IPv4 headers */ struct icmp_iphdr_s { @@ -122,8 +141,9 @@ struct icmp_iphdr_s uint8_t icode; /* Further qualifies the ICMP messsage */ uint16_t icmpchksum; /* Checksum of ICMP header and data */ - /* Data following the ICMP header contains the data specific to the - * message type indicated by the Type and Code fields. + /* All ICMP packets have an 8-byte header and variable-sized data section. + * The first 4 bytes of the header have fixed format, while the last 4 bytes + * depend on the type/code of that ICMP packet. */ /* ICMP_ECHO_REQUEST and ICMP_ECHO_REPLY data */ diff --git a/include/nuttx/net/tcp.h b/include/nuttx/net/tcp.h index fd26d7ba5e..67f7507757 100644 --- a/include/nuttx/net/tcp.h +++ b/include/nuttx/net/tcp.h @@ -95,9 +95,16 @@ # define TCP_STOPPED 0x10 /* Bit 4: stopped */ /* Bit 5-7: Unused, but not available */ -/* TCP header sizes */ +/* TCP header sizes + * + * The minimum size header is 5 words and the maximum is 15 words thus + * giving the minimum size of 20 bytes and maximum of 60 bytes, allowing for + * up to 40 bytes of options in the header. + */ -#define TCP_HDRLEN 20 /* Size of TCP header */ +#define TCP_HDRLEN 20 /* Size of TCP header (minimum) */ +#define TCP_OPT_HDRLEN(n) (20 + ((n) << 2)) /* Size of TCP header w/options */ +#define TCP_MAX_HDRLEN 60 /* Maximum size of TCP header */ #ifdef CONFIG_NET_IPv4 # define IPv4TCP_HDRLEN (TCP_HDRLEN + IPv4_HDRLEN) /* Size of IPv4 + TCP header */ diff --git a/net/Kconfig b/net/Kconfig index c3a8022a75..6a1ce6ab11 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -299,6 +299,23 @@ config NET_IPFORWARD reason why IPv4 forwarding has not been implemented, it just has not yet been done. +config NET_IPFORWARD_NSTRUCT + int "Number of pre-allocated forwarding structures" + default 4 + depends on NET_IPFORWARD && CONFIG_NETDEV_MULTINIC + ---help--- + When packets are forward from on device to another, a structure must + be allocated to hold the state of forwarding across several + asynchronous events. Those structures are pre-allocated for + minimal, deterministic performance and to prevent hogging of memory + (of course, that means that this value must be carefully selected + for your application). This setting defines the number of such pre- + allocated structures. + + NOTE: This setting effectively puts a maximum on the number of + packets that may be waiting to be forwarded from one network device + to another. + endmenu # Internet Protocol Selection source "net/socket/Kconfig" diff --git a/net/devif/Make.defs b/net/devif/Make.defs index 714f4356e1..c436648101 100644 --- a/net/devif/Make.defs +++ b/net/devif/Make.defs @@ -51,6 +51,12 @@ NET_CSRCS += ipv6_forward.c endif endif +ifeq ($(CONFIG_NET_IPFORWARD),y) +ifeq ($(CONFIG_NETDEV_MULTINIC),y) +NET_CSRCS += ip_forward.c +endif +endif + # I/O buffer chain support required? ifeq ($(CONFIG_MM_IOB),y) diff --git a/net/devif/devif_initialize.c b/net/devif/devif_initialize.c index 4142019e2c..be858e5920 100644 --- a/net/devif/devif_initialize.c +++ b/net/devif/devif_initialize.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/devif/devif_initialize.c * - * Copyright (C) 2007-2011, 2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2011, 2014, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Adapted for NuttX from logic in uIP which also has a BSD-like license: @@ -50,6 +50,7 @@ #include #include +#include "devif/ip_forward.h" #include "devif/devif.h" /**************************************************************************** @@ -167,5 +168,11 @@ void devif_initialize(void) /* Initialize callback support */ devif_callback_init(); + +#ifdef HAVE_FWDALLOC + /* Initialize IP forwarding support */ + + ip_forward_initialize(); +#endif } #endif /* CONFIG_NET */ diff --git a/net/devif/ip_forward.c b/net/devif/ip_forward.c new file mode 100644 index 0000000000..a1a59e23f5 --- /dev/null +++ b/net/devif/ip_forward.c @@ -0,0 +1,139 @@ +/**************************************************************************** + * net/devif/ip_forward.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 + +#include "devif/ip_forward.h" + +#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NETDEV_MULTINIC) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This is an array of pre-allocating forwarding structures */ + +static struct forward_s g_fwdpool[CONFIG_NET_IPFORWARD_NSTRUCT]; + +/* This is a list of free forwarding structures */ + +static FAR struct forward_s *g_fwdfree; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ip_forward_initialize + * + * Description: + * Initialize the struct forward_s allocator. + * + * Assumptions: + * Called early in system initialization. + * + ****************************************************************************/ + +void ip_forward_initialize(void) +{ + FAR struct forward_s *fwd; + int i; + + /* Add all pre-allocated forwarding structures to the free list */ + + g_fwdfree = NULL; + + for (i = 0; i < CONFIG_NET_IPFORWARD_NSTRUCT; i++) + { + fwd = &g_fwdpool[i]; + fwd->f_flink = g_fwdfree; + g_fwdfree = fwd; + } +} + +/**************************************************************************** + * Name: ip_forward_alloc + * + * Description: + * Allocate a forwarding structure by removing a pre-allocated entry from + * a free list. + * + * Assumptions: + * Caller holds the network lock. Mutually excluvive access to the free + * list is assured by this lock. + * + ****************************************************************************/ + +FAR struct forward_s *ip_forward_alloc(void) +{ + FAR struct forward_s *fwd; + + fwd = g_fwdfree; + if (fwd != NULL) + { + g_fwdfree = fwd->f_flink; + memset (fwd, 0, sizeof(struct forward_s)); + } + + return fwd; +} + +/**************************************************************************** + * Name: ip_forward_free + * + * Description: + * Free a forwarding structure by adding it to a free list. + * + * Assumptions: + * Caller holds the network lock. Mutually excluvive access to the free + * list is assured by this lock. + * + ****************************************************************************/ + +void ip_forward_free(FAR struct forward_s *fwd) +{ + fwd->f_flink = g_fwdfree; + g_fwdfree = fwd; +} + +#endif /* CONFIG_NET_IPFORWARD && CONFIG_NETDEV_MULTINIC */ diff --git a/net/devif/ip_forward.h b/net/devif/ip_forward.h new file mode 100644 index 0000000000..a61fab2667 --- /dev/null +++ b/net/devif/ip_forward.h @@ -0,0 +1,186 @@ +/**************************************************************************** + * net/devif/ip_forward.h + * + * 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. + * + ****************************************************************************/ + +#ifndef __NET_DEVIF_IP_FORWARD_H +#define __NET_DEVIF_IP_FORWARD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include +#include + +#undef HAVE_FWDALLOC +#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NETDEV_MULTINIC) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define HAVE_FWDALLOC 1 + +#ifndef CONFIG_NET_IPFORWARD_NSTRUCT +# define CONFIG_NET_IPFORWARD_NSTRUCT 4 +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* IPv4 + L2 header */ + +#ifdef CONFIG_NET_IPv4 +struct ipv6_fwdhdr_s +{ + struct ipv4_hdr_s l2; + union + { +#ifdef CONFIG_NET_TCP + uint8_t pad[TCP_MAX_HDRLEN]; + struct tcp_hdr_s tcp; +#endif +#ifdef CONFIG_NET_UDP + struct udp_hdr_s udp; +#endif +#ifdef CONFIG_NET_ICMPv6 + struct icmp_hdr_s icmp; +#endif + } l3; +}; +#endif + +/* IPv6 + L2 header */ + +#ifdef CONFIG_NET_IPv6 +struct ipv6_fwdhdr_s +{ + struct ipv6_hdr_s l2; + union + { +#ifdef CONFIG_NET_TCP + uint8_t pad[TCP_MAX_HDRLEN]; + struct tcp_hdr_s tcp; +#endif +#ifdef CONFIG_NET_UDP + struct udp_hdr_s udp; +#endif +#ifdef CONFIG_NET_ICMPv6 + struct icmpv6_hdr_s icmpv6; +#endif + } l3; +}; +#endif + +/* IPv4 or IPv6 + L2 header */ + +union ip_fwdhdr_u +{ +#ifdef CONFIG_NET_IPv4 + struct ipv4_fwdhdr_s ipv4; +#endif +#ifdef CONFIG_NET_IPv6 + struct ipv6_fwdhdr_s ipv6; +#endif +}; + +/* This is the send state structure */ + +struct net_driver_s; /* Forward reference */ +struct iob_s; /* Forward reference */ + +struct forward_s +{ + FAR struct forward_s *f_flink; /* Supports a singly linked list */ + FAR struct net_driver_s *f_dev; /* Forwarding device */ + FAR struct iob_s *f_iob; /* IOBs containing the data payload */ + union ip_fwdhdr_u f_hdr; /* Copy of original L2+L3 headers */ + uint8_t f_hdrsize; /* The size of the L2+L3 headers */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: ip_forward_initialize + * + * Description: + * Initialize the struct forward_s allocator. + * + * Assumptions: + * Called early in system initialization. + * + ****************************************************************************/ + +void ip_forward_initialize(void); + +/**************************************************************************** + * Name: ip_forward_alloc + * + * Description: + * Allocate a forwarding structure by removing a pre-allocated entry from + * a free list. + * + * Assumptions: + * Caller holds the network lock. Mutually excluvive access to the free + * list is assured by this lock. + * + ****************************************************************************/ + +FAR struct forward_s *ip_forward_alloc(void); + +/**************************************************************************** + * Name: ip_forward_free + * + * Description: + * Free a forwarding structure by adding it to a free list. + * + * Assumptions: + * Caller holds the network lock. Mutually excluvive access to the free + * list is assured by this lock. + * + ****************************************************************************/ + +void ip_forward_free(FAR struct forward_s *fwd); + +#endif /* CONFIG_NET_IPFORWARD && CONFIG_NETDEV_MULTINIC */ +#endif /* __NET_DEVIF_IP_FORWARD_H */ diff --git a/net/devif/ipv6_forward.c b/net/devif/ipv6_forward.c index f04323e5d9..951ed25f34 100644 --- a/net/devif/ipv6_forward.c +++ b/net/devif/ipv6_forward.c @@ -39,6 +39,7 @@ #include +#include #include #include @@ -49,45 +50,14 @@ #include "netdev/netdev.h" #include "sixlowpan/sixlowpan.h" +#include "udp/udp.h" #include "tcp/tcp.h" +#include "icmpv6/icmpv6.h" +#include "devif/ip_forward.h" #include "devif/devif.h" #if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_IPv6) -/**************************************************************************** - * Private Types - ****************************************************************************/ - -#if defined(CONFIG_NETDEV_MULTINIC) && \ - (defined(CONFIG_NET_UDP) || defined(CONFIG_NET_ICMPv6)) - -/* IPv6 + UDP or ICMPv6 header */ - -struct ipv6l3_hdr_s -{ - struct ipv6_hdr_s ipv6; - union - { -#ifdef CONFIG_NET_UDP - struct udp_hdr_s udp; -#endif -#ifdef CONFIG_NET_ICMPv6 - struct icmpv6_iphdr_s icmp; -#endif - } u; -}; - -/* This is the send state structure */ - -struct forward_s -{ - FAR struct net_driver_s *dev; /* Forwarding device */ - struct ipv6l3_hdr_s hdr; /* Copy of origin L2+L3 headers */ - FAR struct iob_queue_s iobq; /* IOBs contained the data payload */ -}; - -#endif /* CONFIG_NETDEV_MULTINIC && (CONFIG_NET_UDP || CONFIG_NET_ICMPv6) */ - /**************************************************************************** * Private Functions ****************************************************************************/ @@ -218,50 +188,188 @@ static int ipv6_hdrsize(FAR struct ipv6_hdr_s *ipv6) * Name: ipv6_dev_forward * * Description: - * Set up to forward the UDP or ICMPv6 packet on the specified device. - * This function will set up a send "interrupt" handler that will perform - * the actual send asynchronously and must return without waiting for the - * send to complete. + * This function is called from ipv6_forward when it is necessary to + * forward a packet from the current device to different device. In this + * case, the forwarding operation must be performed asynchronously when + * the TX poll is received from the forwarding device. * * Input Parameters: - * dev - The device on which the packet should be forwarded. - * ipv6 - A pointer to the IPv6 header in within the IPv6 packet. This - * is immeidately followed by the L3 header which may be UDP or - * ICMPv6. - * iob - A list of IOBs containing the data payload to be sent. + * dev - The device on which the packet was received and which + * contains the IPv6 packet. + * fwdddev - The device on which the packet must be forwarded. + * ipv6 - A pointer to the IPv6 header in within the IPv6 packet * * Returned Value: - * Zero is returned if the packet was successfully forwarded; A negated + * Zero is returned if the packet was successfully forward; A negated * errno value is returned if the packet is not forwardable. In that - * latter case, the caller should free the IOB list and drop the packet. + * latter case, the caller (ipv6_input()) should drop the packet. * ****************************************************************************/ -#if defined(CONFIG_NETDEV_MULTINIC) && \ - (defined(CONFIG_NET_UDP) || defined(CONFIG_NET_ICMPv6)) +#ifdef CONFIG_NETDEV_MULTINIC static int ipv6_dev_forward(FAR struct net_driver_s *dev, - FAR struct ipv6_hdr_s *ipv6, - FAR struct iob_s *iob) + FAR struct net_driver_s *fwddev, + FAR struct ipv6_hdr_s *ipv6) { - /* Notify the forwarding device that TX data is available */ + FAR struct forward_s *fwd = NULL; + int hdrsize; + int ret; - /* Set up to send the packet when the selected device polls for TX data. */ + /* Perform any necessary packet conversions. */ -#warning Missing logic + ret = ipv6_packet_conversion(dev, fwddev, ipv6); + if (ret < 0) + { + FAR uint8_t *payload; + unsigned int paysize; - /* REVISIT: For Ethernet we may have to fix up the Ethernet header: - * - source MAC, the MAC of the current device. - * - dest MAC, the MAC associated with the destination IPv6 adress. - * This will involve ICMPv6 and Neighbor Discovery. - */ + /* Get a pre-allocated forwarding structure, This structure will be + * completely zeroed when we receive it. + */ - nwarn("WARNING: UPD/ICMPv6 packet forwarding not yet supported\n"); - return -ENOSYS; -} -#else -# define ipv6_dev_forward(dev,ipv6,iob) -EPROTONOSUPPORT + fwd = ip_forward_alloc(); + if (fwd == NULL) + { + nwarn("WARNING: Failed to allocate forwarding structure\n"); + ret = -ENOMEM; + goto errout; + } + + /* Initialize the easy stuff in the forwarding structure */ + + fwd->f_dev = fwddev; /* Forwarding device */ + + /* Get the size of the IPv6 + L3 header. Use this to determine start + * of the data payload. + * + * Remember that the size of the L1 header has already been subtracted + * from dev->d_len. + */ + + hdrsize = ipv6_hdrsize(ipv6); + if (hdrsize < IPv6_HDRLEN) + { + nwarn("WARNING: Could not determine L2+L3 header size\n"); + ret = -EPROTONOSUPPORT; + goto errout_with_fwd; + } + + /* Save the entire L2 and L3 headers in the state structure */ + + if (hdrsize > sizeof(union ip_fwdhdr_u)) + { + nwarn("WARNING: Header is too big for pre-allocated structure\n"); + ret = -E2BIG; + goto errout_with_fwd; + } + + memcpy(&fwd->f_hdr, ipv6, hdrsize); + fwd->f_hdrsize = hdrsize; + + /* Use the L2 + L3 header size to determine start and size of the data + * payload. + * + * Remember that the size of the L1 header has already been subtracted + * from dev->d_len. + */ + + payload = (FAR uint8_t *)ipv6 + hdrsize; + paysize = dev->d_len - hdrsize; + + /* If there is a payload, then copy it into an IOB chain */ + + if (paysize > 0) + { + /* Try to allocate the head of an IOB chain. If this fails, + * the the packet will be dropped; we are not operating in a + * context where waiting for an IOB is a good idea + */ + + fwd->f_iob = iob_tryalloc(false); + if (fwd->f_iob == NULL) + { + nwarn("WARNING: iob_tryalloc() failed\n"); + ret = -ENOMEM; + goto errout_with_fwd; + } + + /* Copy the packet data payload into an IOB chain. + * iob_trycopin() will not wait, but will fail there are no + * available IOBs. + */ + + ret = iob_trycopyin(fwd->f_iob, payload, paysize, 0, false); + if (ret < 0) + { + nwarn("WARNING: iob_trycopyin() failed: %d\n", ret); + goto errout_with_iobchain; + } + } + + /* Then set up to forward the packet according to the protocol */ + + switch (ipv6->proto) + { +#ifdef CONFIG_NET_TCP + case IP_PROTO_TCP: + { + /* Forward a TCP packet, handling ACKs, windowing, etc. */ + + ret = tcp_ipv6_dev_forward(fwd); + } + break; #endif +#ifdef CONFIG_NET_UDP + case IP_PROTO_UDP: + { + /* Forward a UDP packet */ + + ret = udp_ipv6_dev_forward(fwd); + } + break; +#endif + +#ifdef CONFIG_NET_ICMPv6 + case IP_PROTO_ICMP6: + { + /* Forward an ICMPv6 packet */ + + ret = icmpv6_dev_forward(fwd); + } + break; +#endif + + default: + nwarn("WARNING: Unrecognized proto: %u\n", ipv6->proto); + ret = -EPROTONOSUPPORT; + break; + } + } + + if (ret >= 0) + { + dev->d_len = 0; + return OK; + } + +errout_with_iobchain: + if (fwd != NULL && fwd->f_iob != NULL) + { + iob_free_chain(fwd->f_iob); + } + +errout_with_fwd: + if (fwd != NULL) + { + ip_forward_free(fwd); + } + +errout: + return ret; +} +#endif /* CONFIG_NETDEV_MULTINIC */ + /**************************************************************************** * Name: ipv6_decr_ttl * @@ -435,86 +543,12 @@ int ipv6_forward(FAR struct net_driver_s *dev, FAR struct ipv6_hdr_s *ipv6) if (fwddev != dev) { - /* Perform any necessary packet conversions. */ + /* Send the packet asynchrously on the forwarding device. */ - ret = ipv6_packet_conversion(dev, fwddev, ipv6); + ret = ipv6_dev_forward(dev, fwddev, ipv6); if (ret < 0) { - FAR struct iob_s *iob = NULL; - FAR uint8_t *payload; - unsigned int paysize; - int hdrsize; - - /* Get the size of the IPv6 + L3 header. Use this to determine - * start of the data payload. - * - * Remember that the size of the L1 header has already been - * subtracted from dev->d_len. - */ - - hdrsize = ipv6_hdrsize(ipv6); - if (hdrsize < 0) - { - ret = -EPROTONOSUPPORT; - goto drop; - } - - payload = (FAR uint8_t *)ipv6 + hdrsize; - paysize = dev->d_len - hdrsize; - - if (paysize > 0) - { - /* Try to allocate the head of an IOB chain. If this fails, - * the the packet will be dropped; we are not operating in a - * context where waiting for an IOB is a good idea - */ - - iob = iob_tryalloc(false); - if (iob == NULL) - { - ret = -ENOMEM; - goto drop; - } - - /* Copy the packet data payload into an IOB chain. - * iob_trycopin() will not wait, but will fail there are no - * available IOBs. - */ - - ret = iob_trycopyin(iob, payload, paysize, 0, false); - if (ret < 0) - { - iob_free_chain(iob); - goto drop; - } - } - - /* Then set up to forward the packet */ - -#ifdef CONFIG_NET_TCP - if (ipv6->proto == IP_PROTO_TCP) - { - /* Forward a TCP packet, handling ACKs, windowing, etc. */ - - ret = tcp_ipv6_forward(fwddev, ipv6, iob); - } - else -#endif - { - /* Forward a UDP or ICMPv6 packet. Because ipv6_hdrsize() succeeded, - * we know that it is a forward-able type. - */ - - ret = ipv6_dev_forward(fwddev, ipv6, iob); - } - - if (ret < 0) - { - goto drop; - } - - dev->d_len = 0; - return OK; + goto drop; } } else @@ -522,7 +556,11 @@ int ipv6_forward(FAR struct net_driver_s *dev, FAR struct ipv6_hdr_s *ipv6) #if defined(CONFIG_NET_6LOWPAN) /* REVISIT: Currently only suport for 6LoWPAN */ { - /* Single network device */ + /* Single network device. The use case here is where an endpoint acts + * as a hub in a star configuration. This is typical for a wireless star + * configuration where not all endpoints are accessible from all other + * endpoints, but seems less useful for a wired network. + */ /* Perform any necessary packet conversions. If the packet was handled * via a backdoor path (or dropped), then dev->d_len will be zero. If @@ -545,18 +583,21 @@ int ipv6_forward(FAR struct net_driver_s *dev, FAR struct ipv6_hdr_s *ipv6) /* Nothing other 6LoWPAN forwarding is currently handled and that * case was dealt with in ipv6_packet_conversion(). + * + * REVISIT: Is tht an issue? Do other use cases make sense? */ -# warning Missing logic nwarn("WARNING: Packet forwarding supported only for 6LoWPAN\n"); - return -ENOSYS; + ret = -ENOSYS; + goto drop; } } #else /* CONFIG_NET_6LOWPAN */ { nwarn("WARNING: Packet forwarding not supported in this configuration\n"); - return -ENOSYS; + ret = -ENOSYS; + goto drop; } #endif /* CONFIG_NET_6LOWPAN */ diff --git a/net/icmpv6/Make.defs b/net/icmpv6/Make.defs index 272c304753..d634478679 100644 --- a/net/icmpv6/Make.defs +++ b/net/icmpv6/Make.defs @@ -62,6 +62,13 @@ endif ifeq ($(CONFIG_NET_ICMPv6_ROUTER),y) NET_CSRCS += icmpv6_radvertise.c endif + +# IP forwarding + +ifeq ($(CONFIG_NET_IPFORWARD),y) +NET_CSRCS += icmpv6_forward.c +endif + # Include ICMPv6 build support DEPPATH += --dep-path icmpv6 diff --git a/net/icmpv6/icmpv6.h b/net/icmpv6/icmpv6.h index 1f01202b8a..5589ed5061 100644 --- a/net/icmpv6/icmpv6.h +++ b/net/icmpv6/icmpv6.h @@ -176,6 +176,34 @@ int icmpv6_neighbor(const net_ipv6addr_t ipaddr); # define icmpv6_neighbor(i) (0) #endif +/**************************************************************************** + * Name: icmpv6_dev_forward + * + * Description: + * Called by the IP forwarding logic when an ICMPv6 packet is received on + * one network device, but must be forwarded on another network device. + * + * Set up to forward the ICMPv6 packet on the specified device. The + * function will set up a send "interrupt" handler that will perform the + * actual send asynchronously and must return without waiting for the + * send to complete. + * + * Input Parameters: + * fwd - An initialized instance of the common forwarding structure that + * includes everything needed to perform the forwarding operation. + * + * Returned Value: + * Zero is returned if the packet was successfully forwarded; A negated + * errno value is returned if the packet is not forwardable. In that + * latter case, the caller should free the IOB list and drop the packet. + * + ****************************************************************************/ + +#if defined(CONFIG_NETDEV_MULTINIC) && defined(CONFIG_NET_IPFORWARD) +struct forward_s; +int icmpv6_dev_forward(FAR struct forward_s *fwd); +#endif + /**************************************************************************** * Name: icmpv6_poll * diff --git a/net/icmpv6/icmpv6_forward.c b/net/icmpv6/icmpv6_forward.c new file mode 100644 index 0000000000..debbb36d15 --- /dev/null +++ b/net/icmpv6/icmpv6_forward.c @@ -0,0 +1,98 @@ +/**************************************************************************** + * net/icmpv6/icmpv6_forward.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. 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include + +#include "devif/ip_forward.h" +#include "icmpv6/icmpv6.h" + +#if defined(CONFIG_NET) && defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_ICMPv6) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: icmpv6_dev_forward + * + * Description: + * Called by the IP forwarding logic when an ICMPv6 packet is received on + * one network device, but must be forwarded on another network device. + * + * Set up to forward the ICMPv6 packet on the specified device. The + * function will set up a send "interrupt" handler that will perform the + * actual send asynchronously and must return without waiting for the + * send to complete. + * + * Input Parameters: + * fwd - An initialized instance of the common forwarding structure that + * includes everything needed to perform the forwarding operation. + * + * Returned Value: + * Zero is returned if the packet was successfully forwarded; A negated + * errno value is returned if the packet is not forwardable. In that + * latter case, the caller should free the IOB list and drop the packet. + * + ****************************************************************************/ + +#if defined(CONFIG_NETDEV_MULTINIC) && defined(CONFIG_NET_ICMPv6) +int icmpv6_dev_forward(FAR struct forward_s *fwd) +{ + /* Set up to send the packet when the selected device polls for TX data. */ + + /* Notify the forwarding device that TX data is available */ + +#warning Missing logic + + /* REVISIT: For Ethernet we may have to fix up the Ethernet header: + * - source MAC, the MAC of the current device. + * - dest MAC, the MAC associated with the destination IPv6 adress. + * This will involve ICMPv6 and Neighbor Discovery. + */ + + nwarn("WARNING: UPD/ICMPv6 packet forwarding not yet supported\n"); + return -ENOSYS; +} +#endif /* CONFIG_NET_ICMPv6 && CONFIG_NETDEV_MULTINIC */ +#endif /* CONFIG_NET && CONFIG_NET_IPFORWARD && CONFIG_NET_ICMPv6 */ diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index a56068b147..627a114ed6 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -795,19 +795,20 @@ void tcp_send(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, uint16_t flags, uint16_t len); /**************************************************************************** - * Name: tcp_ipv6_forward + * Name: tcp_ipv6_dev_forward * * Description: + * Called by the IP forwarding logic when an TCP packet is received on + * one network device, but must be forwarded on another network device. + * * Set up to forward the TCP packet on the specified device. This * function will set up a send "interrupt" handler that will perform * the actual send asynchronously and must return without waiting for the * send to complete. * * Input Parameters: - * dev - The device on which the packet should be forwarded. - * ipv6 - A pointer to the IPv6 header in within the IPv6 packet. This - * is immeidately followed by the TCP header. - * iob - A list of IOBs containing the data payload to be sent. + * fwd - An initialized instance of the common forwarding structure that + * includes everything needed to perform the forwarding operation. * * Returned Value: * Zero is returned if the packet was successfully forwarded; A negated @@ -818,8 +819,8 @@ void tcp_send(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, #if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_IPv6) && \ defined(CONFIG_NETDEV_MULTINIC) -int tcp_ipv6_forward(FAR struct net_driver_s *dev, - FAR struct ipv6_hdr_s *ipv6, FAR struct iob_s *iob); +struct forward_s; /* Forward reference */ +int tcp_ipv6_dev_forward(FAR struct forward_s *fwd); #endif /**************************************************************************** diff --git a/net/tcp/tcp_forward.c b/net/tcp/tcp_forward.c index 1197224229..ebb4c69b98 100644 --- a/net/tcp/tcp_forward.c +++ b/net/tcp/tcp_forward.c @@ -44,6 +44,7 @@ #include #include +#include "devif/ip_forward.h" #include "tcp/tcp.h" #if defined(CONFIG_NET) && defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_TCP) @@ -53,19 +54,20 @@ ****************************************************************************/ /**************************************************************************** - * Name: tcp_ipv6_forward + * Name: tcp_ipv6_dev_forward * * Description: + * Called by the IP forwarding logic when an TCP packet is received on + * one network device, but must be forwarded on another network device. + * * Set up to forward the TCP packet on the specified device. This * function will set up a send "interrupt" handler that will perform * the actual send asynchronously and must return without waiting for the * send to complete. * * Input Parameters: - * dev - The device on which the packet should be forwarded. - * ipv6 - A pointer to the IPv6 header in within the IPv6 packet. This - * is immeidately followed by the TCP header. - * iob - A list of IOBs containing the data payload to be sent. + * fwd - An initialized instance of the common forwarding structure that + * includes everything needed to perform the forwarding operation. * * Returned Value: * Zero is returned if the packet was successfully forwarded; A negated @@ -75,8 +77,7 @@ ****************************************************************************/ #if defined(CONFIG_NET_IPv6) && defined(CONFIG_NETDEV_MULTINIC) -int tcp_ipv6_forward(FAR struct net_driver_s *dev, - FAR struct ipv6_hdr_s *ipv6, FAR struct iob_s *iob) +int tcp_ipv6_dev_forward(FAR struct forward_s *fwd) { /* Notify the forwarding device that TX data is available */ diff --git a/net/udp/Make.defs b/net/udp/Make.defs index 4b3992911d..e28161496e 100644 --- a/net/udp/Make.defs +++ b/net/udp/Make.defs @@ -48,6 +48,12 @@ NET_CSRCS += udp_netpoll.c endif endif +# IP forwarding + +ifeq ($(CONFIG_NET_IPFORWARD),y) +NET_CSRCS += udp_forward.c +endif + # Transport layer NET_CSRCS += udp_conn.c udp_devpoll.c udp_send.c udp_input.c udp_finddev.c diff --git a/net/udp/udp.h b/net/udp/udp.h index 83197afae3..64d2e7aa3d 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -428,6 +428,35 @@ FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn); uint16_t udp_callback(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn, uint16_t flags); +/**************************************************************************** + * Name: udp_ipv6_dev_forward + * + * Description: + * Called by the IP forwarding logic when an UDP packet is received on + * one network device, but must be forwarded on another network device. + * + * Set up to forward the UDP packet on the specified device. This + * function will set up a send "interrupt" handler that will perform the + * actual send asynchronously and must return without waiting for the + * send to complete. + * + * Input Parameters: + * fwd - An initialized instance of the common forwarding structure that + * includes everything needed to perform the forwarding operation. + * + * Returned Value: + * Zero is returned if the packet was successfully forwarded; A negated + * errno value is returned if the packet is not forwardable. In that + * latter case, the caller should free the IOB list and drop the packet. + * + ****************************************************************************/ + +#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_IPv6) && \ + defined(CONFIG_NETDEV_MULTINIC) +struct forward_s; /* Forward reference */ +int udp_ipv6_dev_forward(FAR struct forward_s *fwd); +#endif + /**************************************************************************** * Name: psock_udp_send * diff --git a/net/udp/udp_forward.c b/net/udp/udp_forward.c new file mode 100644 index 0000000000..e1e5fc92f4 --- /dev/null +++ b/net/udp/udp_forward.c @@ -0,0 +1,98 @@ +/**************************************************************************** + * net/udp/udp_forward.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. 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include + +#include "devif/ip_forward.h" +#include "udp/udp.h" + +#if defined(CONFIG_NET) && defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_UDP) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: udp_ipv6_dev_forward + * + * Description: + * Called by the IP forwarding logic when an UDP packet is received on + * one network device, but must be forwarded on another network device. + * + * Set up to forward the UDP packet on the specified device. This + * function will set up a send "interrupt" handler that will perform the + * actual send asynchronously and must return without waiting for the + * send to complete. + * + * Input Parameters: + * fwd - An initialized instance of the common forwarding structure that + * includes everything needed to perform the forwarding operation. + * + * Returned Value: + * Zero is returned if the packet was successfully forwarded; A negated + * errno value is returned if the packet is not forwardable. In that + * latter case, the caller should free the IOB list and drop the packet. + * + ****************************************************************************/ + +#if defined(CONFIG_NET_IPv6) && defined(CONFIG_NETDEV_MULTINIC) +int udp_ipv6_dev_forward(FAR struct forward_s *fwd) +{ + /* Set up to send the packet when the selected device polls for TX data. */ + + /* Notify the forwarding device that TX data is available */ + +#warning Missing logic + + /* REVISIT: For Ethernet we may have to fix up the Ethernet header: + * - source MAC, the MAC of the current device. + * - dest MAC, the MAC associated with the destination IPv6 adress. + * This will involve ICMPv6 and Neighbor Discovery. + */ + + nwarn("WARNING: UPD/ICMPv6 packet forwarding not yet supported\n"); + return -ENOSYS; +} +#endif /* CONFIG_NET_IPv6 && CONFIG_NETDEV_MULTINIC */ +#endif /* CONFIG_NET && CONFIG_NET_IPFORWARD && CONFIG_NET_UDP */