mirror of
https://github.com/espressif/openthread.git
synced 2026-11-10 00:11:20 +00:00
[posix] let -I choose the utun number on macOS (#13742)
A macOS utun has no free name; the kernel assigns utunN with the lowest free N, so the Thread interface's name changed between restarts and nothing could refer to it in advance: not ot-ctl, not a firewall rule, not a service file. The requested interface name was ignored. Honour a requested name utunN: ask the kernel for that unit (sc_unit is the number plus one) and die with EBUSY if it exists. The digits must be the whole rest of the name, written as the kernel names the interface (no leading zero), and fit, or the daemon dies with OT_EXIT_INVALID_ARGUMENTS rather than silently getting another utun. The default name, which main.c passes when -I is not given, and an empty name keep the kernel's choice as before; any other name cannot be honoured on macOS and ends the daemon with OT_EXIT_INVALID_ARGUMENTS too. check-posix-pty requests a utun name on macOS and asserts, on both platforms, that the daemon created the interface it was asked for; the CLI leg on macOS also asks for utunabc and expects exit code 2.
This commit is contained in:
+13
-3
@@ -251,8 +251,12 @@ do_check()
|
||||
timeout_run 10 test -c "${SOCAT_PTY}"
|
||||
echo 'SOCAT_PTY' "${SOCAT_PTY}"
|
||||
|
||||
# Cover setting a valid network interface name.
|
||||
VALID_NETIF_NAME="wan$(date +%H%M%S)"
|
||||
# Cover setting a valid network interface name. On macOS only a utun number can be chosen.
|
||||
if [[ ${OSTYPE} == darwin* ]]; then
|
||||
VALID_NETIF_NAME="utun$((200 + 10#$(date +%S)))"
|
||||
else
|
||||
VALID_NETIF_NAME="wan$(date +%H%M%S)"
|
||||
fi
|
||||
readonly VALID_NETIF_NAME
|
||||
|
||||
RADIO_URL="spinel+hdlc+uart://${SOCAT_PTY}?region=US&max-power-table-mbm=1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600"
|
||||
@@ -263,8 +267,8 @@ do_check()
|
||||
sudo -E "$PWD/build/posix/src/posix/ot-daemon" -d5 -v -I "${VALID_NETIF_NAME}" "${RADIO_URL}" >"${OT_DAEMON_OUTPUT}" 2>&1 &
|
||||
OT_DAEMON_JOB=$!
|
||||
sleep 3
|
||||
# macOS cannot explicitly set network interface name
|
||||
NETIF_NAME=$(grep -o 'Thread interface: .\+' "${OT_DAEMON_OUTPUT}" | cut -d: -f2 | tr -d ' \r\n')
|
||||
[[ ${NETIF_NAME} == "${VALID_NETIF_NAME}" ]] || die "ot-daemon created ${NETIF_NAME}, not the requested ${VALID_NETIF_NAME}"
|
||||
OT_CTL_PATH="$PWD/build/posix/src/posix/ot-ctl"
|
||||
if [[ ${OT_DAEMON_ALLOW_ALL} == 1 ]] || [[ -n ${OT_ISOLATED_REEXEC:-} ]]; then
|
||||
OT_CTL=("${OT_CTL_PATH}")
|
||||
@@ -316,6 +320,12 @@ do_check()
|
||||
readonly INVALID_NETIF_NAME
|
||||
sudo "${OT_CLI}" -I "${INVALID_NETIF_NAME}" -n "${RADIO_URL}" || test $? = 2
|
||||
|
||||
if [[ ${OSTYPE} == darwin* ]]; then
|
||||
# A utun name needs a number. The check runs when the interface is created, after a dry run ends,
|
||||
# so no -n here; the CLI exits with 2 (OT_EXIT_INVALID_ARGUMENTS) before it would block.
|
||||
sudo "${OT_CLI}" -I utunabc "${RADIO_URL}" || test $? = 2
|
||||
fi
|
||||
|
||||
OT_CLI_CMD="$PWD/build/posix/src/posix/ot-cli ${RADIO_URL}"
|
||||
fi
|
||||
|
||||
|
||||
@@ -3389,10 +3389,41 @@ static void platformConfigureTunDevice(otPlatformConfig *aPlatformConfig)
|
||||
#if defined(__APPLE__) && (OPENTHREAD_POSIX_CONFIG_MACOS_TUN_OPTION == OT_POSIX_CONFIG_MACOS_UTUN)
|
||||
static void platformConfigureTunDevice(otPlatformConfig *aPlatformConfig)
|
||||
{
|
||||
(void)aPlatformConfig;
|
||||
int err = 0;
|
||||
constexpr char kUtunPrefix[] = "utun";
|
||||
int err = 0;
|
||||
struct sockaddr_ctl addr;
|
||||
struct ctl_info info;
|
||||
uint32_t unit = 0; // 0: the kernel picks the lowest free utun
|
||||
const char *name = aPlatformConfig->mInterfaceName;
|
||||
|
||||
// A requested name utunN asks for that unit, which gives the interface a stable name across restarts; the
|
||||
// digits must be the whole rest of the name, written as the kernel names the interface (no leading zero).
|
||||
// The default name, which main.c passes when -I is not given, leaves the choice to the kernel, the only way
|
||||
// to a free utun; any other name cannot be honoured on macOS and is refused.
|
||||
if ((name != nullptr) && (strncmp(name, kUtunPrefix, sizeof(kUtunPrefix) - 1) == 0))
|
||||
{
|
||||
const char *digits = name + sizeof(kUtunPrefix) - 1;
|
||||
char *end;
|
||||
unsigned long number;
|
||||
|
||||
errno = 0;
|
||||
number = strtoul(digits, &end, 10);
|
||||
|
||||
if ((*digits < '0') || (*digits > '9') || ((*digits == '0') && (digits[1] != '\0')) || (*end != '\0') ||
|
||||
(errno != 0) || (number >= UINT32_MAX) || (strlen(name) >= IFNAMSIZ))
|
||||
{
|
||||
LogCrit("Invalid utun interface name: %s", name);
|
||||
DieNow(OT_EXIT_INVALID_ARGUMENTS);
|
||||
}
|
||||
|
||||
unit = static_cast<uint32_t>(number) + 1; // sc_unit is the utun number plus one
|
||||
}
|
||||
else if ((name != nullptr) && (name[0] != '\0') &&
|
||||
(strcmp(name, OPENTHREAD_POSIX_CONFIG_THREAD_NETIF_DEFAULT_NAME) != 0))
|
||||
{
|
||||
LogCrit("Interface name %s cannot be chosen on macOS: use utunN for a given utun, or none", name);
|
||||
DieNow(OT_EXIT_INVALID_ARGUMENTS);
|
||||
}
|
||||
|
||||
sTunFd = ot::Posix::SocketWithCloseExec(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL, ot::Posix::kSocketNonBlock);
|
||||
VerifyOrDie(sTunFd >= 0, OT_EXIT_ERROR_ERRNO);
|
||||
@@ -3407,9 +3438,17 @@ static void platformConfigureTunDevice(otPlatformConfig *aPlatformConfig)
|
||||
addr.sc_family = AF_SYSTEM;
|
||||
addr.ss_sysaddr = AF_SYS_CONTROL;
|
||||
|
||||
addr.sc_unit = 0;
|
||||
err = connect(sTunFd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
VerifyOrDie(err == 0, OT_EXIT_ERROR_ERRNO);
|
||||
addr.sc_unit = unit;
|
||||
err = connect(sTunFd, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr));
|
||||
if (err != 0)
|
||||
{
|
||||
int error = errno; // the log call may change it, and the exit code reports it
|
||||
|
||||
// EBUSY: the requested utun exists already.
|
||||
LogCrit("Failed to create %s: %s", (unit != 0) ? name : "a utun", strerror(error));
|
||||
errno = error;
|
||||
DieNow(OT_EXIT_ERROR_ERRNO);
|
||||
}
|
||||
|
||||
socklen_t devNameLen;
|
||||
devNameLen = (socklen_t)sizeof(gNetifName);
|
||||
|
||||
Reference in New Issue
Block a user