mirror of
https://github.com/espressif/openthread.git
synced 2026-08-18 08:29:52 +00:00
[posix] support interface name in ot-ctl (#6552)
This commit adds the Thread interface name to unix socket of OpenThread daemon, so that ot-ctl can specify which daemon to connect to.
This commit is contained in:
+10
-7
@@ -117,18 +117,21 @@ do_check()
|
||||
RADIO_URL="spinel+hdlc+uart://${CORE_PTY}?region=US&max-power-table=11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26"
|
||||
|
||||
if [[ ${OT_DAEMON} == 'on' ]]; then
|
||||
sudo "$PWD/build/posix/src/posix/ot-daemon" -d7 -v -I "${VALID_NETIF_NAME}" "${RADIO_URL}" &
|
||||
sudo "$PWD/build/posix/src/posix/ot-daemon" -d7 -v -I "${VALID_NETIF_NAME}" "${RADIO_URL}" 2>&1 | tee "${OT_OUTPUT}" &
|
||||
sleep 3
|
||||
OT_CLI_CMD="$PWD/build/posix/src/posix/ot-ctl"
|
||||
sudo "${OT_CLI_CMD}" panid 0xface | grep 'Done' || die 'failed to set panid with ot-ctl'
|
||||
# macOS cannot explicitly set network interface name
|
||||
NETIF_NAME=$(grep -o 'Thread interface: .\+' "${OT_OUTPUT}" | cut -d: -f2 | tr -d ' \r\n')
|
||||
OT_CTL="$PWD/build/posix/src/posix/ot-ctl"
|
||||
sudo "${OT_CTL}" -I "${NETIF_NAME}" panid 0xface | grep 'Done' || die 'failed to set panid with ot-ctl'
|
||||
|
||||
# verify this reset and factoryreset end immediately
|
||||
sudo "${OT_CLI_CMD}" reset
|
||||
sudo "${OT_CTL}" -I "${NETIF_NAME}" reset
|
||||
# sleep a while for daemon ready
|
||||
sleep 2
|
||||
sudo "${OT_CLI_CMD}" factoryreset
|
||||
sudo "${OT_CTL}" -I "${NETIF_NAME}" factoryreset
|
||||
# sleep a while for daemon ready
|
||||
sleep 2
|
||||
OT_CLI_CMD="${OT_CTL} -I ${NETIF_NAME}"
|
||||
else
|
||||
OT_CLI="$PWD/build/posix/src/posix/ot-cli"
|
||||
sudo "${OT_CLI}" -I "${VALID_NETIF_NAME}" -n "${RADIO_URL}"
|
||||
@@ -201,9 +204,9 @@ EOF
|
||||
if [[ ${OT_DAEMON} == 'on' ]]; then
|
||||
sudo killall -9 expect || true
|
||||
sudo killall -9 ot-ctl || true
|
||||
NETIF_INDEX=$(ip link show "${VALID_NETIF_NAME}" | cut -f 1 -d ":" | head -n 1)
|
||||
NETIF_INDEX=$(ip link show "${NETIF_NAME}" | cut -f 1 -d ":" | head -n 1)
|
||||
sudo PATH="$(dirname "${OT_CLI_CMD}"):${PATH}" \
|
||||
python3 "$PWD/tests/scripts/misc/test_multicast_join.py" "${NETIF_INDEX}" \
|
||||
python3 "$PWD/tests/scripts/misc/test_multicast_join.py" "${NETIF_INDEX}" "${NETIF_NAME}" \
|
||||
|| die 'multicast group join failed'
|
||||
fi
|
||||
|
||||
|
||||
+81
-12
@@ -43,6 +43,7 @@
|
||||
#define OPENTHREAD_USE_READLINE (HAVE_LIBEDIT || HAVE_LIBREADLINE)
|
||||
|
||||
#include <assert.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -62,6 +63,13 @@
|
||||
|
||||
#include "platform-posix.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct Config
|
||||
{
|
||||
const char *mNetifName;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kLineBufferSize = OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH,
|
||||
@@ -71,10 +79,10 @@ static_assert(kLineBufferSize >= sizeof("> "), "kLineBufferSize is too small");
|
||||
static_assert(kLineBufferSize >= sizeof("Done\r\n"), "kLineBufferSize is too small");
|
||||
static_assert(kLineBufferSize >= sizeof("Error "), "kLineBufferSize is too small");
|
||||
|
||||
static int sSessionFd = -1;
|
||||
int sSessionFd = -1;
|
||||
|
||||
#if OPENTHREAD_USE_READLINE
|
||||
static void InputCallback(char *aLine)
|
||||
void InputCallback(char *aLine)
|
||||
{
|
||||
if (aLine != nullptr)
|
||||
{
|
||||
@@ -89,7 +97,7 @@ static void InputCallback(char *aLine)
|
||||
}
|
||||
#endif // OPENTHREAD_USE_READLINE
|
||||
|
||||
static bool DoWrite(int aFile, const void *aBuffer, size_t aSize)
|
||||
bool DoWrite(int aFile, const void *aBuffer, size_t aSize)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
@@ -111,7 +119,7 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ConnectSession(void)
|
||||
int ConnectSession(const Config &aConfig)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -128,7 +136,12 @@ static int ConnectSession(void)
|
||||
|
||||
memset(&sockname, 0, sizeof(struct sockaddr_un));
|
||||
sockname.sun_family = AF_UNIX;
|
||||
strncpy(sockname.sun_path, OPENTHREAD_POSIX_DAEMON_SOCKET_NAME, sizeof(sockname.sun_path) - 1);
|
||||
ret = snprintf(sockname.sun_path, sizeof(sockname.sun_path), OPENTHREAD_POSIX_DAEMON_SOCKET_NAME,
|
||||
aConfig.mNetifName);
|
||||
VerifyOrExit(ret >= 0 && static_cast<size_t>(ret) < sizeof(sockname.sun_path), {
|
||||
errno = EINVAL;
|
||||
ret = -1;
|
||||
});
|
||||
|
||||
ret = connect(sSessionFd, reinterpret_cast<const struct sockaddr *>(&sockname), sizeof(struct sockaddr_un));
|
||||
}
|
||||
@@ -137,7 +150,7 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool ReconnectSession(void)
|
||||
bool ReconnectSession(Config &aConfig)
|
||||
{
|
||||
bool ok = false;
|
||||
uint32_t delay = 0; // 100ms
|
||||
@@ -149,7 +162,7 @@ static bool ReconnectSession(void)
|
||||
usleep(delay);
|
||||
delay = delay > 0 ? delay * 2 : 100000;
|
||||
|
||||
rval = ConnectSession();
|
||||
rval = ConnectSession(aConfig);
|
||||
|
||||
VerifyOrExit(rval == -1, ok = true);
|
||||
|
||||
@@ -161,11 +174,64 @@ exit:
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool IsSeparator(char aChar)
|
||||
enum
|
||||
{
|
||||
kOptInterfaceName = 'I',
|
||||
kOptHelp = 'h',
|
||||
};
|
||||
|
||||
const struct option kOptions[] = {
|
||||
{"interface-name", required_argument, NULL, kOptInterfaceName},
|
||||
{"help", required_argument, NULL, kOptHelp},
|
||||
};
|
||||
|
||||
void PrintUsage(const char *aProgramName, FILE *aStream, int aExitCode)
|
||||
{
|
||||
fprintf(aStream,
|
||||
"Syntax:\n"
|
||||
" %s [Options] [--] ...\n"
|
||||
"Options:\n"
|
||||
" -h --help Display this usage information.\n"
|
||||
" -I --interface-name name Thread network interface name.\n",
|
||||
aProgramName);
|
||||
exit(aExitCode);
|
||||
}
|
||||
|
||||
bool IsSeparator(char aChar)
|
||||
{
|
||||
return (aChar == ' ') || (aChar == '\t') || (aChar == '\r') || (aChar == '\n');
|
||||
}
|
||||
|
||||
Config ParseArg(int &aArgCount, char **&aArgVector)
|
||||
{
|
||||
Config config = {"wpan0"};
|
||||
|
||||
optind = 1;
|
||||
|
||||
for (int index, option; (option = getopt_long(aArgCount, aArgVector, "I:h", kOptions, &index)) != -1;)
|
||||
{
|
||||
switch (option)
|
||||
{
|
||||
case kOptInterfaceName:
|
||||
config.mNetifName = optarg;
|
||||
break;
|
||||
case kOptHelp:
|
||||
PrintUsage(aArgVector[0], stdout, OT_EXIT_SUCCESS);
|
||||
break;
|
||||
default:
|
||||
PrintUsage(aArgVector[0], stderr, OT_EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
aArgCount -= optind;
|
||||
aArgVector += optind;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
bool isInteractive = true;
|
||||
@@ -174,15 +240,18 @@ int main(int argc, char *argv[])
|
||||
char lineBuffer[kLineBufferSize];
|
||||
size_t lineBufferWritePos = 0;
|
||||
int ret;
|
||||
Config config;
|
||||
|
||||
VerifyOrExit(ConnectSession() != -1, perror("connect session failed"); ret = OT_EXIT_FAILURE);
|
||||
config = ParseArg(argc, argv);
|
||||
|
||||
if (argc > 1)
|
||||
VerifyOrExit(ConnectSession(config) != -1, perror("connect session failed"); ret = OT_EXIT_FAILURE);
|
||||
|
||||
if (argc > 0)
|
||||
{
|
||||
char buffer[kLineBufferSize];
|
||||
size_t count = 0;
|
||||
|
||||
for (int i = 1; i < argc; i++)
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
for (const char *c = argv[i]; *c; ++c)
|
||||
{
|
||||
@@ -259,7 +328,7 @@ int main(int argc, char *argv[])
|
||||
if (rval == 0)
|
||||
{
|
||||
// daemon closed sSessionFd
|
||||
if (isInteractive && ReconnectSession())
|
||||
if (isInteractive && ReconnectSession(config))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -296,6 +296,7 @@ static otInstance *InitInstance(PosixConfig *aConfig)
|
||||
IgnoreError(otLoggingSetLevel(aConfig->mLogLevel));
|
||||
|
||||
instance = otSysInit(&aConfig->mPlatformConfig);
|
||||
syslog(LOG_INFO, "Thread interface: %s", otSysGetThreadNetifName());
|
||||
|
||||
atexit(otSysDeinit);
|
||||
|
||||
|
||||
@@ -148,7 +148,18 @@ void platformDaemonEnable(otInstance *aInstance)
|
||||
DieNow(OT_EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sDaemonLock = open(OPENTHREAD_POSIX_DAEMON_SOCKET_LOCK, O_CREAT | O_RDONLY | O_CLOEXEC, 0600);
|
||||
{
|
||||
static_assert(sizeof(OPENTHREAD_POSIX_DAEMON_SOCKET_LOCK) == sizeof(OPENTHREAD_POSIX_DAEMON_SOCKET_NAME),
|
||||
"sock and lock file name pattern should have the same length!");
|
||||
char lockfile[sizeof(sockname.sun_path)];
|
||||
|
||||
ret = snprintf(lockfile, sizeof(lockfile), OPENTHREAD_POSIX_DAEMON_SOCKET_LOCK, gNetifName);
|
||||
if (ret < 0 && static_cast<size_t>(ret) >= sizeof(lockfile))
|
||||
{
|
||||
DieNowWithMessage("lockfile", OT_EXIT_INVALID_ARGUMENTS);
|
||||
}
|
||||
sDaemonLock = open(lockfile, O_CREAT | O_RDONLY | O_CLOEXEC, 0600);
|
||||
}
|
||||
|
||||
if (sDaemonLock == -1)
|
||||
{
|
||||
@@ -162,10 +173,13 @@ void platformDaemonEnable(otInstance *aInstance)
|
||||
|
||||
memset(&sockname, 0, sizeof(struct sockaddr_un));
|
||||
|
||||
(void)unlink(OPENTHREAD_POSIX_DAEMON_SOCKET_NAME);
|
||||
|
||||
sockname.sun_family = AF_UNIX;
|
||||
strncpy(sockname.sun_path, OPENTHREAD_POSIX_DAEMON_SOCKET_NAME, sizeof(sockname.sun_path) - 1);
|
||||
ret = snprintf(sockname.sun_path, sizeof(sockname.sun_path), OPENTHREAD_POSIX_DAEMON_SOCKET_NAME, gNetifName);
|
||||
if (ret < 0 && static_cast<size_t>(ret) >= sizeof(sockname.sun_path))
|
||||
{
|
||||
DieNowWithMessage("sockfile", OT_EXIT_INVALID_ARGUMENTS);
|
||||
}
|
||||
(void)unlink(sockname.sun_path);
|
||||
|
||||
ret = bind(sListenSocket, (const struct sockaddr *)&sockname, sizeof(struct sockaddr_un));
|
||||
|
||||
|
||||
@@ -83,7 +83,11 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME
|
||||
#define OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME "/tmp/openthread"
|
||||
#ifdef __linux__
|
||||
#define OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME "/run/openthread-%s"
|
||||
#else
|
||||
#define OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME "/tmp/openthread-%s"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
||||
@@ -162,6 +162,8 @@ otInstance *otSysInit(otPlatformConfig *aPlatformConfig)
|
||||
platformNetifInit(instance, aPlatformConfig->mInterfaceName);
|
||||
#elif OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
|
||||
platformUdpInit(aPlatformConfig->mInterfaceName);
|
||||
#else
|
||||
gNetifName[0] = '\0';
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE || OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
||||
|
||||
@@ -36,21 +36,22 @@ import time
|
||||
from ipaddress import ip_address
|
||||
|
||||
|
||||
def get_maddrs():
|
||||
lines = subprocess.run(['ot-ctl', 'ipmaddr'], stdout=subprocess.PIPE).stdout.decode().split()
|
||||
def get_maddrs(if_name):
|
||||
lines = subprocess.run(['ot-ctl', '-I', if_name, 'ipmaddr'], stdout=subprocess.PIPE).stdout.decode().split()
|
||||
return [ip_address(l) for l in lines if l.startswith('ff')]
|
||||
|
||||
|
||||
def main():
|
||||
group = 'ff02::158'
|
||||
if_index = int(sys.argv[1])
|
||||
if_name = sys.argv[2]
|
||||
|
||||
with socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) as s:
|
||||
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, if_index)
|
||||
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP,
|
||||
struct.pack('16si', socket.inet_pton(socket.AF_INET6, group), if_index))
|
||||
time.sleep(2)
|
||||
maddrs = get_maddrs()
|
||||
maddrs = get_maddrs(if_name)
|
||||
print(maddrs)
|
||||
if not any(addr == ip_address(group) for addr in maddrs):
|
||||
return -1
|
||||
@@ -59,7 +60,7 @@ def main():
|
||||
struct.pack('16si', socket.inet_pton(socket.AF_INET6, group), if_index))
|
||||
|
||||
time.sleep(2)
|
||||
maddrs = get_maddrs()
|
||||
maddrs = get_maddrs(if_name)
|
||||
print(maddrs)
|
||||
if any(addr == ip_address(group) for addr in maddrs):
|
||||
return -1
|
||||
|
||||
Reference in New Issue
Block a user