| /* |
| * |
| * Copyright (c) 2020 Project CHIP Authors |
| * Copyright (c) 2013-2018 Nest Labs, Inc. |
| * |
| * 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. |
| */ |
| |
| /** |
| * @file |
| * This file implements constants, globals and interfaces common to |
| * and used by all CHP Inet layer library test applications and |
| * tools. |
| * |
| * NOTE: These do not comprise a public part of the CHIP API and |
| * are subject to change without notice. |
| * |
| */ |
| |
| #ifndef __STDC_LIMIT_MACROS |
| #define __STDC_LIMIT_MACROS |
| #endif |
| #ifndef __STDC_FORMAT_MACROS |
| #define __STDC_FORMAT_MACROS |
| #endif |
| |
| #include "TestInetCommon.h" |
| |
| #include <new> |
| #include <vector> |
| |
| #include <inttypes.h> |
| #include <signal.h> |
| #include <stdint.h> |
| #include <string.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include <inet/InetFaultInjection.h> |
| #include <support/CHIPFaultInjection.h> |
| #include <system/SystemFaultInjection.h> |
| #include <system/SystemTimer.h> |
| |
| #if CHIP_SYSTEM_CONFIG_USE_LWIP |
| #include <lwip/dns.h> |
| #include <lwip/init.h> |
| #include <lwip/netif.h> |
| #include <lwip/sys.h> |
| #include <lwip/tcpip.h> |
| #include <netif/etharp.h> |
| |
| #if CHIP_TARGET_STYLE_UNIX |
| |
| // TapAddrAutoconf and TapInterface are only needed for LwIP on |
| // sockets simulation in which a host tap/tun interface is used to |
| // proxy the LwIP stack onto a host native network interface. |
| |
| #include "TapAddrAutoconf.h" |
| #include "TapInterface.h" |
| #endif // CHIP_TARGET_STYLE_UNIX |
| #endif // CHIP_SYSTEM_CONFIG_USE_LWIP |
| |
| #if CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| #include <arpa/inet.h> |
| #include <sys/select.h> |
| #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| |
| using namespace chip; |
| |
| #if CHIP_SYSTEM_CONFIG_USE_LWIP |
| static sys_mbox_t * sLwIPEventQueue = NULL; |
| static unsigned int sLwIPAcquireCount = 0; |
| |
| static void AcquireLwIP(void) |
| { |
| if (sLwIPAcquireCount++ == 0) |
| { |
| sys_mbox_new(sLwIPEventQueue, 100); |
| } |
| } |
| |
| static void ReleaseLwIP(void) |
| { |
| #if !(LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 1) |
| if (sLwIPAcquireCount > 0 && --sLwIPAcquireCount == 0) |
| { |
| tcpip_finish(NULL, NULL); |
| } |
| #endif |
| } |
| #endif // CHIP_SYSTEM_CONFIG_USE_LWIP |
| |
| struct RestartCallbackContext |
| { |
| int mArgc; |
| char ** mArgv; |
| }; |
| |
| static void RebootCallbackFn(void); |
| static void PostInjectionCallbackFn(nl::FaultInjection::Manager * aManager, nl::FaultInjection::Identifier aId, |
| nl::FaultInjection::Record * aFaultRecord); |
| |
| static struct RestartCallbackContext sRestartCallbackCtx; |
| static nl::FaultInjection::Callback sFuzzECHeaderCb; |
| static nl::FaultInjection::Callback sAsyncEventCb; |
| |
| // clang-format off |
| static nl::FaultInjection::GlobalContext sFaultInjectionGlobalContext = { |
| { |
| RebootCallbackFn, |
| PostInjectionCallbackFn |
| } |
| }; |
| // clang-format on |
| |
| System::Layer gSystemLayer; |
| |
| Inet::InetLayer gInet; |
| |
| #if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| #if CHIP_TARGET_STYLE_UNIX |
| // TapAddrAutoconf and TapInterface are only needed for LwIP on |
| // sockets simulation in which a host tap/tun interface is used to |
| // proxy the LwIP stack onto a host native network interface. |
| // CollectTapAddresses() is only available on such targets. |
| |
| static std::vector<TapInterface> sTapIFs; |
| #endif // CHIP_TARGET_STYLE_UNIX |
| static std::vector<struct netif> sNetIFs; // interface to filter |
| #endif // CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| |
| #if CHIP_SYSTEM_CONFIG_USE_LWIP |
| |
| static bool NetworkIsReady(); |
| static void OnLwIPInitComplete(void * arg); |
| #endif // CHIP_SYSTEM_CONFIG_USE_LWIP |
| |
| char gDefaultTapDeviceName[32]; |
| bool gDone = false; |
| bool gSigusr1Received = false; |
| |
| static void UseStdoutLineBuffering() |
| { |
| // Set stdout to be line buffered with a buffer of 512 (will flush on new line |
| // or when the buffer of 512 is exceeded). |
| setvbuf(stdout, nullptr, _IOLBF, 512); |
| } |
| |
| void InitTestInetCommon() |
| { |
| UseStdoutLineBuffering(); |
| } |
| |
| static void ExitOnSIGUSR1Handler(int signum) |
| { |
| // exit() allows us a slightly better clean up (gcov data) than SIGINT's exit |
| exit(0); |
| } |
| |
| // We set a hook to exit when we receive SIGUSR1, SIGTERM or SIGHUP |
| void SetSIGUSR1Handler(void) |
| { |
| SetSignalHandler(ExitOnSIGUSR1Handler); |
| } |
| |
| void SetSignalHandler(SignalHandler handler) |
| { |
| struct sigaction sa; |
| int signals[] = { SIGUSR1 }; |
| size_t i; |
| |
| memset(&sa, 0, sizeof(sa)); |
| sa.sa_handler = handler; |
| |
| for (i = 0; i < sizeof(signals) / sizeof(signals[0]); i++) |
| { |
| if (sigaction(signals[i], &sa, nullptr) == -1) |
| { |
| perror("Can't catch signal"); |
| exit(1); |
| } |
| } |
| } |
| |
| void InitSystemLayer() |
| { |
| #if CHIP_SYSTEM_CONFIG_USE_LWIP |
| AcquireLwIP(); |
| |
| gSystemLayer.Init(sLwIPEventQueue); |
| #else // !CHIP_SYSTEM_CONFIG_USE_LWIP |
| gSystemLayer.Init(nullptr); |
| #endif // !CHIP_SYSTEM_CONFIG_USE_LWIP |
| } |
| |
| void ShutdownSystemLayer() |
| { |
| gSystemLayer.Shutdown(); |
| |
| #if CHIP_SYSTEM_CONFIG_USE_LWIP |
| ReleaseLwIP(); |
| #endif // CHIP_SYSTEM_CONFIG_USE_LWIP |
| } |
| |
| #if CHIP_SYSTEM_CONFIG_USE_LWIP |
| static void PrintNetworkState() |
| { |
| char intfName[10]; |
| |
| for (size_t j = 0; j < gNetworkOptions.TapDeviceName.size(); j++) |
| { |
| struct netif * netIF = &(sNetIFs[j]); |
| #if CHIP_TARGET_STYLE_UNIX |
| // TapAddrAutoconf and TapInterface are only needed for LwIP on |
| // sockets simulation in which a host tap/tun interface is used to |
| // proxy the LwIP stack onto a host native network interface. |
| // CollectTapAddresses() is only available on such targets. |
| |
| TapInterface * tapIF = &(sTapIFs[j]); |
| #endif // CHIP_TARGET_STYLE_UNIX |
| GetInterfaceName(netIF, intfName, sizeof(intfName)); |
| |
| printf("LwIP interface ready\n"); |
| printf(" Interface Name: %s\n", intfName); |
| printf(" Tap Device: %s\n", gNetworkOptions.TapDeviceName[j]); |
| #if CHIP_TARGET_STYLE_UNIX |
| // TapAddrAutoconf and TapInterface are only needed for LwIP on |
| // sockets simulation in which a host tap/tun interface is used to |
| // proxy the LwIP stack onto a host native network interface. |
| // CollectTapAddresses() is only available on such targets. |
| |
| printf(" MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", tapIF->macAddr[0], tapIF->macAddr[1], tapIF->macAddr[2], |
| tapIF->macAddr[3], tapIF->macAddr[4], tapIF->macAddr[5]); |
| #endif // CHIP_TARGET_STYLE_UNIX |
| |
| #if INET_CONFIG_ENABLE_IPV4 |
| printf(" IPv4 Address: %s\n", ipaddr_ntoa(&(netIF->ip_addr))); |
| printf(" IPv4 Mask: %s\n", ipaddr_ntoa(&(netIF->netmask))); |
| printf(" IPv4 Gateway: %s\n", ipaddr_ntoa(&(netIF->gw))); |
| #endif // INET_CONFIG_ENABLE_IPV4 |
| for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) |
| { |
| if (!ip6_addr_isany(netif_ip6_addr(netIF, i))) |
| { |
| printf(" IPv6 address: %s, 0x%02x\n", ip6addr_ntoa(netif_ip6_addr(netIF, i)), netif_ip6_addr_state(netIF, i)); |
| } |
| } |
| } |
| #if INET_CONFIG_ENABLE_DNS_RESOLVER |
| char dnsServerAddrStr[DNS_MAX_NAME_LENGTH]; |
| printf(" DNS Server: %s\n", gNetworkOptions.DNSServerAddr.ToString(dnsServerAddrStr, sizeof(dnsServerAddrStr))); |
| #endif // INET_CONFIG_ENABLE_DNS_RESOLVER |
| } |
| #endif // CHIP_SYSTEM_CONFIG_USE_LWIP |
| |
| void InitNetwork() |
| { |
| void * lContext = nullptr; |
| |
| #if CHIP_SYSTEM_CONFIG_USE_LWIP |
| #if CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| |
| tcpip_init(NULL, NULL); |
| |
| #else // !CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| |
| // If an tap device name hasn't been specified, derive one from the IPv6 interface id. |
| |
| if (gNetworkOptions.TapDeviceName.empty()) |
| { |
| for (size_t j = 0; j < gNetworkOptions.LocalIPv6Addr.size(); j++) |
| { |
| uint64_t iid = gNetworkOptions.LocalIPv6Addr[j].InterfaceId(); |
| char * tap_name = (char *) malloc(sizeof(gDefaultTapDeviceName)); |
| snprintf(tap_name, sizeof(gDefaultTapDeviceName), "chip-dev-%" PRIx64, iid & 0xFFFF); |
| tap_name[sizeof(gDefaultTapDeviceName) - 1] = 0; |
| gNetworkOptions.TapDeviceName.push_back(tap_name); |
| } |
| } |
| |
| #if CHIP_TARGET_STYLE_UNIX |
| // TapAddrAutoconf and TapInterface are only needed for LwIP on |
| // sockets simulation in which a host tap/tun interface is used to |
| // proxy the LwIP stack onto a host native network interface. |
| // CollectTapAddresses() is only available on such targets. |
| |
| sTapIFs.clear(); |
| #endif // CHIP_TARGET_STYLE_UNIX |
| sNetIFs.clear(); |
| |
| for (size_t j = 0; j < gNetworkOptions.TapDeviceName.size(); j++) |
| { |
| #if CHIP_TARGET_STYLE_UNIX |
| // TapAddrAutoconf and TapInterface are only needed for LwIP on |
| // sockets simulation in which a host tap/tun interface is used to |
| // proxy the LwIP stack onto a host native network interface. |
| // CollectTapAddresses() is only available on such targets. |
| |
| TapInterface tapIF; |
| sTapIFs.push_back(tapIF); |
| #endif // CHIP_TARGET_STYLE_UNIX |
| struct netif netIF; |
| sNetIFs.push_back(netIF); |
| } |
| |
| #if CHIP_TARGET_STYLE_UNIX |
| |
| // TapAddrAutoconf and TapInterface are only needed for LwIP on |
| // sockets simulation in which a host tap/tun interface is used to |
| // proxy the LwIP stack onto a host native network interface. |
| // CollectTapAddresses() is only available on such targets. |
| |
| err_t lwipErr; |
| |
| for (size_t j = 0; j < gNetworkOptions.TapDeviceName.size(); j++) |
| { |
| lwipErr = TapInterface_Init(&(sTapIFs[j]), gNetworkOptions.TapDeviceName[j], NULL); |
| if (lwipErr != ERR_OK) |
| { |
| printf("Failed to initialize tap device %s: %s\n", gNetworkOptions.TapDeviceName[j], |
| ErrorStr(System::MapErrorLwIP(lwipErr))); |
| exit(EXIT_FAILURE); |
| } |
| } |
| #endif // CHIP_TARGET_STYLE_UNIX |
| tcpip_init(OnLwIPInitComplete, NULL); |
| |
| // Lock LwIP stack |
| LOCK_TCPIP_CORE(); |
| |
| for (size_t j = 0; j < gNetworkOptions.TapDeviceName.size(); j++) |
| { |
| std::vector<char *> addrsVec; |
| |
| addrsVec.clear(); |
| |
| #if CHIP_TARGET_STYLE_UNIX |
| |
| // TapAddrAutoconf and TapInterface are only needed for LwIP on |
| // sockets simulation in which a host tap/tun interface is used to |
| // proxy the LwIP stack onto a host native network interface. |
| // CollectTapAddresses() is only available on such targets. |
| if (gNetworkOptions.TapUseSystemConfig) |
| { |
| CollectTapAddresses(addrsVec, gNetworkOptions.TapDeviceName[j]); |
| } |
| #endif // CHIP_TARGET_STYLE_UNIX |
| #if INET_CONFIG_ENABLE_IPV4 |
| |
| IPAddress ip4Addr = (j < gNetworkOptions.LocalIPv4Addr.size()) ? gNetworkOptions.LocalIPv4Addr[j] : IPAddress::Any; |
| for (size_t n = 0; n < addrsVec.size(); n++) |
| { |
| IPAddress auto_addr; |
| if (IPAddress::FromString(addrsVec[n], auto_addr) && auto_addr.IsIPv4()) |
| { |
| ip4Addr = auto_addr; |
| } |
| } |
| |
| #if CHIP_TARGET_STYLE_UNIX |
| // TapAddrAutoconf and TapInterface are only needed for LwIP on |
| // sockets simulation in which a host tap/tun interface is used to |
| // proxy the LwIP stack onto a host native network interface. |
| // CollectTapAddresses() is only available on such targets. |
| |
| IPAddress ip4Gateway = (j < gNetworkOptions.IPv4GatewayAddr.size()) ? gNetworkOptions.IPv4GatewayAddr[j] : IPAddress::Any; |
| |
| { |
| #if LWIP_VERSION_MAJOR > 1 |
| ip4_addr_t ip4AddrLwIP, ip4NetmaskLwIP, ip4GatewayLwIP; |
| #else // LWIP_VERSION_MAJOR <= 1 |
| ip_addr_t ip4AddrLwIP, ip4NetmaskLwIP, ip4GatewayLwIP; |
| #endif // LWIP_VERSION_MAJOR <= 1 |
| |
| ip4AddrLwIP = ip4Addr.ToIPv4(); |
| IP4_ADDR(&ip4NetmaskLwIP, 255, 255, 255, 0); |
| ip4GatewayLwIP = ip4Gateway.ToIPv4(); |
| netif_add(&(sNetIFs[j]), &ip4AddrLwIP, &ip4NetmaskLwIP, &ip4GatewayLwIP, &(sTapIFs[j]), TapInterface_SetupNetif, |
| tcpip_input); |
| } |
| #endif // CHIP_TARGET_STYLE_UNIX |
| |
| #endif // INET_CONFIG_ENABLE_IPV4 |
| |
| netif_create_ip6_linklocal_address(&(sNetIFs[j]), 1); |
| |
| #if !(LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 1) |
| if (j < gNetworkOptions.LocalIPv6Addr.size()) |
| { |
| ip6_addr_t ip6addr = gNetworkOptions.LocalIPv6Addr[j].ToIPv6(); |
| s8_t index; |
| netif_add_ip6_address_with_route(&(sNetIFs[j]), &ip6addr, 64, &index); |
| // add ipv6 route for ipv6 address |
| if (j < gNetworkOptions.IPv6GatewayAddr.size()) |
| { |
| static ip6_addr_t br_ip6_addr = gNetworkOptions.IPv6GatewayAddr[j].ToIPv6(); |
| struct ip6_prefix ip6_prefix; |
| ip6_prefix.addr = Inet::IPAddress::Any.ToIPv6(); |
| ip6_prefix.prefix_len = 0; |
| ip6_add_route_entry(&ip6_prefix, &sNetIFs[j], &br_ip6_addr, NULL); |
| } |
| if (index >= 0) |
| { |
| netif_ip6_addr_set_state(&(sNetIFs[j]), index, IP6_ADDR_PREFERRED); |
| } |
| } |
| for (size_t n = 0; n < addrsVec.size(); n++) |
| { |
| IPAddress auto_addr; |
| if (IPAddress::FromString(addrsVec[n], auto_addr) && !auto_addr.IsIPv4()) |
| { |
| ip6_addr_t ip6addr = auto_addr.ToIPv6(); |
| s8_t index; |
| if (auto_addr.IsIPv6LinkLocal()) |
| continue; // skip over the LLA addresses, LwIP is aready adding those |
| if (auto_addr.IsIPv6Multicast()) |
| continue; // skip over the multicast addresses from host for now. |
| netif_add_ip6_address_with_route(&(sNetIFs[j]), &ip6addr, 64, &index); |
| if (index >= 0) |
| { |
| netif_ip6_addr_set_state(&(sNetIFs[j]), index, IP6_ADDR_PREFERRED); |
| } |
| } |
| } |
| #endif |
| |
| netif_set_up(&(sNetIFs[j])); |
| netif_set_link_up(&(sNetIFs[j])); |
| } |
| |
| netif_set_default(&(sNetIFs[0])); |
| // UnLock LwIP stack |
| |
| UNLOCK_TCPIP_CORE(); |
| |
| while (!NetworkIsReady()) |
| { |
| struct timeval lSleepTime; |
| lSleepTime.tv_sec = 0; |
| lSleepTime.tv_usec = 100000; |
| ServiceEvents(lSleepTime); |
| } |
| |
| // FIXME: this is kinda nasty :( |
| // Force new IP address to be ready, bypassing duplicate detection. |
| |
| for (size_t j = 0; j < gNetworkOptions.TapDeviceName.size(); j++) |
| { |
| if (j < gNetworkOptions.LocalIPv6Addr.size()) |
| { |
| netif_ip6_addr_set_state(&(sNetIFs[j]), 2, 0x30); |
| } |
| else |
| { |
| netif_ip6_addr_set_state(&(sNetIFs[j]), 1, 0x30); |
| } |
| } |
| |
| #if INET_CONFIG_ENABLE_DNS_RESOLVER |
| if (gNetworkOptions.DNSServerAddr != IPAddress::Any) |
| { |
| #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5 |
| ip_addr_t dnsServerAddr = gNetworkOptions.DNSServerAddr.ToLwIPAddr(); |
| #else // LWIP_VERSION_MAJOR <= 1 |
| #if INET_CONFIG_ENABLE_IPV4 |
| ip_addr_t dnsServerAddr = gNetworkOptions.DNSServerAddr.ToIPv4(); |
| #else // !INET_CONFIG_ENABLE_IPV4 |
| #error "No support for DNS Resolver without IPv4!" |
| #endif // !INET_CONFIG_ENABLE_IPV4 |
| #endif // LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5 |
| |
| dns_setserver(0, &dnsServerAddr); |
| } |
| #endif // INET_CONFIG_ENABLE_DNS_RESOLVER |
| |
| PrintNetworkState(); |
| |
| #endif // !CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| |
| AcquireLwIP(); |
| lContext = sLwIPEventQueue; |
| |
| #endif // CHIP_SYSTEM_CONFIG_USE_LWIP |
| |
| gInet.Init(gSystemLayer, lContext); |
| } |
| |
| void ServiceEvents(struct ::timeval & aSleepTime) |
| { |
| static bool printed = false; |
| |
| if (!printed) |
| { |
| #if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| if (NetworkIsReady()) |
| #endif |
| { |
| printf("CHIP node ready to service events; PID: %d; PPID: %d\n", getpid(), getppid()); |
| fflush(stdout); |
| printed = true; |
| } |
| } |
| #if CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| fd_set readFDs, writeFDs, exceptFDs; |
| int numFDs = 0; |
| |
| FD_ZERO(&readFDs); |
| FD_ZERO(&writeFDs); |
| FD_ZERO(&exceptFDs); |
| |
| #if CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| if (gSystemLayer.State() == System::kLayerState_Initialized) |
| gSystemLayer.PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime); |
| #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| |
| #if CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| if (gInet.State == InetLayer::kState_Initialized) |
| gInet.PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime); |
| #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| |
| int selectRes = select(numFDs, &readFDs, &writeFDs, &exceptFDs, &aSleepTime); |
| if (selectRes < 0) |
| { |
| printf("select failed: %s\n", ErrorStr(System::MapErrorPOSIX(errno))); |
| return; |
| } |
| #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| |
| if (gSystemLayer.State() == System::kLayerState_Initialized) |
| { |
| #if CHIP_SYSTEM_CONFIG_USE_LWIP |
| static uint32_t sRemainingSystemLayerEventDelay = 0; |
| #endif // CHIP_SYSTEM_CONFIG_USE_LWIP |
| |
| #if CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| |
| gSystemLayer.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs); |
| |
| #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| |
| #if CHIP_SYSTEM_CONFIG_USE_LWIP |
| if (gSystemLayer.State() == System::kLayerState_Initialized) |
| { |
| if (sRemainingSystemLayerEventDelay == 0) |
| { |
| gSystemLayer.DispatchEvents(); |
| sRemainingSystemLayerEventDelay = gNetworkOptions.EventDelay; |
| } |
| else |
| sRemainingSystemLayerEventDelay--; |
| |
| // TODO: Currently timers are delayed by aSleepTime above. A improved solution would have a mechanism to reduce |
| // aSleepTime according to the next timer. |
| |
| gSystemLayer.HandlePlatformTimer(); |
| } |
| #endif // CHIP_SYSTEM_CONFIG_USE_LWIP |
| } |
| |
| #if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| #if CHIP_TARGET_STYLE_UNIX |
| // TapAddrAutoconf and TapInterface are only needed for LwIP on |
| // sockets simulation in which a host tap/tun interface is used to |
| // proxy the LwIP stack onto a host native network interface. |
| // CollectTapAddresses() is only available on such targets. |
| |
| TapInterface_Select(&(sTapIFs[0]), &(sNetIFs[0]), aSleepTime, gNetworkOptions.TapDeviceName.size()); |
| #endif // CHIP_TARGET_STYLE_UNIX |
| #endif // CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| |
| if (gInet.State == InetLayer::kState_Initialized) |
| { |
| #if CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| |
| gInet.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs); |
| |
| #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| } |
| } |
| |
| #if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| static bool NetworkIsReady() |
| { |
| bool ready = true; |
| |
| for (size_t j = 0; j < gNetworkOptions.TapDeviceName.size(); j++) |
| { |
| for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) |
| { |
| if (!ip6_addr_isany(netif_ip6_addr(&(sNetIFs[j]), i)) && ip6_addr_istentative(netif_ip6_addr_state(&(sNetIFs[j]), i))) |
| { |
| ready = false; |
| break; |
| } |
| } |
| } |
| return ready; |
| } |
| |
| static void OnLwIPInitComplete(void * arg) |
| { |
| printf("Waiting for addresses assignment...\n"); |
| } |
| |
| #endif // CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_SOCKETS |
| |
| void ShutdownNetwork() |
| { |
| gInet.Shutdown(); |
| #if CHIP_SYSTEM_CONFIG_USE_LWIP |
| ReleaseLwIP(); |
| #endif |
| } |
| |
| void DumpMemory(const uint8_t * mem, uint32_t len, const char * prefix, uint32_t rowWidth) |
| { |
| int indexWidth = snprintf(nullptr, 0, "%X", len); |
| |
| if (indexWidth < 4) |
| indexWidth = 4; |
| |
| for (uint32_t i = 0; i < len; i += rowWidth) |
| { |
| printf("%s%0*X: ", prefix, indexWidth, i); |
| |
| uint32_t rowEnd = i + rowWidth; |
| |
| uint32_t j = i; |
| for (; j < rowEnd && j < len; j++) |
| printf("%02X ", mem[j]); |
| |
| for (; j < rowEnd; j++) |
| printf(" "); |
| |
| for (j = i; j < rowEnd && j < len; j++) |
| if (isprint((char) mem[j])) |
| printf("%c", mem[j]); |
| else |
| printf("."); |
| |
| printf("\n"); |
| } |
| } |
| |
| void DumpMemory(const uint8_t * mem, uint32_t len, const char * prefix) |
| { |
| const uint32_t kRowWidth = 16; |
| |
| DumpMemory(mem, len, prefix, kRowWidth); |
| } |
| static void RebootCallbackFn(void) |
| { |
| char * lArgv[sRestartCallbackCtx.mArgc + 2]; |
| int i; |
| int j = 0; |
| |
| if (gSigusr1Received) |
| { |
| printf("** skipping restart case after SIGUSR1 **\n"); |
| ExitNow(); |
| } |
| |
| for (i = 0; sRestartCallbackCtx.mArgv[i] != nullptr; i++) |
| { |
| if (strcmp(sRestartCallbackCtx.mArgv[i], "--faults") == 0) |
| { |
| // Skip the --faults argument for now |
| i++; |
| continue; |
| } |
| lArgv[j++] = sRestartCallbackCtx.mArgv[i]; |
| } |
| |
| lArgv[j] = nullptr; |
| |
| for (i = 0; lArgv[i] != nullptr; i++) |
| { |
| printf("argv[%d]: %s\n", i, lArgv[i]); |
| } |
| |
| // Need to close any open file descriptor above stdin/out/err. |
| // There is no portable way to get the max fd number. |
| // Given that CHIP's test apps don't open a large number of files, |
| // FD_SETSIZE should be a reasonable upper bound (see the documentation |
| // of select). |
| for (i = 3; i < FD_SETSIZE; i++) |
| { |
| close(i); |
| } |
| |
| printf("********** Restarting *********\n"); |
| fflush(stdout); |
| execvp(lArgv[0], lArgv); |
| |
| exit: |
| return; |
| } |
| |
| static void PostInjectionCallbackFn(nl::FaultInjection::Manager * aManager, nl::FaultInjection::Identifier aId, |
| nl::FaultInjection::Record * aFaultRecord) |
| { |
| uint16_t numargs = aFaultRecord->mNumArguments; |
| uint16_t i; |
| |
| printf("***** Injecting fault %s_%s, instance number: %u; reboot: %s", aManager->GetName(), aManager->GetFaultNames()[aId], |
| aFaultRecord->mNumTimesChecked, aFaultRecord->mReboot ? "yes" : "no"); |
| if (numargs) |
| { |
| printf(" with %u args:", numargs); |
| |
| for (i = 0; i < numargs; i++) |
| { |
| printf(" %d", aFaultRecord->mArguments[i]); |
| } |
| } |
| |
| printf("\n"); |
| } |
| |
| static bool PrintFaultInjectionMaxArgCbFn(nl::FaultInjection::Manager & mgr, nl::FaultInjection::Identifier aId, |
| nl::FaultInjection::Record * aFaultRecord, void * aContext) |
| { |
| const char * faultName = mgr.GetFaultNames()[aId]; |
| |
| if (gFaultInjectionOptions.PrintFaultCounters && aFaultRecord->mNumArguments) |
| { |
| printf("FI_instance_params: %s_%s_s%u maxArg: %u;\n", mgr.GetName(), faultName, aFaultRecord->mNumTimesChecked, |
| aFaultRecord->mArguments[0]); |
| } |
| |
| return false; |
| } |
| |
| static bool PrintCHIPFaultInjectionMaxArgCbFn(nl::FaultInjection::Identifier aId, nl::FaultInjection::Record * aFaultRecord, |
| void * aContext) |
| { |
| nl::FaultInjection::Manager & mgr = chip::FaultInjection::GetManager(); |
| |
| return PrintFaultInjectionMaxArgCbFn(mgr, aId, aFaultRecord, aContext); |
| } |
| |
| static bool PrintSystemFaultInjectionMaxArgCbFn(nl::FaultInjection::Identifier aId, nl::FaultInjection::Record * aFaultRecord, |
| void * aContext) |
| { |
| nl::FaultInjection::Manager & mgr = chip::System::FaultInjection::GetManager(); |
| |
| return PrintFaultInjectionMaxArgCbFn(mgr, aId, aFaultRecord, aContext); |
| } |
| |
| void SetupFaultInjectionContext(int argc, char * argv[]) |
| { |
| SetupFaultInjectionContext(argc, argv, nullptr, nullptr); |
| } |
| |
| void SetupFaultInjectionContext(int argc, char * argv[], int32_t (*aNumEventsAvailable)(void), |
| void (*aInjectAsyncEvents)(int32_t index)) |
| { |
| nl::FaultInjection::Manager & weavemgr = chip::FaultInjection::GetManager(); |
| nl::FaultInjection::Manager & systemmgr = chip::System::FaultInjection::GetManager(); |
| |
| sRestartCallbackCtx.mArgc = argc; |
| sRestartCallbackCtx.mArgv = argv; |
| |
| nl::FaultInjection::SetGlobalContext(&sFaultInjectionGlobalContext); |
| |
| memset(&sFuzzECHeaderCb, 0, sizeof(sFuzzECHeaderCb)); |
| sFuzzECHeaderCb.mCallBackFn = PrintCHIPFaultInjectionMaxArgCbFn; |
| weavemgr.InsertCallbackAtFault(chip::FaultInjection::kFault_FuzzExchangeHeaderTx, &sFuzzECHeaderCb); |
| |
| if (aNumEventsAvailable && aInjectAsyncEvents) |
| { |
| memset(&sAsyncEventCb, 0, sizeof(sAsyncEventCb)); |
| sAsyncEventCb.mCallBackFn = PrintSystemFaultInjectionMaxArgCbFn; |
| systemmgr.InsertCallbackAtFault(chip::System::FaultInjection::kFault_AsyncEvent, &sAsyncEventCb); |
| |
| chip::System::FaultInjection::SetAsyncEventCallbacks(aNumEventsAvailable, aInjectAsyncEvents); |
| } |
| } |