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