blob: 3ff1a242020cc273094ca70d3ba83eaf0dc7a266 [file] [log] [blame]
/*
*
* Copyright (c) 2020-2023 Project CHIP Authors
*
* Licensed 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.
*/
#include <inet/InetInterfaceImpl.h>
#if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
#include <ifaddrs.h>
#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>
#include <net/if.h>
namespace chip {
namespace Inet {
using namespace chip;
void if_freenameindexImpl(struct if_nameindex * inArray)
{
if (inArray == nullptr)
{
return;
}
for (size_t i = 0; inArray[i].if_index != 0; i++)
{
if (inArray[i].if_name != nullptr)
{
Platform::MemoryFree(inArray[i].if_name);
}
}
Platform::MemoryFree(inArray);
}
struct if_nameindex * if_nameindexImpl()
{
int err;
size_t intfIter = 0;
size_t maxIntfNum = 0;
size_t numIntf = 0;
size_t numAddrs = 0;
struct if_nameindex * retval = nullptr;
struct if_nameindex * tmpval = nullptr;
struct ifaddrs * addrList = nullptr;
struct ifaddrs * addrIter = nullptr;
const char * lastIntfName = "";
err = getifaddrs(&addrList);
VerifyOrExit(err >= 0, );
// coalesce on consecutive interface names
for (addrIter = addrList; addrIter != nullptr; addrIter = addrIter->ifa_next)
{
numAddrs++;
if (strcmp(addrIter->ifa_name, lastIntfName) != 0)
{
numIntf++;
lastIntfName = addrIter->ifa_name;
}
}
tmpval = (struct if_nameindex *) Platform::MemoryAlloc((numIntf + 1) * sizeof(struct if_nameindex));
VerifyOrExit(tmpval != nullptr, );
memset(tmpval, 0, (numIntf + 1) * sizeof(struct if_nameindex));
lastIntfName = "";
for (addrIter = addrList; addrIter != nullptr; addrIter = addrIter->ifa_next)
{
if (strcmp(addrIter->ifa_name, lastIntfName) == 0)
{
continue;
}
unsigned index = if_nametoindex(addrIter->ifa_name);
if (index != 0)
{
tmpval[intfIter].if_index = index;
tmpval[intfIter].if_name = strdup(addrIter->ifa_name);
intfIter++;
}
lastIntfName = addrIter->ifa_name;
}
// coalesce on interface index
maxIntfNum = 0;
for (size_t i = 0; tmpval[i].if_index != 0; i++)
{
if (maxIntfNum < tmpval[i].if_index)
{
maxIntfNum = tmpval[i].if_index;
}
}
retval = (struct if_nameindex *) Platform::MemoryAlloc((maxIntfNum + 1) * sizeof(struct if_nameindex));
VerifyOrExit(retval != nullptr, );
memset(retval, 0, (maxIntfNum + 1) * sizeof(struct if_nameindex));
for (size_t i = 0; tmpval[i].if_index != 0; i++)
{
struct if_nameindex * intf = &tmpval[i];
if (retval[intf->if_index - 1].if_index == 0)
{
retval[intf->if_index - 1] = *intf;
}
else
{
free(intf->if_name);
intf->if_index = 0;
intf->if_name = 0;
}
}
intfIter = 0;
// coalesce potential gaps between indeces
for (size_t i = 0; i < maxIntfNum; i++)
{
if (retval[i].if_index != 0)
{
retval[intfIter] = retval[i];
intfIter++;
}
}
for (size_t i = intfIter; i < maxIntfNum; i++)
{
retval[i].if_index = 0;
retval[i].if_name = nullptr;
}
exit:
if (tmpval != nullptr)
{
Platform::MemoryFree(tmpval);
}
if (addrList != nullptr)
{
freeifaddrs(addrList);
}
return retval;
}
} // namespace Inet
} // namespace chip
#endif