diff --git a/net/nat/ipv4_nat_entry.c b/net/nat/ipv4_nat_entry.c index 0d2645243b9..189143cc6ee 100644 --- a/net/nat/ipv4_nat_entry.c +++ b/net/nat/ipv4_nat_entry.c @@ -411,6 +411,7 @@ ipv4_nat_outbound_entry_find(FAR struct net_driver_s *dev, uint8_t protocol, FAR hash_node_t *tmp; uint16_t external_port; int32_t current_time = TICK2SEC(clock_systime_ticks()); + int ret; ipv4_nat_reclaim_entry(current_time); @@ -454,9 +455,10 @@ 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); - external_port = nat_port_select(dev, PF_INET, protocol, - (FAR union ip_addr_u *)&dev->d_ipaddr, local_port); - if (!external_port) + ret = nat_port_select(dev, PF_INET, protocol, + (FAR union ip_addr_u *)&dev->d_ipaddr, local_port, + &external_port); + if (ret < 0) { nwarn("WARNING: Failed to find an available port!\n"); return NULL; diff --git a/net/nat/ipv6_nat_entry.c b/net/nat/ipv6_nat_entry.c index 1f8229dae89..6f6c6309327 100644 --- a/net/nat/ipv6_nat_entry.c +++ b/net/nat/ipv6_nat_entry.c @@ -411,6 +411,7 @@ ipv6_nat_outbound_entry_find(FAR struct net_driver_s *dev, uint8_t protocol, FAR union ip_addr_u *external_ip; uint16_t external_port; int32_t current_time = TICK2SEC(clock_systime_ticks()); + int ret; ipv6_nat_reclaim_entry(current_time); @@ -457,10 +458,10 @@ ipv6_nat_outbound_entry_find(FAR struct net_driver_s *dev, uint8_t protocol, 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); + ret = nat_port_select(dev, PF_INET6, protocol, external_ip, local_port, + &external_port); - if (!external_port) + if (ret < 0) { nwarn("WARNING: Failed to find an available port!\n"); return NULL; diff --git a/net/nat/nat.c b/net/nat/nat.c index 9ff052a1c5d..ff2ea994954 100644 --- a/net/nat/nat.c +++ b/net/nat/nat.c @@ -56,13 +56,14 @@ static rmutex_t g_nat_lock = NXRMUTEX_INITIALIZER; * 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). - * local_port - The local port (in network byte order), as reference. + * domain - The domain of the packet. + * protocol - The L4 protocol of the packet. + * ip - The IP bind with the port (in network byte order). + * local_port - The local port (in network byte order), as reference. + * external_port - The selected external port (in network byte order). * * Returned Value: - * port number on success; 0 on failure + * 0 on success; a negated errno on failure. * ****************************************************************************/ @@ -71,12 +72,15 @@ static rmutex_t g_nat_lock = NXRMUTEX_INITIALIZER; (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( +static int nat_port_select_without_stack( uint8_t domain, uint8_t protocol, FAR const union ip_addr_u *ip, - uint16_t local_port) + uint16_t local_port, FAR uint16_t *external_port) { uint16_t portno = local_port; uint16_t hport = NTOHS(portno); + + DEBUGASSERT(external_port != NULL); + while (nat_port_inuse(domain, protocol, ip, portno)) { NET_PORT_NEXT_NH(portno, hport); @@ -84,11 +88,12 @@ static uint16_t nat_port_select_without_stack( { /* We have looped back, failed. */ - return 0; + return -EADDRINUSE; } } - return portno; + *external_port = portno; + return OK; } #endif @@ -216,22 +221,26 @@ bool nat_port_inuse(uint8_t domain, uint8_t protocol, * 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. + * 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. + * external_port - The selected external port. * * Returned Value: - * External port number on success; 0 on failure + * 0 on success; a negated errno 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) +int 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, + FAR uint16_t *external_port) { + DEBUGASSERT(external_port != NULL); + switch (protocol) { #ifdef CONFIG_NET_TCP @@ -249,10 +258,17 @@ uint16_t nat_port_select(FAR struct net_driver_s *dev, ret = tcp_selectport(domain, external_ip, 0); } - return ret > 0 ? ret : 0; + if (ret < 0) + { + return ret; + } + + *external_port = ret; + return OK; #else return nat_port_select_without_stack(domain, IP_PROTO_TCP, - external_ip, local_port); + external_ip, local_port, + external_port); #endif } #endif @@ -284,10 +300,12 @@ uint16_t nat_port_select(FAR struct net_driver_s *dev, /* TODO: Try keep origin port as possible. */ - return HTONS(udp_select_port(domain, &u)); + *external_port = HTONS(udp_select_port(domain, &u)); + return *external_port == 0 ? -EADDRINUSE : OK; #else return nat_port_select_without_stack(domain, IP_PROTO_UDP, - external_ip, local_port); + external_ip, local_port, + external_port); #endif } #endif @@ -306,14 +324,16 @@ uint16_t nat_port_select(FAR struct net_driver_s *dev, { /* We have looped back, failed. */ - return 0; + return -EADDRINUSE; } } - return id; + *external_port = id; + return OK; #else return nat_port_select_without_stack(domain, IP_PROTO_ICMP, - external_ip, local_port); + external_ip, local_port, + external_port); #endif } #endif @@ -332,14 +352,16 @@ uint16_t nat_port_select(FAR struct net_driver_s *dev, { /* We have looped back, failed. */ - return 0; + return -EADDRINUSE; } } - return id; + *external_port = id; + return OK; #else return nat_port_select_without_stack(domain, IP_PROTO_ICMP6, - external_ip, local_port); + external_ip, local_port, + external_port); #endif } #endif @@ -347,7 +369,8 @@ uint16_t nat_port_select(FAR struct net_driver_s *dev, /* Select original port for unsupported protocol. */ - return local_port; + *external_port = local_port; + return OK; } /**************************************************************************** diff --git a/net/nat/nat.h b/net/nat/nat.h index 7ed03b37151..f328347b635 100644 --- a/net/nat/nat.h +++ b/net/nat/nat.h @@ -256,21 +256,23 @@ bool nat_port_inuse(uint8_t domain, uint8_t protocol, * 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. + * 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. + * external_port - The selected external port. * * Returned Value: - * External port number on success; 0 on failure + * 0 on success; a negated errno 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); +int 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, + FAR uint16_t *external_port); /**************************************************************************** * Name: nat_expire_time