IP forwarding: Flesh out TCP, UDP, and ICMPv6 packet forwarding logic.

This commit is contained in:
Gregory Nutt
2017-07-05 11:01:16 -06:00
parent 65c3fa6375
commit 31f832d8c5
20 changed files with 1102 additions and 162 deletions
+2 -2
View File
@@ -883,8 +883,8 @@ Click Shield
D2 PA5 microBUS1 GPIO interrupt input PA5 D2 PA5 microBUS1 GPIO interrupt input PA5
D3 PA6 microBUS2 GPIO interrupt input PA6 D3 PA6 microBUS2 GPIO interrupt input PA6
D4 PD27 *** Not used *** D4 PD27 *** Not used ***
D5 PD11 microBUS2 PWM PD11 PWMC0_H0 D5 PD11 microBUS2 PWMB PD11 PWMC0_H0
D6 PC19 microBUS1 PWN PC19 PWMC0_H2 D6 PC19 microBUS1 PWMA PC19 PWMC0_H2
D7 PA2 *** Not used *** D7 PA2 *** Not used ***
D8 PA17 *** Not used *** D8 PA17 *** Not used ***
D9 PC9 microBUS2 CS GPIO output PC9 D9 PC9 microBUS2 CS GPIO output PC9
+2 -2
View File
@@ -1486,8 +1486,8 @@ Click Shield
D2 PA5 microBUS1 GPIO interrupt input PA5 D2 PA5 microBUS1 GPIO interrupt input PA5
D3 PA6 microBUS2 GPIO interrupt input PA6 D3 PA6 microBUS2 GPIO interrupt input PA6
D4 PD27 *** Not used *** D4 PD27 *** Not used ***
D5 PD11 microBUS2 PWM PD11 PWMC0_H0 D5 PD11 microBUS2 PWMB PD11 PWMC0_H0
D6 PC19 microBUS1 PWN PC19 PWMC0_H2 D6 PC19 microBUS1 PWMA PC19 PWMC0_H2
D7 PA2 *** Not used *** D7 PA2 *** Not used ***
D8 PA17 *** Not used *** D8 PA17 *** Not used ***
D9 PC9 microBUS2 CS GPIO output PC9 D9 PC9 microBUS2 CS GPIO output PC9
+1 -1
View File
@@ -53,7 +53,7 @@ endif
ifeq ($(CONFIG_NET_IPFORWARD),y) ifeq ($(CONFIG_NET_IPFORWARD),y)
ifeq ($(CONFIG_NETDEV_MULTINIC),y) ifeq ($(CONFIG_NETDEV_MULTINIC),y)
NET_CSRCS += ip_forward.c NET_CSRCS += ip_forward.c devif_forward.c
endif endif
endif endif
+102
View File
@@ -0,0 +1,102 @@
/****************************************************************************
* net/devif/devif_forward.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. 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 <nuttx/config.h>
#include <string.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/net/netdev.h>
#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 */
-28
View File
@@ -48,34 +48,6 @@
#ifdef CONFIG_MM_IOB #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 * Public Functions
****************************************************************************/ ****************************************************************************/
+2 -29
View File
@@ -47,33 +47,7 @@
#include <nuttx/net/netdev.h> #include <nuttx/net/netdev.h>
/**************************************************************************** #include "devif/devif.h"
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Type Declarations
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Public Constant Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Constant Data
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
@@ -87,8 +61,7 @@
* the network interface driver. * the network interface driver.
* *
* Assumptions: * Assumptions:
* Called from the interrupt level or, at a minimum, with interrupts * The network is locked.
* disabled.
* *
****************************************************************************/ ****************************************************************************/
+48 -6
View File
@@ -49,6 +49,10 @@
#include <nuttx/net/tcp.h> #include <nuttx/net/tcp.h>
#include <nuttx/net/icmpv6.h> #include <nuttx/net/icmpv6.h>
#include "udp/udp.h"
#include "tcp/tcp.h"
#include "icmpv6/icmpv6.h"
#undef HAVE_FWDALLOC #undef HAVE_FWDALLOC
#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NETDEV_MULTINIC) #if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NETDEV_MULTINIC)
@@ -69,7 +73,7 @@
/* IPv4 + L2 header */ /* IPv4 + L2 header */
#ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv4
struct ipv6_fwdhdr_s struct fwd_ipv4hdr_u
{ {
struct ipv4_hdr_s l2; struct ipv4_hdr_s l2;
union union
@@ -91,7 +95,7 @@ struct ipv6_fwdhdr_s
/* IPv6 + L2 header */ /* IPv6 + L2 header */
#ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv6
struct ipv6_fwdhdr_s struct fwd_ipv6hdr_u
{ {
struct ipv6_hdr_s l2; struct ipv6_hdr_s l2;
union union
@@ -112,18 +116,34 @@ struct ipv6_fwdhdr_s
/* IPv4 or IPv6 + L2 header */ /* IPv4 or IPv6 + L2 header */
union ip_fwdhdr_u union fwd_iphdr_u
{ {
#ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv4
struct ipv4_fwdhdr_s ipv4; struct fwd_ipv4hdr_u ipv4;
#endif #endif
#ifdef CONFIG_NET_IPv6 #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 #endif
}; };
/* This is the send state structure */ /* This is the send state structure */
struct devif_callback_s; /* Forward refernce */
struct net_driver_s; /* Forward reference */ struct net_driver_s; /* Forward reference */
struct iob_s; /* Forward reference */ struct iob_s; /* Forward reference */
@@ -132,7 +152,9 @@ struct forward_s
FAR struct forward_s *f_flink; /* Supports a singly linked list */ FAR struct forward_s *f_flink; /* Supports a singly linked list */
FAR struct net_driver_s *f_dev; /* Forwarding device */ FAR struct net_driver_s *f_dev; /* Forwarding device */
FAR struct iob_s *f_iob; /* IOBs containing the data payload */ FAR struct iob_s *f_iob; /* IOBs containing the data payload */
union ip_fwdhdr_u f_hdr; /* Copy of original L2+L3 headers */ 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 */ 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); 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 /* CONFIG_NET_IPFORWARD && CONFIG_NETDEV_MULTINIC */
#endif /* __NET_DEVIF_IP_FORWARD_H */ #endif /* __NET_DEVIF_IP_FORWARD_H */
+33 -8
View File
@@ -225,6 +225,17 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev,
FAR uint8_t *payload; FAR uint8_t *payload;
unsigned int paysize; 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 /* Get a pre-allocated forwarding structure, This structure will be
* completely zeroed when we receive it. * 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 * Remember that the size of the L1 header has already been subtracted
* from dev->d_len. * 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); 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 */ /* 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"); nwarn("WARNING: Header is too big for pre-allocated structure\n");
ret = -E2BIG; ret = -E2BIG;
@@ -278,7 +293,12 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev,
payload = (FAR uint8_t *)ipv6 + hdrsize; payload = (FAR uint8_t *)ipv6 + hdrsize;
paysize = dev->d_len - 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) 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) switch (ipv6->proto)
{ {
#ifdef CONFIG_NET_TCP #ifdef CONFIG_NET_TCP
case IP_PROTO_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; break;
#endif #endif
@@ -327,7 +352,7 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev,
{ {
/* Forward a UDP packet */ /* Forward a UDP packet */
ret = udp_ipv6_dev_forward(fwd); ret = udp_forward(fwd);
} }
break; break;
#endif #endif
@@ -337,7 +362,7 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev,
{ {
/* Forward an ICMPv6 packet */ /* Forward an ICMPv6 packet */
ret = icmpv6_dev_forward(fwd); ret = icmpv6_forward(fwd);
} }
break; break;
#endif #endif
@@ -428,7 +453,7 @@ static int ipv6_decr_ttl(FAR struct ipv6_hdr_s *ipv6)
* Name: ipv6_dropstats * Name: ipv6_dropstats
* *
* Description: * Description:
* Update statistics for a droped packet. * Update statistics for a dropped packet.
* *
* Input Parameters: * Input Parameters:
* ipv6 - A convenience pointer to the IPv6 header in within the IPv6 * ipv6 - A convenience pointer to the IPv6 header in within the IPv6
+2
View File
@@ -66,8 +66,10 @@ endif
# IP forwarding # IP forwarding
ifeq ($(CONFIG_NET_IPFORWARD),y) ifeq ($(CONFIG_NET_IPFORWARD),y)
ifeq ($(CONFIG_NETDEV_MULTINIC),y)
NET_CSRCS += icmpv6_forward.c NET_CSRCS += icmpv6_forward.c
endif endif
endif
# Include ICMPv6 build support # Include ICMPv6 build support
+6 -4
View File
@@ -55,8 +55,10 @@
/* Allocate a new ICMPv6 data callback */ /* Allocate a new ICMPv6 data callback */
#define icmpv6_callback_alloc(dev) devif_callback_alloc(dev, &(dev)->d_conncb) #define icmpv6_callback_alloc(dev) \
#define icmpv6_callback_free(dev,cb) devif_dev_callback_free(dev, cb) devif_callback_alloc((dev), &(dev)->d_conncb)
#define icmpv6_callback_free(dev,cb) \
devif_dev_callback_free((dev), (cb))
/**************************************************************************** /****************************************************************************
* Public Type Definitions * Public Type Definitions
@@ -177,7 +179,7 @@ int icmpv6_neighbor(const net_ipv6addr_t ipaddr);
#endif #endif
/**************************************************************************** /****************************************************************************
* Name: icmpv6_dev_forward * Name: icmpv6_forward
* *
* Description: * Description:
* Called by the IP forwarding logic when an ICMPv6 packet is received on * 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) #if defined(CONFIG_NETDEV_MULTINIC) && defined(CONFIG_NET_IPFORWARD)
struct forward_s; struct forward_s;
int icmpv6_dev_forward(FAR struct forward_s *fwd); int icmpv6_forward(FAR struct forward_s *fwd);
#endif #endif
/**************************************************************************** /****************************************************************************
+242 -18
View File
@@ -37,30 +37,251 @@
#include <nuttx/config.h> #include <nuttx/config.h>
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <debug.h> #include <debug.h>
#include <net/if.h>
#include <nuttx/mm/iob.h> #include <nuttx/mm/iob.h>
#include <nuttx/net/netdev.h> #include <nuttx/net/netdev.h>
#include <nuttx/net/ip.h> #include <nuttx/net/ip.h>
#include <nuttx/net/netstats.h>
#include "devif/ip_forward.h" #include "devif/ip_forward.h"
#include "devif/devif.h"
#include "netdev/netdev.h"
#include "icmpv6/icmpv6.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 * Public Functions
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
* Name: icmpv6_dev_forward * Name: icmpv6_forward_addrchck
* *
* Description: * 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. * 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 * function will set up a send "interrupt" handler that will perform the
* actual send asynchronously and must return without waiting for the * actual send asynchronously and must return without waiting for the
* send to complete. * send to complete.
@@ -76,23 +297,26 @@
* *
****************************************************************************/ ****************************************************************************/
#if defined(CONFIG_NETDEV_MULTINIC) && defined(CONFIG_NET_ICMPv6) int icmpv6_forward(FAR struct forward_s *fwd)
int icmpv6_dev_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: /* Notify the device driver of the availability of TX data */
* - 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"); netdev_txnotify_dev(fwd->f_dev);
return -ENOSYS; return OK;
} }
#endif /* CONFIG_NET_ICMPv6 && CONFIG_NETDEV_MULTINIC */
#endif /* CONFIG_NET && CONFIG_NET_IPFORWARD && CONFIG_NET_ICMPv6 */ return -EBUSY;
}
#endif /* CONFIG_NET_IPFORWARD && CONFIG_NET_ICMPv6 && CONFIG_NETDEV_MULTINIC */
+3 -1
View File
@@ -1,7 +1,7 @@
############################################################################ ############################################################################
# net/tcp/Make.defs # net/tcp/Make.defs
# #
# Copyright (C) 2014 Gregory Nutt. All rights reserved. # Copyright (C) 2014, 2017 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org> # Author: Gregory Nutt <gnutt@nuttx.org>
# #
# Redistribution and use in source and binary forms, with or without # 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 # IP forwarding
ifeq ($(CONFIG_NET_IPFORWARD),y) ifeq ($(CONFIG_NET_IPFORWARD),y)
ifeq ($(CONFIG_NETDEV_MULTINIC),y)
NET_CSRCS += tcp_forward.c NET_CSRCS += tcp_forward.c
endif endif
endif
# TCP write buffering # TCP write buffering
+9 -9
View File
@@ -71,18 +71,18 @@
*/ */
# define tcp_callback_alloc(conn) \ # 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) \ # 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 /* These macros allocate and free callback structures used for receiving
* notifications of device-related events. * notifications of device-related events.
*/ */
# define tcp_monitor_callback_alloc(conn) \ # 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) \ # define tcp_monitor_callback_free(conn,cb) \
devif_conn_callback_free(conn->dev, cb, NULL) devif_conn_callback_free((conn)->dev, (cb), NULL)
#else #else
/* These macros allocate and free callback structures used for receiving /* These macros allocate and free callback structures used for receiving
@@ -90,9 +90,9 @@
*/ */
# define tcp_callback_alloc(conn) \ # 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) \ # 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 /* These macros allocate and free callback structures used for receiving
* notifications of device-related events. * notifications of device-related events.
@@ -101,7 +101,7 @@
# define tcp_monitor_callback_alloc(conn) \ # define tcp_monitor_callback_alloc(conn) \
devif_callback_alloc(g_netdevices, NULL) devif_callback_alloc(g_netdevices, NULL)
# define tcp_monitor_callback_free(conn,cb) \ # define tcp_monitor_callback_free(conn,cb) \
devif_conn_callback_free(g_netdevices, cb, NULL) devif_conn_callback_free(g_netdevices, (cb), NULL)
#endif #endif
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS #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); uint16_t flags, uint16_t len);
/**************************************************************************** /****************************************************************************
* Name: tcp_ipv6_dev_forward * Name: tcp_forward
* *
* Description: * Description:
* Called by the IP forwarding logic when an TCP packet is received on * 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) && \ #if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_IPv6) && \
defined(CONFIG_NETDEV_MULTINIC) defined(CONFIG_NETDEV_MULTINIC)
struct forward_s; /* Forward reference */ struct forward_s; /* Forward reference */
int tcp_ipv6_dev_forward(FAR struct forward_s *fwd); int tcp_forward(FAR struct forward_s *fwd);
#endif #endif
/**************************************************************************** /****************************************************************************
+346 -21
View File
@@ -37,32 +37,316 @@
#include <nuttx/config.h> #include <nuttx/config.h>
#include <string.h>
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <debug.h> #include <debug.h>
#include <net/if.h>
#include <nuttx/mm/iob.h> #include <nuttx/mm/iob.h>
#include <nuttx/net/netdev.h> #include <nuttx/net/netdev.h>
#include <nuttx/net/ip.h> #include <nuttx/net/ip.h>
#include <nuttx/net/netstats.h>
#include "devif/ip_forward.h" #include "devif/ip_forward.h"
#include "devif/devif.h"
#include "netdev/netdev.h"
#include "tcp/tcp.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 * 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: * Description:
* Called by the IP forwarding logic when an TCP packet is received on * Called by the IP forwarding logic when an TCP packet is received on
* one network device, but must be forwarded on another network device. * one network device, but must be forwarded on another network device.
* *
* Set up to forward the TCP packet on the specified device. This * Set up to forward the TCP packet on the specified device. This
* function will set up a send "interrupt" handler that will perform * function will set up a send "interrupt" handler that will perform the
* the actual send asynchronously and must return without waiting for the * actual send asynchronously and must return without waiting for the
* send to complete. * send to complete.
* *
* Input Parameters: * Input Parameters:
@@ -76,27 +360,68 @@
* *
****************************************************************************/ ****************************************************************************/
#if defined(CONFIG_NET_IPv6) && defined(CONFIG_NETDEV_MULTINIC) int tcp_forward(FAR struct forward_s *fwd)
int tcp_ipv6_dev_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. /* Set up some minimal connection structure so that we appear to be a
* TCP packets must obey ACK and windowing rules. * real TCP connection.
*/ */
#warning Missing logic conn->dev = fwd->f_dev;
/* REVISIT: For Ethernet we may have to fix up the Ethernet header: #ifdef CONFIG_NET_IPv4
* - source MAC, the MAC of the current device. #ifdef CONFIG_NET_IPv6
* - dest MAC, the MAC associated with the destination IPv6 adress. if ((fwd->f_hdr.ipv4.l2.vhl & IP_VERSION_MASK) == IPv4_VERSION)
* This will involve ICMPv6 and Neighbor Discovery. #endif
* - Because of TCP window, the packet may have to be sent in smaller {
* pieces. 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"); #if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
return -ENOSYS; 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 /* CONFIG_NET_IPv6 && CONFIG_NETDEV_MULTINIC */ #endif
#endif /* CONFIG_NET && CONFIG_NET_IPFORWARD && CONFIG_NET_TCP */ #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_IPFORWARD && CONFIG_NET_TCP && CONFIG_NETDEV_MULTINIC */
+1 -1
View File
@@ -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, static inline void tcpsend_ipselect(FAR struct net_driver_s *dev,
FAR struct tcp_conn_s *conn) FAR struct tcp_conn_s *conn)
{ {
/* Which domain the socket support */ /* Which domain does the socket support */
if (conn->domain == PF_INET) if (conn->domain == PF_INET)
{ {
+2
View File
@@ -51,8 +51,10 @@ endif
# IP forwarding # IP forwarding
ifeq ($(CONFIG_NET_IPFORWARD),y) ifeq ($(CONFIG_NET_IPFORWARD),y)
ifeq ($(CONFIG_NETDEV_MULTINIC),y)
NET_CSRCS += udp_forward.c NET_CSRCS += udp_forward.c
endif endif
endif
# Transport layer # Transport layer
+4 -4
View File
@@ -69,9 +69,9 @@
/* Allocate a new UDP data callback */ /* Allocate a new UDP data callback */
#define udp_callback_alloc(dev,conn) \ #define udp_callback_alloc(dev,conn) \
devif_callback_alloc(dev, &conn->list) devif_callback_alloc((dev), &(conn)->list)
#define udp_callback_free(dev,conn,cb) \ #define udp_callback_free(dev,conn,cb) \
devif_conn_callback_free(dev, cb, &conn->list) devif_conn_callback_free((dev), (cb), &(conn)->list)
/**************************************************************************** /****************************************************************************
* Public Type Definitions * 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); FAR struct udp_conn_s *conn, uint16_t flags);
/**************************************************************************** /****************************************************************************
* Name: udp_ipv6_dev_forward * Name: udp_forward
* *
* Description: * Description:
* Called by the IP forwarding logic when an UDP packet is received on * 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) && \ #if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_IPv6) && \
defined(CONFIG_NETDEV_MULTINIC) defined(CONFIG_NETDEV_MULTINIC)
struct forward_s; /* Forward reference */ struct forward_s; /* Forward reference */
int udp_ipv6_dev_forward(FAR struct forward_s *fwd); int udp_forward(FAR struct forward_s *fwd);
#endif #endif
/**************************************************************************** /****************************************************************************
+285 -16
View File
@@ -37,24 +37,290 @@
#include <nuttx/config.h> #include <nuttx/config.h>
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <debug.h> #include <debug.h>
#include <net/if.h>
#include <nuttx/mm/iob.h> #include <nuttx/mm/iob.h>
#include <nuttx/net/netdev.h> #include <nuttx/net/netdev.h>
#include <nuttx/net/ip.h> #include <nuttx/net/ip.h>
#include <nuttx/net/netstats.h>
#include "devif/ip_forward.h" #include "devif/ip_forward.h"
#include "devif/devif.h"
#include "netdev/netdev.h"
#include "udp/udp.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 * 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: * Description:
* Called by the IP forwarding logic when an UDP packet is received on * 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_forward(FAR struct forward_s *fwd)
int udp_ipv6_dev_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: /* Notify the device driver of the availability of TX data */
* - 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"); netdev_txnotify_dev(fwd->f_dev);
return -ENOSYS; return OK;
} }
#endif /* CONFIG_NET_IPv6 && CONFIG_NETDEV_MULTINIC */
#endif /* CONFIG_NET && CONFIG_NET_IPFORWARD && CONFIG_NET_UDP */ return -EBUSY;
}
#endif /* CONFIG_NET_IPFORWARD && CONFIG_NET_UDP && CONFIG_NETDEV_MULTINIC */
+3 -3
View File
@@ -126,7 +126,7 @@ struct sendto_s
* TRUE:timeout FALSE:no timeout * TRUE:timeout FALSE:no timeout
* *
* Assumptions: * 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 * None
* *
* Assumptions: * 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 * Modified value of the input flags
* *
* Assumptions: * Assumptions:
* Running at the interrupt level * The network is locked
* *
****************************************************************************/ ****************************************************************************/