/* * * 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 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS #include #include #include #include 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