diff --git a/.travis/check-posix-app-pty b/.travis/check-posix-app-pty index 38d0d5a24..2a2caea6c 100755 --- a/.travis/check-posix-app-pty +++ b/.travis/check-posix-app-pty @@ -37,22 +37,25 @@ die() { at_exit() { EXIT_CODE=$? - sudo killall wpantund || true + + sudo killall expect || true killall socat || true + exit $EXIT_CODE } build() { ./bootstrap COVERAGE=1 make -f examples/Makefile-posix - COVERAGE=1 make -f src/posix/Makefile-posix PLATFORM_UDP=1 + COVERAGE=1 make -f src/posix/Makefile-posix PLATFORM_NETIF=1 PLATFORM_UDP=1 } check() { trap at_exit INT TERM EXIT SOCAT_OUTPUT=/tmp/ot-socat - socat -d -d pty,raw,b115200,echo=0 pty,raw,b115200,echo=0 > /dev/null 2> $SOCAT_OUTPUT & + OT_OUTPUT=/tmp/ot-output + socat -d -d pty,raw,echo=0 pty,raw,echo=0 > /dev/null 2> $SOCAT_OUTPUT & while true; do if test $(head -n2 $SOCAT_OUTPUT | wc -l) = 2; then RADIO_PTY=$(head -n1 $SOCAT_OUTPUT | grep -o '/dev/.\+') @@ -67,37 +70,48 @@ check() { RADIO_NCP_PATH="$(pwd)/$(ls output/*linux*/bin/ot-ncp-radio)" $RADIO_NCP_PATH 1 > $RADIO_PTY < $RADIO_PTY & - OT_NCP_PATH="$(pwd)/$(ls output/posix/*linux*/bin/ot-ncp)" - PLATFORM_NETIF=wpan0 sudo -E wpantund -I wpan0 -o Thread:Config:FilterRLOCAddresses 0 -s "system:${OT_NCP_PATH} ${CORE_PTY}" & + OT_CLI_PATH="$(pwd)/$(ls output/posix/*linux*/bin/ot-cli)" + sudo expect < $OT_OUTPUT & +spawn $OT_CLI_PATH ${OT_NCP_PATH} ${CORE_PTY} +send "panid 0xface\r\n" +expect "Done" +send "ifconfig up\r\n" +expect "Done" +send "thread start\r\n" +expect "Done" +sleep 5 +send "state\r\n" +expect "leader" +expect "Done" +send "extaddr\r\n" +expect "Done" +send "ipaddr\r\n" +expect "Done" +wait +EOF + # wait until the node becomes leader while true; do sleep 5 - if sudo wpanctl status; then + if grep -q leader $OT_OUTPUT; then break else - echo 'Still waiting for wpantund' + echo 'Still waiting for leader' fi done - sudo wpanctl leave || true - sudo wpanctl form -c 18 OpenThreadTest - - mleid=$(sudo wpanctl status | grep MeshLocalAddress | cut -d'"' -f4) - echo "ML-EID is: ${mleid}" - netstat -an | grep -q 61631 || die 'TMF port is not available!' - xaddress=$(sudo wpanctl get 'NCP:ExtendedAddress' | cut -d= -f2 | tr -d ' []') - echo "Extended address is: ${xaddress}" + extaddr=$(awk '/extaddr/{getline; print}' $OT_OUTPUT | tr -d '\r\n') + echo "Extended address is: ${extaddr}" + + LEADER_ALOC=fdde:ad00:beef::ff:fe00:fc00 # Retrievie extended address through network diagnostic get - coap_response=$(echo -n '120100' | xxd -r -p | coap-client -m POST coap://[${mleid}]:61631/d/dg -f- | xxd -p -u | grep 0008) + coap_response=$(echo -n '120100' | xxd -r -p | coap-client -m POST coap://[${LEADER_ALOC}]:61631/d/dg -f- | xxd -p | grep 0008) echo "CoAP response is: ${coap_response}" # Verify CoAP response contains the extended address - [[ "${coap_response}" = *${xaddress}* ]] || die 'failed to get extended address' - - # Leave so that code coverage will be flushed - sudo wpanctl leave || true + [[ "${coap_response}" = *${extaddr}* ]] && echo 'Success' || die 'failed to get extended address' } main() { diff --git a/configure.ac b/configure.ac index 98cac2c85..3edc2b0a0 100644 --- a/configure.ac +++ b/configure.ac @@ -861,6 +861,35 @@ AC_SUBST(OPENTHREAD_ENABLE_PLATFORM_UDP) AM_CONDITIONAL([OPENTHREAD_ENABLE_PLATFORM_UDP], [test "${enable_platform_udp}" = "yes"]) AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_PLATFORM_UDP], [${OPENTHREAD_ENABLE_PLATFORM_UDP}], [Define to 1 to enable platform UDP.]) +# +# Platform Netif +# + +AC_ARG_ENABLE(platform_netif, + [AS_HELP_STRING([--enable-platform-netif],[Enable platform Netif support @<:@default=no@:>@.])], + [ + case "${enableval}" in + no|yes) + enable_platform_netif=${enableval} + ;; + *) + AC_MSG_ERROR([Invalid value ${enable_platform_netif} for --enable-platform-netif]) + ;; + esac + ], + [enable_platform_netif=no]) + +if test "$enable_platform_netif" = "yes"; then + OPENTHREAD_ENABLE_PLATFORM_NETIF=1 +else + OPENTHREAD_ENABLE_PLATFORM_NETIF=0 +fi + +AC_MSG_RESULT(${enable_platform_netif}) +AC_SUBST(OPENTHREAD_ENABLE_PLATFORM_NETIF) +AM_CONDITIONAL([OPENTHREAD_ENABLE_PLATFORM_NETIF], [test "${enable_platform_netif}" = 'yes']) +AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_PLATFORM_NETIF], [${OPENTHREAD_ENABLE_PLATFORM_NETIF}], [Define to 1 to enable platform Netif.]) + # # Thread Commissioner # diff --git a/src/posix/Makefile-posix b/src/posix/Makefile-posix index 3478fe244..3b102c620 100644 --- a/src/posix/Makefile-posix +++ b/src/posix/Makefile-posix @@ -84,6 +84,10 @@ ifeq ($(DISABLE_EXECUTABLE), 1) configure_OPTIONS += --enable-executable=no endif +ifeq ($(PLATFORM_NETIF),1) +configure_OPTIONS += --enable-platform-netif +endif + ifeq (${SNTP_CLIENT}, 1) configure_OPTIONS += --enable-sntp-client endif diff --git a/src/posix/main.c b/src/posix/main.c index 0cf116bd7..dd027668d 100644 --- a/src/posix/main.c +++ b/src/posix/main.c @@ -85,6 +85,9 @@ int main(int argc, char *argv[]) #if OPENTHREAD_POSIX_APP == OPENTHREAD_POSIX_APP_NCP otNcpInit(instance); #elif OPENTHREAD_POSIX_APP == OPENTHREAD_POSIX_APP_CLI +#if OPENTHREAD_ENABLE_PLATFORM_NETIF + otSysInitNetif(instance); +#endif otCliUartInit(instance); #endif diff --git a/src/posix/platform/Makefile.am b/src/posix/platform/Makefile.am index 2a3b9e2a7..1265a91ee 100644 --- a/src/posix/platform/Makefile.am +++ b/src/posix/platform/Makefile.am @@ -44,6 +44,7 @@ libopenthread_posix_a_SOURCES = \ hdlc_interface.cpp \ logging.c \ misc.c \ + netif.cpp \ radio_spinel.cpp \ random.c \ settings.cpp \ diff --git a/src/posix/platform/hdlc_interface.hpp b/src/posix/platform/hdlc_interface.hpp index 04a090bea..84024a1a8 100644 --- a/src/posix/platform/hdlc_interface.hpp +++ b/src/posix/platform/hdlc_interface.hpp @@ -34,7 +34,7 @@ #ifndef POSIX_APP_HDLC_INTERFACE_HPP_ #define POSIX_APP_HDLC_INTERFACE_HPP_ -#include "openthread-core-config.h" +#include "platform-posix.h" #include "hdlc.hpp" diff --git a/src/posix/platform/logging.c b/src/posix/platform/logging.c index ba88015f7..2f356c542 100644 --- a/src/posix/platform/logging.c +++ b/src/posix/platform/logging.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include diff --git a/src/posix/platform/netif.cpp b/src/posix/platform/netif.cpp new file mode 100644 index 000000000..0fdf2d4f5 --- /dev/null +++ b/src/posix/platform/netif.cpp @@ -0,0 +1,519 @@ +/* + * Copyright (c) 2018, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the platform network on Linux. + */ + +#include "platform-posix.h" + +#include +#include +#include +#include +#if __linux__ +#include +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "common/code_utils.hpp" +#include "common/logging.hpp" +#include "net/ip6_address.hpp" + +#if OPENTHREAD_ENABLE_PLATFORM_NETIF + +#ifndef OPENTHREAD_POSIX_TUN_DEVICE +#define OPENTHREAD_POSIX_TUN_DEVICE "/dev/net/tun" +#endif // OPENTHREAD_TUN_DEVICE + +// from linux/ipv6.h +struct in6_ifreq +{ + struct in6_addr ifr6_addr; + __u32 ifr6_prefixlen; + int ifr6_ifindex; +}; + +static otInstance * sInstance = NULL; +static int sTunFd = -1; ///< Used to exchange IPv6 packets. +static int sIpFd = -1; ///< Used to manage IPv6 stack on Thread interface. +static int sNetlinkFd = -1; ///< Used to receive netlink events. +static unsigned int sTunIndex = 0; +static char sTunName[IFNAMSIZ]; + +static const size_t kMaxIp6Size = 1536; +static const uint8_t kMulticastPrefixLength = 128; + +static void UpdateUnicast(otInstance *aInstance, const otIp6Address &aAddress, uint8_t aPrefixLength, bool aIsAdded) +{ + struct in6_ifreq ifr6; + otError error = OT_ERROR_NONE; + + assert(sInstance == aInstance); + + VerifyOrExit(sIpFd > 0, error = OT_ERROR_INVALID_STATE); + + memcpy(&ifr6.ifr6_addr, &aAddress, sizeof(ifr6.ifr6_addr)); + + ifr6.ifr6_ifindex = sTunIndex; + ifr6.ifr6_prefixlen = aPrefixLength; + + VerifyOrExit(ioctl(sIpFd, (aIsAdded ? SIOCSIFADDR : SIOCDIFADDR), &ifr6) == 0, perror("ioctl"); + error = OT_ERROR_FAILED); + +exit: + if (error == OT_ERROR_NONE) + { + otLogInfoPlat("%s: %s", __func__, otThreadErrorToString(error)); + } + else + { + otLogCritPlat("%s: %s", __func__, otThreadErrorToString(error)); + exit(OT_EXIT_FAILURE); + } +} + +static void UpdateMulticast(otInstance *aInstance, const otIp6Address &aAddress, bool aIsAdded) +{ + struct ipv6_mreq mreq; + otError error = OT_ERROR_NONE; + + assert(sInstance == aInstance); + + VerifyOrExit(sIpFd > 0); + memcpy(&mreq.ipv6mr_multiaddr, &aAddress, sizeof(mreq.ipv6mr_multiaddr)); + mreq.ipv6mr_interface = sTunIndex; + + VerifyOrExit( + setsockopt(sIpFd, IPPROTO_IPV6, (aIsAdded ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP), &mreq, sizeof(mreq)) == 0, + perror("setsockopt"); + error = OT_ERROR_FAILED); + +exit: + if (error == OT_ERROR_NONE) + { + otLogInfoPlat("%s: %s", __func__, otThreadErrorToString(error)); + } + else + { + otLogCritPlat("%s: %s", __func__, otThreadErrorToString(error)); + exit(OT_EXIT_FAILURE); + } +} + +static void UpdateLink(otInstance *aInstance) +{ + otError error = OT_ERROR_NONE; + struct ifreq ifr; + + assert(sInstance == aInstance); + + VerifyOrExit(sIpFd > 0); + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, sTunName, sizeof(ifr.ifr_name)); + VerifyOrExit(ioctl(sIpFd, SIOCGIFFLAGS, &ifr) == 0, perror("ioctl"); error = OT_ERROR_FAILED); + + if (otIp6IsEnabled(aInstance)) + { + ifr.ifr_flags |= IFF_UP; + } + else + { + ifr.ifr_flags &= ~IFF_UP; + } + + VerifyOrExit(ioctl(sIpFd, SIOCSIFFLAGS, &ifr) == 0, perror("ioctl"); error = OT_ERROR_FAILED); + +exit: + if (error == OT_ERROR_NONE) + { + otLogInfoPlat("%s: %s", __func__, otThreadErrorToString(error)); + } + else + { + otLogWarnPlat("%s: %s", __func__, otThreadErrorToString(error)); + } +} + +static void processAddressChange(const otIp6Address *aAddress, uint8_t aPrefixLength, bool aIsAdded, void *aContext) +{ + if (aAddress->mFields.m8[0] == 0xff) + { + UpdateMulticast(static_cast(aContext), *aAddress, aIsAdded); + } + else + { + UpdateUnicast(static_cast(aContext), *aAddress, aPrefixLength, aIsAdded); + } +} + +static void processStateChange(otChangedFlags aFlags, void *aContext) +{ + if (OT_CHANGED_THREAD_NETIF_STATE | aFlags) + { + UpdateLink(static_cast(aContext)); + } +} + +static void processReceive(otMessage *aMessage, void *aContext) +{ + char packet[kMaxIp6Size]; + otError error = OT_ERROR_NONE; + uint16_t length = otMessageGetLength(aMessage); + + assert(sInstance == aContext); + + VerifyOrExit(sTunFd > 0); + + VerifyOrExit(otMessageRead(aMessage, 0, packet, sizeof(packet)) == length, error = OT_ERROR_NO_BUFS); + + VerifyOrExit(write(sTunFd, packet, length) == length, perror("write"); error = OT_ERROR_FAILED); + +exit: + otMessageFree(aMessage); + + if (error == OT_ERROR_NONE) + { + otLogInfoPlat("%s: %s", __func__, otThreadErrorToString(error)); + } + else + { + otLogWarnPlat("%s: %s", __func__, otThreadErrorToString(error)); + } +} + +static void processTransmit(otInstance *aInstance) +{ + otMessage *message = NULL; + ssize_t rval; + char packet[kMaxIp6Size]; + otError error = OT_ERROR_NONE; + + assert(sInstance == aInstance); + + rval = read(sTunFd, packet, sizeof(packet)); + VerifyOrExit(rval > 0, error = OT_ERROR_FAILED); + + message = otIp6NewMessage(aInstance, NULL); + VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS); + + SuccessOrExit(error = otMessageAppend(message, packet, rval)); + + error = otIp6Send(aInstance, message); + message = NULL; + +exit: + if (message != NULL) + { + otMessageFree(message); + } + + if (error == OT_ERROR_NONE) + { + otLogInfoPlat("%s: %s", __func__, otThreadErrorToString(error)); + } + else + { + otLogWarnPlat("%s: %s", __func__, otThreadErrorToString(error)); + } +} + +static void processNetifAddrEvent(otInstance *aInstance, struct nlmsghdr *aNetlinkMessage) +{ + struct ifaddrmsg *ifaddr = reinterpret_cast(NLMSG_DATA(aNetlinkMessage)); + size_t rtaLength; + otError error = OT_ERROR_NONE; + + VerifyOrExit(ifaddr->ifa_index == static_cast(sTunIndex) && ifaddr->ifa_family == AF_INET6); + + rtaLength = IFA_PAYLOAD(aNetlinkMessage); + + for (struct rtattr *rta = reinterpret_cast(IFA_RTA(ifaddr)); RTA_OK(rta, rtaLength); + rta = RTA_NEXT(rta, rtaLength)) + { + switch (rta->rta_type) + { + case IFA_ADDRESS: + case IFA_LOCAL: + case IFA_BROADCAST: + case IFA_ANYCAST: + { + ot::Ip6::Address addr; + memcpy(&addr, RTA_DATA(rta), sizeof(addr)); + + if (aNetlinkMessage->nlmsg_type == RTM_NEWADDR) + { + if (!addr.IsMulticast()) + { + otNetifAddress netAddr; + + netAddr.mAddress = addr; + netAddr.mPrefixLength = ifaddr->ifa_prefixlen; + SuccessOrExit(error = otIp6AddUnicastAddress(aInstance, &netAddr)); + } + else + { + SuccessOrExit(error = otIp6SubscribeMulticastAddress(aInstance, &addr)); + } + } + else if (aNetlinkMessage->nlmsg_type == RTM_DELADDR) + { + if (!addr.IsMulticast()) + { + otIp6RemoveUnicastAddress(aInstance, &addr); + } + else + { + otIp6UnsubscribeMulticastAddress(aInstance, &addr); + } + } + else + { + continue; + } + break; + } + default: + break; + } + } + +exit: + if (error == OT_ERROR_NONE) + { + otLogInfoPlat("%s: %s", __func__, otThreadErrorToString(error)); + } + else + { + otLogWarnPlat("%s: %s", __func__, otThreadErrorToString(error)); + } +} + +static void processNetifLinkEvent(otInstance *aInstance, struct nlmsghdr *aNetlinkMessage) +{ + struct ifinfomsg *ifinfo = reinterpret_cast(NLMSG_DATA(aNetlinkMessage)); + otError error = OT_ERROR_NONE; + + VerifyOrExit(ifinfo->ifi_index == static_cast(sTunIndex)); + SuccessOrExit(error = otIp6SetEnabled(aInstance, ifinfo->ifi_flags & IFF_UP)); + +exit: + if (error == OT_ERROR_NONE) + { + otLogInfoPlat("%s: %s", __func__, otThreadErrorToString(error)); + } + else + { + otLogWarnPlat("%s: %s", __func__, otThreadErrorToString(error)); + } +} + +static void processNetifEvent(otInstance *aInstance) +{ + const size_t kMaxNetifEvent = 8192; + ssize_t length; + char buffer[kMaxNetifEvent]; + + length = recv(sNetlinkFd, buffer, sizeof(buffer), 0); + + VerifyOrExit(length > 0); + + for (struct nlmsghdr *msg = reinterpret_cast(buffer); NLMSG_OK(msg, length); + msg = NLMSG_NEXT(msg, length)) + { + switch (msg->nlmsg_type) + { + case RTM_NEWADDR: + case RTM_DELADDR: + processNetifAddrEvent(aInstance, msg); + break; + + case RTM_NEWLINK: + case RTM_DELLINK: + processNetifLinkEvent(aInstance, msg); + break; + + default: + break; + } + } + +exit: + return; +} + +void platformNetifInit(otInstance *aInstance) +{ + struct ifreq ifr; + + sIpFd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP); + VerifyOrExit(sIpFd > 0); + + sNetlinkFd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + VerifyOrExit(sNetlinkFd > 0); + + { + struct sockaddr_nl sa; + + memset(&sa, 0, sizeof(sa)); + sa.nl_family = AF_NETLINK; + sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV6_IFADDR; + VerifyOrExit(bind(sNetlinkFd, reinterpret_cast(&sa), sizeof(sa)) == 0); + } + + sTunFd = open(OPENTHREAD_POSIX_TUN_DEVICE, O_RDWR); + VerifyOrExit(sTunFd > 0, otLogCritPlat("Unable to open tun device %s", OPENTHREAD_POSIX_TUN_DEVICE)); + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TUN | IFF_NO_PI; + strncpy(ifr.ifr_name, "wpan%d", IFNAMSIZ); + + VerifyOrExit(ioctl(sTunFd, TUNSETIFF, static_cast(&ifr)) == 0, + otLogCritPlat("Unable to configure tun device %s", OPENTHREAD_POSIX_TUN_DEVICE)); +#if defined(ARPHRD_6LOWPAN) + VerifyOrExit(ioctl(sTunFd, TUNSETLINK, ARPHRD_6LOWPAN) == 0, + otLogCritPlat("Unable to set link type of tun device %s", OPENTHREAD_POSIX_TUN_DEVICE)); +#else + VerifyOrExit(ioctl(sTunFd, TUNSETLINK, ARPHRD_ETHER) == 0, + otLogCritPlat("Unable to set link type of tun device %s", OPENTHREAD_POSIX_TUN_DEVICE)); +#endif + + sTunIndex = if_nametoindex(ifr.ifr_name); + VerifyOrExit(sTunIndex > 0); + + strncpy(sTunName, ifr.ifr_name, sizeof(sTunName)); +#if OPENTHREAD_ENABLE_PLATFORM_UDP + platformUdpInit(sTunName); +#endif + + otIp6SetReceiveCallback(aInstance, processReceive, aInstance); + otIp6SetAddressCallback(aInstance, processAddressChange, aInstance); + otSetStateChangedCallback(aInstance, processStateChange, aInstance); + sInstance = aInstance; + +exit: + if (sTunIndex == 0) + { + if (sTunFd != -1) + { + close(sTunFd); + sTunFd = -1; + } + + if (sIpFd != -1) + { + close(sIpFd); + sIpFd = -1; + } + + if (sNetlinkFd != -1) + { + close(sNetlinkFd); + sNetlinkFd = -1; + } + + exit(OT_EXIT_FAILURE); + } +} + +void platformNetifUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, fd_set *aErrorFdSet, int *aMaxFd) +{ + OT_UNUSED_VARIABLE(aWriteFdSet); + + VerifyOrExit(sTunIndex > 0); + + assert(sTunFd > 0); + assert(sNetlinkFd > 0); + assert(sIpFd > 0); + + FD_SET(sTunFd, aReadFdSet); + FD_SET(sTunFd, aErrorFdSet); + FD_SET(sNetlinkFd, aReadFdSet); + FD_SET(sNetlinkFd, aErrorFdSet); + + if (sTunFd > *aMaxFd) + { + *aMaxFd = sTunFd; + } + + if (sNetlinkFd > *aMaxFd) + { + *aMaxFd = sNetlinkFd; + } + +exit: + return; +} + +void platformNetifProcess(const fd_set *aReadFdSet, const fd_set *aWriteFdSet, const fd_set *aErrorFdSet) +{ + OT_UNUSED_VARIABLE(aWriteFdSet); + VerifyOrExit(sTunIndex > 0); + + if (FD_ISSET(sTunFd, aErrorFdSet)) + { + close(sTunFd); + exit(OT_EXIT_FAILURE); + } + + if (FD_ISSET(sNetlinkFd, aErrorFdSet)) + { + close(sNetlinkFd); + exit(OT_EXIT_FAILURE); + } + + if (FD_ISSET(sTunFd, aReadFdSet)) + { + processTransmit(sInstance); + } + + if (FD_ISSET(sNetlinkFd, aReadFdSet)) + { + processNetifEvent(sInstance); + } + +exit: + return; +} + +#endif // OPENTHREAD_ENABLE_PLATFORM_NETIF diff --git a/src/posix/platform/openthread-core-posix-config.h b/src/posix/platform/openthread-core-posix-config.h index 99adf6f3e..4c17b6f05 100644 --- a/src/posix/platform/openthread-core-posix-config.h +++ b/src/posix/platform/openthread-core-posix-config.h @@ -42,14 +42,4 @@ */ #define OPENTHREAD_CONFIG_PLATFORM_INFO "POSIX-APP" -/** - * @def OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE - * - * Define as 1 to enable PTY device support in POSIX app. - * - */ -#ifndef OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE -#define OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE 1 -#endif - #endif // OPENTHREAD_CORE_POSIX_CONFIG_H_ diff --git a/src/posix/platform/openthread-system.h b/src/posix/platform/openthread-system.h index 90351781d..26dbc107c 100644 --- a/src/posix/platform/openthread-system.h +++ b/src/posix/platform/openthread-system.h @@ -55,6 +55,14 @@ extern "C" { */ otInstance *otSysInit(int argc, char *argv[]); +/** + * This function performs platform network interface initialization. + * + * @param[in] aInstance A pointer to the OpenThread instance. + * + */ +void otSysInitNetif(otInstance *aInstance); + /** * This function performs all platform-specific deinitialization for OpenThread's drivers. * diff --git a/src/posix/platform/platform-posix.h b/src/posix/platform/platform-posix.h index 29b506bc6..81b63cf01 100644 --- a/src/posix/platform/platform-posix.h +++ b/src/posix/platform/platform-posix.h @@ -35,15 +35,20 @@ #ifndef PLATFORM_POSIX_H_ #define PLATFORM_POSIX_H_ -#include -#include - #include #include #include -#include "openthread-core-config.h" +/** + * @def OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE + * + * Define as 1 to enable PTY device support in POSIX app. + * + */ +#ifndef OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE +#define OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE 1 +#endif #ifdef __cplusplus extern "C" { @@ -231,6 +236,35 @@ void platformUartUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, fd_set *aE */ void platformUartProcess(const fd_set *aReadFdSet, const fd_set *aWriteFdSet, const fd_set *aErrorFdSet); +/** + * This function initializes platform netif. + * + * @param[in] aInstance A pointer to the OpenThread instance. + * + */ +void platformNetifInit(otInstance *aInstance); + +/** + * This function updates the file descriptor sets with file descriptors used by platform netif module. + * + * @param[inout] aReadFdSet A pointer to the read file descriptors. + * @param[inout] aWriteFdSet A pointer to the write file descriptors. + * @param[inout] aErrorFdSet A pointer to the error file descriptors. + * @param[inout] aMaxFd A pointer to the max file descriptor. + * + */ +void platformNetifUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, fd_set *aErrorFdSet, int *aMaxFd); + +/** + * This function performs platform netif processing. + * + * @param[in] aReadFdSet A pointer to the read file descriptors. + * @param[in] aWriteFdSet A pointer to the write file descriptors. + * @param[in] aErrorFdSet A pointer to the error file descriptors. + * + */ +void platformNetifProcess(const fd_set *aReadFdSet, const fd_set *aWriteFdSet, const fd_set *aErrorFdSet); + /** * This function restores the Uart. * @@ -337,8 +371,10 @@ void otSimRadioSpinelProcess(otInstance *aInstance, const struct Event *aEvent); /** * This function initializes platform UDP driver. * + * @param[in] aIfName The name of Thread's platform network interface. + * */ -void platformUdpInit(void); +void platformUdpInit(const char *aIfName); /** * This function performs platform UDP driver processing. diff --git a/src/posix/platform/system.c b/src/posix/platform/system.c index 49187c218..84bb47b7d 100644 --- a/src/posix/platform/system.c +++ b/src/posix/platform/system.c @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -144,8 +145,8 @@ otInstance *otSysInit(int aArgCount, char *aArgVector[]) platformAlarmInit(speedUpFactor); platformRadioInit(radioFile, radioConfig); platformRandomInit(); -#if OPENTHREAD_ENABLE_PLATFORM_UDP - platformUdpInit(); +#if OPENTHREAD_ENABLE_PLATFORM_UDP && OPENTHREAD_ENABLE_PLATFORM_NETIF == 0 + platformUdpInit(getenv("PLATFORM_NETIF")); #endif instance = otInstanceInitSingle(); @@ -164,6 +165,13 @@ otInstance *otSysInit(int aArgCount, char *aArgVector[]) return instance; } +#if OPENTHREAD_ENABLE_PLATFORM_NETIF +void otSysInitNetif(otInstance *aInstance) +{ + platformNetifInit(aInstance); +} +#endif + void otSysDeinit(void) { #if OPENTHREAD_POSIX_VIRTUAL_TIME @@ -223,6 +231,9 @@ void otSysProcessDrivers(otInstance *aInstance) #if OPENTHREAD_ENABLE_PLATFORM_UDP platformUdpUpdateFdSet(aInstance, &readFdSet, &maxFd); #endif +#if OPENTHREAD_ENABLE_PLATFORM_NETIF + platformNetifUpdateFdSet(&readFdSet, &writeFdSet, &errorFdSet, &maxFd); +#endif #if OPENTHREAD_POSIX_VIRTUAL_TIME otSimUpdateFdSet(&readFdSet, &writeFdSet, &errorFdSet, &maxFd, &timeout); #else @@ -284,6 +295,9 @@ void otSysProcessDrivers(otInstance *aInstance) #endif platformUartProcess(&readFdSet, &writeFdSet, &errorFdSet); platformAlarmProcess(aInstance); +#if OPENTHREAD_ENABLE_PLATFORM_NETIF + platformNetifProcess(&readFdSet, &writeFdSet, &errorFdSet); +#endif #if OPENTHREAD_ENABLE_PLATFORM_UDP platformUdpProcess(aInstance, &readFdSet); #endif diff --git a/src/posix/platform/udp.cpp b/src/posix/platform/udp.cpp index 17004f10f..a4639214a 100644 --- a/src/posix/platform/udp.cpp +++ b/src/posix/platform/udp.cpp @@ -379,10 +379,14 @@ exit: return; } -void platformUdpInit(void) +void platformUdpInit(const char *aIfName) { - const char *platformNetif = getenv("PLATFORM_NETIF"); - sPlatNetifIndex = if_nametoindex(platformNetif); + if (aIfName == NULL) + { + exit(OT_EXIT_INVALID_ARGUMENTS); + } + + sPlatNetifIndex = if_nametoindex(aIfName); if (sPlatNetifIndex == 0) {