Skip to content

Commit

Permalink
[Inet] ToLwIPAddr() with IPAddressType (#13063)
Browse files Browse the repository at this point in the history
#### Problem

Fixes #11273 _IPAddress ANY has only one constant state, however addressType_

#### Change overview

Factor similar code in UDP and TCP into a new version of
`IPAddress::ToLwIPAddr()` that accounts for the requested
address type (IPv4 vs IPv6).

#### Testing

Added a unit test.
  • Loading branch information
kpschoedel authored and pull[bot] committed Jul 14, 2023
1 parent 99d9324 commit 1220282
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 38 deletions.
48 changes: 40 additions & 8 deletions src/inet/IPAddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@

#include <inet/IPAddress.h>

#include <inet/InetError.h>
#include <lib/core/CHIPEncoding.h>
#include <lib/support/CodeUtils.h>

#include "arpa-inet-compatibility.h"

Expand Down Expand Up @@ -127,28 +129,58 @@ ip_addr_t IPAddress::ToLwIPAddr(void) const
{
#if INET_CONFIG_ENABLE_IPV4
case IPAddressType::kIPv4:
IP_SET_TYPE_VAL(ret, IPADDR_TYPE_V4);
*ip_2_ip4(&ret) = IPAddress::ToIPv4();
ip_addr_copy_from_ip4(ret, IPAddress::ToIPv4());
break;
#endif // INET_CONFIG_ENABLE_IPV4

case IPAddressType::kIPv6:
IP_SET_TYPE_VAL(ret, IPADDR_TYPE_V6);
*ip_2_ip6(&ret) = IPAddress::ToIPv6();
ip_addr_copy_from_ip6(ret, IPAddress::ToIPv6());
break;

default:
#if INET_CONFIG_ENABLE_IPV4
ret = *IP_ADDR_ANY;
#else
ret = *IP6_ADDR_ANY;
#endif
break;
}

return ret;
}

CHIP_ERROR IPAddress::ToLwIPAddr(IPAddressType addressType, ip_addr_t & outAddress) const
{
VerifyOrReturnError(addressType != IPAddressType::kUnknown, CHIP_ERROR_INVALID_ARGUMENT);

switch (Type())
{
#if INET_CONFIG_ENABLE_IPV4
case IPAddressType::kIPv4:
ip_addr_copy_from_ip4(outAddress, IPAddress::ToIPv4());
return (addressType == IPAddressType::kIPv6) ? INET_ERROR_WRONG_ADDRESS_TYPE : CHIP_NO_ERROR;
#endif // INET_CONFIG_ENABLE_IPV4

case IPAddressType::kIPv6:
ip_addr_copy_from_ip6(outAddress, IPAddress::ToIPv6());
#if INET_CONFIG_ENABLE_IPV4
return (addressType == IPAddressType::kIPv4) ? INET_ERROR_WRONG_ADDRESS_TYPE : CHIP_NO_ERROR;
#else
return CHIP_NO_ERROR;
#endif // INET_CONFIG_ENABLE_IPV4

case IPAddressType::kAny:
#if INET_CONFIG_ENABLE_IPV4
if (addressType == IPAddressType::kIPv4)
{
outAddress = *IP4_ADDR_ANY;
return CHIP_NO_ERROR;
}
#endif // INET_CONFIG_ENABLE_IPV4
outAddress = *IP6_ADDR_ANY;
return CHIP_NO_ERROR;

default:
return INET_ERROR_WRONG_ADDRESS_TYPE;
}
}

lwip_ip_addr_type IPAddress::ToLwIPAddrType(IPAddressType typ)
{
lwip_ip_addr_type ret;
Expand Down
10 changes: 10 additions & 0 deletions src/inet/IPAddress.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <string.h>
#include <type_traits>

#include <lib/core/CHIPError.h>
#include <lib/support/BitFlags.h>
#include <lib/support/DLLUtil.h>

Expand Down Expand Up @@ -485,6 +486,15 @@ class DLL_EXPORT IPAddress
*/
ip_addr_t ToLwIPAddr(void) const;

/**
* Extract the IP address as a LwIP ip_addr_t structure.
*
* If the IP address is Any, the result is IP6_ADDR_ANY unless the requested addressType is kIPv4.
* If the requested addressType is IPAddressType::kAny, extracts the IP address as an LwIP ip_addr_t structure.
* Otherwise, returns INET_ERROR_WRONG_ADDRESS_TYPE if the requested addressType does not match the IP address.
*/
CHIP_ERROR ToLwIPAddr(IPAddressType addressType, ip_addr_t & outAddress) const;

/**
* @brief Convert the INET layer address type to its underlying LwIP type.
*
Expand Down
22 changes: 5 additions & 17 deletions src/inet/TCPEndPointImplLwIP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,30 +67,18 @@ CHIP_ERROR TCPEndPointImplLwIP::BindImpl(IPAddressType addrType, const IPAddress
CHIP_ERROR res = GetPCB(addrType);

// Bind the PCB to the specified address/port.
ip_addr_t ipAddr;
if (res == CHIP_NO_ERROR)
{
if (reuseAddr)
{
ip_set_option(mTCP, SOF_REUSEADDR);
}
res = addr.ToLwIPAddr(addrType, ipAddr);
}

ip_addr_t ipAddr;
if (addr != IPAddress::Any)
{
ipAddr = addr.ToLwIPAddr();
}
else if (addrType == IPAddressType::kIPv6)
{
ipAddr = ip6_addr_any;
}
#if INET_CONFIG_ENABLE_IPV4
else if (addrType == IPAddressType::kIPv4)
{
ipAddr = ip_addr_any;
}
#endif // INET_CONFIG_ENABLE_IPV4
else
res = INET_ERROR_WRONG_ADDRESS_TYPE;
if (res == CHIP_NO_ERROR)
{
res = chip::System::MapErrorLwIP(tcp_bind(mTCP, &ipAddr, port));
}

Expand Down
18 changes: 5 additions & 13 deletions src/inet/UDPEndPointImplLwIP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,22 +72,14 @@ CHIP_ERROR UDPEndPointImplLwIP::BindImpl(IPAddressType addressType, const IPAddr
CHIP_ERROR res = GetPCB(addressType);

// Bind the PCB to the specified address/port.
ip_addr_t ipAddr;
if (res == CHIP_NO_ERROR)
{
ip_addr_t ipAddr = address.ToLwIPAddr();

// TODO: IPAddress ANY has only one constant state, however addressType
// has separate IPV4 and IPV6 'any' settings. This tries to correct
// for this as LWIP default if IPv4 is compiled in is to consider
// 'any == any_v4'
//
// We may want to consider having separate AnyV4 and AnyV6 constants
// inside CHIP to resolve this ambiguity
if ((address.Type() == IPAddressType::kAny) && (addressType == IPAddressType::kIPv6))
{
ipAddr = *IP6_ADDR_ANY;
}
res = address.ToLwIPAddr(addressType, ipAddr);
}

if (res == CHIP_NO_ERROR)
{
res = chip::System::MapErrorLwIP(udp_bind(mUDP, &ipAddr, port));
}

Expand Down
107 changes: 107 additions & 0 deletions src/inet/tests/TestInetAddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include <nlunit-test.h>

#include <inet/IPPrefix.h>
#include <inet/InetError.h>

#include <lib/support/CodeUtils.h>
#include <lib/support/UnitTestRegistration.h>
Expand Down Expand Up @@ -1710,6 +1711,109 @@ void CheckIPPrefix(nlTestSuite * inSuite, void * inContext)
}
}

#if CHIP_SYSTEM_CONFIG_USE_LWIP

bool sameLwIPAddress(const ip6_addr_t & a, const ip6_addr_t & b)
{
return (a.addr[0] == b.addr[0]) && (a.addr[1] == b.addr[1]) && (a.addr[2] == b.addr[2]) && (a.addr[3] == b.addr[3]);
}

#if LWIP_IPV4 && LWIP_IPV6
bool sameLwIPAddress(const ip_addr_t & a, const ip_addr_t & b)
{
switch (a.type)
{
case IPADDR_TYPE_V4:
return (b.type == IPADDR_TYPE_V4) && (a.u_addr.ip4.addr == b.u_addr.ip4.addr);
case IPADDR_TYPE_V6:
return (b.type == IPADDR_TYPE_V6) && sameLwIPAddress(a.u_addr.ip6, b.u_addr.ip6);
default:
return false;
}
}
#endif // LWIP_IPV4 && LWIP_IPV6

/**
* Test ToLwIPAddress()
*/
void CheckToLwIPAddr(nlTestSuite * inSuite, void * inContext)
{
const struct TestContext * lContext = static_cast<const struct TestContext *>(inContext);
IPAddressExpandedContextIterator lCurrent = lContext->mIPAddressExpandedContextRange.mBegin;
IPAddressExpandedContextIterator lEnd = lContext->mIPAddressExpandedContextRange.mEnd;
CHIP_ERROR err;
ip_addr_t lwip_expected_addr, lwip_check_addr;

while (lCurrent != lEnd)
{
IPAddress test_addr;

SetupIPAddress(test_addr, lCurrent);

#if INET_CONFIG_ENABLE_IPV4
if (lCurrent->mAddr.mAddrType == IPAddressType::kIPv4)
{
ip_addr_copy_from_ip4(lwip_expected_addr, test_addr.ToIPv4());
lwip_check_addr = test_addr.ToLwIPAddr();
NL_TEST_ASSERT(inSuite, sameLwIPAddress(lwip_expected_addr, lwip_check_addr));

err = test_addr.ToLwIPAddr(IPAddressType::kAny, lwip_check_addr);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, sameLwIPAddress(lwip_expected_addr, lwip_check_addr));

err = test_addr.ToLwIPAddr(IPAddressType::kIPv4, lwip_check_addr);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, sameLwIPAddress(lwip_expected_addr, lwip_check_addr));

err = test_addr.ToLwIPAddr(IPAddressType::kIPv6, lwip_check_addr);
NL_TEST_ASSERT(inSuite, err == INET_ERROR_WRONG_ADDRESS_TYPE);
}
else
#endif // INET_CONFIG_ENABLE_IPV4
if (lCurrent->mAddr.mAddrType == IPAddressType::kIPv6)
{
ip_addr_copy_from_ip6(lwip_expected_addr, test_addr.ToIPv6());
lwip_check_addr = test_addr.ToLwIPAddr();
NL_TEST_ASSERT(inSuite, sameLwIPAddress(lwip_expected_addr, lwip_check_addr));

err = test_addr.ToLwIPAddr(IPAddressType::kAny, lwip_check_addr);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, sameLwIPAddress(lwip_expected_addr, lwip_check_addr));

err = test_addr.ToLwIPAddr(IPAddressType::kIPv6, lwip_check_addr);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, sameLwIPAddress(lwip_expected_addr, lwip_check_addr));

#if INET_CONFIG_ENABLE_IPV4
err = test_addr.ToLwIPAddr(IPAddressType::kIPv4, lwip_check_addr);
NL_TEST_ASSERT(inSuite, err == INET_ERROR_WRONG_ADDRESS_TYPE);
#endif // INET_CONFIG_ENABLE_IPV4
}
else if (lCurrent->mAddr.mAddrType == IPAddressType::kAny)
{
lwip_check_addr = test_addr.ToLwIPAddr();
NL_TEST_ASSERT(inSuite, sameLwIPAddress(*IP6_ADDR_ANY, lwip_check_addr));

err = test_addr.ToLwIPAddr(IPAddressType::kAny, lwip_check_addr);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, sameLwIPAddress(*IP6_ADDR_ANY, lwip_check_addr));

err = test_addr.ToLwIPAddr(IPAddressType::kIPv6, lwip_check_addr);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, sameLwIPAddress(*IP6_ADDR_ANY, lwip_check_addr));

#if INET_CONFIG_ENABLE_IPV4
err = test_addr.ToLwIPAddr(IPAddressType::kIPv4, lwip_check_addr);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, sameLwIPAddress(*IP4_ADDR_ANY, lwip_check_addr));
#endif // INET_CONFIG_ENABLE_IPV4
}

++lCurrent;
}
}
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP

/**
* Test Suite. It lists all the test functions.
*/
Expand Down Expand Up @@ -1750,6 +1854,9 @@ const nlTest sTests[] =
NL_TEST_DEF("Assemble IPv6 Transient Multicast address", CheckMakeIPv6TransientMulticast),
NL_TEST_DEF("Assemble IPv6 Prefix Multicast address", CheckMakeIPv6PrefixMulticast),
NL_TEST_DEF("IPPrefix test", CheckIPPrefix),
#if CHIP_SYSTEM_CONFIG_USE_LWIP
NL_TEST_DEF("Convert IPAddress to LwIP address", CheckToLwIPAddr),
#endif
NL_TEST_SENTINEL()
};
// clang-format on
Expand Down

0 comments on commit 1220282

Please sign in to comment.