This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit f3b34c84c2f970b21881abf397be12969913fbc8
Author: Zhe Weng <[email protected]>
AuthorDate: Wed Mar 13 17:04:55 2024 +0800

    net/nat: Support IPv6 Masquerading (NAT66)
    
    Notes:
    1. This version of NAT66 is a stateful one like NAT44, corresponding to 
Linux's MASQUERADE target of ip6tables.  We can support stateless NAT66 & NPTv6 
later by slightly modify the address & port selection logic (maybe just match 
the rules and skip the entry find).
    2. We're using same flag `IFF_NAT` for both NAT44 & NAT66 to make control 
easier.  Which means, if we enable NAT, both NAT44 & NAT66 will be enabled.  If 
we don't want one of them, we can just disable that one in Kconfig.
    3. Maybe we can accelerate the checksum adjustment by pre-calculate a 
difference of checksum, and apply it to each packet, instead of calling 
`net_chksum_adjust` each time.  Just a thought, maybe do it later.
    4. IP fragment segments on NAT66 connections are not supported yet.
    
    Signed-off-by: Zhe Weng <[email protected]>
---
 Documentation/components/net/nat.rst           |  37 +-
 net/devif/ipv4_input.c                         |   8 +-
 net/devif/ipv6_input.c                         |   7 +
 net/ipforward/ipv4_forward.c                   |   8 +-
 net/ipforward/ipv6_forward.c                   |  51 +-
 net/nat/CMakeLists.txt                         |   6 +-
 net/nat/Kconfig                                |  52 +-
 net/nat/Make.defs                              |   6 +-
 net/nat/ipv4_nat.c                             |  19 +-
 net/nat/ipv4_nat_entry.c                       |  48 +-
 net/nat/ipv6_nat.c                             | 692 +++++++++++++++++++++++++
 net/nat/{ipv4_nat_entry.c => ipv6_nat_entry.c} | 254 ++++-----
 net/nat/nat.c                                  |  74 ++-
 net/nat/nat.h                                  |  91 +++-
 14 files changed, 1130 insertions(+), 223 deletions(-)

diff --git a/Documentation/components/net/nat.rst 
b/Documentation/components/net/nat.rst
index 621e7b738b..abd1b380f1 100644
--- a/Documentation/components/net/nat.rst
+++ b/Documentation/components/net/nat.rst
@@ -46,10 +46,13 @@ Configuration Options
 ``CONFIG_NET_NAT``
   Enable or disable Network Address Translation (NAT) function.
   Depends on ``CONFIG_NET_IPFORWARD``.
-``CONFIG_NET_NAT_FULL_CONE``
+``CONFIG_NET_NAT44`` & ``CONFIG_NET_NAT66``
+  Enable or disable NAT on IPv4 / IPv6.
+  Depends on ``CONFIG_NET_NAT``.
+``CONFIG_NET_NAT44_FULL_CONE`` & ``CONFIG_NET_NAT66_FULL_CONE``
   Enable Full Cone NAT logic. Full Cone NAT is easier to traverse than
   Symmetric NAT, and uses less resources than Symmetric NAT.
-``CONFIG_NET_NAT_SYMMETRIC``
+``CONFIG_NET_NAT44_SYMMETRIC`` & ``CONFIG_NET_NAT66_SYMMETRIC``
   Enable Symmetric NAT logic. Symmetric NAT will be safer than Full Cone NAT,
   be more difficult to traverse, and has more entries which may lead to 
heavier load.
 ``CONFIG_NET_NAT_HASH_BITS``
@@ -63,6 +66,8 @@ Configuration Options
   The expiration time for idle UDP entry in NAT.
 ``CONFIG_NET_NAT_ICMP_EXPIRE_SEC``
   The expiration time for idle ICMP entry in NAT.
+``CONFIG_NET_NAT_ICMPv6_EXPIRE_SEC``
+  The expiration time for idle ICMPv6 entry in NAT.
 ``CONFIG_NET_NAT_ENTRY_RECLAIM_SEC``
   The time to auto reclaim all expired NAT entries. A value of zero will
   disable auto reclaiming.
@@ -133,6 +138,10 @@ Validated on Ubuntu 22.04 x86_64 with NuttX SIM by 
following steps:
     ifconfig eth1 10.0.10.2
     ifup eth1
 
+    # IPv6 if you need
+    ifconfig eth0 inet6 add fc00:1::2/64 gw fc00:1::1
+    ifconfig eth1 inet6 add fc00:10::2/64
+
 4. Configure IP & namespace & route on host side (maybe need to be root, then 
try ``sudo -i``)
 
   ..  code-block:: bash
@@ -162,6 +171,22 @@ Validated on Ubuntu 22.04 x86_64 with NuttX SIM by 
following steps:
     iptables -A FORWARD -i $IF_0 -o $IF_HOST -j ACCEPT
     sysctl -w net.ipv4.ip_forward=1
 
+    # IPv6 if you need
+    IP6_HOST_0="fc00:1::1"
+    IP6_HOST_1="fc00:10::1"
+    IP6_NUTTX_1="fc00:10::2"
+
+    # add address and set default route
+    ip -6 addr add $IP6_HOST_0/64 dev $IF_0
+    ip netns exec LAN ip -6 addr add $IP6_HOST_1/64 dev $IF_1
+    ip netns exec LAN ip -6 route add default dev $IF_1 via $IP6_NUTTX_1
+
+    # nat to allow NuttX to access the internet
+    ip6tables -t nat -A POSTROUTING -o $IF_HOST -j MASQUERADE
+    ip6tables -A FORWARD -i $IF_HOST -o $IF_0 -j ACCEPT
+    ip6tables -A FORWARD -i $IF_0 -o $IF_HOST -j ACCEPT
+    sysctl -w net.ipv6.conf.all.forwarding=1
+
 5. Do anything in the LAN namespace will go through NAT
 
   ..  code-block:: shell
@@ -174,20 +199,26 @@ Validated on Ubuntu 22.04 x86_64 with NuttX SIM by 
following steps:
   ..  code-block:: shell
 
     # Host side
-    python3 -m http.server
+    python3 -m http.server -b ::
     # LAN side
     for i in {1..20000}; do sudo ip netns exec LAN curl 
'http://10.0.1.1:8000/' > /dev/null 2>1; done
+    for i in {1..20000}; do sudo ip netns exec LAN curl 
'http://[fc00:1::1]:8000/' > /dev/null 2>1; done
 
   ..  code-block:: shell
 
     # LAN side
     sudo ip netns exec LAN ping 8.8.8.8
+    sudo ip netns exec LAN ping 2001:4860:4860::8888
 
   ..  code-block:: shell
 
     # LAN side
     sudo ip netns exec LAN traceroute -n 8.8.8.8     # ICMP error msg of UDP
     sudo ip netns exec LAN traceroute -n -T 8.8.8.8  # ICMP error msg of TCP
+    sudo ip netns exec LAN traceroute -n -I 8.8.8.8  # ICMP error msg of ICMP
+    sudo ip netns exec LAN traceroute -n 2001:4860:4860::8888
+    sudo ip netns exec LAN traceroute -n -T 2001:4860:4860::8888
+    sudo ip netns exec LAN traceroute -n -I 2001:4860:4860::8888
 
   ..  code-block:: shell
 
diff --git a/net/devif/ipv4_input.c b/net/devif/ipv4_input.c
index 4e7f2eb16f..0875c786a8 100644
--- a/net/devif/ipv4_input.c
+++ b/net/devif/ipv4_input.c
@@ -235,14 +235,10 @@ static int ipv4_in(FAR struct net_driver_s *dev)
       goto drop;
     }
 
-#ifdef CONFIG_NET_NAT
+#ifdef CONFIG_NET_NAT44
   /* Try NAT inbound, rule matching will be performed in NAT module. */
 
-  if (ipv4_nat_inbound(dev, ipv4) < 0)
-    {
-      nwarn("WARNING: Performing NAT inbound failed!\n");
-      goto drop;
-    }
+  ipv4_nat_inbound(dev, ipv4);
 #endif
 
   /* Get the destination IP address in a friendlier form */
diff --git a/net/devif/ipv6_input.c b/net/devif/ipv6_input.c
index 3be7d875a9..b6e133c78d 100644
--- a/net/devif/ipv6_input.c
+++ b/net/devif/ipv6_input.c
@@ -47,6 +47,7 @@
 #include "pkt/pkt.h"
 #include "icmpv6/icmpv6.h"
 
+#include "nat/nat.h"
 #include "netdev/netdev.h"
 #include "ipforward/ipforward.h"
 #include "inet/inet.h"
@@ -296,6 +297,12 @@ static int ipv6_in(FAR struct net_driver_s *dev)
       nxthdr    = exthdr->nxthdr;
     }
 
+#ifdef CONFIG_NET_NAT66
+  /* Try NAT inbound, rule matching will be performed in NAT module. */
+
+  ipv6_nat_inbound(dev, ipv6);
+#endif
+
 #ifdef CONFIG_NET_BROADCAST
   /* Check for a multicast packet, which may be destined to us (even if
    * there is no IP address yet assigned to the device).  We only expect
diff --git a/net/ipforward/ipv4_forward.c b/net/ipforward/ipv4_forward.c
index 11ffb88613..8554546933 100644
--- a/net/ipforward/ipv4_forward.c
+++ b/net/ipforward/ipv4_forward.c
@@ -286,13 +286,13 @@ static int ipv4_dev_forward(FAR struct net_driver_s *dev,
       goto errout_with_fwd;
     }
 
-#ifdef CONFIG_NET_NAT
+#ifdef CONFIG_NET_NAT44
   /* Try NAT outbound, rule matching will be performed in NAT module. */
 
   ret = ipv4_nat_outbound(fwd->f_dev, ipv4, NAT_MANIP_SRC);
   if (ret < 0)
     {
-      nwarn("WARNING: Performing NAT outbound failed, dropping!\n");
+      nwarn("WARNING: Performing NAT44 outbound failed, dropping!\n");
       goto errout_with_fwd;
     }
 #endif
@@ -532,13 +532,13 @@ drop:
 
 #ifdef CONFIG_NET_ICMP
 reply:
-#  ifdef CONFIG_NET_NAT
+#  ifdef CONFIG_NET_NAT44
   /* Before we reply ICMP, call NAT outbound to try to translate destination
    * address & port back to original status.
    */
 
   ipv4_nat_outbound(dev, ipv4, NAT_MANIP_DST);
-#  endif /* CONFIG_NET_NAT */
+#  endif /* CONFIG_NET_NAT44 */
 
   icmp_reply(dev, icmp_reply_type, icmp_reply_code);
   return OK;
diff --git a/net/ipforward/ipv6_forward.c b/net/ipforward/ipv6_forward.c
index 769fce8138..5f39a0ad08 100644
--- a/net/ipforward/ipv6_forward.c
+++ b/net/ipforward/ipv6_forward.c
@@ -35,6 +35,7 @@
 #include <nuttx/net/netdev.h>
 #include <nuttx/net/netstats.h>
 
+#include "nat/nat.h"
 #include "netdev/netdev.h"
 #include "sixlowpan/sixlowpan.h"
 #include "devif/devif.h"
@@ -423,6 +424,17 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev,
           goto errout_with_fwd;
         }
 
+#ifdef CONFIG_NET_NAT66
+      /* Try NAT outbound, rule matching will be performed in NAT module. */
+
+      ret = ipv6_nat_outbound(fwd->f_dev, ipv6, NAT_MANIP_SRC);
+      if (ret < 0)
+        {
+          nwarn("WARNING: Performing NAT66 outbound failed, dropping!\n");
+          goto errout_with_fwd;
+        }
+#endif
+
       /* Then set up to forward the packet according to the protocol. */
 
       ret = ipfwd_forward(fwd);
@@ -560,6 +572,11 @@ int ipv6_forward(FAR struct net_driver_s *dev, FAR struct 
ipv6_hdr_s *ipv6)
 {
   FAR struct net_driver_s *fwddev;
   int ret;
+#ifdef CONFIG_NET_ICMPv6
+  int icmpv6_reply_type;
+  int icmpv6_reply_code;
+  int icmpv6_reply_data;
+#endif /* CONFIG_NET_ICMP */
 
   /* Search for a device that can forward this packet. */
 
@@ -659,18 +676,22 @@ drop:
   switch (ret)
     {
       case -ENETUNREACH:
-        icmpv6_reply(dev, ICMPv6_DEST_UNREACHABLE, ICMPv6_ADDR_UNREACH, 0);
-        return OK;
+        icmpv6_reply_type = ICMPv6_DEST_UNREACHABLE;
+        icmpv6_reply_code = ICMPv6_ADDR_UNREACH;
+        icmpv6_reply_data = 0;
+        goto reply;
 
       case -EFBIG:
-        icmpv6_reply(dev, ICMPv6_PACKET_TOO_BIG, 0,
-                     NETDEV_PKTSIZE(fwddev) - NET_LL_HDRLEN(fwddev));
-        return OK;
+        icmpv6_reply_type = ICMPv6_PACKET_TOO_BIG;
+        icmpv6_reply_code = 0;
+        icmpv6_reply_data = NETDEV_PKTSIZE(fwddev) - NET_LL_HDRLEN(fwddev);
+        goto reply;
 
       case -EMULTIHOP:
-        icmpv6_reply(dev, ICMPv6_PACKET_TIME_EXCEEDED, ICMPV6_EXC_HOPLIMIT,
-                     0);
-        return OK;
+        icmpv6_reply_type = ICMPv6_PACKET_TIME_EXCEEDED;
+        icmpv6_reply_code = ICMPV6_EXC_HOPLIMIT;
+        icmpv6_reply_data = 0;
+        goto reply;
 
       default:
         break; /* We don't know how to reply, just go on (to drop). */
@@ -679,6 +700,20 @@ drop:
 
   dev->d_len = 0;
   return ret;
+
+#ifdef CONFIG_NET_ICMPv6
+reply:
+#  ifdef CONFIG_NET_NAT66
+  /* Before we reply ICMPv6, call NAT outbound to try to translate
+   * destination address & port back to original status.
+   */
+
+  ipv6_nat_outbound(dev, ipv6, NAT_MANIP_DST);
+#  endif /* CONFIG_NET_NAT66 */
+
+  icmpv6_reply(dev, icmpv6_reply_type, icmpv6_reply_code, icmpv6_reply_data);
+  return OK;
+#endif /* CONFIG_NET_ICMP */
 }
 
 /****************************************************************************
diff --git a/net/nat/CMakeLists.txt b/net/nat/CMakeLists.txt
index ebf100a46a..9bb2c7443a 100644
--- a/net/nat/CMakeLists.txt
+++ b/net/nat/CMakeLists.txt
@@ -24,10 +24,14 @@ if(CONFIG_NET_NAT)
 
   list(APPEND SRCS nat.c)
 
-  if(CONFIG_NET_IPv4)
+  if(CONFIG_NET_NAT44)
     list(APPEND SRCS ipv4_nat.c ipv4_nat_entry.c)
   endif()
 
+  if(CONFIG_NET_NAT66)
+    list(APPEND SRCS ipv6_nat.c ipv6_nat_entry.c)
+  endif()
+
   target_sources(net PRIVATE ${SRCS})
 
 endif()
diff --git a/net/nat/Kconfig b/net/nat/Kconfig
index 0ce9e71b1d..dd95682772 100644
--- a/net/nat/Kconfig
+++ b/net/nat/Kconfig
@@ -6,27 +6,58 @@
 config NET_NAT
        bool "Network Address Translation (NAT)"
        default n
-       depends on NET_IPFORWARD && IOB_BUFSIZE >= 68
+       depends on NET_IPFORWARD
        ---help---
                Enable or disable Network Address Translation (NAT) function.
 
                Note: When forwarding IPv4 packet and applying NAT, NAT may be
                applied directly on a single I/O buffer containing L3 packet 
header,
                and NAT may need a continuous buffer of at least 68 Bytes
-               (IPv4 20B + ICMP 8B + IPv4 20B + TCP 20B).
+               (IPv4 20B + ICMP 8B + IPv4 20B + TCP 20B). And 108 Bytes for 
IPv6.
+
+config NET_NAT44
+       bool "IPv4-to-IPv4 NAT (NAT44)"
+       default y
+       depends on NET_IPv4 && NET_NAT
+       depends on IOB_BUFSIZE >= 68
 
 choice
-       prompt "NAT Type"
-       default NET_NAT_FULL_CONE
-       depends on NET_NAT
+       prompt "NAT44 Type"
+       default NET_NAT44_FULL_CONE
+       depends on NET_NAT44
 
-config NET_NAT_FULL_CONE
+config NET_NAT44_FULL_CONE
        bool "Full Cone NAT"
        ---help---
                Full Cone NAT is easier to traverse than Symmetric NAT, and uses
                less resources than Symmetric NAT.
 
-config NET_NAT_SYMMETRIC
+config NET_NAT44_SYMMETRIC
+       bool "Symmetric NAT"
+       ---help---
+               Symmetric NAT will be safer than Full Cone NAT, be more 
difficult
+               to traverse, and has more entries which may lead to heavier 
load.
+
+endchoice
+
+config NET_NAT66
+       bool "IPv6-to-IPv6 NAT (NAT66)"
+       default y
+       depends on NET_IPv6 && NET_NAT
+       depends on IOB_BUFSIZE >= 108
+
+choice
+       prompt "NAT66 Type"
+       default NET_NAT66_FULL_CONE
+       depends on NET_NAT66
+
+config NET_NAT66_FULL_CONE
+       bool "Full Cone NAT"
+       ---help---
+               Full Cone NAT is easier to traverse than Symmetric NAT, and uses
+               less resources than Symmetric NAT.
+
+config NET_NAT66_SYMMETRIC
        bool "Symmetric NAT"
        ---help---
                Symmetric NAT will be safer than Full Cone NAT, be more 
difficult
@@ -73,6 +104,13 @@ config NET_NAT_ICMP_EXPIRE_SEC
                Note: The default value 60 is suggested by RFC5508, Section 3.2,
                Page 8.
 
+config NET_NAT_ICMPv6_EXPIRE_SEC
+       int "ICMPv6 NAT entry expiration seconds"
+       default 60
+       depends on NET_NAT
+       ---help---
+               The expiration time for idle ICMPv6 entry in NAT.
+
 config NET_NAT_ENTRY_RECLAIM_SEC
        int "The time to auto reclaim all expired entries"
        default 3600
diff --git a/net/nat/Make.defs b/net/nat/Make.defs
index ee4fe9cbe2..b5316ca4c9 100644
--- a/net/nat/Make.defs
+++ b/net/nat/Make.defs
@@ -24,10 +24,14 @@ ifeq ($(CONFIG_NET_NAT),y)
 
 NET_CSRCS += nat.c
 
-ifeq ($(CONFIG_NET_IPv4),y)
+ifeq ($(CONFIG_NET_NAT44),y)
 NET_CSRCS += ipv4_nat.c ipv4_nat_entry.c
 endif
 
+ifeq ($(CONFIG_NET_NAT66),y)
+NET_CSRCS += ipv6_nat.c ipv6_nat_entry.c
+endif
+
 # Include NAT build support
 
 DEPPATH += --dep-path nat
diff --git a/net/nat/ipv4_nat.c b/net/nat/ipv4_nat.c
index 06c627bd4e..ac4e6e45a1 100644
--- a/net/nat/ipv4_nat.c
+++ b/net/nat/ipv4_nat.c
@@ -37,7 +37,7 @@
 #include "nat/nat.h"
 #include "utils/utils.h"
 
-#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
+#ifdef CONFIG_NET_NAT44
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -732,15 +732,10 @@ ipv4_nat_outbound_internal(FAR struct net_driver_s *dev,
  *   dev   - The device on which the packet is received.
  *   ipv4  - Points to the IPv4 header with dev->d_buf.
  *
- * Returned Value:
- *   Zero is returned if NAT is successfully applied, or is not enabled for
- *   this packet;
- *   A negated errno value is returned if error occured.
- *
  ****************************************************************************/
 
-int ipv4_nat_inbound(FAR struct net_driver_s *dev,
-                     FAR struct ipv4_hdr_s *ipv4)
+void ipv4_nat_inbound(FAR struct net_driver_s *dev,
+                      FAR struct ipv4_hdr_s *ipv4)
 {
   /* We only process packets from NAT device and targeting at the address
    * assigned to the device.
@@ -755,11 +750,9 @@ int ipv4_nat_inbound(FAR struct net_driver_s *dev,
         {
           /* Inbound without entry is OK (e.g. towards NuttX itself), skip. */
 
-          return OK;
+          return;
         }
     }
-
-  return OK;
 }
 
 /****************************************************************************
@@ -801,11 +794,11 @@ int ipv4_nat_outbound(FAR struct net_driver_s *dev,
         {
           /* Outbound entry creation failed, should have entry. */
 
-          return -ENOMEM;
+          return -ENOENT;
         }
     }
 
   return OK;
 }
 
-#endif /* CONFIG_NET_NAT && CONFIG_NET_IPv4 */
+#endif /* CONFIG_NET_NAT44 */
diff --git a/net/nat/ipv4_nat_entry.c b/net/nat/ipv4_nat_entry.c
index 7b033a5d0f..1534e448f4 100644
--- a/net/nat/ipv4_nat_entry.c
+++ b/net/nat/ipv4_nat_entry.c
@@ -34,14 +34,14 @@
 
 #include "nat/nat.h"
 
-#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
+#ifdef CONFIG_NET_NAT44
 
 /****************************************************************************
  * Private Data
  ****************************************************************************/
 
-static DECLARE_HASHTABLE(g_table_inbound, CONFIG_NET_NAT_HASH_BITS);
-static DECLARE_HASHTABLE(g_table_outbound, CONFIG_NET_NAT_HASH_BITS);
+static DECLARE_HASHTABLE(g_nat44_inbound, CONFIG_NET_NAT_HASH_BITS);
+static DECLARE_HASHTABLE(g_nat44_outbound, CONFIG_NET_NAT_HASH_BITS);
 
 /****************************************************************************
  * Private Functions
@@ -134,16 +134,16 @@ ipv4_nat_entry_create(uint8_t protocol,
   entry->external_port = external_port;
   entry->local_ip      = local_ip;
   entry->local_port    = local_port;
-#ifdef CONFIG_NET_NAT_SYMMETRIC
+#ifdef CONFIG_NET_NAT44_SYMMETRIC
   entry->peer_ip       = peer_ip;
   entry->peer_port     = peer_port;
 #endif
 
   ipv4_nat_entry_refresh(entry);
 
-  hashtable_add(g_table_inbound, &entry->hash_inbound,
+  hashtable_add(g_nat44_inbound, &entry->hash_inbound,
                 ipv4_nat_inbound_key(external_ip, external_port, protocol));
-  hashtable_add(g_table_outbound, &entry->hash_outbound,
+  hashtable_add(g_nat44_outbound, &entry->hash_outbound,
                 ipv4_nat_outbound_key(local_ip, local_port, protocol));
 
   return entry;
@@ -162,16 +162,16 @@ ipv4_nat_entry_create(uint8_t protocol,
 
 static void ipv4_nat_entry_delete(FAR struct ipv4_nat_entry *entry)
 {
-  ninfo("INFO: Removing NAT entry proto=%" PRIu8
+  ninfo("INFO: Removing NAT44 entry proto=%" PRIu8
         ", local=%" PRIx32 ":%" PRIu16 ", external=:%" PRIu16 "\n",
         entry->protocol, entry->local_ip, entry->local_port,
         entry->external_port);
 
-  hashtable_delete(g_table_inbound, &entry->hash_inbound,
+  hashtable_delete(g_nat44_inbound, &entry->hash_inbound,
                    ipv4_nat_inbound_key(entry->external_ip,
                                         entry->external_port,
                                         entry->protocol));
-  hashtable_delete(g_table_outbound, &entry->hash_outbound,
+  hashtable_delete(g_nat44_outbound, &entry->hash_outbound,
                    ipv4_nat_outbound_key(entry->local_ip,
                                          entry->local_port,
                                          entry->protocol));
@@ -207,9 +207,9 @@ static void ipv4_nat_reclaim_entry(int32_t current_time)
       int count = 0;
       int i;
 
-      ninfo("INFO: Reclaiming all expired NAT entries.\n");
+      ninfo("INFO: Reclaiming all expired NAT44 entries.\n");
 
-      hashtable_for_every_safe(g_table_inbound, p, tmp, i)
+      hashtable_for_every_safe(g_nat44_inbound, p, tmp, i)
         {
           FAR struct ipv4_nat_entry *entry =
             container_of(p, struct ipv4_nat_entry, hash_inbound);
@@ -221,10 +221,12 @@ static void ipv4_nat_reclaim_entry(int32_t current_time)
             }
         }
 
-      ninfo("INFO: %d expired NAT entries reclaimed.\n", count);
+      ninfo("INFO: %d expired NAT44 entries reclaimed.\n", count);
       next_reclaim_time = current_time + CONFIG_NET_NAT_ENTRY_RECLAIM_SEC;
     }
 }
+#else
+#  define ipv4_nat_reclaim_entry(t)
 #endif
 
 /****************************************************************************
@@ -239,7 +241,7 @@ static void ipv4_nat_reclaim_entry(int32_t current_time)
  *   any device.
  *
  * Input Parameters:
- *   dev        - The device on which NAT entries will be cleared.
+ *   dev - The device on which NAT entries will be cleared.
  *
  * Assumptions:
  *   NAT is initialized.
@@ -252,9 +254,9 @@ void ipv4_nat_entry_clear(FAR struct net_driver_s *dev)
   FAR hash_node_t *tmp;
   int i;
 
-  ninfo("INFO: Clearing all NAT entries for %s\n", dev->d_ifname);
+  ninfo("INFO: Clearing all NAT44 entries for %s\n", dev->d_ifname);
 
-  hashtable_for_every_safe(g_table_inbound, p, tmp, i)
+  hashtable_for_every_safe(g_nat44_inbound, p, tmp, i)
     {
       FAR struct ipv4_nat_entry *entry =
         container_of(p, struct ipv4_nat_entry, hash_inbound);
@@ -293,16 +295,14 @@ ipv4_nat_inbound_entry_find(uint8_t protocol, in_addr_t 
external_ip,
   FAR hash_node_t *p;
   FAR hash_node_t *tmp;
   bool skip_ip = net_ipv4addr_cmp(external_ip, INADDR_ANY);
-#ifdef CONFIG_NET_NAT_SYMMETRIC
+#ifdef CONFIG_NET_NAT44_SYMMETRIC
   bool skip_peer = net_ipv4addr_cmp(peer_ip, INADDR_ANY);
 #endif
   int32_t current_time = TICK2SEC(clock_systime_ticks());
 
-#if CONFIG_NET_NAT_ENTRY_RECLAIM_SEC > 0
   ipv4_nat_reclaim_entry(current_time);
-#endif
 
-  hashtable_for_every_possible_safe(g_table_inbound, p, tmp,
+  hashtable_for_every_possible_safe(g_nat44_inbound, p, tmp,
                   ipv4_nat_inbound_key(external_ip, external_port, protocol))
     {
       FAR struct ipv4_nat_entry *entry =
@@ -319,7 +319,7 @@ ipv4_nat_inbound_entry_find(uint8_t protocol, in_addr_t 
external_ip,
       if (entry->protocol == protocol &&
           (skip_ip || net_ipv4addr_cmp(entry->external_ip, external_ip)) &&
           entry->external_port == external_port
-#ifdef CONFIG_NET_NAT_SYMMETRIC
+#ifdef CONFIG_NET_NAT44_SYMMETRIC
           && (skip_peer || (net_ipv4addr_cmp(entry->peer_ip, peer_ip) &&
                             entry->peer_port == peer_port))
 #endif
@@ -376,11 +376,9 @@ ipv4_nat_outbound_entry_find(FAR struct net_driver_s *dev, 
uint8_t protocol,
   uint16_t external_port;
   int32_t current_time = TICK2SEC(clock_systime_ticks());
 
-#if CONFIG_NET_NAT_ENTRY_RECLAIM_SEC > 0
   ipv4_nat_reclaim_entry(current_time);
-#endif
 
-  hashtable_for_every_possible_safe(g_table_outbound, p, tmp,
+  hashtable_for_every_possible_safe(g_nat44_outbound, p, tmp,
                       ipv4_nat_outbound_key(local_ip, local_port, protocol))
     {
       FAR struct ipv4_nat_entry *entry =
@@ -398,7 +396,7 @@ ipv4_nat_outbound_entry_find(FAR struct net_driver_s *dev, 
uint8_t protocol,
           net_ipv4addr_cmp(entry->external_ip, dev->d_ipaddr) &&
           net_ipv4addr_cmp(entry->local_ip, local_ip) &&
           entry->local_port == local_port
-#ifdef CONFIG_NET_NAT_SYMMETRIC
+#ifdef CONFIG_NET_NAT44_SYMMETRIC
           && net_ipv4addr_cmp(entry->peer_ip, peer_ip) &&
           entry->peer_port == peer_port
 #endif
@@ -432,4 +430,4 @@ ipv4_nat_outbound_entry_find(FAR struct net_driver_s *dev, 
uint8_t protocol,
                                local_ip, local_port, peer_ip, peer_port);
 }
 
-#endif /* CONFIG_NET_NAT && CONFIG_NET_IPv4 */
+#endif /* CONFIG_NET_NAT44 */
diff --git a/net/nat/ipv6_nat.c b/net/nat/ipv6_nat.c
new file mode 100644
index 0000000000..c03a3c6f87
--- /dev/null
+++ b/net/nat/ipv6_nat.c
@@ -0,0 +1,692 @@
+/****************************************************************************
+ * net/nat/ipv6_nat.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <debug.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <nuttx/net/icmpv6.h>
+#include <nuttx/net/tcp.h>
+#include <nuttx/net/udp.h>
+
+#include "nat/nat.h"
+#include "utils/utils.h"
+
+#ifdef CONFIG_NET_NAT66
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static FAR struct ipv6_nat_entry *
+ipv6_nat_inbound_internal(FAR struct ipv6_hdr_s *ipv6,
+                          enum nat_manip_type_e manip_type);
+
+static FAR struct ipv6_nat_entry *
+ipv6_nat_outbound_internal(FAR struct net_driver_s *dev,
+                           FAR struct ipv6_hdr_s *ipv6,
+                           enum nat_manip_type_e manip_type);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipv6_nat_ip_adjust
+ *
+ * Description:
+ *   Adjust address and checksum for network packet.
+ *
+ * Input Parameters:
+ *   l4chksum   - Points to the L4 checksum to adjust, NULL for not adjust.
+ *   old_ip     - The IP to be set.
+ *   new_ip     - The IP to set into header.
+ *
+ ****************************************************************************/
+
+static void ipv6_nat_ip_adjust(FAR uint16_t *l4chksum, FAR uint16_t *old_ip,
+                               net_ipv6addr_t new_ip)
+{
+  /* TODO: Maybe we can accelerate the checksum adjustment by pre-calculate a
+   * difference of checksum, and apply it to each packet, instead of calling
+   * chksum_adjust each time.
+   */
+
+  if (l4chksum != NULL)
+    {
+      nat_chksum_adjust(l4chksum, old_ip, new_ip, sizeof(net_ipv6addr_t));
+    }
+
+  net_ipv6addr_hdrcopy(old_ip, new_ip);
+}
+
+/****************************************************************************
+ * Name: ipv6_nat_port_adjust
+ *
+ * Description:
+ *   Adjust port and checksum for network packet.
+ *
+ * Input Parameters:
+ *   l4chksum - Points to the L4 checksum to adjust, NULL for not adjust.
+ *   old_port - The port to be set.
+ *   new_port - The port to set into header.
+ *
+ ****************************************************************************/
+
+static void ipv6_nat_port_adjust(FAR uint16_t *l4chksum,
+                                 FAR uint16_t *old_port, uint16_t new_port)
+{
+  if (l4chksum != NULL)
+    {
+      nat_chksum_adjust(l4chksum, old_port, &new_port, sizeof(new_port));
+    }
+
+  *old_port = new_port;
+}
+
+/****************************************************************************
+ * Name: ipv6_nat_inbound_tcp
+ *
+ * Description:
+ *   Check if a received TCP packet belongs to a NAT entry. If so, translate
+ *   the external IP/Port to local IP/Port.
+ *
+ * Input Parameters:
+ *   ipv6       - Points to the IPv6 header to translate.
+ *   tcp        - Points to the TCP header to translate.
+ *   manip_type - Whether external IP/Port is in source or destination.
+ *
+ * Returned Value:
+ *   The corresponding NAT entry of the packet.
+ *
+ * Assumptions:
+ *   Packet is received on NAT device and is targeting at the address
+ *   assigned to the device.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_TCP
+static FAR struct ipv6_nat_entry *
+ipv6_nat_inbound_tcp(FAR struct ipv6_hdr_s *ipv6, FAR struct tcp_hdr_s *tcp,
+                     enum nat_manip_type_e manip_type)
+{
+  FAR uint16_t              *external_ip   = MANIP_IPADDR(ipv6, manip_type);
+  FAR uint16_t              *external_port = MANIP_PORT(tcp, manip_type);
+  FAR uint16_t              *peer_ip       = PEER_IPADDR(ipv6, manip_type);
+  FAR uint16_t              *peer_port     = PEER_PORT(tcp, manip_type);
+  FAR struct ipv6_nat_entry *entry         =
+                 ipv6_nat_inbound_entry_find(IP_PROTO_TCP,
+                                             external_ip, *external_port,
+                                             peer_ip, *peer_port, true);
+  if (!entry)
+    {
+      return NULL;
+    }
+
+  /* Note: Field tcpchksum is not guaranteed exists in TCP header inside
+   * ICMPv6 Error MSG, but we manually guarantee that it is inside valid
+   * address (IOB >= IP + ICMPv6 + IP + TCP), so we can update it safely.
+   */
+
+  ipv6_nat_port_adjust(&tcp->tcpchksum, external_port, entry->local_port);
+  ipv6_nat_ip_adjust(&tcp->tcpchksum, external_ip, entry->local_ip);
+
+  return entry;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipv6_nat_inbound_udp
+ *
+ * Description:
+ *   Check if a received UDP packet belongs to a NAT entry. If so, translate
+ *   the external IP/Port to local IP/Port.
+ *
+ * Input Parameters:
+ *   ipv6       - Points to the IPv6 header to translate.
+ *   udp        - Points to the UDP header to translate.
+ *   manip_type - Whether external IP/Port is in source or destination.
+ *
+ * Returned Value:
+ *   The corresponding NAT entry of the packet.
+ *
+ * Assumptions:
+ *   Packet is received on NAT device and is targeting at the address
+ *   assigned to the device.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_UDP
+static FAR struct ipv6_nat_entry *
+ipv6_nat_inbound_udp(FAR struct ipv6_hdr_s *ipv6, FAR struct udp_hdr_s *udp,
+                     enum nat_manip_type_e manip_type)
+{
+  FAR uint16_t              *external_ip   = MANIP_IPADDR(ipv6, manip_type);
+  FAR uint16_t              *external_port = MANIP_PORT(udp, manip_type);
+  FAR uint16_t              *peer_ip       = PEER_IPADDR(ipv6, manip_type);
+  FAR uint16_t              *peer_port     = PEER_PORT(udp, manip_type);
+  FAR uint16_t              *udpchksum;
+  FAR struct ipv6_nat_entry *entry         =
+                 ipv6_nat_inbound_entry_find(IP_PROTO_UDP,
+                                             external_ip, *external_port,
+                                             peer_ip, *peer_port, true);
+
+  if (!entry)
+    {
+      return NULL;
+    }
+
+  /* UDP checksum has special case 0 (no checksum) */
+
+  udpchksum = udp->udpchksum != 0 ? &udp->udpchksum : NULL;
+
+  ipv6_nat_port_adjust(udpchksum, external_port, entry->local_port);
+  ipv6_nat_ip_adjust(udpchksum, external_ip, entry->local_ip);
+
+  return entry;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipv6_nat_inbound_icmpv6
+ *
+ * Description:
+ *   Check if a received ICMPv6 packet belongs to a NAT entry. If so,
+ *   translate the external IP/ID to local IP/ID.
+ *
+ * Input Parameters:
+ *   ipv6       - Points to the IPv6 header to translate.
+ *   icmpv6     - Points to the ICMPv6 header to translate.
+ *   manip_type - Whether external IP is in source or destination.
+ *
+ * Returned Value:
+ *   The corresponding NAT entry of the packet.
+ *
+ * Assumptions:
+ *   Packet is received on g_dev and is targeting at the address assigned to
+ *   g_dev.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_ICMPv6
+static FAR struct ipv6_nat_entry *
+ipv6_nat_inbound_icmpv6(FAR struct ipv6_hdr_s *ipv6,
+                        FAR struct icmpv6_hdr_s *icmpv6,
+                        enum nat_manip_type_e manip_type)
+{
+  FAR uint16_t              *external_ip = MANIP_IPADDR(ipv6, manip_type);
+  FAR uint16_t              *peer_ip     = PEER_IPADDR(ipv6, manip_type);
+  FAR struct ipv6_nat_entry *entry;
+
+  switch (icmpv6->type)
+    {
+      case ICMPv6_ECHO_REQUEST:
+      case ICMPv6_ECHO_REPLY:
+        entry = ipv6_nat_inbound_entry_find(IP_PROTO_ICMP6,
+                                            external_ip, icmpv6->data[0],
+                                            peer_ip, icmpv6->data[0], true);
+        if (!entry)
+          {
+            return NULL;
+          }
+
+        ipv6_nat_port_adjust(&icmpv6->chksum,
+                             &icmpv6->data[0], entry->local_port);
+        ipv6_nat_ip_adjust(&icmpv6->chksum, external_ip, entry->local_ip);
+        return entry;
+
+      case ICMPv6_DEST_UNREACHABLE:
+      case ICMPv6_PACKET_TOO_BIG:
+      case ICMPv6_PACKET_TIME_EXCEEDED:
+      case ICMPv6_PACKET_PARAM_PROBLEM:
+        /* ICMPv6 Error MSG inside another ICMPv6 Error MSG is forbidden by
+         * RFC4443, Section 2.4, Page 6, so we only process the outermost
+         * ICMPv6 Error MSG (manip type is DST).
+         */
+
+        if (manip_type == NAT_MANIP_DST)
+          {
+            /* The payload in the ICMPv6 packet is the origin packet we sent.
+             * We don't need to check or backup any inner L4 data, because
+             * every ICMPv6 error message (type < 128) MUST include as much
+             * of the IPv6 offending (invoking) packet as possible. And the
+             * inner packet will be translated by the inbound process
+             * without needed to modify any outer packet checksum.
+             */
+
+            FAR struct ipv6_hdr_s *inner =
+                (FAR struct ipv6_hdr_s *)(icmpv6 + 1);
+
+            /* Find entry and translate inner. */
+
+            entry = ipv6_nat_inbound_internal(inner, NAT_MANIP_SRC);
+
+            if (!entry)
+              {
+                return NULL;
+              }
+
+            /* Adjust outer IP */
+
+            ipv6_nat_ip_adjust(&icmpv6->chksum, external_ip,
+                               entry->local_ip);
+
+            return entry;
+          }
+    }
+
+  return NULL;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipv6_nat_outbound_tcp
+ *
+ * Description:
+ *   Check if we want to perform NAT with this outbound TCP packet before
+ *   sending it. If so, translate the local IP/Port to external IP/Port.
+ *
+ * Input Parameters:
+ *   dev        - The device to sent the packet (to get external IP).
+ *   ipv6       - Points to the IPv6 header to translate.
+ *   tcp        - Points to the TCP header to translate.
+ *   manip_type - Whether local IP/Port is in source or destination.
+ *
+ * Returned Value:
+ *   The corresponding NAT entry of the packet.
+ *
+ * Assumptions:
+ *   Packet will be sent on NAT device.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_TCP
+static FAR struct ipv6_nat_entry *
+ipv6_nat_outbound_tcp(FAR struct net_driver_s *dev,
+                      FAR struct ipv6_hdr_s *ipv6, FAR struct tcp_hdr_s *tcp,
+                      enum nat_manip_type_e manip_type)
+{
+  FAR uint16_t              *local_ip   = MANIP_IPADDR(ipv6, manip_type);
+  FAR uint16_t              *local_port = MANIP_PORT(tcp, manip_type);
+  FAR uint16_t              *peer_ip    = PEER_IPADDR(ipv6, manip_type);
+  FAR uint16_t              *peer_port  = PEER_PORT(tcp, manip_type);
+  FAR struct ipv6_nat_entry *entry;
+
+  /* Only create entry when it's the outermost packet (manip type is SRC). */
+
+  entry = ipv6_nat_outbound_entry_find(dev, IP_PROTO_TCP,
+              local_ip, *local_port, peer_ip, *peer_port,
+              manip_type == NAT_MANIP_SRC);
+  if (!entry)
+    {
+      return NULL;
+    }
+
+  /* Note: Field tcpchksum is not guaranteed exists in TCP header inside
+   * ICMPv6 Error MSG, but we manually guarantee that it is inside valid
+   * address (IOB >= IP + ICMPv6 + IP + TCP), so we can update it safely.
+   */
+
+  ipv6_nat_port_adjust(&tcp->tcpchksum, local_port, entry->external_port);
+  ipv6_nat_ip_adjust(&tcp->tcpchksum, local_ip, entry->external_ip);
+
+  return entry;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipv6_nat_outbound_udp
+ *
+ * Description:
+ *   Check if we want to perform NAT with this outbound UDP packet before
+ *   sending it. If so, translate the local IP/Port to external IP/Port.
+ *
+ * Input Parameters:
+ *   dev        - The device to sent the packet (to get external IP).
+ *   ipv6       - Points to the IPv6 header to translate.
+ *   udp        - Points to the UDP header to translate.
+ *   manip_type - Whether local IP/Port is in source or destination.
+ *
+ * Returned Value:
+ *   The corresponding NAT entry of the packet.
+ *
+ * Assumptions:
+ *   Packet will be sent on NAT device.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_UDP
+static FAR struct ipv6_nat_entry *
+ipv6_nat_outbound_udp(FAR struct net_driver_s *dev,
+                      FAR struct ipv6_hdr_s *ipv6, FAR struct udp_hdr_s *udp,
+                      enum nat_manip_type_e manip_type)
+{
+  FAR uint16_t              *local_ip   = MANIP_IPADDR(ipv6, manip_type);
+  FAR uint16_t              *local_port = MANIP_PORT(udp, manip_type);
+  FAR uint16_t              *peer_ip    = PEER_IPADDR(ipv6, manip_type);
+  FAR uint16_t              *peer_port  = PEER_PORT(udp, manip_type);
+  FAR uint16_t              *udpchksum;
+  FAR struct ipv6_nat_entry *entry;
+
+  /* Only create entry when it's the outermost packet (manip type is SRC). */
+
+  entry = ipv6_nat_outbound_entry_find(dev, IP_PROTO_UDP,
+              local_ip, *local_port, peer_ip, *peer_port,
+              manip_type == NAT_MANIP_SRC);
+  if (!entry)
+    {
+      return NULL;
+    }
+
+  /* UDP checksum has special case 0 (no checksum) */
+
+  udpchksum = udp->udpchksum != 0 ? &udp->udpchksum : NULL;
+
+  ipv6_nat_port_adjust(udpchksum, local_port, entry->external_port);
+  ipv6_nat_ip_adjust(udpchksum, local_ip, entry->external_ip);
+
+  return entry;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipv6_nat_outbound_icmpv6
+ *
+ * Description:
+ *   Check if we want to perform NAT with this outbound ICMPv6 packet before
+ *   sending it. If so, translate the local IP/ID to external IP/ID.
+ *
+ * Input Parameters:
+ *   dev        - The device to sent the packet (to get external IP).
+ *   ipv6       - Points to the IPv6 header to translate.
+ *   icmpv6     - Points to the ICMPv6 header to translate.
+ *   manip_type - Whether local IP is in source or destination.
+ *
+ * Returned Value:
+ *   The corresponding NAT entry of the packet.
+ *
+ * Assumptions:
+ *   Packet will be sent on NAT device.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_ICMPv6
+static FAR struct ipv6_nat_entry *
+ipv6_nat_outbound_icmpv6(FAR struct net_driver_s *dev,
+                         FAR struct ipv6_hdr_s *ipv6,
+                         FAR struct icmpv6_hdr_s *icmpv6,
+                         enum nat_manip_type_e manip_type)
+{
+  FAR uint16_t              *local_ip = MANIP_IPADDR(ipv6, manip_type);
+  FAR uint16_t              *peer_ip  = PEER_IPADDR(ipv6, manip_type);
+  FAR struct ipv6_nat_entry *entry;
+
+  switch (icmpv6->type)
+    {
+      case ICMPv6_ECHO_REQUEST:
+      case ICMPv6_ECHO_REPLY:
+
+        /* Note: Only create new entry when it's the outermost packet (that
+         * is, manip type is SRC).
+         */
+
+        entry = ipv6_nat_outbound_entry_find(dev, IP_PROTO_ICMP6,
+                    local_ip, icmpv6->data[0], peer_ip, icmpv6->data[0],
+                    manip_type == NAT_MANIP_SRC);
+        if (!entry)
+          {
+            return NULL;
+          }
+
+        ipv6_nat_port_adjust(&icmpv6->chksum,
+                             &icmpv6->data[0], entry->external_port);
+        ipv6_nat_ip_adjust(&icmpv6->chksum, local_ip, entry->external_ip);
+        return entry;
+
+      case ICMPv6_DEST_UNREACHABLE:
+      case ICMPv6_PACKET_TOO_BIG:
+      case ICMPv6_PACKET_TIME_EXCEEDED:
+      case ICMPv6_PACKET_PARAM_PROBLEM:
+        /* ICMPv6 Error MSG inside another ICMPv6 Error MSG is forbidden by
+         * RFC4443, Section 2.4, Page 6, so we only process the outermost
+         * ICMPv6 Error MSG (manip type is DST).
+         */
+
+        if (manip_type == NAT_MANIP_SRC)
+          {
+            /* The payload in the ICMPv6 packet is the origin packet we got.
+             * We don't need to check or backup any inner L4 data, because
+             * every ICMPv6 error message (type < 128) MUST include as much
+             * of the IPv6 offending (invoking) packet as possible. And the
+             * inner packet will be translated by the inbound process
+             * without needed to modify any outer packet checksum.
+             */
+
+            FAR struct ipv6_hdr_s *inner =
+                (FAR struct ipv6_hdr_s *)(icmpv6 + 1);
+
+            /* Find entry and translate inner. */
+
+            entry = ipv6_nat_outbound_internal(dev, inner, NAT_MANIP_DST);
+
+            if (!entry)
+              {
+                return NULL;
+              }
+
+            /* Adjust outer IP */
+
+            ipv6_nat_ip_adjust(&icmpv6->chksum, local_ip,
+                               entry->external_ip);
+
+            return entry;
+          }
+    }
+
+  return NULL;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipv6_nat_inbound_internal
+ *
+ * Description:
+ *   Check if a received packet belongs to a NAT entry. If so, translate
+ *   the external IP/Port to local IP/Port.
+ *
+ * Input Parameters:
+ *   ipv6       - Points to the IPv6 header to translate.
+ *   manip_type - Whether external IP/Port is in source or destination.
+ *
+ * Returned Value:
+ *   The corresponding NAT entry of the packet.
+ *
+ * Assumptions:
+ *   Packet is received on NAT device and is targeting at the address
+ *   assigned to the device.
+ *
+ ****************************************************************************/
+
+static FAR struct ipv6_nat_entry *
+ipv6_nat_inbound_internal(FAR struct ipv6_hdr_s *ipv6,
+                          enum nat_manip_type_e manip_type)
+{
+  uint8_t proto;
+  FAR void *l4hdr = net_ipv6_payload(ipv6, &proto);
+
+  switch (ipv6->proto)
+    {
+#ifdef CONFIG_NET_TCP
+      case IP_PROTO_TCP:
+        return ipv6_nat_inbound_tcp(ipv6, l4hdr, manip_type);
+#endif
+
+#ifdef CONFIG_NET_UDP
+      case IP_PROTO_UDP:
+        return ipv6_nat_inbound_udp(ipv6, l4hdr, manip_type);
+#endif
+
+#ifdef CONFIG_NET_ICMPv6
+      case IP_PROTO_ICMP6:
+        return ipv6_nat_inbound_icmpv6(ipv6, l4hdr, manip_type);
+#endif
+    }
+
+  return NULL;
+}
+
+/****************************************************************************
+ * Name: ipv6_nat_outbound_internal
+ *
+ * Description:
+ *   Check if we want to perform NAT with this outbound packet before
+ *   sending it. If so, translate the local IP/Port to external IP/Port.
+ *
+ * Input Parameters:
+ *   dev        - The device to sent the packet (to get external IP).
+ *   ipv6       - Points to the IPv6 header to translate.
+ *   manip_type - Whether local IP/Port is in source or destination.
+ *
+ * Returned Value:
+ *   The corresponding NAT entry of the packet.
+ *
+ * Assumptions:
+ *   Packet will be sent on NAT device.
+ *
+ ****************************************************************************/
+
+static FAR struct ipv6_nat_entry *
+ipv6_nat_outbound_internal(FAR struct net_driver_s *dev,
+                           FAR struct ipv6_hdr_s *ipv6,
+                           enum nat_manip_type_e manip_type)
+{
+  uint8_t proto;
+  FAR void *l4hdr = net_ipv6_payload(ipv6, &proto);
+
+  switch (proto)
+    {
+#ifdef CONFIG_NET_TCP
+      case IP_PROTO_TCP:
+        return ipv6_nat_outbound_tcp(dev, ipv6, l4hdr, manip_type);
+#endif
+
+#ifdef CONFIG_NET_UDP
+      case IP_PROTO_UDP:
+        return ipv6_nat_outbound_udp(dev, ipv6, l4hdr, manip_type);
+#endif
+
+#ifdef CONFIG_NET_ICMPv6
+      case IP_PROTO_ICMP6:
+        return ipv6_nat_outbound_icmpv6(dev, ipv6, l4hdr, manip_type);
+#endif
+    }
+
+  return NULL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipv6_nat_inbound
+ *
+ * Description:
+ *   Check if a received packet belongs to a NAT entry. If so, translate it.
+ *
+ * Input Parameters:
+ *   dev   - The device on which the packet is received.
+ *   ipv6  - Points to the IPv6 header with dev->d_buf.
+ *
+ ****************************************************************************/
+
+void ipv6_nat_inbound(FAR struct net_driver_s *dev,
+                      FAR struct ipv6_hdr_s *ipv6)
+{
+  /* We only process packets from NAT device and targeting at the address
+   * assigned to the device.
+   */
+
+  if (IFF_IS_NAT(dev->d_flags) &&
+      NETDEV_IS_MY_V6ADDR(dev, ipv6->destipaddr))
+    {
+      FAR struct ipv6_nat_entry *entry =
+          ipv6_nat_inbound_internal(ipv6, NAT_MANIP_DST);
+      if (!entry)
+        {
+          /* Inbound without entry is OK (e.g. towards NuttX itself), skip. */
+
+          return;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: ipv6_nat_outbound
+ *
+ * Description:
+ *   Check if we want to perform NAT with this outbound packet before sending
+ *   it. If so, translate it.
+ *
+ * Input Parameters:
+ *   dev   - The device on which the packet will be sent.
+ *   ipv6  - Points to the IPv6 header to be filled into dev->d_buf later.
+ *   manip_type - Whether local IP/Port is in source or destination.
+ *
+ * Returned Value:
+ *   Zero is returned if NAT is successfully applied, or is not enabled for
+ *   this packet;
+ *   A negated errno value is returned if error occured.
+ *
+ ****************************************************************************/
+
+int ipv6_nat_outbound(FAR struct net_driver_s *dev,
+                      FAR struct ipv6_hdr_s *ipv6,
+                      enum nat_manip_type_e manip_type)
+{
+  /* We only process packets targeting at NAT device but not targeting at the
+   * address assigned to the device.
+   */
+
+  if (IFF_IS_NAT(dev->d_flags) &&
+      !NETDEV_IS_MY_V6ADDR(dev, ipv6->srcipaddr) &&
+      !NETDEV_IS_MY_V6ADDR(dev, ipv6->destipaddr))
+    {
+      FAR struct ipv6_nat_entry *entry =
+          ipv6_nat_outbound_internal(dev, ipv6, manip_type);
+      if (manip_type == NAT_MANIP_SRC && !entry)
+        {
+          /* Outbound entry creation failed, should have entry. */
+
+          return -ENOENT;
+        }
+    }
+
+  return OK;
+}
+
+#endif /* CONFIG_NET_NAT66 */
diff --git a/net/nat/ipv4_nat_entry.c b/net/nat/ipv6_nat_entry.c
similarity index 55%
copy from net/nat/ipv4_nat_entry.c
copy to net/nat/ipv6_nat_entry.c
index 7b033a5d0f..e9e4a00a43 100644
--- a/net/nat/ipv4_nat_entry.c
+++ b/net/nat/ipv6_nat_entry.c
@@ -1,5 +1,5 @@
 /****************************************************************************
- * net/nat/ipv4_nat_entry.c
+ * net/nat/ipv6_nat_entry.c
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -32,55 +32,43 @@
 #include <nuttx/kmalloc.h>
 #include <nuttx/nuttx.h>
 
+#include "inet/inet.h"
 #include "nat/nat.h"
 
-#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
+#ifdef CONFIG_NET_NAT66
 
 /****************************************************************************
  * Private Data
  ****************************************************************************/
 
-static DECLARE_HASHTABLE(g_table_inbound, CONFIG_NET_NAT_HASH_BITS);
-static DECLARE_HASHTABLE(g_table_outbound, CONFIG_NET_NAT_HASH_BITS);
+static DECLARE_HASHTABLE(g_nat66_inbound, CONFIG_NET_NAT_HASH_BITS);
+static DECLARE_HASHTABLE(g_nat66_outbound, CONFIG_NET_NAT_HASH_BITS);
 
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
 
 /****************************************************************************
- * Name: ipv4_nat_inbound_key
+ * Name: ipv6_nat_hash_key
  *
  * Description:
- *   Create an inbound hash key for NAT.
+ *   Create a hash key for NAT66.
  *
  ****************************************************************************/
 
-static inline uint32_t ipv4_nat_inbound_key(in_addr_t external_ip,
-                                            uint16_t external_port,
-                                            uint8_t protocol)
+static inline uint32_t ipv6_nat_hash_key(const net_ipv6addr_t ip,
+                                         uint16_t port, uint8_t protocol)
 {
-  return NTOHL(external_ip) ^ /* external ip may different in higher bits. */
-         ((uint32_t)protocol << 16) ^ external_port;
-}
-
-/****************************************************************************
- * Name: ipv4_nat_outbound_key
- *
- * Description:
- *   Create an outbound hash key for NAT.
- *
- ****************************************************************************/
+  uint32_t key = (((uint32_t)ip[0] << 16) | ip[1]) ^
+                 (((uint32_t)ip[2] << 16) | ip[3]) ^
+                 (((uint32_t)ip[4] << 16) | ip[5]) ^
+                 (((uint32_t)ip[6] << 16) | ip[7]);
 
-static inline uint32_t ipv4_nat_outbound_key(in_addr_t local_ip,
-                                             uint16_t local_port,
-                                             uint8_t protocol)
-{
-  return NTOHL(local_ip) ^ /* NTOHL makes sure difference is in lower bits. */
-         ((uint32_t)protocol << 8) ^ ((uint32_t)local_port << 16);
+  return key ^ ((uint32_t)protocol << 16) ^ port;
 }
 
 /****************************************************************************
- * Name: ipv4_nat_entry_refresh
+ * Name: ipv6_nat_entry_refresh
  *
  * Description:
  *   Refresh a NAT entry, update its expiration time.
@@ -90,13 +78,13 @@ static inline uint32_t ipv4_nat_outbound_key(in_addr_t 
local_ip,
  *
  ****************************************************************************/
 
-static void ipv4_nat_entry_refresh(FAR struct ipv4_nat_entry *entry)
+static void ipv6_nat_entry_refresh(FAR struct ipv6_nat_entry *entry)
 {
   entry->expire_time = nat_expire_time(entry->protocol);
 }
 
 /****************************************************************************
- * Name: ipv4_nat_entry_create
+ * Name: ipv6_nat_entry_create
  *
  * Description:
  *   Create a NAT entry and insert into entry list.
@@ -115,42 +103,44 @@ static void ipv4_nat_entry_refresh(FAR struct 
ipv4_nat_entry *entry)
  *
  ****************************************************************************/
 
-static FAR struct ipv4_nat_entry *
-ipv4_nat_entry_create(uint8_t protocol,
-                      in_addr_t external_ip, uint16_t external_port,
-                      in_addr_t local_ip, uint16_t local_port,
-                      in_addr_t peer_ip, uint16_t peer_port)
+static FAR struct ipv6_nat_entry *
+ipv6_nat_entry_create(uint8_t protocol, const net_ipv6addr_t external_ip,
+                      uint16_t external_port, const net_ipv6addr_t local_ip,
+                      uint16_t local_port, const net_ipv6addr_t peer_ip,
+                      uint16_t peer_port)
 {
-  FAR struct ipv4_nat_entry *entry =
-      kmm_malloc(sizeof(struct ipv4_nat_entry));
+  FAR struct ipv6_nat_entry *entry =
+      kmm_malloc(sizeof(struct ipv6_nat_entry));
   if (entry == NULL)
     {
-      nwarn("WARNING: Failed to allocate IPv4 NAT entry\n");
+      nwarn("WARNING: Failed to allocate IPv6 NAT entry\n");
       return NULL;
     }
 
   entry->protocol      = protocol;
-  entry->external_ip   = external_ip;
   entry->external_port = external_port;
-  entry->local_ip      = local_ip;
   entry->local_port    = local_port;
-#ifdef CONFIG_NET_NAT_SYMMETRIC
-  entry->peer_ip       = peer_ip;
+#ifdef CONFIG_NET_NAT66_SYMMETRIC
   entry->peer_port     = peer_port;
 #endif
+  net_ipv6addr_copy(entry->external_ip, external_ip);
+  net_ipv6addr_copy(entry->local_ip, local_ip);
+#ifdef CONFIG_NET_NAT66_SYMMETRIC
+  net_ipv6addr_copy(entry->peer_ip, peer_ip);
+#endif
 
-  ipv4_nat_entry_refresh(entry);
+  ipv6_nat_entry_refresh(entry);
 
-  hashtable_add(g_table_inbound, &entry->hash_inbound,
-                ipv4_nat_inbound_key(external_ip, external_port, protocol));
-  hashtable_add(g_table_outbound, &entry->hash_outbound,
-                ipv4_nat_outbound_key(local_ip, local_port, protocol));
+  hashtable_add(g_nat66_inbound, &entry->hash_inbound,
+                ipv6_nat_hash_key(external_ip, external_port, protocol));
+  hashtable_add(g_nat66_outbound, &entry->hash_outbound,
+                ipv6_nat_hash_key(local_ip, local_port, protocol));
 
   return entry;
 }
 
 /****************************************************************************
- * Name: ipv4_nat_entry_delete
+ * Name: ipv6_nat_entry_delete
  *
  * Description:
  *   Delete a NAT entry and remove from entry list.
@@ -160,27 +150,30 @@ ipv4_nat_entry_create(uint8_t protocol,
  *
  ****************************************************************************/
 
-static void ipv4_nat_entry_delete(FAR struct ipv4_nat_entry *entry)
+static void ipv6_nat_entry_delete(FAR struct ipv6_nat_entry *entry)
 {
-  ninfo("INFO: Removing NAT entry proto=%" PRIu8
-        ", local=%" PRIx32 ":%" PRIu16 ", external=:%" PRIu16 "\n",
-        entry->protocol, entry->local_ip, entry->local_port,
-        entry->external_port);
-
-  hashtable_delete(g_table_inbound, &entry->hash_inbound,
-                   ipv4_nat_inbound_key(entry->external_ip,
-                                        entry->external_port,
-                                        entry->protocol));
-  hashtable_delete(g_table_outbound, &entry->hash_outbound,
-                   ipv4_nat_outbound_key(entry->local_ip,
-                                         entry->local_port,
-                                         entry->protocol));
+  ninfo("INFO: Removing NAT66 entry proto=%" PRIu8
+        ", local=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%" PRIu16
+        ", external=:%" PRIu16 "\n",
+        entry->protocol, entry->local_ip[0], entry->local_ip[1],
+        entry->local_ip[2], entry->local_ip[3], entry->local_ip[4],
+        entry->local_ip[5], entry->local_ip[6], entry->local_ip[7],
+        entry->local_port, entry->external_port);
+
+  hashtable_delete(g_nat66_inbound, &entry->hash_inbound,
+                   ipv6_nat_hash_key(entry->external_ip,
+                                     entry->external_port,
+                                     entry->protocol));
+  hashtable_delete(g_nat66_outbound, &entry->hash_outbound,
+                   ipv6_nat_hash_key(entry->local_ip,
+                                     entry->local_port,
+                                     entry->protocol));
 
   kmm_free(entry);
 }
 
 /****************************************************************************
- * Name: ipv4_nat_reclaim_entry
+ * Name: ipv6_nat_reclaim_entry
  *
  * Description:
  *   Try reclaim all expired NAT entries.
@@ -196,7 +189,7 @@ static void ipv4_nat_entry_delete(FAR struct ipv4_nat_entry 
*entry)
  ****************************************************************************/
 
 #if CONFIG_NET_NAT_ENTRY_RECLAIM_SEC > 0
-static void ipv4_nat_reclaim_entry(int32_t current_time)
+static void ipv6_nat_reclaim_entry(int32_t current_time)
 {
   static int32_t next_reclaim_time = CONFIG_NET_NAT_ENTRY_RECLAIM_SEC;
 
@@ -207,24 +200,26 @@ static void ipv4_nat_reclaim_entry(int32_t current_time)
       int count = 0;
       int i;
 
-      ninfo("INFO: Reclaiming all expired NAT entries.\n");
+      ninfo("INFO: Reclaiming all expired NAT66 entries.\n");
 
-      hashtable_for_every_safe(g_table_inbound, p, tmp, i)
+      hashtable_for_every_safe(g_nat66_inbound, p, tmp, i)
         {
-          FAR struct ipv4_nat_entry *entry =
-            container_of(p, struct ipv4_nat_entry, hash_inbound);
+          FAR struct ipv6_nat_entry *entry =
+            container_of(p, struct ipv6_nat_entry, hash_inbound);
 
           if (entry->expire_time - current_time <= 0)
             {
-              ipv4_nat_entry_delete(entry);
+              ipv6_nat_entry_delete(entry);
               count++;
             }
         }
 
-      ninfo("INFO: %d expired NAT entries reclaimed.\n", count);
+      ninfo("INFO: %d expired NAT66 entries reclaimed.\n", count);
       next_reclaim_time = current_time + CONFIG_NET_NAT_ENTRY_RECLAIM_SEC;
     }
 }
+#else
+#  define ipv6_nat_reclaim_entry(t)
 #endif
 
 /****************************************************************************
@@ -232,42 +227,42 @@ static void ipv4_nat_reclaim_entry(int32_t current_time)
  ****************************************************************************/
 
 /****************************************************************************
- * Name: ipv4_nat_entry_clear
+ * Name: ipv6_nat_entry_clear
  *
  * Description:
  *   Clear all entries related to dev. Called when NAT will be disabled on
  *   any device.
  *
  * Input Parameters:
- *   dev        - The device on which NAT entries will be cleared.
+ *   dev - The device on which NAT entries will be cleared.
  *
  * Assumptions:
  *   NAT is initialized.
  *
  ****************************************************************************/
 
-void ipv4_nat_entry_clear(FAR struct net_driver_s *dev)
+void ipv6_nat_entry_clear(FAR struct net_driver_s *dev)
 {
   FAR hash_node_t *p;
   FAR hash_node_t *tmp;
   int i;
 
-  ninfo("INFO: Clearing all NAT entries for %s\n", dev->d_ifname);
+  ninfo("INFO: Clearing all NAT66 entries for %s\n", dev->d_ifname);
 
-  hashtable_for_every_safe(g_table_inbound, p, tmp, i)
+  hashtable_for_every_safe(g_nat66_inbound, p, tmp, i)
     {
-      FAR struct ipv4_nat_entry *entry =
-        container_of(p, struct ipv4_nat_entry, hash_inbound);
+      FAR struct ipv6_nat_entry *entry =
+        container_of(p, struct ipv6_nat_entry, hash_inbound);
 
-      if (net_ipv4addr_cmp(entry->external_ip, dev->d_ipaddr))
+      if (NETDEV_IS_MY_V6ADDR(dev, entry->external_ip))
         {
-          ipv4_nat_entry_delete(entry);
+          ipv6_nat_entry_delete(entry);
         }
     }
 }
 
 /****************************************************************************
- * Name: ipv4_nat_inbound_entry_find
+ * Name: ipv6_nat_inbound_entry_find
  *
  * Description:
  *   Find the inbound entry in NAT entry list.
@@ -285,49 +280,49 @@ void ipv4_nat_entry_clear(FAR struct net_driver_s *dev)
  *
  ****************************************************************************/
 
-FAR struct ipv4_nat_entry *
-ipv4_nat_inbound_entry_find(uint8_t protocol, in_addr_t external_ip,
-                            uint16_t external_port, in_addr_t peer_ip,
+FAR struct ipv6_nat_entry *
+ipv6_nat_inbound_entry_find(uint8_t protocol,
+                            const net_ipv6addr_t external_ip,
+                            uint16_t external_port,
+                            const net_ipv6addr_t peer_ip,
                             uint16_t peer_port, bool refresh)
 {
   FAR hash_node_t *p;
   FAR hash_node_t *tmp;
-  bool skip_ip = net_ipv4addr_cmp(external_ip, INADDR_ANY);
-#ifdef CONFIG_NET_NAT_SYMMETRIC
-  bool skip_peer = net_ipv4addr_cmp(peer_ip, INADDR_ANY);
+  bool skip_ip = net_ipv6addr_cmp(external_ip, g_ipv6_unspecaddr);
+#ifdef CONFIG_NET_NAT66_SYMMETRIC
+  bool skip_peer = net_ipv6addr_cmp(peer_ip, g_ipv6_unspecaddr);
 #endif
   int32_t current_time = TICK2SEC(clock_systime_ticks());
 
-#if CONFIG_NET_NAT_ENTRY_RECLAIM_SEC > 0
-  ipv4_nat_reclaim_entry(current_time);
-#endif
+  ipv6_nat_reclaim_entry(current_time);
 
-  hashtable_for_every_possible_safe(g_table_inbound, p, tmp,
-                  ipv4_nat_inbound_key(external_ip, external_port, protocol))
+  hashtable_for_every_possible_safe(g_nat66_inbound, p, tmp,
+                    ipv6_nat_hash_key(external_ip, external_port, protocol))
     {
-      FAR struct ipv4_nat_entry *entry =
-        container_of(p, struct ipv4_nat_entry, hash_inbound);
+      FAR struct ipv6_nat_entry *entry =
+        container_of(p, struct ipv6_nat_entry, hash_inbound);
 
       /* Remove expired entries. */
 
       if (entry->expire_time - current_time <= 0)
         {
-          ipv4_nat_entry_delete(entry);
+          ipv6_nat_entry_delete(entry);
           continue;
         }
 
       if (entry->protocol == protocol &&
-          (skip_ip || net_ipv4addr_cmp(entry->external_ip, external_ip)) &&
+          (skip_ip || net_ipv6addr_cmp(entry->external_ip, external_ip)) &&
           entry->external_port == external_port
-#ifdef CONFIG_NET_NAT_SYMMETRIC
-          && (skip_peer || (net_ipv4addr_cmp(entry->peer_ip, peer_ip) &&
+#ifdef CONFIG_NET_NAT66_SYMMETRIC
+          && (skip_peer || (net_ipv6addr_cmp(entry->peer_ip, peer_ip) &&
                             entry->peer_port == peer_port))
 #endif
           )
         {
           if (refresh)
             {
-              ipv4_nat_entry_refresh(entry);
+              ipv6_nat_entry_refresh(entry);
             }
 
           return entry;
@@ -336,16 +331,19 @@ ipv4_nat_inbound_entry_find(uint8_t protocol, in_addr_t 
external_ip,
 
   if (refresh) /* false = a test of whether entry exists, no need to warn */
     {
-      nwarn("WARNING: Failed to find IPv4 inbound NAT entry for "
-            "proto=%" PRIu8 ", external=%" PRIx32 ":%" PRIu16 "\n",
-            protocol, external_ip, external_port);
+      nwarn("WARNING: Failed to find IPv6 inbound NAT entry for proto="
+            "%" PRIu8 ",external=[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:"
+            "%" PRIu16 "\n",
+            protocol, external_ip[0], external_ip[1], external_ip[2],
+            external_ip[3], external_ip[4], external_ip[5], external_ip[6],
+            external_ip[7], external_port);
     }
 
   return NULL;
 }
 
 /****************************************************************************
- * Name: ipv4_nat_outbound_entry_find
+ * Name: ipv6_nat_outbound_entry_find
  *
  * Description:
  *   Find the outbound entry in NAT entry list. Create one if corresponding
@@ -365,46 +363,46 @@ ipv4_nat_inbound_entry_find(uint8_t protocol, in_addr_t 
external_ip,
  *
  ****************************************************************************/
 
-FAR struct ipv4_nat_entry *
-ipv4_nat_outbound_entry_find(FAR struct net_driver_s *dev, uint8_t protocol,
-                             in_addr_t local_ip, uint16_t local_port,
-                             in_addr_t peer_ip, uint16_t peer_port,
-                             bool try_create)
+FAR struct ipv6_nat_entry *
+ipv6_nat_outbound_entry_find(FAR struct net_driver_s *dev, uint8_t protocol,
+                             const net_ipv6addr_t local_ip,
+                             uint16_t local_port,
+                             const net_ipv6addr_t peer_ip,
+                             uint16_t peer_port, bool try_create)
 {
   FAR hash_node_t *p;
   FAR hash_node_t *tmp;
+  FAR union ip_addr_u *external_ip;
   uint16_t external_port;
   int32_t current_time = TICK2SEC(clock_systime_ticks());
 
-#if CONFIG_NET_NAT_ENTRY_RECLAIM_SEC > 0
-  ipv4_nat_reclaim_entry(current_time);
-#endif
+  ipv6_nat_reclaim_entry(current_time);
 
-  hashtable_for_every_possible_safe(g_table_outbound, p, tmp,
-                      ipv4_nat_outbound_key(local_ip, local_port, protocol))
+  hashtable_for_every_possible_safe(g_nat66_outbound, p, tmp,
+                          ipv6_nat_hash_key(local_ip, local_port, protocol))
     {
-      FAR struct ipv4_nat_entry *entry =
-        container_of(p, struct ipv4_nat_entry, hash_outbound);
+      FAR struct ipv6_nat_entry *entry =
+        container_of(p, struct ipv6_nat_entry, hash_outbound);
 
       /* Remove expired entries. */
 
       if (entry->expire_time - current_time <= 0)
         {
-          ipv4_nat_entry_delete(entry);
+          ipv6_nat_entry_delete(entry);
           continue;
         }
 
       if (entry->protocol == protocol &&
-          net_ipv4addr_cmp(entry->external_ip, dev->d_ipaddr) &&
-          net_ipv4addr_cmp(entry->local_ip, local_ip) &&
+          NETDEV_IS_MY_V6ADDR(dev, entry->external_ip) &&
+          net_ipv6addr_cmp(entry->local_ip, local_ip) &&
           entry->local_port == local_port
-#ifdef CONFIG_NET_NAT_SYMMETRIC
-          && net_ipv4addr_cmp(entry->peer_ip, peer_ip) &&
+#ifdef CONFIG_NET_NAT66_SYMMETRIC
+          && net_ipv6addr_cmp(entry->peer_ip, peer_ip) &&
           entry->peer_port == peer_port
 #endif
           )
         {
-          ipv4_nat_entry_refresh(entry);
+          ipv6_nat_entry_refresh(entry);
           return entry;
         }
     }
@@ -416,20 +414,24 @@ ipv4_nat_outbound_entry_find(FAR struct net_driver_s 
*dev, uint8_t protocol,
 
   /* Failed to find the entry, create one. */
 
-  ninfo("INFO: Failed to find IPv4 outbound NAT entry for "
-        "proto=%" PRIu8 ", local=%" PRIx32 ":%" PRIu16 ", try create one.\n",
-        protocol, local_ip, local_port);
+  ninfo("INFO: Failed to find IPv6 outbound NAT entry for proto=%" PRIu8
+        ", local=[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%" PRIu16
+        ", try create one.\n",
+        protocol, local_ip[0], local_ip[1], local_ip[2], local_ip[3],
+        local_ip[4], local_ip[5], local_ip[6], local_ip[7], local_port);
+
+  external_ip = (FAR union ip_addr_u *)netdev_ipv6_srcaddr(dev, peer_ip);
+  external_port = nat_port_select(dev, PF_INET6, protocol,
+                                  external_ip, local_port);
 
-  external_port = nat_port_select(dev, PF_INET, protocol,
-                          (FAR union ip_addr_u *)&dev->d_ipaddr, local_port);
   if (!external_port)
     {
       nwarn("WARNING: Failed to find an available port!\n");
       return NULL;
     }
 
-  return ipv4_nat_entry_create(protocol, dev->d_ipaddr, external_port,
+  return ipv6_nat_entry_create(protocol, external_ip->ipv6, external_port,
                                local_ip, local_port, peer_ip, peer_port);
 }
 
-#endif /* CONFIG_NET_NAT && CONFIG_NET_IPv4 */
+#endif /* CONFIG_NET_NAT66 */
diff --git a/net/nat/nat.c b/net/nat/nat.c
index 0c3dc02907..a44f91b37b 100644
--- a/net/nat/nat.c
+++ b/net/nat/nat.c
@@ -27,6 +27,8 @@
 #include <debug.h>
 
 #include "icmp/icmp.h"
+#include "icmpv6/icmpv6.h"
+#include "inet/inet.h"
 #include "nat/nat.h"
 #include "tcp/tcp.h"
 #include "udp/udp.h"
@@ -57,7 +59,8 @@
 
 #if (defined(CONFIG_NET_TCP) && defined(CONFIG_NET_TCP_NO_STACK))  || \
     (defined(CONFIG_NET_UDP) && defined(CONFIG_NET_UDP_NO_STACK))  || \
-    (defined(CONFIG_NET_ICMP) && !defined(CONFIG_NET_ICMP_SOCKET))
+    (defined(CONFIG_NET_ICMP) && !defined(CONFIG_NET_ICMP_SOCKET)) || \
+    (defined(CONFIG_NET_ICMPv6) && !defined(CONFIG_NET_ICMPv6_SOCKET))
 
 static uint16_t nat_port_select_without_stack(
     uint8_t domain, uint8_t protocol, FAR const union ip_addr_u *ip,
@@ -145,9 +148,12 @@ int nat_disable(FAR struct net_driver_s *dev)
 
   /* Clear entries related to dev. */
 
-#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_NAT44
   ipv4_nat_entry_clear(dev);
 #endif
+#ifdef CONFIG_NET_NAT66
+  ipv6_nat_entry_clear(dev);
+#endif
 
   IFF_CLR_NAT(dev->d_flags);
 
@@ -175,7 +181,7 @@ int nat_disable(FAR struct net_driver_s *dev)
 bool nat_port_inuse(uint8_t domain, uint8_t protocol,
                     FAR const union ip_addr_u *ip, uint16_t port)
 {
-#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_NAT44
   if (domain == PF_INET)
     {
       return !!ipv4_nat_inbound_entry_find(protocol, ip->ipv4, port,
@@ -183,6 +189,14 @@ bool nat_port_inuse(uint8_t domain, uint8_t protocol,
     }
 #endif
 
+#ifdef CONFIG_NET_NAT66
+  if (domain == PF_INET6)
+    {
+      return !!ipv6_nat_inbound_entry_find(protocol, ip->ipv6, port,
+                                           g_ipv6_unspecaddr, 0, false);
+    }
+#endif
+
   return false;
 }
 
@@ -239,8 +253,25 @@ uint16_t nat_port_select(FAR struct net_driver_s *dev,
         {
 #ifndef CONFIG_NET_UDP_NO_STACK
           union ip_binding_u u;
-          u.ipv4.laddr = external_ip->ipv4;
-          u.ipv4.raddr = INADDR_ANY;
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+          if (domain == PF_INET)
+#endif
+            {
+              u.ipv4.laddr = external_ip->ipv4;
+              u.ipv4.raddr = INADDR_ANY;
+            }
+#endif
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+          else
+#endif
+            {
+              net_ipv6addr_copy(u.ipv6.laddr, external_ip->ipv6);
+              net_ipv6addr_copy(u.ipv6.raddr, g_ipv6_unspecaddr);
+            }
+#endif
 
           /* TODO: Try keep origin port as possible. */
 
@@ -278,6 +309,33 @@ uint16_t nat_port_select(FAR struct net_driver_s *dev,
 #endif
         }
 #endif
+
+#ifdef CONFIG_NET_ICMPv6
+      case IP_PROTO_ICMP6:
+        {
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+          uint16_t id = local_port;
+          uint16_t hid = NTOHS(id);
+          while (icmpv6_active(id) ||
+                 nat_port_inuse(domain, IP_PROTO_ICMP6, external_ip, id))
+            {
+              ++hid;
+              if (hid >= CONFIG_NET_DEFAULT_MAX_PORT ||
+                  hid < CONFIG_NET_DEFAULT_MIN_PORT)
+                {
+                  hid = CONFIG_NET_DEFAULT_MIN_PORT;
+                }
+
+              id = HTONS(hid);
+            }
+
+          return id;
+#else
+          return nat_port_select_without_stack(domain, IP_PROTO_ICMP6,
+                                               external_ip, local_port);
+#endif
+        }
+#endif
     }
 
   /* Select original port for unsupported protocol. */
@@ -332,6 +390,12 @@ uint32_t nat_expire_time(uint8_t protocol)
                CONFIG_NET_NAT_ICMP_EXPIRE_SEC;
 #endif
 
+#ifdef CONFIG_NET_ICMPv6
+      case IP_PROTO_ICMP6:
+        return TICK2SEC(clock_systime_ticks()) +
+               CONFIG_NET_NAT_ICMPv6_EXPIRE_SEC;
+#endif
+
       default:
         nwarn("WARNING: Unsupported protocol %" PRIu8 "\n", protocol);
         return 0;
diff --git a/net/nat/nat.h b/net/nat/nat.h
index c5921c77db..ed4acd60f1 100644
--- a/net/nat/nat.h
+++ b/net/nat/nat.h
@@ -87,12 +87,12 @@ struct ipv4_nat_entry
 
   in_addr_t  local_ip;       /* IP address of the local (private) host. */
   in_addr_t  external_ip;    /* External IP address. */
-#ifdef CONFIG_NET_NAT_SYMMETRIC
+#ifdef CONFIG_NET_NAT44_SYMMETRIC
   in_addr_t  peer_ip;        /* Peer IP address. */
 #endif
   uint16_t   local_port;     /* Port of the local (private) host. */
   uint16_t   external_port;  /* The external port of local (private) host. */
-#ifdef CONFIG_NET_NAT_SYMMETRIC
+#ifdef CONFIG_NET_NAT44_SYMMETRIC
   uint16_t   peer_port;      /* Peer port. */
 #endif
   uint8_t    protocol;       /* L4 protocol (TCP, UDP etc). */
@@ -100,6 +100,26 @@ struct ipv4_nat_entry
   int32_t    expire_time;    /* The expiration time of this entry. */
 };
 
+struct ipv6_nat_entry
+{
+  hash_node_t    hash_inbound;
+  hash_node_t    hash_outbound;
+
+  net_ipv6addr_t local_ip;      /* IP address of the local host. */
+  net_ipv6addr_t external_ip;   /* External IP address. */
+#ifdef CONFIG_NET_NAT66_SYMMETRIC
+  net_ipv6addr_t peer_ip;       /* Peer IP address. */
+#endif
+  uint16_t       local_port;    /* Port of the local host. */
+  uint16_t       external_port; /* The external port of local host. */
+#ifdef CONFIG_NET_NAT66_SYMMETRIC
+  uint16_t       peer_port;     /* Peer port. */
+#endif
+  uint8_t        protocol;      /* L4 protocol (TCP, UDP etc). */
+
+  int32_t        expire_time;   /* The expiration time of this entry. */
+};
+
 /* NAT IP/Port manipulate type, to indicate whether to manipulate source or
  * destination IP/Port in a packet.
  */
@@ -149,37 +169,36 @@ int nat_enable(FAR struct net_driver_s *dev);
 int nat_disable(FAR struct net_driver_s *dev);
 
 /****************************************************************************
- * Name: ipv4_nat_inbound
+ * Name: ipv4/ipv6_nat_inbound
  *
  * Description:
  *   Check if a received packet belongs to a NAT entry. If so, translate it.
  *
  * Input Parameters:
- *   dev   - The device on which the packet is received.
- *   ipv4  - Points to the IPv4 header with dev->d_buf.
- *
- * Returned Value:
- *   Zero is returned if NAT is successfully applied, or is not enabled for
- *   this packet;
- *   A negated errno value is returned if error occured.
+ *   dev       - The device on which the packet is received.
+ *   ipv4/ipv6 - Points to the IP header with dev->d_buf.
  *
  ****************************************************************************/
 
-#ifdef CONFIG_NET_IPv4
-int ipv4_nat_inbound(FAR struct net_driver_s *dev,
-                     FAR struct ipv4_hdr_s *ipv4);
+#ifdef CONFIG_NET_NAT44
+void ipv4_nat_inbound(FAR struct net_driver_s *dev,
+                      FAR struct ipv4_hdr_s *ipv4);
+#endif
+#ifdef CONFIG_NET_NAT66
+void ipv6_nat_inbound(FAR struct net_driver_s *dev,
+                      FAR struct ipv6_hdr_s *ipv6);
 #endif
 
 /****************************************************************************
- * Name: ipv4_nat_outbound
+ * Name: ipv4/ipv6_nat_outbound
  *
  * Description:
  *   Check if we want to perform NAT with this outbound packet before sending
  *   it. If so, translate it.
  *
  * Input Parameters:
- *   dev   - The device on which the packet will be sent.
- *   ipv4  - Points to the IPv4 header to be filled into dev->d_buf later.
+ *   dev        - The device on which the packet will be sent.
+ *   ipv4/ipv6  - Points to the IP header to be filled into dev->d_buf later.
  *   manip_type - Whether local IP/Port is in source or destination.
  *
  * Returned Value:
@@ -189,11 +208,16 @@ int ipv4_nat_inbound(FAR struct net_driver_s *dev,
  *
  ****************************************************************************/
 
-#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_NAT44
 int ipv4_nat_outbound(FAR struct net_driver_s *dev,
                       FAR struct ipv4_hdr_s *ipv4,
                       enum nat_manip_type_e manip_type);
 #endif
+#ifdef CONFIG_NET_NAT66
+int ipv6_nat_outbound(FAR struct net_driver_s *dev,
+                      FAR struct ipv6_hdr_s *ipv6,
+                      enum nat_manip_type_e manip_type);
+#endif
 
 /****************************************************************************
  * Name: nat_port_inuse
@@ -255,26 +279,29 @@ uint16_t nat_port_select(FAR struct net_driver_s *dev,
 uint32_t nat_expire_time(uint8_t protocol);
 
 /****************************************************************************
- * Name: ipv4_nat_entry_clear
+ * Name: ipv4/ipv6_nat_entry_clear
  *
  * Description:
  *   Clear all entries related to dev. Called when NAT will be disabled on
  *   any device.
  *
  * Input Parameters:
- *   dev        - The device on which NAT entries will be cleared.
+ *   dev - The device on which NAT entries will be cleared.
  *
  * Assumptions:
  *   NAT is initialized.
  *
  ****************************************************************************/
 
-#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_NAT44
 void ipv4_nat_entry_clear(FAR struct net_driver_s *dev);
 #endif
+#ifdef CONFIG_NET_NAT66
+void ipv6_nat_entry_clear(FAR struct net_driver_s *dev);
+#endif
 
 /****************************************************************************
- * Name: ipv4_nat_inbound_entry_find
+ * Name: ipv4/ipv6_nat_inbound_entry_find
  *
  * Description:
  *   Find the inbound entry in NAT entry list.
@@ -292,15 +319,23 @@ void ipv4_nat_entry_clear(FAR struct net_driver_s *dev);
  *
  ****************************************************************************/
 
-#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_NAT44
 FAR struct ipv4_nat_entry *
 ipv4_nat_inbound_entry_find(uint8_t protocol, in_addr_t external_ip,
                             uint16_t external_port, in_addr_t peer_ip,
                             uint16_t peer_port, bool refresh);
 #endif
+#ifdef CONFIG_NET_NAT66
+FAR struct ipv6_nat_entry *
+ipv6_nat_inbound_entry_find(uint8_t protocol,
+                            const net_ipv6addr_t external_ip,
+                            uint16_t external_port,
+                            const net_ipv6addr_t peer_ip,
+                            uint16_t peer_port, bool refresh);
+#endif
 
 /****************************************************************************
- * Name: ipv4_nat_outbound_entry_find
+ * Name: ipv4/ipv6_nat_outbound_entry_find
  *
  * Description:
  *   Find the outbound entry in NAT entry list. Create one if corresponding
@@ -320,13 +355,21 @@ ipv4_nat_inbound_entry_find(uint8_t protocol, in_addr_t 
external_ip,
  *
  ****************************************************************************/
 
-#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_NAT44
 FAR struct ipv4_nat_entry *
 ipv4_nat_outbound_entry_find(FAR struct net_driver_s *dev, uint8_t protocol,
                              in_addr_t local_ip, uint16_t local_port,
                              in_addr_t peer_ip, uint16_t peer_port,
                              bool try_create);
 #endif
+#ifdef CONFIG_NET_NAT66
+FAR struct ipv6_nat_entry *
+ipv6_nat_outbound_entry_find(FAR struct net_driver_s *dev, uint8_t protocol,
+                             const net_ipv6addr_t local_ip,
+                             uint16_t local_port,
+                             const net_ipv6addr_t peer_ip,
+                             uint16_t peer_port, bool try_create);
+#endif
 
 #endif /* CONFIG_NET_NAT */
 #endif /* __NET_NAT_NAT_H */

Reply via email to