NuttX has supported the Internet Protocol Version 4 (IPv4) for many years. There have been fragments of IPv6 in the code base for many years as well, but these fragments were not more than place markers and not functional.

But recently, post NuttX-7.6, I have focused some effort into completing the IPv6 implementation. This Wiki page contains notes from that integration effort and will, hopefully, evolve to provide full documentation for NuttX IPv6 support.

Current status: Basic functionality is complete and verified. That includes ICMPPv6 Neighbor Discover Protocol, IPCMPv6 Echo Request/Response (for ping6), TCP/IPv6, and UDP/IPv6. It has also been proven that you can support a platform with both IPv4 and IPv6 enabled.

Ethernet Driver Requirements

Basic Driver Requirements

In order to support IPv6, Ethernet drivers must do the following:

All existing NuttX Ethernet drivers have already been modified to support the requirements of the first two bullets. However, additional logic must be added to most of the existing Ethernet drivers to support the final requirement.

Multicast Address Filtering

Each Ethernet device connects to the Ethernet wire via a PHY and so potentially has access to every packet that passes on the wire. In promiscuous mode, that is the behavior that is desired but normally it is not: The amount of traffic that appears on the wire would swamp most modest MCUs in promiscuous mode. So instead, the Ethernet MAC hardware will support address filtering. That is, the hardware will look at the Ethernet header at the beginning of each packet and will ignore packets that do not have the desired information in the Ethernet header. The software will see only those filtered packets that are desired.

Typically, the Ethernet MAC is set-up for unicast address filtering: The hardware is programmed so that that only packets whose destination Ethernet MAC address matches the MAC address programmed into the hardware are accepted. In addition, special broadcast Ethernet addresses will also be accepted. In this way, the volume of Ethernet data received by the MCU is greatly reduced.

Multicast addresses are a little different. Unlike broadcast addresses, there are many possible multicast addresses and so the Ethernet MAC hardware must support some special capability to match the destination Ethernet address in an incoming packet with a variety of multicast addresses. Usually this involves hashing the Ethernet address and performing a hash table lookup to check for an address match.

Each Ethernet driver uses a common interface that is defined in nuttx/include/nuttx/net/netdev.h. That interface defines, among other things, a set of calls into the Ethernet driver to perform a variety of functions. One of those functions is multicast address filtering:

  #ifdef CONFIG_NET_IGMP
    int (*d_addmac)(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
    int (*d_rmmac)(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
  #endif

The d_addmac() interface adds a multicast address to the hash table; d_rmmac() removes a multicast address from the hash table.

These interface is only required if IGMP is supported, but the underlying ability to program multicast address filtered is required for full IPv6 support. This interface exists in all Ethernet drivers but most are currently place holders and are to-be-provided. At present, only the STMicro STM32, the TI Tiva TM4C, and the Atmel SAM3/4 and SAMA5D3/4 Ethernet drivers support multicast hash tables. This capability will have to be added to any additional Ethernet drivers that are modified to support IPv6.

ICMPv6 Neighbor Discovery Protocol

The ICMPv6 Neighbor Discover protocol is the reason for this additional address filtering. The ICMPv6 Neighbor Discovery Protocol is the replacement for IPv4's ARP. It differents from ARP in the it is implemented not at the Ethernet link layer, but within the IPv6 layer. In order to receive broadcast packets to ICMPv6, the IPv6 Multicast address of 33.33.ff.xx.xx.xx is used, where the xx.xx.xx part derives from the IPv6 address. The Ethernet driver filtering logic must be modified so that it accepts packets directed to the that MAC address.

At present, this additional support is only implemented for the TI Tiva TM4C129X Ethernet driver. Below is a snippet of code from that drier showing how this is implemented:

      /* Set the MAC address */
    
      tiva_macaddress(priv);
    
    #ifdef CONFIG_NET_ICMPv6
      /* Set up the IPv6 multicast address */
    
      tiva_ipv6multicast(priv);
    #endif

Where tiva_macaddress() sets up the normal MAC address filtering and tiva_ipv6multicast() sets up the special filtering needed by IPv6:

    /****************************************************************************
    
    #ifdef CONFIG_NET_ICMPv6
    static void tiva_ipv6multicast(FAR struct tiva_ethmac_s *priv)
    {
      struct net_driver_s *dev;
      uint16_t tmp16;
      uint8_t mac[6];
    
      /* For ICMPv6, we need to add the IPv6 multicast address
    
      mac[0] = 0x33;
      mac[1] = 0x33;
    
      dev    = &priv->dev;
      tmp16  = dev->d_ipv6addr[6];
      mac[2] = 0xff;
      mac[3] = tmp16 >> 8;
    
      tmp16  = dev->d_ipv6addr[7];
      mac[4] = tmp16 & 0xff;
      mac[5] = tmp16 >> 8;
    
      nvdbg("IPv6 Multicast: %02x:%02x:%02x:%02x:%02x:%02x\n",
            mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    
      (void)tiva_addmac(dev, mac);
    
    #ifdef CONFIG_NET_ICMPv6_AUTOCONF
      /* Add the IPv6 all link-local nodes Ethernet address.  This is the
    
      (void)tiva_addmac(dev, g_ipv6_ethallnodes.ether_addr_octet);
    
    #endif /* CONFIG_NET_ICMPv6_AUTOCONF */
    #ifdef CONFIG_NET_ICMPv6_ROUTER
      /* Add the IPv6 all link-local routers Ethernet address.  This is the
    
      (void)tiva_addmac(dev, g_ipv6_ethallrouters.ether_addr_octet);
    
    #endif /* CONFIG_NET_ICMPv6_ROUTER */
    }
    #endif /* CONFIG_NET_ICMPv6 */

The following Ethernet drivers are complete and IPv6 ready. All others Ethernet drivers have all required IPv6 support except that they are missing (1) the required ICMPv6 addressing filtering described above and/or (2) support for multi-cast address filtering.

Board Configurations

At present, there are three board configuration that are pre-configured to use IPv6: nuttx/boards/arm/tiva/dk-tm4c129x/configs/ipv6, {{ nuttx/boards/arm/stm32/stm32f4discovery/ipv6}}, and nuttx/boards/arm/tiva/tm4c1294-launchpad/configs/ipv6. These default configurations have only IPv6 enabled. But the README files at in those board directories describes how to enable both IPv4 and IPv6 simultaneously.

Ping

Ping from Host PC

Ping from Windows cmd Terminal
    ping -6 fc00::2
Ping from Linux shell
    ping6 fc00::2

Ping from the NuttShell (NSH)

    nsh> ping6 fc00::2

NSH ifconfig

IPv4 Only

CONFIG_NET_IPv4=y and CONFIG_NET_IPv6=n

    nsh> ifconfig
    eth0    Link encap: Ethernet HWaddr 00:1a:b6:02:81:14 at UP
            inet addr:10.0.0.2 DRaddr:10.0.0.1 Mask:255.255.255.0
    
                 IPv4   TCP   UDP  ICMP
    Received     003b  001c  0000  0004
    Dropped      001b  0000  0000  0000
      IPv4        VHL: 0000 Frg: 0000
      Checksum   0000  0000  0000  ----
      TCP         ACK: 0000 SYN: 0000
                  RST: 0000 0000
      Type       0000  ----  ----  0000
    Sent         0031  002d  0000  0004
      Rexmit     ----  ----  0000  ----

NOTE: The detailed packet statistics only appear if CONFIG_NET_STATISTICS is enabled.

IPv6 Only

CONFIG_NET_IPv4=n and CONFIG_NET_IPv6=y

    nsh> ifconfig
    eth0    Link encap: Ethernet HWaddr 00:1a:b6:02:81:14 at UP
            inet6 addr:fc00::2
            inet6 DRaddr:fc00::1
            inet6 Mask:ffff:ffff:ffff::ffff:ffff:ffff:ff80
    
                 IPv6   TCP   UDP  ICMPv6
    Received     0007  0000  0000  0007
    Dropped      0000  0000  0000  0000
      IPv6        VHL: 0000
      Checksum   ----  0000  0000  ----
      TCP         ACK: 0000 SYN: 0000
                  RST: 0000 0000
      Type       0000  ----  ----  0000
    Sent         0011  0000  0000  0011
      Rexmit     ----  ----  0000  ----

Both IPv4 and IPv6

CONFIG_NET_IPv4=y and CONFIG_NET_IPv6=y

    nsh> ifconfig
    eth0    Link encap: Ethernet HWaddr 00:1a:b6:02:81:14 at UP
            inet addr:10.0.0.2 DRaddr:10.0.0.1 Mask:255.255.255.0
            inet6 addr:fc00::2
            inet6 DRaddr:fc00::1
            inet6 Mask:ffff:ffff:ffff::ffff:ffff:ffff:ff80
    
                 IPv4  IPv6   TCP   UDP  ICMP  ICMPv6
    Received     0047  000a  001c  0000  0004  000a
    Dropped      0027  0000  0000  0000  0000  0000
      IPv4        VHL: 0000 Frg: 0000
      IPv6        VHL: 0000
      Checksum   0000  ----  0000  0000  ----  ----
      TCP         ACK: 0000 SYN: 0000
                  RST: 0000 0000
      Type       0000  0000  ----  ----  0000  0000
    Sent         0033  000a  002f  0000  0004  000a
      Rexmit     ----  ----  ----  0000  ----  ----

Tests, Applications, and Network Utilities

In addition to the core RTOS support IPv6, changes are also required to networking tests, to networking aware applications, and, of course, to all of the network utils (netutils).