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 f2ff5cee03353acb4acf817a2c1709722c1b4391
Author: Zhe Weng <[email protected]>
AuthorDate: Mon Mar 18 18:41:38 2024 +0800

    net/nat: Make some IPv4 NAT functions as common
    
    To prepare for future IPv6 NAT functions.
    - Rename common ipv4_nat_xxx to nat_xxx
    - Move some common definitions into header
    
    Signed-off-by: Zhe Weng <[email protected]>
---
 Documentation/components/net/nat.rst |  12 +-
 net/nat/CMakeLists.txt               |   6 +-
 net/nat/Make.defs                    |   2 +
 net/nat/ipv4_nat.c                   | 129 +------------
 net/nat/ipv4_nat_entry.c             | 189 +------------------
 net/nat/nat.c                        | 341 +++++++++++++++++++++++++++++++++++
 net/nat/nat.h                        |  93 +++++++++-
 net/netfilter/ipt_nat.c              |   4 +-
 net/tcp/tcp_conn.c                   |  10 +-
 net/udp/udp_conn.c                   |  14 +-
 10 files changed, 462 insertions(+), 338 deletions(-)

diff --git a/Documentation/components/net/nat.rst 
b/Documentation/components/net/nat.rst
index 773bb5bf1a..621e7b738b 100644
--- a/Documentation/components/net/nat.rst
+++ b/Documentation/components/net/nat.rst
@@ -75,10 +75,10 @@ Configuration Options
 Usage
 =====
 
-  - :c:func:`ipv4_nat_enable()`
-  - :c:func:`ipv4_nat_disable()`
+  - :c:func:`nat_enable()`
+  - :c:func:`nat_disable()`
 
-.. c:function:: int ipv4_nat_enable(FAR struct net_driver_s *dev);
+.. c:function:: int nat_enable(FAR struct net_driver_s *dev);
 
   Enable NAT function on a network device, on which the outbound packets
   will be masqueraded.
@@ -86,7 +86,7 @@ Usage
   :return: Zero is returned if NAT function is successfully enabled on
     the device; A negated errno value is returned if failed.
 
-.. c:function:: int ipv4_nat_disable(FAR struct net_driver_s *dev);
+.. c:function:: int nat_disable(FAR struct net_driver_s *dev);
 
   Disable NAT function on a network device.
 
@@ -107,7 +107,7 @@ Validated on Ubuntu 22.04 x86_64 with NuttX SIM by 
following steps:
       # CONFIG_SIM_NET_BRIDGE is not set
       CONFIG_SIM_NETDEV_NUMBER=2
 
-2. Call ``ipv4_nat_enable`` on one dev on startup, or manually enable NAT
+2. Call ``nat_enable`` on one dev on startup, or manually enable NAT
    with ``iptables`` command (either may work).
 
   ..  code-block:: c
@@ -116,7 +116,7 @@ Validated on Ubuntu 22.04 x86_64 with NuttX SIM by 
following steps:
       int netdriver_init(void)
       {
         ...
-        ipv4_nat_enable(&g_sim_dev[0]);
+        nat_enable(&g_sim_dev[0]);
         ...
       }
 
diff --git a/net/nat/CMakeLists.txt b/net/nat/CMakeLists.txt
index 0e8dd83f5c..ebf100a46a 100644
--- a/net/nat/CMakeLists.txt
+++ b/net/nat/CMakeLists.txt
@@ -22,8 +22,12 @@
 
 if(CONFIG_NET_NAT)
 
+  list(APPEND SRCS nat.c)
+
   if(CONFIG_NET_IPv4)
-    target_sources(net PRIVATE ipv4_nat.c ipv4_nat_entry.c)
+    list(APPEND SRCS ipv4_nat.c ipv4_nat_entry.c)
   endif()
 
+  target_sources(net PRIVATE ${SRCS})
+
 endif()
diff --git a/net/nat/Make.defs b/net/nat/Make.defs
index 43d185837e..ee4fe9cbe2 100644
--- a/net/nat/Make.defs
+++ b/net/nat/Make.defs
@@ -22,6 +22,8 @@
 
 ifeq ($(CONFIG_NET_NAT),y)
 
+NET_CSRCS += nat.c
+
 ifeq ($(CONFIG_NET_IPv4),y)
 NET_CSRCS += ipv4_nat.c ipv4_nat_entry.c
 endif
diff --git a/net/nat/ipv4_nat.c b/net/nat/ipv4_nat.c
index c3a81b064a..06c627bd4e 100644
--- a/net/nat/ipv4_nat.c
+++ b/net/nat/ipv4_nat.c
@@ -26,7 +26,6 @@
 
 #include <assert.h>
 #include <debug.h>
-#include <errno.h>
 #include <stdint.h>
 #include <string.h>
 #include <sys/types.h>
@@ -44,28 +43,6 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
-/* Adjust checksums in headers. */
-
-#define chksum_adjust(chksum,optr,nptr,len) \
-  net_chksum_adjust((FAR uint16_t *)(chksum), (FAR uint16_t *)(optr), len, \
-                    (FAR uint16_t *)(nptr), len)
-
-/* Getting IP & Port to manipulate from L3/L4 header. */
-
-#define MANIP_IPADDR(iphdr,manip_type) \
-  ((manip_type) == NAT_MANIP_SRC ? (iphdr)->srcipaddr : (iphdr)->destipaddr)
-
-#define MANIP_PORT(l4hdr,manip_type) \
-  ((manip_type) == NAT_MANIP_SRC ? &(l4hdr)->srcport : &(l4hdr)->destport)
-
-/* Getting peer IP & Port (just other than MANIP) */
-
-#define PEER_IPADDR(iphdr,manip_type) \
-  ((manip_type) != NAT_MANIP_SRC ? (iphdr)->srcipaddr : (iphdr)->destipaddr)
-
-#define PEER_PORT(l4hdr,manip_type) \
-  ((manip_type) != NAT_MANIP_SRC ? &(l4hdr)->srcport : &(l4hdr)->destport)
-
 /* Getting L4 header from IPv4 header. */
 
 #define L4_HDR(ipv4) \
@@ -151,10 +128,10 @@ static void ipv4_nat_ip_adjust(FAR struct ipv4_hdr_s 
*ipv4,
 {
   if (l4chksum != NULL)
     {
-      chksum_adjust(l4chksum, old_ip, &new_ip, sizeof(new_ip));
+      nat_chksum_adjust(l4chksum, old_ip, &new_ip, sizeof(new_ip));
     }
 
-  chksum_adjust(&ipv4->ipchksum, old_ip, &new_ip, sizeof(new_ip));
+  nat_chksum_adjust(&ipv4->ipchksum, old_ip, &new_ip, sizeof(new_ip));
   net_ipv4addr_hdrcopy(old_ip, &new_ip);
 }
 
@@ -176,7 +153,7 @@ static void ipv4_nat_port_adjust(FAR uint16_t *l4chksum,
 {
   if (l4chksum != NULL)
     {
-      chksum_adjust(l4chksum, old_port, &new_port, sizeof(new_port));
+      nat_chksum_adjust(l4chksum, old_port, &new_port, sizeof(new_port));
     }
 
   *old_port = new_port;
@@ -400,8 +377,8 @@ ipv4_nat_inbound_icmp(FAR struct ipv4_hdr_s *ipv4,
              * and the overall checksum of IPv4 header will not change.
              */
 
-            chksum_adjust(&icmp->icmpchksum, inner_l4hdrbak, inner_l4,
-                          inner_l4hdrlen);
+            nat_chksum_adjust(&icmp->icmpchksum, inner_l4hdrbak, inner_l4,
+                              inner_l4hdrlen);
 
             return entry;
           }
@@ -639,8 +616,8 @@ ipv4_nat_outbound_icmp(FAR struct net_driver_s *dev,
              * and the overall checksum of IPv4 header will not change.
              */
 
-            chksum_adjust(&icmp->icmpchksum, inner_l4hdrbak, inner_l4,
-                          inner_l4hdrlen);
+            nat_chksum_adjust(&icmp->icmpchksum, inner_l4hdrbak, inner_l4,
+                              inner_l4hdrlen);
 
             return entry;
           }
@@ -745,74 +722,6 @@ ipv4_nat_outbound_internal(FAR struct net_driver_s *dev,
  * Public Functions
  ****************************************************************************/
 
-/****************************************************************************
- * Name: ipv4_nat_enable
- *
- * Description:
- *   Enable NAT function on a network device.
- *
- * Input Parameters:
- *   dev   - The device on which the outbound packets will be masqueraded.
- *
- * Returned Value:
- *   Zero is returned if NAT function is successfully enabled on the device;
- *   A negated errno value is returned if failed.
- *
- ****************************************************************************/
-
-int ipv4_nat_enable(FAR struct net_driver_s *dev)
-{
-  net_lock();
-
-  if (IFF_IS_NAT(dev->d_flags))
-    {
-      nwarn("WARNING: NAT was already enabled for %s!\n", dev->d_ifname);
-      net_unlock();
-      return -EEXIST;
-    }
-
-  IFF_SET_NAT(dev->d_flags);
-
-  net_unlock();
-  return OK;
-}
-
-/****************************************************************************
- * Name: ipv4_nat_disable
- *
- * Description:
- *   Disable NAT function on a network device.
- *
- * Input Parameters:
- *   dev   - The device on which the NAT function will be disabled.
- *
- * Returned Value:
- *   Zero is returned if NAT function is successfully disabled on the device;
- *   A negated errno value is returned if failed.
- *
- ****************************************************************************/
-
-int ipv4_nat_disable(FAR struct net_driver_s *dev)
-{
-  net_lock();
-
-  if (!IFF_IS_NAT(dev->d_flags))
-    {
-      nwarn("WARNING: NAT was not enabled for %s!\n", dev->d_ifname);
-      net_unlock();
-      return -ENODEV;
-    }
-
-  /* Clear entries related to dev. */
-
-  ipv4_nat_entry_clear(dev);
-
-  IFF_CLR_NAT(dev->d_flags);
-
-  net_unlock();
-  return OK;
-}
-
 /****************************************************************************
  * Name: ipv4_nat_inbound
  *
@@ -899,28 +808,4 @@ int ipv4_nat_outbound(FAR struct net_driver_s *dev,
   return OK;
 }
 
-/****************************************************************************
- * Name: ipv4_nat_port_inuse
- *
- * Description:
- *   Check whether a port is currently used by NAT.
- *
- * Input Parameters:
- *   protocol      - The L4 protocol of the packet.
- *   ip            - The IP bind with the port (in network byte order).
- *   port          - The port number to check (in network byte order).
- *
- * Returned Value:
- *   True if the port is already used by NAT, otherwise false.
- *
- ****************************************************************************/
-
-bool ipv4_nat_port_inuse(uint8_t protocol, in_addr_t ip, uint16_t port)
-{
-  FAR struct ipv4_nat_entry *entry =
-      ipv4_nat_inbound_entry_find(protocol, ip, port, INADDR_ANY, 0, false);
-
-  return entry != NULL;
-}
-
 #endif /* CONFIG_NET_NAT && CONFIG_NET_IPv4 */
diff --git a/net/nat/ipv4_nat_entry.c b/net/nat/ipv4_nat_entry.c
index 8f2624a5f9..7b033a5d0f 100644
--- a/net/nat/ipv4_nat_entry.c
+++ b/net/nat/ipv4_nat_entry.c
@@ -31,12 +31,8 @@
 #include <nuttx/hashtable.h>
 #include <nuttx/kmalloc.h>
 #include <nuttx/nuttx.h>
-#include <nuttx/queue.h>
 
-#include "icmp/icmp.h"
 #include "nat/nat.h"
-#include "tcp/tcp.h"
-#include "udp/udp.h"
 
 #if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
 
@@ -83,152 +79,6 @@ static inline uint32_t ipv4_nat_outbound_key(in_addr_t 
local_ip,
          ((uint32_t)protocol << 8) ^ ((uint32_t)local_port << 16);
 }
 
-/****************************************************************************
- * Name: ipv4_nat_select_port_without_stack
- *
- * Description:
- *   Select an available port number for TCP/UDP protocol, or id for ICMP.
- *   Used when corresponding stack is disabled.
- *
- * Input Parameters:
- *   protocol   - The L4 protocol of the packet.
- *   ip         - The IP bind with the port (in network byte order).
- *   portno     - The local port (in network byte order), as reference.
- *
- * Returned Value:
- *   port number on success; 0 on failure
- *
- ****************************************************************************/
-
-#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))
-
-static uint16_t ipv4_nat_select_port_without_stack(
-    uint8_t protocol, in_addr_t ip, uint16_t portno)
-{
-  uint16_t hport = NTOHS(portno);
-  while (ipv4_nat_port_inuse(protocol, ip, portno))
-    {
-      ++hport;
-      if (hport >= CONFIG_NET_DEFAULT_MAX_PORT ||
-          hport < CONFIG_NET_DEFAULT_MIN_PORT)
-        {
-          hport = CONFIG_NET_DEFAULT_MIN_PORT;
-        }
-
-      portno = HTONS(hport);
-    }
-
-  return portno;
-}
-
-#endif
-
-/****************************************************************************
- * Name: ipv4_nat_select_port
- *
- * Description:
- *   Select an available port number for TCP/UDP protocol, or id for ICMP.
- *
- * Input Parameters:
- *   dev        - The device on which the packet will be sent.
- *   protocol   - The L4 protocol of the packet.
- *   local_port - The local port of the packet, as reference.
- *
- * Returned Value:
- *   port number on success; 0 on failure
- *
- ****************************************************************************/
-
-static uint16_t ipv4_nat_select_port(FAR struct net_driver_s *dev,
-                                     uint8_t protocol,
-                                     uint16_t local_port)
-{
-  switch (protocol)
-    {
-#ifdef CONFIG_NET_TCP
-      case IP_PROTO_TCP:
-        {
-#ifndef CONFIG_NET_TCP_NO_STACK
-          /* Try to select local_port first. */
-
-          int ret = tcp_selectport(PF_INET,
-                        (FAR const union ip_addr_u *)&dev->d_ipaddr,
-                        local_port);
-
-          /* If failed, try select another unused port. */
-
-          if (ret < 0)
-            {
-              ret = tcp_selectport(PF_INET,
-                        (FAR const union ip_addr_u *)&dev->d_ipaddr, 0);
-            }
-
-          return ret > 0 ? ret : 0;
-#else
-          return ipv4_nat_select_port_without_stack(IP_PROTO_TCP,
-                                                    dev->d_ipaddr,
-                                                    local_port);
-#endif
-        }
-#endif
-
-#ifdef CONFIG_NET_UDP
-      case IP_PROTO_UDP:
-        {
-#ifndef CONFIG_NET_UDP_NO_STACK
-          union ip_binding_u u;
-          u.ipv4.laddr = dev->d_ipaddr;
-          u.ipv4.raddr = INADDR_ANY;
-
-          /* TODO: Try keep origin port as possible. */
-
-          return HTONS(udp_select_port(PF_INET, &u));
-#else
-          return ipv4_nat_select_port_without_stack(IP_PROTO_UDP,
-                                                    dev->d_ipaddr,
-                                                    local_port);
-#endif
-        }
-#endif
-
-#ifdef CONFIG_NET_ICMP
-      case IP_PROTO_ICMP:
-        {
-#ifdef CONFIG_NET_ICMP_SOCKET
-          uint16_t id = local_port;
-          uint16_t hid = NTOHS(id);
-          while (icmp_findconn(dev, id) ||
-                 ipv4_nat_port_inuse(IP_PROTO_ICMP, dev->d_ipaddr, 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 ipv4_nat_select_port_without_stack(IP_PROTO_ICMP,
-                                                    dev->d_ipaddr,
-                                                    local_port);
-#endif
-        }
-#endif
-    }
-
-  /* TODO: Currently select original port for unsupported protocol, maybe
-   * return zero to indicate failure.
-   */
-
-  return local_port;
-}
-
 /****************************************************************************
  * Name: ipv4_nat_entry_refresh
  *
@@ -242,40 +92,7 @@ static uint16_t ipv4_nat_select_port(FAR struct 
net_driver_s *dev,
 
 static void ipv4_nat_entry_refresh(FAR struct ipv4_nat_entry *entry)
 {
-  /* Note: May add logic here to move recent node to head side if each chain
-   * in hashtable is still too long (with long expire time).
-   */
-
-  switch (entry->protocol)
-    {
-#ifdef CONFIG_NET_TCP
-      case IP_PROTO_TCP:
-        /* NOTE: According to RFC2663, Section 2.6, Page 5, we can reduce the
-         * time to 4min if we have received FINs from both side of one
-         * connection, and keep 24h for other TCP connections. However, full
-         * cone NAT may have multiple connections on one entry, so this
-         * optimization may not work and we only use one expiration time.
-         */
-
-        entry->expire_time = TICK2SEC(clock_systime_ticks()) +
-                             CONFIG_NET_NAT_TCP_EXPIRE_SEC;
-        break;
-#endif
-
-#ifdef CONFIG_NET_UDP
-      case IP_PROTO_UDP:
-        entry->expire_time = TICK2SEC(clock_systime_ticks()) +
-                             CONFIG_NET_NAT_UDP_EXPIRE_SEC;
-        break;
-#endif
-
-#ifdef CONFIG_NET_ICMP
-      case IP_PROTO_ICMP:
-        entry->expire_time = TICK2SEC(clock_systime_ticks()) +
-                             CONFIG_NET_NAT_ICMP_EXPIRE_SEC;
-        break;
-#endif
-  }
+  entry->expire_time = nat_expire_time(entry->protocol);
 }
 
 /****************************************************************************
@@ -556,6 +373,7 @@ ipv4_nat_outbound_entry_find(FAR struct net_driver_s *dev, 
uint8_t protocol,
 {
   FAR hash_node_t *p;
   FAR hash_node_t *tmp;
+  uint16_t external_port;
   int32_t current_time = TICK2SEC(clock_systime_ticks());
 
 #if CONFIG_NET_NAT_ENTRY_RECLAIM_SEC > 0
@@ -602,7 +420,8 @@ ipv4_nat_outbound_entry_find(FAR struct net_driver_s *dev, 
uint8_t protocol,
         "proto=%" PRIu8 ", local=%" PRIx32 ":%" PRIu16 ", try create one.\n",
         protocol, local_ip, local_port);
 
-  uint16_t external_port = ipv4_nat_select_port(dev, protocol, 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");
diff --git a/net/nat/nat.c b/net/nat/nat.c
new file mode 100644
index 0000000000..0c3dc02907
--- /dev/null
+++ b/net/nat/nat.c
@@ -0,0 +1,341 @@
+/****************************************************************************
+ * net/nat/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 "icmp/icmp.h"
+#include "nat/nat.h"
+#include "tcp/tcp.h"
+#include "udp/udp.h"
+
+#ifdef CONFIG_NET_NAT
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nat_port_select_without_stack
+ *
+ * Description:
+ *   Select an available port number for TCP/UDP protocol, or id for ICMP.
+ *   Used when corresponding stack is disabled.
+ *
+ * Input Parameters:
+ *   domain     - The domain of the packet.
+ *   protocol   - The L4 protocol of the packet.
+ *   ip         - The IP bind with the port (in network byte order).
+ *   portno     - The local port (in network byte order), as reference.
+ *
+ * Returned Value:
+ *   port number on success; 0 on failure
+ *
+ ****************************************************************************/
+
+#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))
+
+static uint16_t nat_port_select_without_stack(
+    uint8_t domain, uint8_t protocol, FAR const union ip_addr_u *ip,
+    uint16_t portno)
+{
+  uint16_t hport = NTOHS(portno);
+  while (nat_port_inuse(domain, protocol, ip, portno))
+    {
+      ++hport;
+      if (hport >= CONFIG_NET_DEFAULT_MAX_PORT ||
+          hport < CONFIG_NET_DEFAULT_MIN_PORT)
+        {
+          hport = CONFIG_NET_DEFAULT_MIN_PORT;
+        }
+
+      portno = HTONS(hport);
+    }
+
+  return portno;
+}
+
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nat_enable
+ *
+ * Description:
+ *   Enable NAT function on a network device.
+ *
+ * Input Parameters:
+ *   dev   - The device on which the outbound packets will be masqueraded.
+ *
+ * Returned Value:
+ *   Zero is returned if NAT function is successfully enabled on the device;
+ *   A negated errno value is returned if failed.
+ *
+ ****************************************************************************/
+
+int nat_enable(FAR struct net_driver_s *dev)
+{
+  net_lock();
+
+  if (IFF_IS_NAT(dev->d_flags))
+    {
+      nwarn("WARNING: NAT was already enabled for %s!\n", dev->d_ifname);
+      net_unlock();
+      return -EEXIST;
+    }
+
+  IFF_SET_NAT(dev->d_flags);
+
+  net_unlock();
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nat_disable
+ *
+ * Description:
+ *   Disable NAT function on a network device.
+ *
+ * Input Parameters:
+ *   dev   - The device on which the NAT function will be disabled.
+ *
+ * Returned Value:
+ *   Zero is returned if NAT function is successfully disabled on the device;
+ *   A negated errno value is returned if failed.
+ *
+ ****************************************************************************/
+
+int nat_disable(FAR struct net_driver_s *dev)
+{
+  net_lock();
+
+  if (!IFF_IS_NAT(dev->d_flags))
+    {
+      nwarn("WARNING: NAT was not enabled for %s!\n", dev->d_ifname);
+      net_unlock();
+      return -ENODEV;
+    }
+
+  /* Clear entries related to dev. */
+
+#ifdef CONFIG_NET_IPv4
+  ipv4_nat_entry_clear(dev);
+#endif
+
+  IFF_CLR_NAT(dev->d_flags);
+
+  net_unlock();
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nat_port_inuse
+ *
+ * Description:
+ *   Check whether a port is currently used by NAT.
+ *
+ * Input Parameters:
+ *   domain        - The domain of the packet.
+ *   protocol      - The L4 protocol of the packet.
+ *   ip            - The IP bind with the port (in network byte order).
+ *   port          - The port number to check (in network byte order).
+ *
+ * Returned Value:
+ *   True if the port is already used by NAT, otherwise false.
+ *
+ ****************************************************************************/
+
+bool nat_port_inuse(uint8_t domain, uint8_t protocol,
+                    FAR const union ip_addr_u *ip, uint16_t port)
+{
+#ifdef CONFIG_NET_IPv4
+  if (domain == PF_INET)
+    {
+      return !!ipv4_nat_inbound_entry_find(protocol, ip->ipv4, port,
+                                           INADDR_ANY, 0, false);
+    }
+#endif
+
+  return false;
+}
+
+/****************************************************************************
+ * Name: nat_port_select
+ *
+ * Description:
+ *   Select an available port number for TCP/UDP protocol, or id for ICMP.
+ *
+ * Input Parameters:
+ *   dev         - The device on which the packet will be sent.
+ *   domain      - The domain of the packet.
+ *   protocol    - The L4 protocol of the packet.
+ *   external_ip - The external IP bind with the port.
+ *   local_port  - The local port of the packet, as reference.
+ *
+ * Returned Value:
+ *   External port number on success; 0 on failure
+ *
+ ****************************************************************************/
+
+uint16_t nat_port_select(FAR struct net_driver_s *dev,
+                         uint8_t domain, uint8_t protocol,
+                         FAR const union ip_addr_u *external_ip,
+                         uint16_t local_port)
+{
+  switch (protocol)
+    {
+#ifdef CONFIG_NET_TCP
+      case IP_PROTO_TCP:
+        {
+#ifndef CONFIG_NET_TCP_NO_STACK
+          /* Try to select local_port first. */
+
+          int ret = tcp_selectport(domain, external_ip, local_port);
+
+          /* If failed, try select another unused port. */
+
+          if (ret < 0)
+            {
+              ret = tcp_selectport(domain, external_ip, 0);
+            }
+
+          return ret > 0 ? ret : 0;
+#else
+          return nat_port_select_without_stack(domain, IP_PROTO_TCP,
+                                               external_ip, local_port);
+#endif
+        }
+#endif
+
+#ifdef CONFIG_NET_UDP
+      case IP_PROTO_UDP:
+        {
+#ifndef CONFIG_NET_UDP_NO_STACK
+          union ip_binding_u u;
+          u.ipv4.laddr = external_ip->ipv4;
+          u.ipv4.raddr = INADDR_ANY;
+
+          /* TODO: Try keep origin port as possible. */
+
+          return HTONS(udp_select_port(domain, &u));
+#else
+          return nat_port_select_without_stack(domain, IP_PROTO_UDP,
+                                               external_ip, local_port);
+#endif
+        }
+#endif
+
+#ifdef CONFIG_NET_ICMP
+      case IP_PROTO_ICMP:
+        {
+#ifdef CONFIG_NET_ICMP_SOCKET
+          uint16_t id = local_port;
+          uint16_t hid = NTOHS(id);
+          while (icmp_findconn(dev, id) ||
+                 nat_port_inuse(domain, IP_PROTO_ICMP, 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_ICMP,
+                                               external_ip, local_port);
+#endif
+        }
+#endif
+    }
+
+  /* Select original port for unsupported protocol. */
+
+  return local_port;
+}
+
+/****************************************************************************
+ * Name: nat_expire_time
+ *
+ * Description:
+ *   Get the expiration time of a specific protocol.
+ *
+ * Input Parameters:
+ *   protocol - The L4 protocol of the packet.
+ *
+ * Returned Value:
+ *   The expiration time of the protocol.
+ *
+ ****************************************************************************/
+
+uint32_t nat_expire_time(uint8_t protocol)
+{
+  /* Note: May add logic here to move recent node to head side if each chain
+   * in hashtable is still too long (with long expire time).
+   */
+
+  switch (protocol)
+    {
+#ifdef CONFIG_NET_TCP
+      case IP_PROTO_TCP:
+        /* NOTE: According to RFC2663, Section 2.6, Page 5, we can reduce the
+         * time to 4min if we have received FINs from both side of one
+         * connection, and keep 24h for other TCP connections. However, full
+         * cone NAT may have multiple connections on one entry, so this
+         * optimization may not work and we only use one expiration time.
+         */
+
+        return TICK2SEC(clock_systime_ticks()) +
+               CONFIG_NET_NAT_TCP_EXPIRE_SEC;
+#endif
+
+#ifdef CONFIG_NET_UDP
+      case IP_PROTO_UDP:
+        return TICK2SEC(clock_systime_ticks()) +
+               CONFIG_NET_NAT_UDP_EXPIRE_SEC;
+#endif
+
+#ifdef CONFIG_NET_ICMP
+      case IP_PROTO_ICMP:
+        return TICK2SEC(clock_systime_ticks()) +
+               CONFIG_NET_NAT_ICMP_EXPIRE_SEC;
+#endif
+
+      default:
+        nwarn("WARNING: Unsupported protocol %" PRIu8 "\n", protocol);
+        return 0;
+  }
+}
+
+#endif /* CONFIG_NET_NAT */
diff --git a/net/nat/nat.h b/net/nat/nat.h
index 6273ecc131..c5921c77db 100644
--- a/net/nat/nat.h
+++ b/net/nat/nat.h
@@ -36,7 +36,33 @@
 #include <nuttx/net/ip.h>
 #include <nuttx/net/netdev.h>
 
-#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
+#ifdef CONFIG_NET_NAT
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Adjust checksums in headers. */
+
+#define nat_chksum_adjust(chksum,optr,nptr,len) \
+  net_chksum_adjust((FAR uint16_t *)(chksum), (FAR uint16_t *)(optr), len, \
+                    (FAR uint16_t *)(nptr), len)
+
+/* Getting IP & Port to manipulate from L3/L4 header. */
+
+#define MANIP_IPADDR(iphdr,manip_type) \
+  ((manip_type) == NAT_MANIP_SRC ? (iphdr)->srcipaddr : (iphdr)->destipaddr)
+
+#define MANIP_PORT(l4hdr,manip_type) \
+  ((manip_type) == NAT_MANIP_SRC ? &(l4hdr)->srcport : &(l4hdr)->destport)
+
+/* Getting peer IP & Port (just other than MANIP) */
+
+#define PEER_IPADDR(iphdr,manip_type) \
+  ((manip_type) != NAT_MANIP_SRC ? (iphdr)->srcipaddr : (iphdr)->destipaddr)
+
+#define PEER_PORT(l4hdr,manip_type) \
+  ((manip_type) != NAT_MANIP_SRC ? &(l4hdr)->srcport : &(l4hdr)->destport)
 
 /****************************************************************************
  * Public Types
@@ -89,7 +115,7 @@ enum nat_manip_type_e
  ****************************************************************************/
 
 /****************************************************************************
- * Name: ipv4_nat_enable
+ * Name: nat_enable
  *
  * Description:
  *   Enable NAT function on a network device.
@@ -103,10 +129,10 @@ enum nat_manip_type_e
  *
  ****************************************************************************/
 
-int ipv4_nat_enable(FAR struct net_driver_s *dev);
+int nat_enable(FAR struct net_driver_s *dev);
 
 /****************************************************************************
- * Name: ipv4_nat_disable
+ * Name: nat_disable
  *
  * Description:
  *   Disable NAT function on a network device.
@@ -120,7 +146,7 @@ int ipv4_nat_enable(FAR struct net_driver_s *dev);
  *
  ****************************************************************************/
 
-int ipv4_nat_disable(FAR struct net_driver_s *dev);
+int nat_disable(FAR struct net_driver_s *dev);
 
 /****************************************************************************
  * Name: ipv4_nat_inbound
@@ -139,8 +165,10 @@ int ipv4_nat_disable(FAR struct net_driver_s *dev);
  *
  ****************************************************************************/
 
+#ifdef CONFIG_NET_IPv4
 int ipv4_nat_inbound(FAR struct net_driver_s *dev,
                      FAR struct ipv4_hdr_s *ipv4);
+#endif
 
 /****************************************************************************
  * Name: ipv4_nat_outbound
@@ -161,17 +189,20 @@ int ipv4_nat_inbound(FAR struct net_driver_s *dev,
  *
  ****************************************************************************/
 
+#ifdef CONFIG_NET_IPv4
 int ipv4_nat_outbound(FAR struct net_driver_s *dev,
                       FAR struct ipv4_hdr_s *ipv4,
                       enum nat_manip_type_e manip_type);
+#endif
 
 /****************************************************************************
- * Name: ipv4_nat_port_inuse
+ * Name: nat_port_inuse
  *
  * Description:
  *   Check whether a port is currently used by NAT.
  *
  * Input Parameters:
+ *   domain        - The domain of the packet.
  *   protocol      - The L4 protocol of the packet.
  *   ip            - The IP bind with the port (in network byte order).
  *   port          - The port number to check (in network byte order).
@@ -181,7 +212,47 @@ int ipv4_nat_outbound(FAR struct net_driver_s *dev,
  *
  ****************************************************************************/
 
-bool ipv4_nat_port_inuse(uint8_t protocol, in_addr_t ip, uint16_t port);
+bool nat_port_inuse(uint8_t domain, uint8_t protocol,
+                    FAR const union ip_addr_u *ip, uint16_t port);
+
+/****************************************************************************
+ * Name: nat_port_select
+ *
+ * Description:
+ *   Select an available port number for TCP/UDP protocol, or id for ICMP.
+ *
+ * Input Parameters:
+ *   dev         - The device on which the packet will be sent.
+ *   domain      - The domain of the packet.
+ *   protocol    - The L4 protocol of the packet.
+ *   external_ip - The external IP bind with the port.
+ *   local_port  - The local port of the packet, as reference.
+ *
+ * Returned Value:
+ *   External port number on success; 0 on failure
+ *
+ ****************************************************************************/
+
+uint16_t nat_port_select(FAR struct net_driver_s *dev,
+                         uint8_t domain, uint8_t protocol,
+                         FAR const union ip_addr_u *external_ip,
+                         uint16_t local_port);
+
+/****************************************************************************
+ * Name: nat_expire_time
+ *
+ * Description:
+ *   Get the expiration time of a specific protocol.
+ *
+ * Input Parameters:
+ *   protocol - The L4 protocol of the packet.
+ *
+ * Returned Value:
+ *   The expiration time of the protocol.
+ *
+ ****************************************************************************/
+
+uint32_t nat_expire_time(uint8_t protocol);
 
 /****************************************************************************
  * Name: ipv4_nat_entry_clear
@@ -198,7 +269,9 @@ bool ipv4_nat_port_inuse(uint8_t protocol, in_addr_t ip, 
uint16_t port);
  *
  ****************************************************************************/
 
+#ifdef CONFIG_NET_IPv4
 void ipv4_nat_entry_clear(FAR struct net_driver_s *dev);
+#endif
 
 /****************************************************************************
  * Name: ipv4_nat_inbound_entry_find
@@ -219,10 +292,12 @@ void ipv4_nat_entry_clear(FAR struct net_driver_s *dev);
  *
  ****************************************************************************/
 
+#ifdef CONFIG_NET_IPv4
 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
 
 /****************************************************************************
  * Name: ipv4_nat_outbound_entry_find
@@ -245,11 +320,13 @@ ipv4_nat_inbound_entry_find(uint8_t protocol, in_addr_t 
external_ip,
  *
  ****************************************************************************/
 
+#ifdef CONFIG_NET_IPv4
 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
 
-#endif /* CONFIG_NET_NAT && CONFIG_NET_IPv4 */
+#endif /* CONFIG_NET_NAT */
 #endif /* __NET_NAT_NAT_H */
diff --git a/net/netfilter/ipt_nat.c b/net/netfilter/ipt_nat.c
index 914845fff4..682f3018ce 100644
--- a/net/netfilter/ipt_nat.c
+++ b/net/netfilter/ipt_nat.c
@@ -60,12 +60,12 @@ static int adjust_nat(FAR struct net_driver_s *dev, FAR 
void *arg)
       if (strcmp(target->u.user.name, XT_MASQUERADE_TARGET) == 0 &&
           strcmp(dev->d_ifname, entry->ip.outiface) == 0)
         {
-          ipv4_nat_enable(dev);
+          nat_enable(dev);
           return 0;
         }
     }
 
-  ipv4_nat_disable(dev);
+  nat_disable(dev);
   return 0;
 }
 
diff --git a/net/tcp/tcp_conn.c b/net/tcp/tcp_conn.c
index 4d7fbf98a3..1deac8d001 100644
--- a/net/tcp/tcp_conn.c
+++ b/net/tcp/tcp_conn.c
@@ -617,9 +617,8 @@ int tcp_selectport(uint8_t domain,
           portno = HTONS(g_last_tcp_port);
         }
       while (tcp_listener(domain, ipaddr, portno)
-#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
-             || (domain == PF_INET &&
-                 ipv4_nat_port_inuse(IP_PROTO_TCP, ipaddr->ipv4, portno))
+#ifdef CONFIG_NET_NAT
+             || nat_port_inuse(domain, IP_PROTO_TCP, ipaddr, portno)
 #endif
       );
     }
@@ -630,9 +629,8 @@ int tcp_selectport(uint8_t domain,
        */
 
       if (tcp_listener(domain, ipaddr, portno)
-#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
-          || (domain == PF_INET &&
-              ipv4_nat_port_inuse(IP_PROTO_TCP, ipaddr->ipv4, portno))
+#ifdef CONFIG_NET_NAT
+          || nat_port_inuse(domain, IP_PROTO_TCP, ipaddr, portno)
 #endif
       )
         {
diff --git a/net/udp/udp_conn.c b/net/udp/udp_conn.c
index 1e9b09ab8d..31da06e12b 100644
--- a/net/udp/udp_conn.c
+++ b/net/udp/udp_conn.c
@@ -567,10 +567,9 @@ uint16_t udp_select_port(uint8_t domain, FAR union 
ip_binding_u *u)
         }
     }
   while (udp_find_conn(domain, u, HTONS(g_last_udp_port), 0) != NULL
-#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
-         || (domain == PF_INET &&
-             ipv4_nat_port_inuse(IP_PROTO_UDP, u->ipv4.laddr,
-                                 HTONS(g_last_udp_port)))
+#ifdef CONFIG_NET_NAT
+         || nat_port_inuse(domain, IP_PROTO_UDP, (FAR union ip_addr_u *)u,
+                           HTONS(g_last_udp_port))
 #endif
   );
 
@@ -939,10 +938,9 @@ int udp_bind(FAR struct udp_conn_s *conn, FAR const struct 
sockaddr *addr)
                         0
 #endif
                        ) == NULL
-#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
-          && !(conn->domain == PF_INET &&
-               ipv4_nat_port_inuse(IP_PROTO_UDP, conn->u.ipv4.laddr,
-                                   portno))
+#ifdef CONFIG_NET_NAT
+          && !nat_port_inuse(conn->domain, IP_PROTO_UDP,
+                             (FAR union ip_addr_u *)&conn->u, portno)
 #endif
       )
         {


Reply via email to