diff --git a/configs/same70-xplained/README.txt b/configs/same70-xplained/README.txt index e2275469698..0e611261f9a 100644 --- a/configs/same70-xplained/README.txt +++ b/configs/same70-xplained/README.txt @@ -883,8 +883,8 @@ Click Shield D2 PA5 microBUS1 GPIO interrupt input PA5 D3 PA6 microBUS2 GPIO interrupt input PA6 D4 PD27 *** Not used *** - D5 PD11 microBUS2 PWM PD11 PWMC0_H0 - D6 PC19 microBUS1 PWN PC19 PWMC0_H2 + D5 PD11 microBUS2 PWMB PD11 PWMC0_H0 + D6 PC19 microBUS1 PWMA PC19 PWMC0_H2 D7 PA2 *** Not used *** D8 PA17 *** Not used *** D9 PC9 microBUS2 CS GPIO output PC9 diff --git a/configs/samv71-xult/README.txt b/configs/samv71-xult/README.txt index c408f4dc863..3b234ba3f28 100644 --- a/configs/samv71-xult/README.txt +++ b/configs/samv71-xult/README.txt @@ -1486,8 +1486,8 @@ Click Shield D2 PA5 microBUS1 GPIO interrupt input PA5 D3 PA6 microBUS2 GPIO interrupt input PA6 D4 PD27 *** Not used *** - D5 PD11 microBUS2 PWM PD11 PWMC0_H0 - D6 PC19 microBUS1 PWN PC19 PWMC0_H2 + D5 PD11 microBUS2 PWMB PD11 PWMC0_H0 + D6 PC19 microBUS1 PWMA PC19 PWMC0_H2 D7 PA2 *** Not used *** D8 PA17 *** Not used *** D9 PC9 microBUS2 CS GPIO output PC9 diff --git a/net/devif/Make.defs b/net/devif/Make.defs index c436648101d..4dcce7379b6 100644 --- a/net/devif/Make.defs +++ b/net/devif/Make.defs @@ -53,7 +53,7 @@ endif ifeq ($(CONFIG_NET_IPFORWARD),y) ifeq ($(CONFIG_NETDEV_MULTINIC),y) -NET_CSRCS += ip_forward.c +NET_CSRCS += ip_forward.c devif_forward.c endif endif diff --git a/net/devif/devif_forward.c b/net/devif/devif_forward.c new file mode 100644 index 00000000000..87e4ad07e58 --- /dev/null +++ b/net/devif/devif_forward.c @@ -0,0 +1,102 @@ +/**************************************************************************** + * net/devif/devif_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 "devif/ip_forward.h" +#include "devif/devif.h" + +#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NETDEV_MULTINIC) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: devif_forward + * + * Description: + * Called from protocol-specific IP forwarding logic to re-send a packet. + * + * Input Parameters: + * fwd - An initialized instance of the common forwarding structure that + * includes everything needed to perform the forwarding operation. + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +void devif_forward(FAR struct forward_s *fwd) +{ + unsigned int offset; + int ret; + + DEBUGASSERT(fwd != NULL && fwd->f_dev != NULL); + offset = NET_LL_HDRLEN(fwd->f_dev); + + /* Copy the saved L2 + L3 header */ + + DEBUGASSERT(offset + fwd->f_hdrsize <= NET_DEV_MTU(fwd->f_dev)); + memcpy(&fwd->f_dev->d_buf[offset], &fwd->f_hdr, fwd->f_hdrsize); + offset += fwd->f_hdrsize; + + /* Copy the IOB chain that contains the payload */ + + if (fwd->f_iob != NULL && fwd->f_iob->io_pktlen > 0) + { + DEBUGASSERT(offset + fwd->f_iob->io_pktlen <= NET_DEV_MTU(fwd->f_dev)); + ret = iob_copyout(&fwd->f_dev->d_buf[offset], fwd->f_iob, + fwd->f_iob->io_pktlen, 0); + + DEBUGASSERT(ret == fwd->f_iob->io_pktlen); + offset += fwd->f_iob->io_pktlen; + } + + fwd->f_dev->d_sndlen = offset; +} + +#endif /* CONFIG_NET_IPFORWARD && CONFIG_NETDEV_MULTINIC */ diff --git a/net/devif/devif_iobsend.c b/net/devif/devif_iobsend.c index 5575a2b60ca..7b44a2068cc 100644 --- a/net/devif/devif_iobsend.c +++ b/net/devif/devif_iobsend.c @@ -48,34 +48,6 @@ #ifdef CONFIG_MM_IOB -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Type Declarations - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Public Constant Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Constant Data - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/net/devif/devif_send.c b/net/devif/devif_send.c index 8bcfedb0b01..43c913a97b6 100644 --- a/net/devif/devif_send.c +++ b/net/devif/devif_send.c @@ -47,33 +47,7 @@ #include -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Type Declarations - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Public Constant Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Constant Data - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ +#include "devif/devif.h" /**************************************************************************** * Public Functions @@ -87,8 +61,7 @@ * the network interface driver. * * Assumptions: - * Called from the interrupt level or, at a minimum, with interrupts - * disabled. + * The network is locked. * ****************************************************************************/ diff --git a/net/devif/ip_forward.h b/net/devif/ip_forward.h index a61fab2667d..c8cd65e4deb 100644 --- a/net/devif/ip_forward.h +++ b/net/devif/ip_forward.h @@ -49,6 +49,10 @@ #include #include +#include "udp/udp.h" +#include "tcp/tcp.h" +#include "icmpv6/icmpv6.h" + #undef HAVE_FWDALLOC #if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NETDEV_MULTINIC) @@ -69,7 +73,7 @@ /* IPv4 + L2 header */ #ifdef CONFIG_NET_IPv4 -struct ipv6_fwdhdr_s +struct fwd_ipv4hdr_u { struct ipv4_hdr_s l2; union @@ -91,7 +95,7 @@ struct ipv6_fwdhdr_s /* IPv6 + L2 header */ #ifdef CONFIG_NET_IPv6 -struct ipv6_fwdhdr_s +struct fwd_ipv6hdr_u { struct ipv6_hdr_s l2; union @@ -112,28 +116,46 @@ struct ipv6_fwdhdr_s /* IPv4 or IPv6 + L2 header */ -union ip_fwdhdr_u +union fwd_iphdr_u { #ifdef CONFIG_NET_IPv4 - struct ipv4_fwdhdr_s ipv4; + struct fwd_ipv4hdr_u ipv4; #endif #ifdef CONFIG_NET_IPv6 - struct ipv6_fwdhdr_s ipv6; + struct fwd_ipv6hdr_u ipv6; +#endif +}; + +/* Connection structures */ + +union fwd_conn_u +{ +#ifdef CONFIG_NET_TCP + struct tcp_conn_s tcp; +#endif +#ifdef CONFIG_NET_UDP + struct udp_conn_s udp; +#endif +#ifdef CONFIG_NET_ICMPv6 + struct icmpv6_conn_s icmpv6; #endif }; /* This is the send state structure */ -struct net_driver_s; /* Forward reference */ -struct iob_s; /* Forward reference */ +struct devif_callback_s; /* Forward refernce */ +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 */ + 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 */ + FAR struct devif_callback_s *f_cb; /* Reference to callback instance */ + union fwd_iphdr_u f_hdr; /* Copy of original L2+L3 headers */ + union fwd_conn_u f_conn; /* Protocol-specific connectin struct */ + uint8_t f_hdrsize; /* The size of the L2+L3 headers */ }; /**************************************************************************** @@ -182,5 +204,25 @@ FAR struct forward_s *ip_forward_alloc(void); void ip_forward_free(FAR struct forward_s *fwd); +/**************************************************************************** + * Name: devif_forward + * + * Description: + * Called from protocol-specific IP forwarding logic to re-send a packet. + * + * Input Parameters: + * fwd - An initialized instance of the common forwarding structure that + * includes everything needed to perform the forwarding operation. + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +void devif_forward(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 eaf868533ff..fa2ec6f77ef 100644 --- a/net/devif/ipv6_forward.c +++ b/net/devif/ipv6_forward.c @@ -225,6 +225,17 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev, FAR uint8_t *payload; unsigned int paysize; + /* Verify that the full packet will fit within the forwarding devices + * MTU. We provide no support for fragmenting forwarded packets. + */ + + if (NET_LL_HDRLEN(fwddev) + dev->d_len > NET_DEV_MTU(fwddev)) + { + nwarn("WARNING: Packet > MTU... Dropping\n"); + ret = -EFBIG; + goto errout; + } + /* Get a pre-allocated forwarding structure, This structure will be * completely zeroed when we receive it. */ @@ -246,6 +257,10 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev, * * Remember that the size of the L1 header has already been subtracted * from dev->d_len. + * + * REVISIT: Consider an alternative design that does not require data + * copying. This would require a pool of d_buf's that are managed by + * the network rather than the network device. */ hdrsize = ipv6_hdrsize(ipv6); @@ -258,7 +273,7 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev, /* Save the entire L2 and L3 headers in the state structure */ - if (hdrsize > sizeof(union ip_fwdhdr_u)) + if (hdrsize > sizeof(union fwd_iphdr_u)) { nwarn("WARNING: Header is too big for pre-allocated structure\n"); ret = -E2BIG; @@ -278,7 +293,12 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev, payload = (FAR uint8_t *)ipv6 + hdrsize; paysize = dev->d_len - hdrsize; - /* If there is a payload, then copy it into an IOB chain */ + /* If there is a payload, then copy it into an IOB chain. + * + * REVISIT: Consider an alternative design that does not require data + * copying. This would require a pool of d_buf's that are managed by + * the network rather than the network device. + */ if (paysize > 0) { @@ -308,16 +328,21 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev, } } - /* Then set up to forward the packet according to the protocol */ + /* Then set up to forward the packet according to the protocol. + * + * REVISIT: Are these protocol specific forwarders necessary? I think + * that this could be done with a single forwarding function for all + * protocols. + */ switch (ipv6->proto) { #ifdef CONFIG_NET_TCP case IP_PROTO_TCP: { - /* Forward a TCP packet, handling ACKs, windowing, etc. */ + /* Forward a TCP packet. */ - ret = tcp_ipv6_dev_forward(fwd); + ret = tcp_forward(fwd); } break; #endif @@ -327,7 +352,7 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev, { /* Forward a UDP packet */ - ret = udp_ipv6_dev_forward(fwd); + ret = udp_forward(fwd); } break; #endif @@ -337,7 +362,7 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev, { /* Forward an ICMPv6 packet */ - ret = icmpv6_dev_forward(fwd); + ret = icmpv6_forward(fwd); } break; #endif @@ -428,7 +453,7 @@ static int ipv6_decr_ttl(FAR struct ipv6_hdr_s *ipv6) * Name: ipv6_dropstats * * Description: - * Update statistics for a droped packet. + * Update statistics for a dropped packet. * * Input Parameters: * ipv6 - A convenience pointer to the IPv6 header in within the IPv6 diff --git a/net/icmpv6/Make.defs b/net/icmpv6/Make.defs index d634478679a..92ac9cf2341 100644 --- a/net/icmpv6/Make.defs +++ b/net/icmpv6/Make.defs @@ -66,8 +66,10 @@ endif # IP forwarding ifeq ($(CONFIG_NET_IPFORWARD),y) +ifeq ($(CONFIG_NETDEV_MULTINIC),y) NET_CSRCS += icmpv6_forward.c endif +endif # Include ICMPv6 build support diff --git a/net/icmpv6/icmpv6.h b/net/icmpv6/icmpv6.h index 5589ed5061f..8ff15abaee2 100644 --- a/net/icmpv6/icmpv6.h +++ b/net/icmpv6/icmpv6.h @@ -55,8 +55,10 @@ /* Allocate a new ICMPv6 data callback */ -#define icmpv6_callback_alloc(dev) devif_callback_alloc(dev, &(dev)->d_conncb) -#define icmpv6_callback_free(dev,cb) devif_dev_callback_free(dev, cb) +#define icmpv6_callback_alloc(dev) \ + devif_callback_alloc((dev), &(dev)->d_conncb) +#define icmpv6_callback_free(dev,cb) \ + devif_dev_callback_free((dev), (cb)) /**************************************************************************** * Public Type Definitions @@ -177,7 +179,7 @@ int icmpv6_neighbor(const net_ipv6addr_t ipaddr); #endif /**************************************************************************** - * Name: icmpv6_dev_forward + * Name: icmpv6_forward * * Description: * Called by the IP forwarding logic when an ICMPv6 packet is received on @@ -201,7 +203,7 @@ int icmpv6_neighbor(const net_ipv6addr_t ipaddr); #if defined(CONFIG_NETDEV_MULTINIC) && defined(CONFIG_NET_IPFORWARD) struct forward_s; -int icmpv6_dev_forward(FAR struct forward_s *fwd); +int icmpv6_forward(FAR struct forward_s *fwd); #endif /**************************************************************************** diff --git a/net/icmpv6/icmpv6_forward.c b/net/icmpv6/icmpv6_forward.c index debbb36d159..ea5ba544c19 100644 --- a/net/icmpv6/icmpv6_forward.c +++ b/net/icmpv6/icmpv6_forward.c @@ -37,30 +37,251 @@ #include +#include #include #include +#include + #include #include #include +#include #include "devif/ip_forward.h" +#include "devif/devif.h" +#include "netdev/netdev.h" #include "icmpv6/icmpv6.h" -#if defined(CONFIG_NET) && defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_ICMPv6) +#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_ICMPv6) && \ + defined(CONFIG_NETDEV_MULTINIC) /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** - * Name: icmpv6_dev_forward + * Name: icmpv6_forward_addrchck * * Description: - * Called by the IP forwarding logic when an ICMPv6 packet is received on + * Check if the destination IP address is in the IPv4 ARP or IPv6 Neighbor + * tables. If not, then the send won't actually make it out... it will be + * replaced with an ARP request (IPv4) or a Neighbor Solicitation (IPv6). + * + * NOTE 1: This could be an expensive check if there are a lot of + * entries in the ARP or Neighbor tables. + * + * NOTE 2: If we are actually harvesting IP addresses on incoming IP + * packets, then this check should not be necessary; the MAC mapping + * should already be in the ARP table in many cases (IPv4 only). + * + * NOTE 3: If CONFIG_NET_ARP_SEND then we can be assured that the IP + * address mapping is already in the ARP table. + * + * Parameters: + * fwd - The forwarding state structure + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_ETHERNET +static inline bool icmpv6_forward_addrchck(FAR struct forward_s *fwd) +{ +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + if (conn->domain == PF_INET) +#endif + { +#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND) + return (arp_find(fwd->f_hdr.ipv4.l2.destipaddr) != NULL); +#else + return true; +#endif + } +#endif /* CONFIG_NET_IPv4 */ + +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + else +#endif + { +#if !defined(CONFIG_NET_ICMPv6_NEIGHBOR) + return (neighbor_findentry(fwd->f_hdr.ipv6.l2.destipaddr) != NULL); +#else + return true; +#endif + } +#endif /* CONFIG_NET_IPv6 */ +} + +#else /* CONFIG_NET_ETHERNET */ +# define icmpv6_forward_addrchck(r) (true) +#endif /* CONFIG_NET_ETHERNET */ + +/**************************************************************************** + * Name: icmpv6_dropstats + * + * Description: + * Update statistics for a dropped packet. + * + * Input Parameters: + * fwd - The forwarding state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_NET_STATISTICS +static void icmpv6_dropstats(FAR struct forward_s *fwd) +{ + /* Increment the count of dropped ICMPV6 packets */ + + g_netstats.icmpv6.drop++; + + /* Increment the count of dropped IPv4 or IPv6 packets */ + +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + if ((fwd->f_hdr.ipv4.l2.vhl & IP_VERSION_MASK) == IPv4_VERSION) +#endif + { + g_netstats.ipv4.drop++; + } +#endif +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + else +#endif + { + g_netstats.ipv6.drop++; + } +#endif +} +#else +# define icmpv6_dropstats(ipv6) +#endif + +/**************************************************************************** + * Name: icmpv6_forward_interrupt + * + * Description: + * This function is called from the interrupt level to perform the actual + * send operation when polled by the lower, device interfacing layer. + * + * Parameters: + * dev The structure of the network driver that caused the interrupt + * conn An instance of the ICMPV6 connection structure cast to void * + * pvpriv An instance of struct forward_s cast to void* + * flags Set of events describing why the callback was invoked + * + * Returned Value: + * Modified value of the input flags + * + * Assumptions: + * The network is locked + * + ****************************************************************************/ + +static uint16_t icmpv6_forward_interrupt(FAR struct net_driver_s *dev, + FAR void *conn, FAR void *pvpriv, + uint16_t flags) +{ + FAR struct forward_s *fwd = (FAR struct forward_s *)pvpriv; + + ninfo("flags: %04x\n", flags); + DEBUGASSERT(fwd != NULL); + + /* Make sure that this is from the forwarding device */ + + if (dev == fwd->f_dev) + { + /* If the network device has gone down, then we will have terminate + * the wait now with an error. + */ + + if ((flags & NETDEV_DOWN) != 0) + { + /* Terminate the transfer with an error. */ + + nwarn("WARNING: Network is down... Dropping\n"); + icmpv6_dropstats(fwd); + } + + /* Check if the outgoing packet is available. It may have been claimed + * by another send interrupt serving a different thread -OR- if the output + * buffer currently contains unprocessed incoming data. In these cases + * we will just have to wait for the next polling cycle. + */ + + else if (dev->d_sndlen > 0 || (flags & ICMPv6_NEWDATA) != 0) + { + /* Another thread has beat us sending data or the buffer is busy, + * Wait for the next polling cycle and check again. + */ + + return flags; + } + + /* It looks like we are good to forward the data */ + + else + { + /* Copy the ICMPv6 data into driver's packet buffer and send it. */ + + devif_forward(fwd); + + /* 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 + * will be replaced with an ARP request or Neighbor Solicitation. + */ + + if (!icmpv6_forward_addrchck(fwd)) + { + return flags; + } + } + + /* Free the allocated callback structure */ + + fwd->f_cb->flags = 0; + fwd->f_cb->priv = NULL; + fwd->f_cb->event = NULL; + + icmpv6_callback_free(dev, fwd->f_cb); + + /* Free any IOBs */ + + if (fwd->f_iob != NULL) + { + iob_free_chain(fwd->f_iob); + } + + /* And release the forwarding state structure */ + + ip_forward_free(fwd); + } + + return flags; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: icmpv6_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 + * Set up to forward the 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. @@ -76,23 +297,26 @@ * ****************************************************************************/ -#if defined(CONFIG_NETDEV_MULTINIC) && defined(CONFIG_NET_ICMPv6) -int icmpv6_dev_forward(FAR struct forward_s *fwd) +int icmpv6_forward(FAR struct forward_s *fwd) { - /* Set up to send the packet when the selected device polls for TX data. */ + DEBUGASSERT(fwd != NULL && fwd->f_dev != NULL); - /* Notify the forwarding device that TX data is available */ + /* Set up the callback in the connection */ -#warning Missing logic + fwd->f_cb = icmpv6_callback_alloc(fwd->f_dev); + if (fwd->f_cb != NULL) + { + fwd->f_cb->flags = (ICMPv6_POLL | NETDEV_DOWN); + fwd->f_cb->priv = (FAR void *)fwd; + fwd->f_cb->event = icmpv6_forward_interrupt; - /* 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. - */ + /* Notify the device driver of the availability of TX data */ - nwarn("WARNING: UPD/ICMPv6 packet forwarding not yet supported\n"); - return -ENOSYS; + netdev_txnotify_dev(fwd->f_dev); + return OK; + } + + return -EBUSY; } -#endif /* CONFIG_NET_ICMPv6 && CONFIG_NETDEV_MULTINIC */ -#endif /* CONFIG_NET && CONFIG_NET_IPFORWARD && CONFIG_NET_ICMPv6 */ + +#endif /* CONFIG_NET_IPFORWARD && CONFIG_NET_ICMPv6 && CONFIG_NETDEV_MULTINIC */ diff --git a/net/icmpv6/icmpv6_neighbor.c b/net/icmpv6/icmpv6_neighbor.c index de7ba28046a..9c58b87a1f8 100644 --- a/net/icmpv6/icmpv6_neighbor.c +++ b/net/icmpv6/icmpv6_neighbor.c @@ -314,7 +314,7 @@ int icmpv6_neighbor(const net_ipv6addr_t ipaddr) (void)sem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */ sem_setprotocol(&state.snd_sem, SEM_PRIO_NONE); - state.snd_retries = 0; /* No retries yet */ + state.snd_retries = 0; /* No retries yet */ net_ipv6addr_copy(state.snd_ipaddr, lookup); /* IP address to query */ #ifdef CONFIG_NETDEV_MULTINIC diff --git a/net/tcp/Make.defs b/net/tcp/Make.defs index f9e7c893882..7f3a88582b5 100644 --- a/net/tcp/Make.defs +++ b/net/tcp/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # net/tcp/Make.defs # -# Copyright (C) 2014 Gregory Nutt. All rights reserved. +# Copyright (C) 2014, 2017 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -63,8 +63,10 @@ NET_CSRCS += tcp_callback.c tcp_backlog.c tcp_ipselect.c # IP forwarding ifeq ($(CONFIG_NET_IPFORWARD),y) +ifeq ($(CONFIG_NETDEV_MULTINIC),y) NET_CSRCS += tcp_forward.c endif +endif # TCP write buffering diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index 627a114ed6c..8b554fff864 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -71,18 +71,18 @@ */ # define tcp_callback_alloc(conn) \ - devif_callback_alloc(conn->dev, &conn->list) + devif_callback_alloc((conn)->dev, &(conn)->list) # define tcp_callback_free(conn,cb) \ - devif_conn_callback_free(conn->dev, cb, &conn->list) + devif_conn_callback_free((conn)->dev, (cb), &(conn)->list) /* These macros allocate and free callback structures used for receiving * notifications of device-related events. */ # define tcp_monitor_callback_alloc(conn) \ - devif_callback_alloc(conn->dev, NULL) + devif_callback_alloc((conn)->dev, NULL) # define tcp_monitor_callback_free(conn,cb) \ - devif_conn_callback_free(conn->dev, cb, NULL) + devif_conn_callback_free((conn)->dev, (cb), NULL) #else /* These macros allocate and free callback structures used for receiving @@ -90,9 +90,9 @@ */ # define tcp_callback_alloc(conn) \ - devif_callback_alloc(g_netdevices, &conn->list) + devif_callback_alloc(g_netdevices, &(conn)->list) # define tcp_callback_free(conn,cb) \ - devif_conn_callback_free(g_netdevices, cb, &conn->list) + devif_conn_callback_free(g_netdevices, (cb), &(conn)->list) /* These macros allocate and free callback structures used for receiving * notifications of device-related events. @@ -101,7 +101,7 @@ # define tcp_monitor_callback_alloc(conn) \ devif_callback_alloc(g_netdevices, NULL) # define tcp_monitor_callback_free(conn,cb) \ - devif_conn_callback_free(g_netdevices, cb, NULL) + devif_conn_callback_free(g_netdevices, (cb), NULL) #endif #ifdef CONFIG_NET_TCP_WRITE_BUFFERS @@ -795,7 +795,7 @@ void tcp_send(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, uint16_t flags, uint16_t len); /**************************************************************************** - * Name: tcp_ipv6_dev_forward + * Name: tcp_forward * * Description: * Called by the IP forwarding logic when an TCP packet is received on @@ -820,7 +820,7 @@ 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) struct forward_s; /* Forward reference */ -int tcp_ipv6_dev_forward(FAR struct forward_s *fwd); +int tcp_forward(FAR struct forward_s *fwd); #endif /**************************************************************************** diff --git a/net/tcp/tcp_forward.c b/net/tcp/tcp_forward.c index ebb4c69b986..22c021aa367 100644 --- a/net/tcp/tcp_forward.c +++ b/net/tcp/tcp_forward.c @@ -37,32 +37,316 @@ #include +#include +#include #include #include +#include + #include #include #include +#include #include "devif/ip_forward.h" +#include "devif/devif.h" +#include "netdev/netdev.h" #include "tcp/tcp.h" -#if defined(CONFIG_NET) && defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_TCP) +#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_TCP) && \ + defined(CONFIG_NETDEV_MULTINIC) /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** - * Name: tcp_ipv6_dev_forward + * Name: forward_ipselect + * + * Description: + * If both IPv4 and IPv6 support are enabled, then we will need to select + * which one to use when generating the outgoing packet. If only one + * domain is selected, then the setup is already in place and we need do + * nothing. + * + * Parameters: + * fwd - The forwarding state structure + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) +static inline void forward_ipselect(FAR struct forward_s *fwd) +{ + /* Which domain the connection support */ + + if (fwd->f_conn.tcp.domain == PF_INET) + { + /* Select the IPv4 domain */ + + tcp_ipv4_select(dev); + } + else /* if (conn->domain == PF_INET6) */ + { + /* Select the IPv6 domain */ + + DEBUGASSERT(conn->domain == PF_INET6); + tcp_ipv6_select(dev); + } +} +#endif + +/**************************************************************************** + * Name: tcp_forward_addrchck + * + * Description: + * Check if the destination IP address is in the IPv4 ARP or IPv6 Neighbor + * tables. If not, then the send won't actually make it out... it will be + * replaced with an ARP request (IPv4) or a Neighbor Solicitation (IPv6). + * + * NOTE 1: This could be an expensive check if there are a lot of + * entries in the ARP or Neighbor tables. + * + * NOTE 2: If we are actually harvesting IP addresses on incoming IP + * packets, then this check should not be necessary; the MAC mapping + * should already be in the ARP table in many cases (IPv4 only). + * + * NOTE 3: If CONFIG_NET_ARP_SEND then we can be assured that the IP + * address mapping is already in the ARP table. + * + * Parameters: + * fwd - The forwarding state structure + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_ETHERNET +static inline bool tcp_forward_addrchck(FAR struct forward_s *fwd) +{ + FAR struct tcp_conn_s *conn = &fwd->f_conn.tcp; + +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + if (conn->domain == PF_INET) +#endif + { +#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND) + return (arp_find(conn->u.ipv4.raddr) != NULL); +#else + return true; +#endif + } +#endif /* CONFIG_NET_IPv4 */ + +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + else +#endif + { +#if !defined(CONFIG_NET_ICMPv6_NEIGHBOR) + return (neighbor_findentry(conn->u.ipv6.raddr) != NULL); +#else + return true; +#endif + } +#endif /* CONFIG_NET_IPv6 */ + + UNUSED(conn); +} + +#else /* CONFIG_NET_ETHERNET */ +# define tcp_forward_addrchck(r) (true) +#endif /* CONFIG_NET_ETHERNET */ + +/**************************************************************************** + * Name: tcp_dropstats + * + * Description: + * Update statistics for a dropped packet. + * + * Input Parameters: + * fwd - The forwarding state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_NET_STATISTICS +static void tcp_dropstats(FAR struct forward_s *fwd) +{ + /* Increment the count of dropped TCP packets */ + + g_netstats.tcp.drop++; + + /* Increment the count of dropped IPv4 or IPv6 packets */ + +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + if (fwd->f_conn.tcp.domain == PF_INET) +#endif + { + g_netstats.ipv4.drop++; + } +#endif +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + else +#endif + { + g_netstats.ipv6.drop++; + } +#endif +} +#else +# define tcp_dropstats(ipv6) +#endif + +/**************************************************************************** + * Name: tcp_forward_interrupt + * + * Description: + * This function is called from the interrupt level to perform the actual + * send operation when polled by the lower, device interfacing layer. + * + * NOTE: Our role here is just data passthrough. We don't really care + * about ACKing, dynamic windows or any of the other TCP complexities. + * That is really something between the two endpoints and does not matter + * the forwarding hub. + * + * Parameters: + * dev The structure of the network driver that caused the interrupt + * conn An instance of the TCP connection structure cast to void * + * pvpriv An instance of struct forward_s cast to void* + * flags Set of events describing why the callback was invoked + * + * Returned Value: + * Modified value of the input flags + * + * Assumptions: + * The network is locked + * + ****************************************************************************/ + +static uint16_t tcp_forward_interrupt(FAR struct net_driver_s *dev, + FAR void *conn, FAR void *pvpriv, + uint16_t flags) +{ + FAR struct forward_s *fwd = (FAR struct forward_s *)pvpriv; + + ninfo("flags: %04x\n", flags); + DEBUGASSERT(fwd != NULL); + + /* Make sure that this is from the forwarding device */ + + if (dev == fwd->f_dev) + { + /* If the network device has gone down, then we will have terminate + * the wait now with an error. + * + * REVISIT: TCP disconnection events should should not be recieved here. + * Rather the disconnection events will be handled by the TCP endpoints. + */ + + if ((flags & NETDEV_DOWN) != 0) + { + /* Terminate the transfer with an error. */ + + nwarn("WARNING: Network is down... Dropping\n"); + tcp_dropstats(fwd); + } + + /* Check if the outgoing packet is available. It may have been claimed + * by a sendto interrupt serving a different thread -OR- if the output + * buffer currently contains unprocessed incoming data. In these cases + * we will just have to wait for the next polling cycle. + */ + + else if (dev->d_sndlen > 0 || (flags & TCP_NEWDATA) != 0) + { + /* Another thread has beat us sending data or the buffer is busy, + * Wait for the next polling cycle and check again. + */ + + return flags; + } + + /* It looks like we are good to forward the data */ + + else + { +#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) + /* If both IPv4 and IPv6 support are enabled, then we will need to + * select which one to use when generating the outgoing packet. + * If only one domain is selected, then the setup is already in + * place and we need do nothing. + */ + + forward_ipselect(dev, fwd); +#endif + /* Copy the user data into d_appdata and send it. */ + + devif_forward(fwd); + + /* 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 + * will be replaced with an ARP request or Neighbor Solicitation. + */ + + if (!tcp_forward_addrchck(fwd)) + { + return flags; + } + } + + /* Free the allocated callback structure */ + + fwd->f_cb->flags = 0; + fwd->f_cb->priv = NULL; + fwd->f_cb->event = NULL; + + tcp_callback_free(&fwd->f_conn.tcp, fwd->f_cb); + + /* Free any IOBs */ + + if (fwd->f_iob != NULL) + { + iob_free_chain(fwd->f_iob); + } + + /* And release the forwarding state structure */ + + ip_forward_free(fwd); + } + + return flags; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tcp_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 + * 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: @@ -76,27 +360,68 @@ * ****************************************************************************/ -#if defined(CONFIG_NET_IPv6) && defined(CONFIG_NETDEV_MULTINIC) -int tcp_ipv6_dev_forward(FAR struct forward_s *fwd) +int tcp_forward(FAR struct forward_s *fwd) { - /* Notify the forwarding device that TX data is available */ + DEBUGASSERT(fwd != NULL && fwd->f_dev != NULL); + FAR struct tcp_conn_s *conn = &fwd->f_conn.tcp; - /* Set up to send the packet when the selected device polls for TX data. - * TCP packets must obey ACK and windowing rules. + /* Set up some minimal connection structure so that we appear to be a + * real TCP connection. */ -#warning Missing logic + conn->dev = fwd->f_dev; - /* 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. - * - Because of TCP window, the packet may have to be sent in smaller - * pieces. - */ +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + if ((fwd->f_hdr.ipv4.l2.vhl & IP_VERSION_MASK) == IPv4_VERSION) +#endif + { + FAR struct ipv4_hdr_s *ipv4 = &fwd->f_hdr.ipv4.l2; + FAR struct tcp_hdr_s *tcp = &fwd->f_hdr.ipv4.l3.tcp; - nwarn("WARNING: TCP packet forwarding not yet supported\n"); - return -ENOSYS; +#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) + conn->domain = PF_INET; +#endif + conn->lport = tcp->srcport; + conn->rport = tcp->destport; + net_ipv4addr_copy(conn->u.ipv4.laddr, ipv4->srcipaddr); + net_ipv4addr_copy(conn->u.ipv4.raddr, ipv4->destipaddr); + } +#endif +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + else +#endif + { + FAR struct ipv6_hdr_s *ipv6 = &fwd->f_hdr.ipv6.l2; + FAR struct tcp_hdr_s *tcp = &fwd->f_hdr.ipv6.l3.tcp; + +#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) + conn->domain = PF_INET6; +#endif + conn->lport = tcp->srcport; + conn->rport = tcp->destport; + net_ipv6addr_copy(conn->u.ipv6.laddr, ipv6->srcipaddr); + net_ipv6addr_copy(conn->u.ipv6.raddr, ipv6->destipaddr); + } +#endif + + /* Set up the callback in the connection */ + + fwd->f_cb = tcp_callback_alloc(conn); + if (fwd->f_cb != NULL) + { + fwd->f_cb->flags = (TCP_POLL | NETDEV_DOWN); + fwd->f_cb->priv = (FAR void *)fwd; + fwd->f_cb->event = tcp_forward_interrupt; + + /* Notify the device driver of the availability of TX data */ + + netdev_txnotify_dev(fwd->f_dev); + return OK; + } + + return -EBUSY; } -#endif /* CONFIG_NET_IPv6 && CONFIG_NETDEV_MULTINIC */ -#endif /* CONFIG_NET && CONFIG_NET_IPFORWARD && CONFIG_NET_TCP */ + +#endif /* CONFIG_NET_IPFORWARD && CONFIG_NET_TCP && CONFIG_NETDEV_MULTINIC */ diff --git a/net/tcp/tcp_send_unbuffered.c b/net/tcp/tcp_send_unbuffered.c index 6bb13f593de..2de4a5a975d 100644 --- a/net/tcp/tcp_send_unbuffered.c +++ b/net/tcp/tcp_send_unbuffered.c @@ -181,7 +181,7 @@ static inline int send_timeout(FAR struct send_s *pstate) static inline void tcpsend_ipselect(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn) { - /* Which domain the socket support */ + /* Which domain does the socket support */ if (conn->domain == PF_INET) { diff --git a/net/udp/Make.defs b/net/udp/Make.defs index e28161496ed..9dda0a16042 100644 --- a/net/udp/Make.defs +++ b/net/udp/Make.defs @@ -51,8 +51,10 @@ endif # IP forwarding ifeq ($(CONFIG_NET_IPFORWARD),y) +ifeq ($(CONFIG_NETDEV_MULTINIC),y) NET_CSRCS += udp_forward.c endif +endif # Transport layer diff --git a/net/udp/udp.h b/net/udp/udp.h index 64d2e7aa3dd..91a690f5fe0 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -68,10 +68,10 @@ /* Allocate a new UDP data callback */ -#define udp_callback_alloc(dev, conn) \ - devif_callback_alloc(dev, &conn->list) -#define udp_callback_free(dev, conn,cb) \ - devif_conn_callback_free(dev, cb, &conn->list) +#define udp_callback_alloc(dev,conn) \ + devif_callback_alloc((dev), &(conn)->list) +#define udp_callback_free(dev,conn,cb) \ + devif_conn_callback_free((dev), (cb), &(conn)->list) /**************************************************************************** * Public Type Definitions @@ -429,7 +429,7 @@ uint16_t udp_callback(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn, uint16_t flags); /**************************************************************************** - * Name: udp_ipv6_dev_forward + * Name: udp_forward * * Description: * Called by the IP forwarding logic when an UDP packet is received on @@ -454,7 +454,7 @@ uint16_t udp_callback(FAR struct net_driver_s *dev, #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); +int udp_forward(FAR struct forward_s *fwd); #endif /**************************************************************************** diff --git a/net/udp/udp_forward.c b/net/udp/udp_forward.c index e1e5fc92f4c..f264ec62bea 100644 --- a/net/udp/udp_forward.c +++ b/net/udp/udp_forward.c @@ -37,24 +37,290 @@ #include +#include #include #include +#include + #include #include #include +#include #include "devif/ip_forward.h" +#include "devif/devif.h" +#include "netdev/netdev.h" #include "udp/udp.h" -#if defined(CONFIG_NET) && defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_UDP) +#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_UDP) && \ + defined(CONFIG_NETDEV_MULTINIC) /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** - * Name: udp_ipv6_dev_forward + * Name: forward_ipselect + * + * Description: + * If both IPv4 and IPv6 support are enabled, then we will need to select + * which one to use when generating the outgoing packet. If only one + * domain is selected, then the setup is already in place and we need do + * nothing. + * + * Parameters: + * fwd - The forwarding state structure + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) +static inline void forward_ipselect(FAR struct forward_s *fwd) +{ + /* Select IPv4 or IPv6 */ + + if ((fwd->f_hdr.ipv4.l2.vhl & IP_VERSION_MASK) == IPv4_VERSION) + { + udp_ipv4_select(fwd->f_dev); + } + else + { + udp_ipv6_select(fwd->f_dev); + } +} +#endif + +/**************************************************************************** + * Name: udp_forward_addrchk + * + * Description: + * Check if the destination IP address is in the IPv4 ARP or IPv6 Neighbor + * tables. If not, then the send won't actually make it out... it will be + * replaced with an ARP request (IPv4) or a Neighbor Solicitation (IPv6). + * + * NOTE 1: This could be an expensive check if there are a lot of + * entries in the ARP or Neighbor tables. + * + * NOTE 2: If we are actually harvesting IP addresses on incoming IP + * packets, then this check should not be necessary; the MAC mapping + * should already be in the ARP table in many cases (IPv4 only). + * + * NOTE 3: If CONFIG_NET_ARP_SEND then we can be assured that the IP + * address mapping is already in the ARP table. + * + * Parameters: + * fwd - The forwarding state structure + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_ETHERNET +static inline bool udp_forward_addrchk(FAR struct forward_s *fwd) +{ +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + if (conn->domain == PF_INET) +#endif + { +#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND) + return (arp_find(fwd->f_hdr.ipv4.l2.destipaddr) != NULL); +#else + return true; +#endif + } +#endif /* CONFIG_NET_IPv4 */ + +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + else +#endif + { +#if !defined(CONFIG_NET_ICMPv6_NEIGHBOR) + return (neighbor_findentry(fwd->f_hdr.ipv6.l2.destipaddr) != NULL); +#else + return true; +#endif + } +#endif /* CONFIG_NET_IPv6 */ +} + +#else /* CONFIG_NET_ETHERNET */ +# define udp_forward_addrchk(r) (true) +#endif /* CONFIG_NET_ETHERNET */ + +/**************************************************************************** + * Name: udp_dropstats + * + * Description: + * Update statistics for a dropped packet. + * + * Input Parameters: + * fwd - The forwarding state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_NET_STATISTICS +static void udp_dropstats(FAR struct forward_s *fwd) +{ + /* Increment the count of dropped UDP packets */ + + g_netstats.udp.drop++; + + /* Increment the count of dropped IPv4 or IPv6 packets */ + +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + if ((fwd->f_hdr.ipv4.l2.vhl & IP_VERSION_MASK) == IPv4_VERSION) +#endif + { + g_netstats.ipv4.drop++; + } +#endif +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + else +#endif + { + g_netstats.ipv6.drop++; + } +#endif +} +#else +# define udp_dropstats(ipv6) +#endif + +/**************************************************************************** + * Name: udp_forward_interrupt + * + * Description: + * This function is called from the interrupt level to perform the actual + * send operation when polled by the lower, device interfacing layer. + * + * Parameters: + * dev The structure of the network driver that caused the interrupt + * conn An instance of the UDP connection structure cast to void * + * pvpriv An instance of struct forward_s cast to void* + * flags Set of events describing why the callback was invoked + * + * Returned Value: + * Modified value of the input flags + * + * Assumptions: + * The network is locked + * + ****************************************************************************/ + +static uint16_t udp_forward_interrupt(FAR struct net_driver_s *dev, + FAR void *conn, FAR void *pvpriv, + uint16_t flags) +{ + FAR struct forward_s *fwd = (FAR struct forward_s *)pvpriv; + + ninfo("flags: %04x\n", flags); + DEBUGASSERT(fwd != NULL); + + /* Make sure that this is from the forwarding device */ + + if (dev == fwd->f_dev) + { + /* If the network device has gone down, then we will have terminate + * the wait now with an error. + */ + + if ((flags & NETDEV_DOWN) != 0) + { + /* Terminate the transfer with an error. */ + + nwarn("WARNING: Network is down... Dropping\n"); + udp_dropstats(fwd); + } + + /* Check if the outgoing packet is available. It may have been claimed + * by a sendto interrupt serving a different thread -OR- if the output + * buffer currently contains unprocessed incoming data. In these cases + * we will just have to wait for the next polling cycle. + */ + + else if (dev->d_sndlen > 0 || (flags & UDP_NEWDATA) != 0) + { + /* Another thread has beat us sending data or the buffer is busy, + * Wait for the next polling cycle and check again. + */ + + return flags; + } + + /* It looks like we are good to forward the data */ + + else + { +#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) + /* If both IPv4 and IPv6 support are enabled, then we will need to + * select which one to use when generating the outgoing packet. + * If only one domain is selected, then the setup is already in + * place and we need do nothing. + */ + + forward_ipselect(dev, fwd); +#endif + /* Copy the user data into d_appdata and send it. */ + + devif_forward(fwd); + + /* 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 + * will be replaced with an ARP request or Neighbor Solicitation. + */ + + if (!udp_forward_addrchk(fwd)) + { + return flags; + } + } + + /* Free the allocated callback structure */ + + fwd->f_cb->flags = 0; + fwd->f_cb->priv = NULL; + fwd->f_cb->event = NULL; + + udp_callback_free(dev, &fwd->f_conn.udp, fwd->f_cb); + + /* Free any IOBs */ + + if (fwd->f_iob != NULL) + { + iob_free_chain(fwd->f_iob); + } + + /* And release the forwarding state structure */ + + ip_forward_free(fwd); + } + + return flags; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: udp_forward * * Description: * Called by the IP forwarding logic when an UDP packet is received on @@ -76,23 +342,26 @@ * ****************************************************************************/ -#if defined(CONFIG_NET_IPv6) && defined(CONFIG_NETDEV_MULTINIC) -int udp_ipv6_dev_forward(FAR struct forward_s *fwd) +int udp_forward(FAR struct forward_s *fwd) { - /* Set up to send the packet when the selected device polls for TX data. */ + DEBUGASSERT(fwd != NULL && fwd->f_dev != NULL); - /* Notify the forwarding device that TX data is available */ + /* Set up the callback in the connection */ -#warning Missing logic + fwd->f_cb = udp_callback_alloc(fwd->f_dev, &fwd->f_conn.udp); + if (fwd->f_cb != NULL) + { + fwd->f_cb->flags = (UDP_POLL | NETDEV_DOWN); + fwd->f_cb->priv = (FAR void *)fwd; + fwd->f_cb->event = udp_forward_interrupt; - /* 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. - */ + /* Notify the device driver of the availability of TX data */ - nwarn("WARNING: UPD/ICMPv6 packet forwarding not yet supported\n"); - return -ENOSYS; + netdev_txnotify_dev(fwd->f_dev); + return OK; + } + + return -EBUSY; } -#endif /* CONFIG_NET_IPv6 && CONFIG_NETDEV_MULTINIC */ -#endif /* CONFIG_NET && CONFIG_NET_IPFORWARD && CONFIG_NET_UDP */ + +#endif /* CONFIG_NET_IPFORWARD && CONFIG_NET_UDP && CONFIG_NETDEV_MULTINIC */ diff --git a/net/udp/udp_psock_sendto.c b/net/udp/udp_psock_sendto.c index 616d1d3b47e..dfc1aaa2e43 100644 --- a/net/udp/udp_psock_sendto.c +++ b/net/udp/udp_psock_sendto.c @@ -126,7 +126,7 @@ struct sendto_s * TRUE:timeout FALSE:no timeout * * Assumptions: - * Running at the interrupt level + * The network is locked * ****************************************************************************/ @@ -170,7 +170,7 @@ static inline int send_timeout(FAR struct sendto_s *pstate) * None * * Assumptions: - * Running at the interrupt level + * The network is locked * ****************************************************************************/ @@ -216,7 +216,7 @@ static inline void sendto_ipselect(FAR struct net_driver_s *dev, * Modified value of the input flags * * Assumptions: - * Running at the interrupt level + * The network is locked * ****************************************************************************/