IP forwading: Add optional support to forward broadcast and multicast packets.

This commit is contained in:
Gregory Nutt 2017-07-06 07:26:01 -06:00
parent 24e9647156
commit 04716a65a5
7 changed files with 563 additions and 248 deletions

View File

@ -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

View File

@ -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.
*

View File

@ -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 */

View File

@ -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 */

View File

@ -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. */

View File

@ -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 */

View File

@ -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);
}