ICMPv6: Add 6LoWPAN and IP forwarding support.

This commit is contained in:
Gregory Nutt 2017-07-09 11:35:26 -06:00
parent 9db4350097
commit 975473fed8
14 changed files with 366 additions and 31 deletions

View File

@ -310,7 +310,7 @@ void netdriver_loop(void)
else
#endif
{
nwarn("WARNING: Unsupported Ethernet type %u\n", eth->type)
nwarn("WARNING: Unsupported Ethernet type %u\n", eth->type);
}
}
}

View File

@ -481,6 +481,33 @@ cxxtest
postpone running C++ static initializers until NuttX has been
initialized.
ipforward
This is an NSH configuration that includes a simple test of the NuttX
IP forwarding logic using apps/examples/ipforward. That example uses
two TUN network devices to represent two networks. The test then sends
packets from one network destined for the other network. The NuttX IP
forwarding logic will recognize that the received packets are not destined
for it and will forward the logic to the other TUN network. The
application logic then both sends the packets on one network and receives
and verifies the forwarded packet recieved on the other network. The
received packets differ from the sent packets only in that the hop limit
(TTL) has been decremented.
Be default, this test will forward TCP packets. The test can be modified
to support forwarding of ICMPv6 multicast packets with these changes to
the .config file:
-CONFIG_EXAMPLES_IPFORWARD_TCP=y
+CONFIG_EXAMPLES_IPFORWARD_ICMPv6=y
+CONFIG_NET_ICMPv6=y
+CONFIG_NET_ICMPv6_PING=y
+CONFIG_NET_ETHERNET=y
Additional required settings will also be selected when you manually
select the above via 'make menuconfig'.
minibasic
This configuration was used to test the Mini Basic port at

View File

@ -106,9 +106,7 @@ CONFIG_HOST_X86_64=y
CONFIG_SIM_X8664_SYSTEMV=y
# CONFIG_SIM_X8664_MICROSOFT is not set
CONFIG_SIM_WALLTIME=y
CONFIG_SIM_NETDEV=y
CONFIG_SIM_NET_HOST_ROUTE=y
# CONFIG_SIM_NET_BRIDGE is not set
# CONFIG_SIM_NETDEV is not set
# CONFIG_SIM_FRAMEBUFFER is not set
# CONFIG_SIM_SPIFLASH is not set
# CONFIG_SIM_QSPIFLASH is not set
@ -808,6 +806,7 @@ CONFIG_BUILTIN_PROXY_STACKSIZE=1024
# CONFIG_EXAMPLES_HIDKBD is not set
# CONFIG_EXAMPLES_IGMP is not set
CONFIG_EXAMPLES_IPFORWARD=y
CONFIG_EXAMPLES_IPFORWARD_TCP=y
CONFIG_EXAMPLES_IPFORWARD_PRIORITY=100
CONFIG_EXAMPLES_IPFORWARD_STACKSIZE=8192
# CONFIG_EXAMPLES_JSON is not set

View File

@ -171,10 +171,8 @@ static void tun_poll_expiry(int argc, wdparm_t arg, ...);
static int tun_ifup(FAR struct net_driver_s *dev);
static int tun_ifdown(FAR struct net_driver_s *dev);
static int tun_txavail(FAR struct net_driver_s *dev);
#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6)
static int tun_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
#endif
#ifdef CONFIG_NET_IGMP
static int tun_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
static int tun_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
#endif
#ifdef CONFIG_NET_ICMPv6
@ -780,7 +778,7 @@ static int tun_txavail(struct net_driver_s *dev)
*
****************************************************************************/
#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6)
#ifdef CONFIG_NET_IGMP
static int tun_addmac(struct net_driver_s *dev, FAR const uint8_t *mac)
{
/* Add the MAC address to the hardware multicast routing table */

View File

@ -107,6 +107,12 @@ systime_t g_polltime;
* IEEE802.15.4 MAC network driver. Under those conditions, 6LoWPAN
* logic will be called to create the IEEE80215.4 frames.
*
* All outgoing ICMPv6 messages come through one of two mechanisms:
*
* 1. The output from internal ICMPv6 message passing. These outgoing
* messages will use device polling and will be handled here.
* 2. ICMPv6 output resulting from TX or timer polling.
*
* Assumptions:
* The network is locked.
*
@ -124,17 +130,25 @@ static void devif_packet_conversion(FAR struct net_driver_s *dev,
if (dev->d_len > 0)
#endif
{
FAR struct ipv6_hdr_s *ipv6 = (FAR struct ipv6_hdr_s *)dev->d_buf;
#ifdef CONFIG_NET_IPv4
if ((ipv6->vtc & IP_VERSION_MASK) != IPv6_VERSION)
{
nerr("ERROR: IPv6 version error: %02x... Packet dropped\n",
ipv6->vtc);
}
else
#endif
#ifdef CONFIG_NET_TCP
if (pkttype == DEVIF_TCP)
{
FAR struct ipv6_hdr_s *ipv6 = (FAR struct ipv6_hdr_s *)dev->d_buf;
/* This packet came from a response to TCP polling and is directed
* to an IEEE802.15.4 device using 6LoWPAN. Verify that the outgoing
* packet is IPv6 with TCP protocol.
*/
if (ipv6->vtc == IPv6_VERSION && ipv6->proto == IP_PROTO_TCP)
if (ipv6->proto == IP_PROTO_TCP)
{
/* Let 6LoWPAN convert IPv6 TCP output into IEEE802.15.4 frames. */
@ -142,17 +156,40 @@ static void devif_packet_conversion(FAR struct net_driver_s *dev,
}
else
{
nerr("ERROR: IPv6 version or protocol error. Packet dropped\n");
nerr(" IP version: %02x proocol: %u\n",
ipv6->vtc, ipv6->proto);
nerr("ERROR: TCP protocol error: %u... Packet dropped\n",
ipv6->proto);
}
}
else
#endif
#ifdef CONFIG_NET_ICMPv6
if (pkttype == DEVIF_ICMP6)
{
/* This packet came from a response to TCP polling and is directed
* to an IEEE802.15.4 device using 6LoWPAN. Verify that the outgoing
* packet is IPv6 with TCP protocol.
*/
if (ipv6->proto == IP_PROTO_ICMP6)
{
/* Let 6LoWPAN convert IPv6 ICMPv6 output into IEEE802.15.4 frames. */
sixlowpan_icmpv6_send(dev, dev, ipv6);
}
else
{
nerr("ERROR: ICMPv6 protocol error: %u... Packet dropped\n",
ipv6->proto);
}
}
else
#endif
{
nerr("ERROR: Non-TCP packet dropped. Packet type: %u\n", pkttype);
nerr("ERROR: Unhandled packet dropped. pkttype=%u protocol=%u\n",
pkttype, ipv6->proto);
}
UNUSED(ipv6);
dev->d_len = 0;
}
}

View File

@ -416,7 +416,7 @@ int ipv6_input(FAR struct net_driver_s *dev)
* during TCP packet processing by the TCP state meachine.
* 3. TCP output resulting from TX or timer polling
*
* Cases 2 is handled here. Logic here detected if (1) an attempt
* Case 3 is handled here. Logic here detects if (1) an attempt
* to return with d_len > 0 and (2) that the device is an
* IEEE802.15.4 MAC network driver. Under those conditions, 6LoWPAN
* logic will be called to create the IEEE80215.4 frames.
@ -457,8 +457,40 @@ int ipv6_input(FAR struct net_driver_s *dev)
/* Forward the ICMPv6 packet */
icmpv6_input(dev);
break;
#ifdef CONFIG_NET_6LOWPAN
/* All outgoing ICMPv6 messages come through one of two mechanisms:
*
* 1. The output from internal ICMPv6 message passing. These
* outgoing messages will use device polling and will be
* handled elsewhere.
* 2. ICMPv6 output resulting from TX or timer polling.
*
* Case 2 is handled here. Logic here detects if (1) an attempt
* to return with d_len > 0 and (2) that the device is an
* IEEE802.15.4 MAC network driver. Under those conditions, 6LoWPAN
* logic will be called to create the IEEE80215.4 frames.
*/
#ifdef CONFIG_NET_MULTILINK
/* Handle the case where multiple link layer protocols are supported */
if (dev->d_len > 0 && dev->d_lltype == CONFIG_NET_6LOWPAN)
#else
if (dev->d_len > 0)
#endif
{
/* Let 6LoWPAN handle the ICMPv6 output */
sixlowpan_icmpv6_send(dev, dev, ipv6);
/* Drop the packet in the d_buf */
goto drop;
}
#endif /* CONFIG_NET_6LOWPAN */
break;
#endif /* CONFIG_NET_ICMPv6 */
default: /* Unrecognized/unsupported protocol */
#ifdef CONFIG_NET_STATISTICS

View File

@ -80,6 +80,12 @@
# define DEV_LLTYPE(d) NET_LL_ETHERNET
#elif defined(CONFIG_NET_6LOWPAN)
# define DEV_LLTYPE(d) NET_LL_IEEE802154
#elif defined(CONFIG_NET_SLIP)
# define DEV_LLTYPE(d) NET_LL_SLIP
#elif defined(CONFIG_NET_TUN)
# define DEV_LLTYPE(d) NET_LL_TUN
#else /* if defined(CONFIG_NET_LOOPBACK) */
# define DEV_LLTYPE(d) NET_LL_LOOPBACK
#endif
/****************************************************************************

View File

@ -140,7 +140,7 @@ static void ipfwd_packet_conversion(FAR struct net_driver_s *dev, int proto)
{
/* Let 6LoWPAN convert IPv6 UDP output into IEEE802.15.4 frames. */
nwerr("ERROR: Missing support for ICMPv6 packet forwarding\n");
sixlowpan_icmpv6_send(dev, dev, ipv6);
}
else
#endif

View File

@ -271,6 +271,36 @@ static int ipv6_packet_conversion(FAR struct net_driver_s *dev,
}
else
#endif
#ifdef CONFIG_NET_ICMPv6
if (ipv6->proto == IP_PROTO_ICMP6)
{
/* Decrement the TTL in the IPv6 header. 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;
}
else
{
/* Let 6LoWPAN convert IPv6 ICMPv6 output into IEEE802.15.4
* frames.
*/
sixlowpan_icmpv6_send(dev, fwddev, ipv6);
/* The packet was forwarded */
dev->d_len = 0;
return PACKET_FORWARDED;
}
}
else
#endif
{
/* Otherwise, we cannot forward the packet */

View File

@ -47,7 +47,17 @@ NET_CSRCS += sixlowpan_tcpsend.c
endif
ifeq ($(CONFIG_NET_UDP),y)
NET_CSRCS += sixlowpan_udpsend.c sixlowpan_send.c
NET_CSRCS += sixlowpan_udpsend.c
endif
ifeq ($(CONFIG_NET_ICMPv6),y)
NET_CSRCS += sixlowpan_icmpv6send.c
endif
ifeq ($(CONFIG_NET_UDP),y)
NET_CSRCS += sixlowpan_send.c
else ifeq ($(CONFIG_NET_ICMPv6),y)
NET_CSRCS += sixlowpan_send.c
endif
ifeq ($(CONFIG_NET_6LOWPAN_COMPRESSION_HC1),y)

View File

@ -147,6 +147,41 @@ void sixlowpan_tcp_send(FAR struct net_driver_s *dev,
FAR struct net_driver_s *fwddev,
FAR struct ipv6_hdr_s *ipv6);
/****************************************************************************
* Name: sixlowpan_icmpv6_send
*
* Description:
* All outgoing ICMPv6 messages come through one of two mechanisms:
*
* 1. The output from internal ICMPv6 message passing. These outgoing
* messages will use device polling.
* 2. ICMPv6 output resulting from TX or timer polling.
*
* Both cases are handled here.
*
* Parameters:
* dev - The network device containing the packet to be sent.
* fwddev - The network device used to send the data. This will be the
* same device except for the IP forwarding case where packets
* are sent across devices.
* ipv6 - A pointer to the IPv6 header in dev->d_buf which lies AFTER
* the L1 header. NOTE: dev->d_len must have been decremented
* by the size of any preceding MAC header.
*
* Returned Value:
* None
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
#ifdef CONFIG_NET_ICMPv6
void sixlowpan_icmpv6_send(FAR struct net_driver_s *dev,
FAR struct net_driver_s *fwddev,
FAR struct ipv6_hdr_s *ipv6);
#endif
/****************************************************************************
* Name: psock_6lowpan_udp_send
*

View File

@ -212,7 +212,7 @@ static uint16_t sixlowpan_protosize(FAR const struct ipv6_hdr_s *ipv6hdr,
*
* Input Parameters:
* ieee - The IEEE802.15.4 MAC driver instance
* ipv6hdr - IPv6 header followed by TCP, UDP, or ICMPv6 header.
* ipv6 - IPv6 header followed by TCP, UDP, or ICMPv6 header.
* buf - Beginning of the packet packet to send (with IPv6 + protocol
* headers)
* buflen - Length of data to send (include IPv6 and protocol headers)
@ -230,7 +230,7 @@ static uint16_t sixlowpan_protosize(FAR const struct ipv6_hdr_s *ipv6hdr,
****************************************************************************/
int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee,
FAR const struct ipv6_hdr_s *destip,
FAR const struct ipv6_hdr_s *ipv6,
FAR const void *buf, size_t buflen,
FAR const struct sixlowpan_tagaddr_s *destmac)
{
@ -266,10 +266,10 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee,
/* Set stream mode for all TCP packets, except FIN packets. */
#if 0 /* Currently the frame type is always data */
if (destip->proto == IP_PROTO_TCP)
if (ipv6->proto == IP_PROTO_TCP)
{
FAR const struct tcp_hdr_s *tcp =
&((FAR const struct ipv6tcp_hdr_s *)destip)->tcp;
&((FAR const struct ipv6tcp_hdr_s *)ipv6)->tcp;
if ((tcp->flags & TCP_FIN) == 0 &&
(tcp->flags & TCP_CTL) != TCP_ACK)
@ -379,9 +379,9 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee,
/* Try to compress the headers */
#if defined(CONFIG_NET_6LOWPAN_COMPRESSION_HC1)
ret = sixlowpan_compresshdr_hc1(ieee, destip, destmac, fptr);
ret = sixlowpan_compresshdr_hc1(ieee, ipv6, destmac, fptr);
#elif defined(CONFIG_NET_6LOWPAN_COMPRESSION_HC06)
ret = sixlowpan_compresshdr_hc06(ieee, destip, destmac, fptr);
ret = sixlowpan_compresshdr_hc06(ieee, ipv6, destmac, fptr);
#else
# error No compression specified
#endif
@ -391,14 +391,14 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee,
{
/* Small.. use IPv6 dispatch (no compression) */
ret = sixlowpan_compress_ipv6hdr(destip, fptr);
ret = sixlowpan_compress_ipv6hdr(ipv6, fptr);
}
/* Get the size of any uncompressed protocol headers */
if (ret == COMPRESS_HDR_INLINE)
{
protosize = sixlowpan_protosize(destip, fptr);
protosize = sixlowpan_protosize(ipv6, fptr);
}
ninfo("Header of length=%u protosize=%u\n", g_frame_hdrlen, protosize);
@ -465,7 +465,7 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee,
if (protosize > 0)
{
FAR uint8_t *src = (FAR uint8_t *)destip + IPv6_HDRLEN;
FAR uint8_t *src = (FAR uint8_t *)ipv6 + IPv6_HDRLEN;
memcpy(fptr + g_frame_hdrlen, src, protosize);
}
@ -625,7 +625,7 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee,
if (protosize > 0)
{
FAR uint8_t *src = (FAR uint8_t *)destip + IPv6_HDRLEN;
FAR uint8_t *src = (FAR uint8_t *)ipv6 + IPv6_HDRLEN;
memcpy(fptr + g_frame_hdrlen, src, protosize);
}

View File

@ -0,0 +1,161 @@
/****************************************************************************
* net/sixlowpan/sixlowpan_icmpv6send.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <debug.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/ip.h>
#include "icmpv6/icmpv6.h"
#include "sixlowpan/sixlowpan_internal.h"
#include "sixlowpan/sixlowpan.h"
#if defined(CONFIG_NET_6LOWPAN) && defined(CONFIG_NET_ICMPv6)
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_icmpv6_send
*
* Description:
* Handles forwarding a ICMPv6 packet via 6LoWPAN. This is currently only
* used by the IPv6 forwarding logic.
*
* Parameters:
* dev - An instance of nework device state structure
* fwddev - The network device used to send the data. This will be the
* same device except for the IP forwarding case where packets
* are sent across devices.
* ipv6 - A pointer to the IPv6 header in dev->d_buf which lies AFTER
* the L1 header. NOTE: dev->d_len must have been decremented
* by the size of any preceding MAC header.
*
* Returned Value:
* None
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
#ifdef CONFIG_NET_IPFORWARD
void sixlowpan_icmpv6_send(FAR struct net_driver_s *dev,
FAR struct net_driver_s *fwddev,
FAR struct ipv6_hdr_s *ipv6)
{
FAR struct ipv6icmp_hdr_s *ipv6icmpv6 = (FAR struct ipv6icmp_hdr_s *)ipv6;
/* Double check */
DEBUGASSERT(dev != NULL && dev->d_len > 0);
ninfo("d_len %u\n", dev->d_len);
if (dev != NULL && dev->d_len > 0)
{
sixlowpan_dumpbuffer("Outgoing ICMPv6 packet",
(FAR const uint8_t *)ipv6icmpv6, dev->d_len);
/* The ICMPv6 data payload should follow the IPv6 header plus the
* protocol header.
*/
if (ipv6icmpv6->ipv6.proto != IP_PROTO_ICMPv6)
{
nwarn("WARNING: Expected ICMPv6 protoype: %u vs %s\n",
ipv6icmpv6->ipv6.proto, IP_PROTO_ICMPv6);
}
else
{
struct sixlowpan_tagaddr_s destmac;
FAR uint8_t *buf;
uint16_t hdrlen;
uint16_t buflen;
int ret;
/* Get the IEEE 802.15.4 MAC address of the destination. This
* assumes an encoding of the MAC address in the IPv6 address.
*/
ret = sixlowpan_destaddrfromip((FAR struct ieee802154_driver_s *)dev,
ipv6icmpv6->ipv6.destipaddr, &destmac);
if (ret < 0)
{
nerr("ERROR: Failed to dest MAC address: %d\n", ret);
goto drop;
}
/* Get the IPv6 + ICMPv6 combined header length. NOTE: This header
* size includes only the common 32-bit header at the beginning of
* each ICMPv6 message.
*/
hdrlen = IPv6_HDRLEN + ICMPv6_HDRLEN;
/* Drop the packet if the buffer length is less than this. */
if (hdrlen > dev->d_len)
{
nwarn("WARNING: Dropping small ICMPv6 packet: %u < %u\n",
buflen, hdrlen);
}
else
{
/* Convert the outgoing packet into a frame list. */
buf = (FAR uint8_t *)ipv6 + hdrlen;
buflen = dev->d_len - hdrlen;
(void)sixlowpan_queue_frames(
(FAR struct ieee802154_driver_s *)fwddev,
&ipv6icmpv6->ipv6, buf, buflen, &destmac);
}
}
}
drop:
dev->d_len = 0;
}
#endif
#endif /* CONFIG_NET_6LOWPAN && CONFIG_NET_ICMPv6 */

View File

@ -356,7 +356,7 @@ int sixlowpan_frame_submit(FAR struct ieee802154_driver_s *ieee,
*
* Input Parameters:
* ieee - The IEEE802.15.4 MAC driver instance
* ipv6hdr - IPv6 header followed by TCP or UDP header.
* ipv6 - IPv6 header followed by TCP or UDP header.
* buf - Beginning of the packet packet to send (with IPv6 + protocol
* headers)
* buflen - Length of data to send (include IPv6 and protocol headers)
@ -374,7 +374,7 @@ int sixlowpan_frame_submit(FAR struct ieee802154_driver_s *ieee,
****************************************************************************/
int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee,
FAR const struct ipv6_hdr_s *ipv6hdr,
FAR const struct ipv6_hdr_s *ipv6,
FAR const void *buf, size_t buflen,
FAR const struct sixlowpan_tagaddr_s *destmac);