IP forwading: Add optional support to forward broadcast and multicast packets.
This commit is contained in:
parent
24e9647156
commit
04716a65a5
10
net/Kconfig
10
net/Kconfig
@ -293,10 +293,18 @@ config NET_IPFORWARD
|
||||
that are not supported by this platform will be forwarded to the
|
||||
appropriate network device. Routing table support may be required.
|
||||
|
||||
config NET_IPFORWARD_BROADCAST
|
||||
bool "Forward broadcast/multicast packets"
|
||||
default n
|
||||
depends on NET_IPFORWARD && NETDEV_MULTINIC
|
||||
---help---
|
||||
If selected, broadcast packets received on one network device will
|
||||
be forwarded though other network devices.
|
||||
|
||||
config NET_IPFORWARD_NSTRUCT
|
||||
int "Number of pre-allocated forwarding structures"
|
||||
default 4
|
||||
depends on NET_IPFORWARD && CONFIG_NETDEV_MULTINIC
|
||||
depends on NET_IPFORWARD && NETDEV_MULTINIC
|
||||
---help---
|
||||
When packets are forwarded from on device to another, a structure
|
||||
must be allocated to hold the state of forwarding across several
|
||||
|
@ -425,66 +425,6 @@ uint16_t devif_conn_event(FAR struct net_driver_s *dev, FAR void *pvconn,
|
||||
uint16_t devif_dev_event(FAR struct net_driver_s *dev, void *pvconn,
|
||||
uint16_t flags);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_forward
|
||||
*
|
||||
* Description:
|
||||
* This function is called from ipv4_input when a packet is received that
|
||||
* is not destined for us. In this case, the packet may need to be
|
||||
* forwarded to another device (or sent back out the same device)
|
||||
* depending configuration, routing table information, and the IPv4
|
||||
* networks served by various network devices.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The device on which the packet was received and which contains
|
||||
* the IPv4 packet.
|
||||
* ipv4 - A convenience pointer to the IPv4 header in within the IPv4
|
||||
* packet
|
||||
*
|
||||
* On input:
|
||||
* - dev->d_buf holds the received packet.
|
||||
* - dev->d_len holds the length of the received packet MINUS the
|
||||
* size of the L1 header. That was subtracted out by ipv4_input.
|
||||
* - ipv4 points to the IPv4 header with dev->d_buf.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned if the packet was successfully forward; A negated
|
||||
* errno value is returned if the packet is not forwardable. In that
|
||||
* latter case, the caller (ipv4_input()) should drop the packet.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_IPv4)
|
||||
int ipv4_forward(FAR struct net_driver_s *dev, FAR struct ipv4_hdr_s *ipv4);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv6_forward
|
||||
*
|
||||
* Description:
|
||||
* This function is called from ipv6_input when a packet is received that
|
||||
* is not destined for us. In this case, the packet may need to be
|
||||
* forwarded to another device (or sent back out the same device)
|
||||
* depending configuration, routing table information, and the IPv6
|
||||
* networks served by various network devices.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The device on which the packet was received and which contains
|
||||
* the IPv6 packet.
|
||||
* ipv6 - A convenience pointer to the IPv6 header in within the IPv6
|
||||
* packet
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned if the packet was successfully forward; A negated
|
||||
* errno value is returned if the packet is not forwardable. In that
|
||||
* latter case, the caller (ipv6_input()) should drop the packet.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_IPv6)
|
||||
int ipv6_forward(FAR struct net_driver_s *dev, FAR struct ipv6_hdr_s *ipv6);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Send data on the current connection.
|
||||
*
|
||||
|
@ -55,7 +55,13 @@
|
||||
#include "icmpv6/icmpv6.h"
|
||||
|
||||
#undef HAVE_FWDALLOC
|
||||
#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NETDEV_MULTINIC)
|
||||
#ifdef CONFIG_NET_IPFORWARD
|
||||
|
||||
/* Must of the logic in this header file applies only for configurations
|
||||
* will multiple network devices.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_NETDEV_MULTINIC
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
@ -205,6 +211,68 @@ FAR struct forward_s *ip_forward_alloc(void);
|
||||
|
||||
void ip_forward_free(FAR struct forward_s *fwd);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_forward_broadcast
|
||||
*
|
||||
* Description:
|
||||
* This function is called from ipv4_input when a broadcast or multicast
|
||||
* packet is received. If CONFIG_NET_IPFORWARD_BROADCAST is enabled, this
|
||||
* function will forward the broadcast packet to other networks through
|
||||
* other network devices.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The device on which the packet was received and which contains
|
||||
* the IPv4 packet.
|
||||
* ipv4 - A convenience pointer to the IPv4 header in within the IPv4
|
||||
* packet
|
||||
*
|
||||
* On input:
|
||||
* - dev->d_buf holds the received packet.
|
||||
* - dev->d_len holds the length of the received packet MINUS the
|
||||
* size of the L1 header. That was subtracted out by ipv4_input.
|
||||
* - ipv4 points to the IPv4 header with dev->d_buf.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_IPFORWARD_BROADCAST
|
||||
void ipv4_forward_broadcast(FAR struct net_driver_s *dev,
|
||||
FAR struct ipv4_hdr_s *ipv4);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv6_forward_broadcast
|
||||
*
|
||||
* Description:
|
||||
* This function is called from ipv6_input when a broadcast or multicast
|
||||
* packet is received. If CONFIG_NET_IPFORWARD_BROADCAST is enabled, this
|
||||
* function will forward the broadcast packet to other networks through
|
||||
* other network devices.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The device on which the packet was received and which contains
|
||||
* the IPv6 packet.
|
||||
* ipv6 - A convenience pointer to the IPv6 header in within the IPv6
|
||||
* packet
|
||||
*
|
||||
* On input:
|
||||
* - dev->d_buf holds the received packet.
|
||||
* - dev->d_len holds the length of the received packet MINUS the
|
||||
* size of the L1 header. That was subtracted out by ipv6_input.
|
||||
* - ipv6 points to the IPv6 header with dev->d_buf.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_IPFORWARD_BROADCAST
|
||||
void ipv6_forward_broadcast(FAR struct net_driver_s *dev,
|
||||
FAR struct ipv6_hdr_s *ipv6);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devif_forward
|
||||
*
|
||||
@ -225,5 +293,67 @@ void ip_forward_free(FAR struct forward_s *fwd);
|
||||
|
||||
void devif_forward(FAR struct forward_s *fwd);
|
||||
|
||||
#endif /* CONFIG_NET_IPFORWARD && CONFIG_NETDEV_MULTINIC */
|
||||
#endif /* CONFIG_NETDEV_MULTINIC */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_forward
|
||||
*
|
||||
* Description:
|
||||
* This function is called from ipv4_input when a packet is received that
|
||||
* is not destined for us. In this case, the packet may need to be
|
||||
* forwarded to another device (or sent back out the same device)
|
||||
* depending configuration, routing table information, and the IPv4
|
||||
* networks served by various network devices.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The device on which the packet was received and which contains
|
||||
* the IPv4 packet.
|
||||
* ipv4 - A convenience pointer to the IPv4 header in within the IPv4
|
||||
* packet
|
||||
*
|
||||
* On input:
|
||||
* - dev->d_buf holds the received packet.
|
||||
* - dev->d_len holds the length of the received packet MINUS the
|
||||
* size of the L1 header. That was subtracted out by ipv4_input.
|
||||
* - ipv4 points to the IPv4 header with dev->d_buf.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned if the packet was successfully forward; A negated
|
||||
* errno value is returned if the packet is not forwardable. In that
|
||||
* latter case, the caller (ipv4_input()) should drop the packet.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
int ipv4_forward(FAR struct net_driver_s *dev, FAR struct ipv4_hdr_s *ipv4);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv6_forward
|
||||
*
|
||||
* Description:
|
||||
* This function is called from ipv6_input when a packet is received that
|
||||
* is not destined for us. In this case, the packet may need to be
|
||||
* forwarded to another device (or sent back out the same device)
|
||||
* depending configuration, routing table information, and the IPv6
|
||||
* networks served by various network devices.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The device on which the packet was received and which contains
|
||||
* the IPv6 packet.
|
||||
* ipv6 - A convenience pointer to the IPv6 header in within the IPv6
|
||||
* packet
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned if the packet was successfully forward; A negated
|
||||
* errno value is returned if the packet is not forwardable. In that
|
||||
* latter case, the caller (ipv6_input()) should drop the packet.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
int ipv6_forward(FAR struct net_driver_s *dev, FAR struct ipv6_hdr_s *ipv6);
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_NET_IPFORWARD */
|
||||
#endif /* __NET_DEVIF_IP_FORWARD_H */
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include <nuttx/net/netstats.h>
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
#include "utils/utils.h"
|
||||
#include "sixlowpan/sixlowpan.h"
|
||||
#include "udp/udp.h"
|
||||
#include "tcp/tcp.h"
|
||||
@ -122,6 +123,119 @@ static int ipv4_hdrsize(FAR struct ipv4_hdr_s *ipv4)
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_decr_ttl
|
||||
*
|
||||
* Description:
|
||||
* Decrement the IPv4 TTL (time to live value). TTL field is set by the
|
||||
* sender of the packet and reduced by every router on the route to its
|
||||
* destination. If the TTL field reaches zero before the datagram arrives
|
||||
* at its destination, then the datagram is discarded and an ICMP error
|
||||
* packet (11 - Time Exceeded) is sent back to the sender.
|
||||
*
|
||||
* The purpose of the TTL field is to avoid a situation in which an
|
||||
* undeliverable datagram keeps circulating on an Internet system, and
|
||||
* such a system eventually becoming swamped by such "immortals".
|
||||
*
|
||||
* Input Parameters:
|
||||
* ipv4 - A pointer to the IPv4 header in within the IPv4 packet to be
|
||||
* forwarded.
|
||||
*
|
||||
* Returned Value:
|
||||
* The new TTL value is returned. A value <= 0 means the hop limit has
|
||||
* expired.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ipv4_decr_ttl(FAR struct ipv4_hdr_s *ipv4)
|
||||
{
|
||||
uint16_t sum;
|
||||
int ttl = (int)ipv4->ttl - 1;
|
||||
|
||||
if (ttl <= 0)
|
||||
{
|
||||
#ifdef CONFIG_NET_ICMP
|
||||
/* Return an ICMP error packet back to the sender. */
|
||||
#warning Missing logic
|
||||
#endif
|
||||
|
||||
/* Return zero which must cause the packet to be dropped */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save the updated TTL value */
|
||||
|
||||
ipv4->ttl = ttl;
|
||||
|
||||
/* Re-calculate the IPv4 checksum. This checksum is the Internet checksum
|
||||
* of the 20 bytes of the IPv4 header. This checksum will be different
|
||||
* because we just modify the IPv4 TTL.
|
||||
*/
|
||||
|
||||
ipv4->ipchksum = 0;
|
||||
sum = chksum(0, (FAR const uint8_t *)ipv4, IPv4_HDRLEN);
|
||||
if (sum == 0)
|
||||
{
|
||||
sum = 0xffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
sum = htons(sum);
|
||||
}
|
||||
|
||||
ipv4->ipchksum = ~sum;
|
||||
return ttl;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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:
|
||||
break;
|
||||
}
|
||||
|
||||
g_netstats.ipv4.drop++;
|
||||
}
|
||||
#else
|
||||
# define ipv4_dropstats(ipv4)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_dev_forward
|
||||
*
|
||||
@ -210,9 +324,22 @@ static int ipv4_dev_forward(FAR struct net_driver_s *dev,
|
||||
goto errout_with_fwd;
|
||||
}
|
||||
|
||||
memcpy(&fwd->f_hdr, ipv4, hdrsize);
|
||||
memcpy(&fwd->f_hdr.ipv4, ipv4, hdrsize);
|
||||
fwd->f_hdrsize = hdrsize;
|
||||
|
||||
/* Decrement the TTL in the copy of the IPv4 header (retaining the
|
||||
* original TTL in the source). If it decrements to zero, then drop
|
||||
* the packet.
|
||||
*/
|
||||
|
||||
ret = ipv4_decr_ttl(&fwd->f_hdr.ipv4.l2);
|
||||
if (ret < 1)
|
||||
{
|
||||
nwarn("WARNING: Hop limit exceeded... Dropping!\n");
|
||||
ret = -EMULTIHOP;
|
||||
goto errout_with_fwd;
|
||||
}
|
||||
|
||||
/* Use the L2 + L3 header size to determine start and size of the data
|
||||
* payload.
|
||||
*
|
||||
@ -317,103 +444,59 @@ errout:
|
||||
#endif /* CONFIG_NETDEV_MULTINIC */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_decr_ttl
|
||||
* Name: ipv4_forward_callback
|
||||
*
|
||||
* Description:
|
||||
* Decrement the IPv4 TTL (time to live value). TTL field is set by the
|
||||
* sender of the packet and reduced by every router on the route to its
|
||||
* destination. If the TTL field reaches zero before the datagram arrives
|
||||
* at its destination, then the datagram is discarded and an ICMP error
|
||||
* packet (11 - Time Exceeded) is sent back to the sender.
|
||||
*
|
||||
* The purpose of the TTL field is to avoid a situation in which an
|
||||
* undeliverable datagram keeps circulating on an Internet system, and
|
||||
* such a system eventually becoming swamped by such "immortals".
|
||||
* This function is a callback from netdev_foreach. It implements the
|
||||
* the broadcase forwarding action for each network device (other than, of
|
||||
* course, the device that received the packet).
|
||||
*
|
||||
* Input Parameters:
|
||||
* ipv4 - A pointer to the IPv4 header in within the IPv4 packet to be
|
||||
* forwarded.
|
||||
* dev - The device on which the packet was received and which contains
|
||||
* the IPv4 packet.
|
||||
* ipv4 - A convenience pointer to the IPv4 header in within the IPv4
|
||||
* packet
|
||||
*
|
||||
* Returned Value:
|
||||
* The new TTL value is returned. A value <= 0 means the hop limit has
|
||||
* expired.
|
||||
* Typically returns zero (meaning to continue the enumeration), but will
|
||||
* return a non-zero to stop the enumeration if an error occurs.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ipv4_decr_ttl(FAR struct ipv4_hdr_s *ipv4)
|
||||
#if defined(CONFIG_NET_IPFORWARD_BROADCAST) && \
|
||||
defined(CONFIG_NETDEV_MULTINIC)
|
||||
int ipv4_forward_callback(FAR struct net_driver_s *fwddev, FAR void *arg)
|
||||
{
|
||||
int ttl = (int)ipv4->ttl - 1;
|
||||
FAR struct net_driver_s *dev = (FAR struct net_driver_s *)arg;
|
||||
FAR struct ipv4_hdr_s *ipv4;
|
||||
int ret;
|
||||
|
||||
if (ttl <= 0)
|
||||
{
|
||||
#ifdef CONFIG_NET_ICMP
|
||||
/* Return an ICMP error packet back to the sender. */
|
||||
#warning Missing logic
|
||||
#endif
|
||||
DEBUGASSERT(fwddev != NULL && dev != NULL && dev->d_buf != NULL);
|
||||
|
||||
/* Return zero which must cause the packet to be dropped */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save the updated TTL value */
|
||||
|
||||
ipv4->ttl = ttl;
|
||||
|
||||
/* NOTE: We do not have to recalculate the IPv4 checksum because (1) the
|
||||
* IPv4 header does not include a checksum itself and (2) the TTL is not
|
||||
* included in the sum for the TCP and UDP headers.
|
||||
/* Check if we are forwarding on the same device that we received the
|
||||
* packet from.
|
||||
*/
|
||||
|
||||
return ttl;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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)
|
||||
if (fwddev != dev)
|
||||
{
|
||||
#ifdef CONFIG_NET_TCP
|
||||
case IP_PROTO_TCP:
|
||||
g_netstats.tcp.drop++;
|
||||
break;
|
||||
#endif
|
||||
/* Recover the pointer to the IPv4 header in the receiving device's
|
||||
* d_buf.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
case IP_PROTO_UDP:
|
||||
g_netstats.udp.drop++;
|
||||
break;
|
||||
#endif
|
||||
ipv4 = (FAR struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)];
|
||||
|
||||
#ifdef CONFIG_NET_ICMP
|
||||
case IP_PROTO_ICMP:
|
||||
g_netstats.icmp.drop++;
|
||||
break;
|
||||
#endif
|
||||
/* Send the packet asynchrously on the forwarding device. */
|
||||
|
||||
default:
|
||||
break;
|
||||
ret = ipv4_dev_forward(dev, fwddev, ipv4);
|
||||
if (ret < 0)
|
||||
{
|
||||
nwarn("WARNING: ipv4_dev_forward failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
g_netstats.ipv4.drop++;
|
||||
return OK;
|
||||
}
|
||||
#else
|
||||
# define ipv4_dropstats(ipv4)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
@ -458,24 +541,6 @@ int ipv4_forward(FAR struct net_driver_s *dev, FAR struct ipv4_hdr_s *ipv4)
|
||||
FAR struct net_driver_s *fwddev;
|
||||
int ret;
|
||||
|
||||
/* Decrement the TTL. If it decrements to zero, then drop the packet */
|
||||
|
||||
ret = ipv4_decr_ttl(ipv4);
|
||||
if (ret < 1)
|
||||
{
|
||||
nwarn("WARNING: Hop limit exceeded... Dropping!\n");
|
||||
ret = -EMULTIHOP;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
/* Re-calculate the IPv4 checksum. This checksum is the Internet checksum
|
||||
* of the 20 bytes of the IPv4 header. This checksum will be different
|
||||
* because we just modify the IPv4 TTL.
|
||||
*/
|
||||
|
||||
ipv4->ipchksum = 0;
|
||||
ipv4->ipchksum = ~ipv4_chksum(dev);
|
||||
|
||||
/* Search for a device that can forward this packet. This is a trivial
|
||||
* search if there is only a single network device (CONFIG_NETDEV_MULTINIC
|
||||
* not defined). But netdev_findby_ipv4addr() will still assure
|
||||
@ -508,7 +573,7 @@ int ipv4_forward(FAR struct net_driver_s *dev, FAR struct ipv4_hdr_s *ipv4)
|
||||
ret = ipv4_dev_forward(dev, fwddev, ipv4);
|
||||
if (ret < 0)
|
||||
{
|
||||
nwarn("WARNING: ipv4_dev_forward faield: %d\n", ret);
|
||||
nwarn("WARNING: ipv4_dev_forward failed: %d\n", ret);
|
||||
goto drop;
|
||||
}
|
||||
}
|
||||
@ -550,4 +615,48 @@ drop:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_forward_broadcast
|
||||
*
|
||||
* Description:
|
||||
* This function is called from ipv4_input when a broadcast or multicast
|
||||
* packet is received. If CONFIG_NET_IPFORWARD_BROADCAST is enabled, this
|
||||
* function will forward the broadcast packet to other networks through
|
||||
* other network devices.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The device on which the packet was received and which contains
|
||||
* the IPv4 packet.
|
||||
* ipv4 - A convenience pointer to the IPv4 header in within the IPv4
|
||||
* packet
|
||||
*
|
||||
* On input:
|
||||
* - dev->d_buf holds the received packet.
|
||||
* - dev->d_len holds the length of the received packet MINUS the
|
||||
* size of the L1 header. That was subtracted out by ipv4_input.
|
||||
* - ipv4 points to the IPv4 header with dev->d_buf.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_NET_IPFORWARD_BROADCAST) && \
|
||||
defined(CONFIG_NETDEV_MULTINIC)
|
||||
void ipv4_forward_broadcast(FAR struct net_driver_s *dev,
|
||||
FAR struct ipv4_hdr_s *ipv4)
|
||||
{
|
||||
/* Don't bother if the TTL would expire */
|
||||
|
||||
if (ipv4->ttl > 1)
|
||||
{
|
||||
/* Forward the the broadcast/multicast packet to all devices except,
|
||||
* of course, the device that received the packet.
|
||||
*/
|
||||
|
||||
(void)netdev_foreach(ipv4_forward_callback, dev);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_NET_IPFORWARD && CONFIG_NET_IPv4 */
|
||||
|
@ -99,6 +99,7 @@
|
||||
#include "icmp/icmp.h"
|
||||
#include "igmp/igmp.h"
|
||||
|
||||
#include "devif/ip_forward.h"
|
||||
#include "devif/devif.h"
|
||||
|
||||
/****************************************************************************
|
||||
@ -403,6 +404,11 @@ int ipv4_input(FAR struct net_driver_s *dev)
|
||||
net_ipv4addr_cmp(net_ip4addr_conv32(ipv4->destipaddr),
|
||||
INADDR_BROADCAST))
|
||||
{
|
||||
#ifdef CONFIG_NET_IPFORWARD_BROADCAST
|
||||
/* Forward broadcast packets */
|
||||
|
||||
ipv4_forward_broadcast(dev, ipv4);
|
||||
#endif
|
||||
return udp_ipv4_input(dev);
|
||||
}
|
||||
|
||||
@ -430,7 +436,15 @@ int ipv4_input(FAR struct net_driver_s *dev)
|
||||
|
||||
#ifdef CONFIG_NET_IGMP
|
||||
in_addr_t destip = net_ip4addr_conv32(ipv4->destipaddr);
|
||||
if (igmp_grpfind(dev, &destip) == NULL)
|
||||
if (igmp_grpfind(dev, &destip) != NULL)
|
||||
{
|
||||
#ifdef CONFIG_NET_IPFORWARD_BROADCAST
|
||||
/* Forward multicast packets */
|
||||
|
||||
ipv4_forward_broadcast(dev, ipv4);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* No.. The packet is not destined for us. */
|
||||
|
@ -186,6 +186,106 @@ static int ipv6_hdrsize(FAR struct ipv6_hdr_s *ipv6)
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv6_decr_ttl
|
||||
*
|
||||
* Description:
|
||||
* Decrement the IPv6 TTL (time to live value). TTL field is set by the
|
||||
* sender of the packet and reduced by every router on the route to its
|
||||
* destination. If the TTL field reaches zero before the datagram arrives
|
||||
* at its destination, then the datagram is discarded and an ICMP error
|
||||
* packet (11 - Time Exceeded) is sent back to the sender.
|
||||
*
|
||||
* The purpose of the TTL field is to avoid a situation in which an
|
||||
* undeliverable datagram keeps circulating on an Internet system, and
|
||||
* such a system eventually becoming swamped by such "immortals".
|
||||
*
|
||||
* Input Parameters:
|
||||
* ipv6 - A pointer to the IPv6 header in within the IPv6 packet to be
|
||||
* forwarded.
|
||||
*
|
||||
* Returned Value:
|
||||
* The new TTL value is returned. A value <= 0 means the hop limit has
|
||||
* expired.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ipv6_decr_ttl(FAR struct ipv6_hdr_s *ipv6)
|
||||
{
|
||||
int ttl = (int)ipv6->ttl - 1;
|
||||
|
||||
if (ttl <= 0)
|
||||
{
|
||||
#ifdef CONFIG_NET_ICMPv6
|
||||
/* Return an ICMPv6 error packet back to the sender. */
|
||||
#warning Missing logic
|
||||
#endif
|
||||
|
||||
/* Return zero which must cause the packet to be dropped */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save the updated TTL value */
|
||||
|
||||
ipv6->ttl = ttl;
|
||||
|
||||
/* NOTE: We do not have to recalculate the IPv6 checksum because (1) the
|
||||
* IPv6 header does not include a checksum itself and (2) the TTL is not
|
||||
* included in the sum for the TCP and UDP headers.
|
||||
*/
|
||||
|
||||
return ttl;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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:
|
||||
break;
|
||||
}
|
||||
|
||||
g_netstats.ipv6.drop++;
|
||||
}
|
||||
#else
|
||||
# define ipv6_dropstats(ipv6)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv6_dev_forward
|
||||
*
|
||||
@ -280,9 +380,22 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev,
|
||||
goto errout_with_fwd;
|
||||
}
|
||||
|
||||
memcpy(&fwd->f_hdr, ipv6, hdrsize);
|
||||
memcpy(&fwd->f_hdr.ipv6, ipv6, hdrsize);
|
||||
fwd->f_hdrsize = hdrsize;
|
||||
|
||||
/* Decrement the TTL in the copy of the IPv6 header (retaining the
|
||||
* original TTL in the source). If it decrements to zero, then drop
|
||||
* the packet.
|
||||
*/
|
||||
|
||||
ret = ipv6_decr_ttl(&fwd->f_hdr.ipv6.l2);
|
||||
if (ret < 1)
|
||||
{
|
||||
nwarn("WARNING: Hop limit exceeded... Dropping!\n");
|
||||
ret = -EMULTIHOP;
|
||||
goto errout_with_fwd;
|
||||
}
|
||||
|
||||
/* Use the L2 + L3 header size to determine start and size of the data
|
||||
* payload.
|
||||
*
|
||||
@ -398,103 +511,59 @@ errout:
|
||||
#endif /* CONFIG_NETDEV_MULTINIC */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv6_decr_ttl
|
||||
* Name: ipv6_forward_callback
|
||||
*
|
||||
* Description:
|
||||
* Decrement the IPv6 TTL (time to live value). TTL field is set by the
|
||||
* sender of the packet and reduced by every router on the route to its
|
||||
* destination. If the TTL field reaches zero before the datagram arrives
|
||||
* at its destination, then the datagram is discarded and an ICMP error
|
||||
* packet (11 - Time Exceeded) is sent back to the sender.
|
||||
*
|
||||
* The purpose of the TTL field is to avoid a situation in which an
|
||||
* undeliverable datagram keeps circulating on an Internet system, and
|
||||
* such a system eventually becoming swamped by such "immortals".
|
||||
* This function is a callback from netdev_foreach. It implements the
|
||||
* the broadcase forwarding action for each network device (other than, of
|
||||
* course, the device that received the packet).
|
||||
*
|
||||
* Input Parameters:
|
||||
* ipv6 - A pointer to the IPv6 header in within the IPv6 packet to be
|
||||
* forwarded.
|
||||
* dev - The device on which the packet was received and which contains
|
||||
* the IPv6 packet.
|
||||
* ipv6 - A convenience pointer to the IPv6 header in within the IPv6
|
||||
* packet
|
||||
*
|
||||
* Returned Value:
|
||||
* The new TTL value is returned. A value <= 0 means the hop limit has
|
||||
* expired.
|
||||
* Typically returns zero (meaning to continue the enumeration), but will
|
||||
* return a non-zero to stop the enumeration if an error occurs.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ipv6_decr_ttl(FAR struct ipv6_hdr_s *ipv6)
|
||||
#if defined(CONFIG_NET_IPFORWARD_BROADCAST) && \
|
||||
defined(CONFIG_NETDEV_MULTINIC)
|
||||
int ipv6_forward_callback(FAR struct net_driver_s *fwddev, FAR void *arg)
|
||||
{
|
||||
int ttl = (int)ipv6->ttl - 1;
|
||||
FAR struct net_driver_s *dev = (FAR struct net_driver_s *)arg;
|
||||
FAR struct ipv6_hdr_s *ipv6;
|
||||
int ret;
|
||||
|
||||
if (ttl <= 0)
|
||||
{
|
||||
#ifdef CONFIG_NET_ICMPv6
|
||||
/* Return an ICMPv6 error packet back to the sender. */
|
||||
#warning Missing logic
|
||||
#endif
|
||||
DEBUGASSERT(fwddev != NULL && dev != NULL && dev->d_buf != NULL);
|
||||
|
||||
/* Return zero which must cause the packet to be dropped */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save the updated TTL value */
|
||||
|
||||
ipv6->ttl = ttl;
|
||||
|
||||
/* NOTE: We do not have to recalculate the IPv6 checksum because (1) the
|
||||
* IPv6 header does not include a checksum itself and (2) the TTL is not
|
||||
* included in the sum for the TCP and UDP headers.
|
||||
/* Check if we are forwarding on the same device that we received the
|
||||
* packet from.
|
||||
*/
|
||||
|
||||
return ttl;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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)
|
||||
if (fwddev != dev)
|
||||
{
|
||||
#ifdef CONFIG_NET_TCP
|
||||
case IP_PROTO_TCP:
|
||||
g_netstats.tcp.drop++;
|
||||
break;
|
||||
#endif
|
||||
/* Recover the pointer to the IPv6 header in the receiving device's
|
||||
* d_buf.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
case IP_PROTO_UDP:
|
||||
g_netstats.udp.drop++;
|
||||
break;
|
||||
#endif
|
||||
ipv6 = (FAR struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)];
|
||||
|
||||
#ifdef CONFIG_NET_ICMPv6
|
||||
case IP_PROTO_ICMP6:
|
||||
g_netstats.icmpv6.drop++;
|
||||
break;
|
||||
#endif
|
||||
/* Send the packet asynchrously on the forwarding device. */
|
||||
|
||||
default:
|
||||
break;
|
||||
ret = ipv6_dev_forward(dev, fwddev, ipv6);
|
||||
if (ret < 0)
|
||||
{
|
||||
nwarn("WARNING: ipv6_dev_forward failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
g_netstats.ipv6.drop++;
|
||||
return OK;
|
||||
}
|
||||
#else
|
||||
# define ipv6_dropstats(ipv6)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
@ -535,16 +604,6 @@ int ipv6_forward(FAR struct net_driver_s *dev, FAR struct ipv6_hdr_s *ipv6)
|
||||
FAR struct net_driver_s *fwddev;
|
||||
int ret;
|
||||
|
||||
/* Decrement the TTL. If it decrements to zero, then drop the packet */
|
||||
|
||||
ret = ipv6_decr_ttl(ipv6);
|
||||
if (ret < 1)
|
||||
{
|
||||
nwarn("WARNING: Hop limit exceeded... Dropping!\n");
|
||||
ret = -EMULTIHOP;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
/* Search for a device that can forward this packet. This is a trivial
|
||||
* search if there is only a single network device (CONFIG_NETDEV_MULTINIC
|
||||
* not defined). But netdev_findby_ipv6addr() will still assure
|
||||
@ -574,7 +633,7 @@ int ipv6_forward(FAR struct net_driver_s *dev, FAR struct ipv6_hdr_s *ipv6)
|
||||
ret = ipv6_dev_forward(dev, fwddev, ipv6);
|
||||
if (ret < 0)
|
||||
{
|
||||
nwarn("WARNING: ipv6_dev_forward faield: %d\n", ret);
|
||||
nwarn("WARNING: ipv6_dev_forward failed: %d\n", ret);
|
||||
goto drop;
|
||||
}
|
||||
}
|
||||
@ -641,4 +700,48 @@ drop:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv6_forward_broadcast
|
||||
*
|
||||
* Description:
|
||||
* This function is called from ipv6_input when a broadcast or multicast
|
||||
* packet is received. If CONFIG_NET_IPFORWARD_BROADCAST is enabled, this
|
||||
* function will forward the broadcast packet to other networks through
|
||||
* other network devices.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The device on which the packet was received and which contains
|
||||
* the IPv6 packet.
|
||||
* ipv6 - A convenience pointer to the IPv6 header in within the IPv6
|
||||
* packet
|
||||
*
|
||||
* On input:
|
||||
* - dev->d_buf holds the received packet.
|
||||
* - dev->d_len holds the length of the received packet MINUS the
|
||||
* size of the L1 header. That was subtracted out by ipv6_input.
|
||||
* - ipv6 points to the IPv6 header with dev->d_buf.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_NET_IPFORWARD_BROADCAST) && \
|
||||
defined(CONFIG_NETDEV_MULTINIC)
|
||||
void ipv6_forward_broadcast(FAR struct net_driver_s *dev,
|
||||
FAR struct ipv6_hdr_s *ipv6)
|
||||
{
|
||||
/* Don't bother if the TTL would expire */
|
||||
|
||||
if (ipv6->ttl > 1)
|
||||
{
|
||||
/* Forward the the broadcast/multicast packet to all devices except,
|
||||
* of course, the device that received the packet.
|
||||
*/
|
||||
|
||||
(void)netdev_foreach(ipv6_forward_callback, dev);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_NET_IPFORWARD && CONFIG_NET_IPv6 */
|
||||
|
@ -100,6 +100,7 @@
|
||||
#include "icmpv6/icmpv6.h"
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
#include "devif/ip_forward.h"
|
||||
#include "devif/devif.h"
|
||||
|
||||
/****************************************************************************
|
||||
@ -183,6 +184,11 @@ static bool check_destipaddr(FAR struct net_driver_s *dev,
|
||||
|
||||
if (ipv6->destipaddr[0] == HTONS(0xff02))
|
||||
{
|
||||
#ifdef CONFIG_NET_IPFORWARD_BROADCAST
|
||||
/* Forward multicast packets */
|
||||
|
||||
ipv6_forward_broadcast(dev, ipv6);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -322,6 +328,11 @@ int ipv6_input(FAR struct net_driver_s *dev)
|
||||
if (ipv6->proto == IP_PROTO_UDP &&
|
||||
net_ipv6addr_cmp(ipv6->destipaddr, g_ipv6_alloneaddr))
|
||||
{
|
||||
#ifdef CONFIG_NET_IPFORWARD_BROADCAST
|
||||
/* Forward broadcast packets */
|
||||
|
||||
ipv6_forward_broadcast(dev, ipv6);
|
||||
#endif
|
||||
return udp_ipv6_input(dev);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user