mirror of
https://github.com/espressif/openthread.git
synced 2026-08-03 17:37:46 +00:00
[posix-app] integrate with platform network interface (#3180)
This commit is contained in:
+34
-20
@@ -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 <<EOF > $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() {
|
||||
|
||||
@@ -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
|
||||
#
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ libopenthread_posix_a_SOURCES = \
|
||||
hdlc_interface.cpp \
|
||||
logging.c \
|
||||
misc.c \
|
||||
netif.cpp \
|
||||
radio_spinel.cpp \
|
||||
random.c \
|
||||
settings.cpp \
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
|
||||
|
||||
@@ -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 <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <ifaddrs.h>
|
||||
#if __linux__
|
||||
#include <linux/if_tun.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#endif
|
||||
#include <net/if.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/ip6.h>
|
||||
#include <openthread/message.h>
|
||||
|
||||
#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<otInstance *>(aContext), *aAddress, aIsAdded);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateUnicast(static_cast<otInstance *>(aContext), *aAddress, aPrefixLength, aIsAdded);
|
||||
}
|
||||
}
|
||||
|
||||
static void processStateChange(otChangedFlags aFlags, void *aContext)
|
||||
{
|
||||
if (OT_CHANGED_THREAD_NETIF_STATE | aFlags)
|
||||
{
|
||||
UpdateLink(static_cast<otInstance *>(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<struct ifaddrmsg *>(NLMSG_DATA(aNetlinkMessage));
|
||||
size_t rtaLength;
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(ifaddr->ifa_index == static_cast<unsigned int>(sTunIndex) && ifaddr->ifa_family == AF_INET6);
|
||||
|
||||
rtaLength = IFA_PAYLOAD(aNetlinkMessage);
|
||||
|
||||
for (struct rtattr *rta = reinterpret_cast<struct rtattr *>(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<struct ifinfomsg *>(NLMSG_DATA(aNetlinkMessage));
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(ifinfo->ifi_index == static_cast<int>(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<struct nlmsghdr *>(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<struct sockaddr *>(&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<void *>(&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
|
||||
@@ -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_
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -35,15 +35,20 @@
|
||||
#ifndef PLATFORM_POSIX_H_
|
||||
#define PLATFORM_POSIX_H_
|
||||
|
||||
#include <openthread-core-config.h>
|
||||
#include <openthread/config.h>
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <openthread/instance.h>
|
||||
|
||||
#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.
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openthread-core-config.h>
|
||||
#include <openthread/tasklet.h>
|
||||
#include <openthread/platform/alarm-milli.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user