1
0
Fork 0
forked from nuttx/nuttx-update

IP forwarding: Major rearchitecting of the outgoing portion of the IP forwarding logic necessary into to properly received device-related forwarding events.

This commit is contained in:
Gregory Nutt 2017-07-07 20:19:26 -06:00
parent 803235ad4b
commit aa2e9c15a5
19 changed files with 369 additions and 1460 deletions

View file

@ -171,12 +171,14 @@
#define UDP_NEWDATA TCP_NEWDATA
#define PKT_NEWDATA TCP_NEWDATA
#define WPAN_NEWDATA TCP_NEWDATA
#define IPFWD_NEWDATA TCP_NEWDATA
#define TCP_SNDACK (1 << 2)
#define TCP_REXMIT (1 << 3)
#define TCP_POLL (1 << 4)
#define UDP_POLL TCP_POLL
#define PKT_POLL TCP_POLL
#define WPAN_POLL TCP_POLL
#define IPFWD_POLL TCP_POLL
#define TCP_BACKLOG (1 << 5)
#define TCP_CLOSE (1 << 6)
#define TCP_ABORT (1 << 7)

View file

@ -87,7 +87,8 @@ void devif_forward(FAR struct forward_s *fwd)
DEBUGASSERT(ret == fwd->f_iob->io_pktlen);
offset += fwd->f_iob->io_pktlen;
fwd->f_dev->d_sndlen = offset;
fwd->f_dev->d_sndlen = 0;
fwd->f_dev->d_len = offset;
}
#endif /* CONFIG_NET_IPFORWARD && CONFIG_NETDEV_MULTINIC */

View file

@ -251,6 +251,28 @@ static inline int devif_poll_icmpv6(FAR struct net_driver_s *dev,
}
#endif /* CONFIG_NET_ICMPv6_PING || CONFIG_NET_ICMPv6_NEIGHBOR*/
/****************************************************************************
* Name: devif_poll_forward
*
* Description:
* Poll the device event to see if any task is waiting to forward a packet.
*
****************************************************************************/
#if defined(CONFIG_NET_IPFORWARD) || defined(CONFIG_NETDEV_MULTINIC)
static inline int devif_poll_forward(FAR struct net_driver_s *dev,
devif_poll_callback_t callback)
{
/* Perform the ICMPv6 poll */
devif_dev_event(dev, NULL, IPFWD_POLL);
/* Call back into the driver */
return callback(dev);
}
#endif /* CONFIG_NET_ICMPv6_PING || CONFIG_NET_ICMPv6_NEIGHBOR*/
/****************************************************************************
* Name: devif_poll_igmp
*
@ -506,6 +528,15 @@ int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback)
bstop = devif_poll_icmpv6(dev, callback);
}
if (!bstop)
#endif
#if defined(CONFIG_NET_IPFORWARD) || defined(CONFIG_NETDEV_MULTINIC)
{
/* Traverse all of the tasks waiting to forward a packet to this device. */
bstop = devif_poll_forward(dev, callback);
}
if (!bstop)
#endif
{

View file

@ -43,14 +43,6 @@ ifeq ($(CONFIG_NET_ICMP_PING),y)
NET_CSRCS += icmp_ping.c icmp_poll.c icmp_send.c
endif
# IP forwarding
ifeq ($(CONFIG_NET_IPFORWARD),y)
ifeq ($(CONFIG_NETDEV_MULTINIC),y)
NET_CSRCS += icmp_forward.c
endif
endif
# Include ICMP build support
DEPPATH += --dep-path icmp

View file

@ -1,304 +0,0 @@
/****************************************************************************
* net/icmp/icmp_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 <assert.h>
#include <errno.h>
#include <debug.h>
#include <net/if.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/ip.h>
#include <nuttx/net/netstats.h>
#include "ipforward/ipforward.h"
#include "devif/devif.h"
#include "netdev/netdev.h"
#include "arp/arp.h"
#include "neighbor/neighbor.h"
#include "icmp/icmp.h"
#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_ICMP) && \
defined(CONFIG_NETDEV_MULTINIC)
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: icmp_forward_addrchck
*
* Description:
* Check if the destination IP address is in the IPv4 ARP table. If not,
* then the send won't actually make it out... it will be replaced with an
* ARP request (IPv4).
*
* NOTE 1: This could be an expensive check if there are a lot of
* entries in the ARP table.
*
* 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.
*
* 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:
* true - The Ethernet MAC address is in the ARP table (OR the network
* device is not Ethernet).
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
#ifdef CONFIG_NET_ETHERNET
static inline bool icmp_forward_addrchck(FAR struct forward_s *fwd)
{
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
FAR union fwd_iphdr_u *iphdr;
#endif
DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL);
/* REVISIT: Could the MAC address not also be in a routing table? */
#ifdef CONFIG_NET_MULTILINK
if (fwd->f_dev->d_lltype != NET_LL_ETHERNET)
{
return true;
}
#endif
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
iphdr = FWD_HEADER(fwd);
return (arp_find(iphdr->ipv4.l2.destipaddr) != NULL);
#else
return true;
#endif
}
#else /* CONFIG_NET_ETHERNET */
# define icmp_forward_addrchck(fwd) (true)
#endif /* CONFIG_NET_ETHERNET */
/****************************************************************************
* Name: icmp_dropstats
*
* Description:
* Update statistics for a dropped packet.
*
* Input Parameters:
* fwd - The forwarding state structure
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_NET_STATISTICS
static inline void icmp_dropstats(FAR struct forward_s *fwd)
{
/* Increment the count of dropped ICMP packets */
g_netstats.icmp.drop++;
g_netstats.ipv4.drop++;
}
#else
# define icmp_dropstats(fwd)
#endif
/****************************************************************************
* Name: icmp_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 ICMP 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 icmp_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 && fwd->f_iob != NULL && fwd->f_dev != 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");
icmp_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 & ICMP_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 ICMP 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 (!icmp_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;
icmp_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 */
ipfwd_free(fwd);
}
return flags;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: icmp_forward
*
* Description:
* Called by the IP forwarding logic when an ICMP packet is received on
* one network device, but must be forwarded on another network device.
*
* Set up to forward the ICMP packet on the specified device. This
* function will set up a send "interrupt" handler that will perform the
* actual send asynchronously and must return without waiting for the
* send to complete.
*
* Input Parameters:
* fwd - An initialized instance of the common forwarding structure that
* includes everything needed to perform the forwarding operation.
*
* Returned Value:
* Zero is returned if the packet was successfully forwarded; A negated
* errno value is returned if the packet is not forwardable. In that
* latter case, the caller should free the IOB list and drop the packet.
*
****************************************************************************/
int icmp_forward(FAR struct forward_s *fwd)
{
DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL);
/* Set up the callback in the connection */
fwd->f_cb = icmp_callback_alloc(fwd->f_dev);
if (fwd->f_cb != NULL)
{
fwd->f_cb->flags = (ICMP_POLL | NETDEV_DOWN);
fwd->f_cb->priv = (FAR void *)fwd;
fwd->f_cb->event = icmp_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_ICMP && CONFIG_NETDEV_MULTINIC */

View file

@ -63,14 +63,6 @@ ifeq ($(CONFIG_NET_ICMPv6_ROUTER),y)
NET_CSRCS += icmpv6_radvertise.c
endif
# IP forwarding
ifeq ($(CONFIG_NET_IPFORWARD),y)
ifeq ($(CONFIG_NETDEV_MULTINIC),y)
NET_CSRCS += icmpv6_forward.c
endif
endif
# Include ICMPv6 build support
DEPPATH += --dep-path icmpv6

View file

@ -178,34 +178,6 @@ int icmpv6_neighbor(const net_ipv6addr_t ipaddr);
# define icmpv6_neighbor(i) (0)
#endif
/****************************************************************************
* 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
* function will set up a send "interrupt" handler that will perform the
* actual send asynchronously and must return without waiting for the
* send to complete.
*
* Input Parameters:
* fwd - An initialized instance of the common forwarding structure that
* includes everything needed to perform the forwarding operation.
*
* Returned Value:
* Zero is returned if the packet was successfully forwarded; A negated
* errno value is returned if the packet is not forwardable. In that
* latter case, the caller should free the IOB list and drop the packet.
*
****************************************************************************/
#if defined(CONFIG_NETDEV_MULTINIC) && defined(CONFIG_NET_IPFORWARD)
struct forward_s;
int icmpv6_forward(FAR struct forward_s *fwd);
#endif
/****************************************************************************
* Name: icmpv6_poll
*

View file

@ -1,300 +0,0 @@
/****************************************************************************
* net/icmpv6/icmpv6_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 <assert.h>
#include <errno.h>
#include <debug.h>
#include <net/if.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/ip.h>
#include <nuttx/net/netstats.h>
#include "ipforward/ipforward.h"
#include "devif/devif.h"
#include "netdev/netdev.h"
#include "arp/arp.h"
#include "neighbor/neighbor.h"
#include "icmpv6/icmpv6.h"
#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_ICMPv6) && \
defined(CONFIG_NETDEV_MULTINIC)
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: icmpv6_forward_addrchck
*
* Description:
* Check if the destination IP address is in the Pv6 Neighbor table. If
* not, then the send won't actually make it out... it will be replaced
* with a Neighbor Solicitation.
*
* NOTE 1: This could be an expensive check if there are a lot of
* entries in the Neighbor table.
*
* NOTE 2: 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:
* true - The Ethernet MAC address is in the Neighbor table (OR the
* network device is not Ethernet).
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
#ifdef CONFIG_NET_ETHERNET
static inline bool icmpv6_forward_addrchck(FAR struct forward_s *fwd)
{
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
FAR union fwd_iphdr_u *iphdr;
#endif
DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL);
/* REVISIT: Could the MAC address not also be in a routing table? */
#ifdef CONFIG_NET_MULTILINK
if (fwd->f_dev->d_lltype != NET_LL_ETHERNET)
{
return true;
}
#endif
#if !defined(CONFIG_NET_ICMPv6_NEIGHBOR)
iphdr = FWD_HEADER(fwd);
return (arp_find(iphdr->ipv6.l2.destipaddr) != NULL);
#else
return true;
#endif
}
#else /* CONFIG_NET_ETHERNET */
# define icmpv6_forward_addrchck(fwd) (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 inline void icmpv6_dropstats(FAR struct forward_s *fwd)
{
/* Increment the count of dropped ICMPv6 packets */
g_netstats.icmpv6.drop++;
g_netstats.ipv6.drop++;
}
#else
# define icmpv6_dropstats(fwd)
#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 && fwd->f_iob != NULL && fwd->f_dev != 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 */
ipfwd_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. This
* function will set up a send "interrupt" handler that will perform the
* actual send asynchronously and must return without waiting for the
* send to complete.
*
* Input Parameters:
* fwd - An initialized instance of the common forwarding structure that
* includes everything needed to perform the forwarding operation.
*
* Returned Value:
* Zero is returned if the packet was successfully forwarded; A negated
* errno value is returned if the packet is not forwardable. In that
* latter case, the caller should free the IOB list and drop the packet.
*
****************************************************************************/
int icmpv6_forward(FAR struct forward_s *fwd)
{
DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL);
/* Set up the callback in the connection */
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;
/* 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_ICMPv6 && CONFIG_NETDEV_MULTINIC */

View file

@ -37,6 +37,8 @@
ifeq ($(CONFIG_NET_IPFORWARD),y)
NET_CSRCS += ipfwd_forward.c
ifeq ($(CONFIG_NET_IPv4),y)
NET_CSRCS += ipv4_forward.c
endif
@ -49,6 +51,10 @@ ifeq ($(CONFIG_NETDEV_MULTINIC),y)
NET_CSRCS += ipfwd_alloc.c
endif
ifeq ($(CONFIG_NET_STATISTICS),y)
NET_CSRCS += ipfwd_dropstats.c
endif
# Include IP forwaring build support
DEPPATH += --dep-path ipforward

View file

@ -135,21 +135,6 @@ union fwd_iphdr_u
#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 devif_callback_s; /* Forward refernce */
@ -162,7 +147,6 @@ struct forward_s
FAR struct net_driver_s *f_dev; /* Forwarding device */
FAR struct iob_s *f_iob; /* IOB chain containing the packet */
FAR struct devif_callback_s *f_cb; /* Reference to callback instance */
union fwd_conn_u f_conn; /* Protocol-specific connection struct */
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
uint8_t f_domain; /* Domain: PF_INET or PF_INET6 */
#endif
@ -296,6 +280,31 @@ void ipv6_forward_broadcast(FAR struct net_driver_s *dev,
void devif_forward(FAR struct forward_s *fwd);
/****************************************************************************
* Name: ipfwd_forward
*
* Description:
* Called by the IP forwarding logic when a packet is received on one
* network device, but must be forwarded on another network device.
*
* Set up to forward the packet on the specified device. This function
* will set up a send "interrupt" handler that will perform the actual
* send asynchronously and must return without waiting for the send to
* complete.
*
* Input Parameters:
* fwd - An initialized instance of the common forwarding structure that
* includes everything needed to perform the forwarding operation.
*
* Returned Value:
* Zero is returned if the packet was successfully forwarded; A negated
* errno value is returned if the packet is not forwardable. In that
* latter case, the caller should free the IOB list and drop the packet.
*
****************************************************************************/
int ipfwd_forward(FAR struct forward_s *fwd);
#endif /* CONFIG_NETDEV_MULTINIC */
/****************************************************************************
@ -358,5 +367,67 @@ int ipv4_forward(FAR struct net_driver_s *dev, FAR struct ipv4_hdr_s *ipv4);
int ipv6_forward(FAR struct net_driver_s *dev, FAR struct ipv6_hdr_s *ipv6);
#endif
/****************************************************************************
* Name: ipv6_dropstats
*
* Description:
* Update statistics for a dropped Ipv6 packet.
*
* Input Parameters:
* ipv6 - A pointer to the IPv6 header in within the IPv6 packet to be
* dropped.
*
* Returned Value:
* None
*
****************************************************************************/
#if defined(CONFIG_NET_STATISTICS) && defined(CONFIG_NET_IPv6)
void ipv6_dropstats(FAR struct ipv6_hdr_s *ipv6);
#else
# define ipv6_dropstats(ipv6)
#endif
/****************************************************************************
* Name: ipv4_dropstats
*
* Description:
* Update statistics for a dropped Ipv4 packet.
*
* Input Parameters:
* ipv4 - A pointer to the IPv4 header in within the IPv4 packet to be
* dropped.
*
* Returned Value:
* None
*
****************************************************************************/
#if defined(CONFIG_NET_STATISTICS) && defined(CONFIG_NET_IPv4)
void ipv4_dropstats(FAR struct ipv4_hdr_s *ipv4);
#else
# define ipv4_dropstats(ipv4)
#endif
/****************************************************************************
* Name: ipfwd_dropstats
*
* Description:
* Update statistics for a dropped packet.
*
* Input Parameters:
* fwd - The forwarding state structure
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_NET_STATISTICS
void ipfwd_dropstats(FAR struct forward_s *fwd)
#else
# define ipfwd_dropstats(fwd)
#endif
#endif /* CONFIG_NET_IPFORWARD */
#endif /* __NET_IPFORWARD_IPFORWARD_H */

View file

@ -0,0 +1,192 @@
/****************************************************************************
* net/ipforward/ipfwd_dropstats.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/net/netstats.h>
#include "ipforward/ipforward.h"
#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_STATISTICS)
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: proto_dropstats
*
* Description:
* Update statistics for a dropped L2 protocol packet.
*
* Input Parameters:
* proto - The protocol from the IPv4 or IPv6 header.
*
* Returned Value:
* On success, zero (OK) is returned. Otherwise, a negated errno value
* is returned. The only error is if th protocol is not recognized.
*
****************************************************************************/
static int proto_dropstats(int proto)
{
switch (proto)
{
#ifdef CONFIG_NET_TCP
case IP_PROTO_TCP:
g_netstats.tcp.drop++;
break;
#endif
#ifdef CONFIG_NET_UDP
case IP_PROTO_UDP:
g_netstats.udp.drop++;
break;
#endif
#ifdef CONFIG_NET_ICMPv6
case IP_PROTO_ICMP6:
g_netstats.icmpv6.drop++;
break;
#endif
default:
retrun -EPROTONOSUPPORT;
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ipv6_dropstats
*
* Description:
* Update statistics for a dropped Ipv6 packet.
*
* Input Parameters:
* ipv6 - A pointer to the IPv6 header in within the IPv6 packet to be
* dropped.
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_NET_IPv6
void ipv6_dropstats(FAR struct ipv6_hdr_s *ipv6)
{
int ret;
ret = proto_dropstats(ipv6->proto);
if (ret < 0)
{
g_netstats.ipv6.protoerr++;
}
g_netstats.ipv6.drop++;
}
#endif
/****************************************************************************
* Name: ipv4_dropstats
*
* Description:
* Update statistics for a dropped Ipv4 packet.
*
* Input Parameters:
* ipv4 - A pointer to the IPv4 header in within the IPv4 packet to be
* dropped.
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_NET_IPv4
void ipv4_dropstats(FAR struct ipv4_hdr_s *ipv4)
{
int ret;
ret = proto_dropstats(ipv6->ipv4);
if (ret < 0)
{
g_netstats.ipv4.protoerr++;
}
g_netstats.ipv4.drop++;
}
#endif
/****************************************************************************
* Name: ipfwd_dropstats
*
* Description:
* Update statistics for a dropped packet.
*
* Input Parameters:
* fwd - The forwarding state structure
*
* Returned Value:
* None
*
****************************************************************************/
void ipfwd_dropstats(FAR struct forward_s *fwd)
{
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (fwd->domain == PF_INET)
#endif
{
ipv4_dropstats((FAR struct ipv4_hdr_s *)fwd->f_iob->io_data);
}
#endif
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else
#endif
{
ipv6_dropstats((FAR struct ipv6_hdr_s *)fwd->f_iob->io_data);
}
#endif
}

View file

@ -1,5 +1,5 @@
/****************************************************************************
* net/udp/udp_forward.c
* net/ipforward/ipfwd_forward.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
@ -49,15 +49,13 @@
#include <nuttx/net/ip.h>
#include <nuttx/net/netstats.h>
#include "ipforward/ipforward.h"
#include "devif/devif.h"
#include "netdev/netdev.h"
#include "arp/arp.h"
#include "neighbor/neighbor.h"
#include "udp/udp.h"
#include "ipforward/ipforward.h"
#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_UDP) && \
defined(CONFIG_NETDEV_MULTINIC)
#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NETDEV_MULTINIC)
/****************************************************************************
* Public Functions
@ -86,23 +84,35 @@
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
static inline void forward_ipselect(FAR struct forward_s *fwd)
{
FAR union fwd_iphdr_u *iphdr = FWD_HEADER(fwd);
FAR struct net_driver_s *dev = fwd->f_dev;
/* Select IPv4 or IPv6 */
if (fwd->f_domain == PF_INET)
{
udp_ipv4_select(fwd->f_dev);
/* Clear a bit in the d_flags to distinguish this from an IPv6 packet */
IFF_SET_IPv4(dev->d_flags);
/* Set the offset to the beginning of the UDP data payload */
dev->d_appdata = &dev->d_buf[IPv4UDP_HDRLEN + NET_LL_HDRLEN(dev)];
}
else
{
udp_ipv6_select(fwd->f_dev);
/* Set a bit in the d_flags to distinguish this from an IPv6 packet */
IFF_SET_IPv6(dev->d_flags);
/* Set the offset to the beginning of the UDP data payload */
dev->d_appdata = &dev->d_buf[IPv6_HDRLEN + NET_LL_HDRLEN(dev)];
}
}
#endif
/****************************************************************************
* Name: udp_forward_addrchk
* Name: ipfwd_addrchk
*
* Description:
* Check if the destination IP address is in the IPv4 ARP or IPv6 Neighbor
@ -132,7 +142,7 @@ static inline void forward_ipselect(FAR struct forward_s *fwd)
****************************************************************************/
#ifdef CONFIG_NET_ETHERNET
static inline bool udp_forward_addrchk(FAR struct forward_s *fwd)
static inline bool ipfwd_addrchk(FAR struct forward_s *fwd)
{
FAR union fwd_iphdr_u *iphdr;
@ -177,59 +187,11 @@ static inline bool udp_forward_addrchk(FAR struct forward_s *fwd)
}
#else /* CONFIG_NET_ETHERNET */
# define udp_forward_addrchk(r) (true)
# define ipfwd_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)
{
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
FAR union fwd_iphdr_u *iphdr = FWD_HEADER(fwd);
#endif
/* 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_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 udp_dropstats(ipv6)
#endif
/****************************************************************************
* Name: udp_forward_interrupt
* Name: ipfwd_interrupt
*
* Description:
* This function is called from the interrupt level to perform the actual
@ -237,7 +199,7 @@ static void udp_dropstats(FAR struct forward_s *fwd)
*
* Parameters:
* dev The structure of the network driver that caused the interrupt
* conn An instance of the UDP connection structure cast to void *
* conn An instance of the forwarding structure cast to void *
* pvpriv An instance of struct forward_s cast to void*
* flags Set of events describing why the callback was invoked
*
@ -249,9 +211,8 @@ static void udp_dropstats(FAR struct forward_s *fwd)
*
****************************************************************************/
static uint16_t udp_forward_interrupt(FAR struct net_driver_s *dev,
FAR void *conn, FAR void *pvpriv,
uint16_t flags)
static uint16_t ipfwd_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;
@ -271,7 +232,7 @@ static uint16_t udp_forward_interrupt(FAR struct net_driver_s *dev,
/* Terminate the transfer with an error. */
nwarn("WARNING: Network is down... Dropping\n");
udp_dropstats(fwd);
ipfwd_dropstats(fwd);
}
/* Check if the outgoing packet is available. It may have been claimed
@ -280,7 +241,7 @@ static uint16_t udp_forward_interrupt(FAR struct net_driver_s *dev,
* we will just have to wait for the next polling cycle.
*/
else if (dev->d_sndlen > 0 || (flags & UDP_NEWDATA) != 0)
else if (dev->d_sndlen > 0 || (flags & IPFWD_NEWDATA) != 0)
{
/* Another thread has beat us sending data or the buffer is busy,
* Wait for the next polling cycle and check again.
@ -311,7 +272,7 @@ static uint16_t udp_forward_interrupt(FAR struct net_driver_s *dev,
* will be replaced with an ARP request or Neighbor Solicitation.
*/
if (!udp_forward_addrchk(fwd))
if (!ipfwd_addrchk(fwd))
{
return flags;
}
@ -323,7 +284,7 @@ static uint16_t udp_forward_interrupt(FAR struct net_driver_s *dev,
fwd->f_cb->priv = NULL;
fwd->f_cb->event = NULL;
udp_callback_free(dev, &fwd->f_conn.udp, fwd->f_cb);
devif_conn_callback_free(dev, fwd->f_cb, NULL);
/* Free any IOBs */
@ -345,16 +306,16 @@ static uint16_t udp_forward_interrupt(FAR struct net_driver_s *dev,
****************************************************************************/
/****************************************************************************
* Name: udp_forward
* Name: ipfwd_forward
*
* Description:
* Called by the IP forwarding logic when an UDP packet is received on
* one network device, but must be forwarded on another network device.
* Called by the IP forwarding logic when a packet is received on one
* network device, but must be forwarded on another network device.
*
* Set up to forward the UDP packet on the specified device. This
* function will set up a send "interrupt" handler that will perform the
* actual send asynchronously and must return without waiting for the
* send to complete.
* Set up to forward the packet on the specified device. This function
* will set up a send "interrupt" handler that will perform the actual
* send asynchronously and must return without waiting for the send to
* complete.
*
* Input Parameters:
* fwd - An initialized instance of the common forwarding structure that
@ -367,18 +328,18 @@ static uint16_t udp_forward_interrupt(FAR struct net_driver_s *dev,
*
****************************************************************************/
int udp_forward(FAR struct forward_s *fwd)
int ipfwd_forward(FAR struct forward_s *fwd)
{
DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL);
/* Set up the callback in the connection */
fwd->f_cb = udp_callback_alloc(fwd->f_dev, &fwd->f_conn.udp);
fwd->f_cb = devif_callback_alloc(fwd->f_dev, NULL);
if (fwd->f_cb != NULL)
{
fwd->f_cb->flags = (UDP_POLL | NETDEV_DOWN);
fwd->f_cb->flags = (IPFWD_POLL | NETDEV_DOWN);
fwd->f_cb->priv = (FAR void *)fwd;
fwd->f_cb->event = udp_forward_interrupt;
fwd->f_cb->event = ipfwd_interrupt;
/* Notify the device driver of the availability of TX data */
@ -389,4 +350,4 @@ int udp_forward(FAR struct forward_s *fwd)
return -EBUSY;
}
#endif /* CONFIG_NET_IPFORWARD && CONFIG_NET_UDP && CONFIG_NETDEV_MULTINIC */
#endif /* CONFIG_NET_IPFORWARD && CONFIG_NETDEV_MULTINIC */

View file

@ -51,9 +51,6 @@
#include "netdev/netdev.h"
#include "utils/utils.h"
#include "sixlowpan/sixlowpan.h"
#include "udp/udp.h"
#include "tcp/tcp.h"
#include "icmp/icmp.h"
#include "ipforward/ipforward.h"
#include "devif/devif.h"
@ -190,55 +187,6 @@ static int ipv4_decr_ttl(FAR struct ipv4_hdr_s *ipv4)
}
#endif
/****************************************************************************
* Name: ipv4_dropstats
*
* Description:
* Update statistics for a dropped packet.
*
* Input Parameters:
* ipv4 - A convenience pointer to the IPv4 header in within the IPv4
* packet to be dropped.
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_NET_STATISTICS
static void ipv4_dropstats(FAR struct ipv4_hdr_s *ipv4)
{
switch (ipv4->proto)
{
#ifdef CONFIG_NET_TCP
case IP_PROTO_TCP:
g_netstats.tcp.drop++;
break;
#endif
#ifdef CONFIG_NET_UDP
case IP_PROTO_UDP:
g_netstats.udp.drop++;
break;
#endif
#ifdef CONFIG_NET_ICMP
case IP_PROTO_ICMP:
g_netstats.icmp.drop++;
break;
#endif
default:
g_netstats.ipv4.protoerr++;
break;
}
g_netstats.ipv4.drop++;
}
#else
# define ipv4_dropstats(ipv4)
#endif
/****************************************************************************
* Name: ipv4_dev_forward
*
@ -366,51 +314,9 @@ static int ipv4_dev_forward(FAR struct net_driver_s *dev,
goto errout_with_iobchain;
}
/* 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 (ipv4->proto)
{
#ifdef CONFIG_NET_TCP
case IP_PROTO_TCP:
{
/* Forward a TCP packet. */
ret = tcp_forward(fwd);
}
break;
#endif
#ifdef CONFIG_NET_UDP
case IP_PROTO_UDP:
{
/* Forward a UDP packet */
ret = udp_forward(fwd);
}
break;
#endif
#ifdef CONFIG_NET_ICMP
case IP_PROTO_ICMP:
{
/* Forward an ICMP packet */
ret = icmp_forward(fwd);
}
break;
#endif
default:
nwarn("WARNING: Unrecognized proto: %u\n", ipv4->proto);
ret = -EPROTONOSUPPORT;
break;
}
/* Then set up to forward the packet according to the protocol. */
ret = ipfwd_forward(fwd);
if (ret >= 0)
{
dev->d_len = 0;

View file

@ -50,11 +50,8 @@
#include "netdev/netdev.h"
#include "sixlowpan/sixlowpan.h"
#include "udp/udp.h"
#include "tcp/tcp.h"
#include "icmpv6/icmpv6.h"
#include "ipforward/ipforward.h"
#include "devif/devif.h"
#include "ipforward/ipforward.h"
#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_IPv6)
@ -183,55 +180,6 @@ static int ipv6_decr_ttl(FAR struct ipv6_hdr_s *ipv6)
}
#endif
/****************************************************************************
* Name: ipv6_dropstats
*
* Description:
* Update statistics for a dropped packet.
*
* Input Parameters:
* ipv6 - A convenience pointer to the IPv6 header in within the IPv6
* packet to be dropped.
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_NET_STATISTICS
static void ipv6_dropstats(FAR struct ipv6_hdr_s *ipv6)
{
switch (ipv6->proto)
{
#ifdef CONFIG_NET_TCP
case IP_PROTO_TCP:
g_netstats.tcp.drop++;
break;
#endif
#ifdef CONFIG_NET_UDP
case IP_PROTO_UDP:
g_netstats.udp.drop++;
break;
#endif
#ifdef CONFIG_NET_ICMPv6
case IP_PROTO_ICMP6:
g_netstats.icmpv6.drop++;
break;
#endif
default:
g_netstats.ipv6.protoerr++;
break;
}
g_netstats.ipv6.drop++;
}
#else
# define ipv6_dropstats(ipv6)
#endif
/****************************************************************************
* Name: ipv6_packet_conversion
*
@ -477,58 +425,16 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev,
goto errout_with_iobchain;
}
/* 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.
*/
/* Then set up to forward the packet according to the protocol. */
switch (ipv6->proto)
ret = ipfwd_forward(fwd);
if (ret >= 0)
{
#ifdef CONFIG_NET_TCP
case IP_PROTO_TCP:
{
/* Forward a TCP packet. */
ret = tcp_forward(fwd);
}
break;
#endif
#ifdef CONFIG_NET_UDP
case IP_PROTO_UDP:
{
/* Forward a UDP packet */
ret = udp_forward(fwd);
}
break;
#endif
#ifdef CONFIG_NET_ICMPv6
case IP_PROTO_ICMP6:
{
/* Forward an ICMPv6 packet */
ret = icmpv6_forward(fwd);
}
break;
#endif
default:
nwarn("WARNING: Unrecognized proto: %u\n", ipv6->proto);
ret = -EPROTONOSUPPORT;
break;
dev->d_len = 0;
return OK;
}
}
if (ret >= 0)
{
dev->d_len = 0;
return OK;
}
errout_with_iobchain:
if (fwd != NULL && fwd->f_iob != NULL)
{

View file

@ -60,14 +60,6 @@ NET_CSRCS += tcp_conn.c tcp_seqno.c tcp_devpoll.c tcp_finddev.c tcp_timer.c
NET_CSRCS += tcp_send.c tcp_input.c tcp_appsend.c tcp_listen.c
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
ifeq ($(CONFIG_NET_TCP_WRITE_BUFFERS),y)

View file

@ -794,37 +794,6 @@ int tcp_accept_connection(FAR struct net_driver_s *dev,
void tcp_send(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
uint16_t flags, uint16_t len);
/****************************************************************************
* 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
* send to complete.
*
* Input Parameters:
* domain - Either PF_INET or PF_INET6
* fwd - An initialized instance of the common forwarding structure
* that includes everything needed to perform the forwarding
* operation.
*
* Returned Value:
* Zero is returned if the packet was successfully forwarded; A negated
* errno value is returned if the packet is not forwardable. In that
* latter case, the caller should free the IOB list and drop the packet.
*
****************************************************************************/
#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_IPv6) && \
defined(CONFIG_NETDEV_MULTINIC)
struct forward_s; /* Forward reference */
int tcp_forward(FAR struct forward_s *fwd);
#endif
/****************************************************************************
* Name: tcp_reset
*

View file

@ -1,443 +0,0 @@
/****************************************************************************
* net/tcp/tcp_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 <errno.h>
#include <debug.h>
#include <net/if.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/ip.h>
#include <nuttx/net/netstats.h>
#include "ipforward/ipforward.h"
#include "devif/devif.h"
#include "netdev/netdev.h"
#include "arp/arp.h"
#include "neighbor/neighbor.h"
#include "tcp/tcp.h"
#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_TCP) && \
defined(CONFIG_NETDEV_MULTINIC)
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* 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_domain == PF_INET)
{
/* Select the IPv4 domain */
tcp_ipv4_select(fwd->f_dev);
}
else /* if (conn->domain == PF_INET6) */
{
/* Select the IPv6 domain */
DEBUGASSERT(fwd->f_conn.tcp.domain == PF_INET6);
tcp_ipv6_select(fwd->f_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:
* true - The Ethernet MAC address is in the ARP or Neighbor table (OR
* the network device is not Ethernet).
*
* 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;
/* REVISIT: Could the MAC address not also be in a routing table? */
#ifdef CONFIG_NET_MULTILINK
if (fwd->f_dev->d_lltype != NET_LL_ETHERNET)
{
return true;
}
#endif
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (fwd->f_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_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 && fwd->f_iob != NULL && fwd->f_dev != 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(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 */
ipfwd_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
* send to complete.
*
* Input Parameters:
* fwd - An initialized instance of the common forwarding structure that
* includes everything needed to perform the forwarding operation.
*
* Returned Value:
* Zero is returned if the packet was successfully forwarded; A negated
* errno value is returned if the packet is not forwardable. In that
* latter case, the caller should free the IOB list and drop the packet.
*
****************************************************************************/
int tcp_forward(FAR struct forward_s *fwd)
{
FAR struct tcp_conn_s *conn = &fwd->f_conn.tcp;
FAR union fwd_iphdr_u *iphdr;
DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL);
/* Set up some minimal connection structure so that we appear to be a
* real TCP connection.
*/
conn->dev = fwd->f_dev;
iphdr = FWD_HEADER(fwd);
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (fwd->f_domain == PF_INET)
#endif
{
FAR struct ipv4_hdr_s *ipv4 = &iphdr->ipv4.l2;
FAR struct tcp_hdr_s *tcp = &iphdr->ipv4.l3.tcp;
#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 = &iphdr->ipv6.l2;
FAR struct tcp_hdr_s *tcp = &iphdr->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 */

View file

@ -48,14 +48,6 @@ NET_CSRCS += udp_netpoll.c
endif
endif
# IP forwarding
ifeq ($(CONFIG_NET_IPFORWARD),y)
ifeq ($(CONFIG_NETDEV_MULTINIC),y)
NET_CSRCS += udp_forward.c
endif
endif
# Transport layer
NET_CSRCS += udp_conn.c udp_devpoll.c udp_send.c udp_input.c udp_finddev.c

View file

@ -428,35 +428,6 @@ FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn);
uint16_t udp_callback(FAR struct net_driver_s *dev,
FAR struct udp_conn_s *conn, uint16_t flags);
/****************************************************************************
* Name: udp_forward
*
* Description:
* Called by the IP forwarding logic when an UDP packet is received on
* one network device, but must be forwarded on another network device.
*
* Set up to forward the UDP packet on the specified device. This
* function will set up a send "interrupt" handler that will perform the
* actual send asynchronously and must return without waiting for the
* send to complete.
*
* Input Parameters:
* fwd - An initialized instance of the common forwarding structure that
* includes everything needed to perform the forwarding operation.
*
* Returned Value:
* Zero is returned if the packet was successfully forwarded; A negated
* errno value is returned if the packet is not forwardable. In that
* latter case, the caller should free the IOB list and drop the packet.
*
****************************************************************************/
#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_IPv6) && \
defined(CONFIG_NETDEV_MULTINIC)
struct forward_s; /* Forward reference */
int udp_forward(FAR struct forward_s *fwd);
#endif
/****************************************************************************
* Name: psock_udp_send
*