blob: 27bcc6efc3bb94db905aeb1d638e169521130080 [file] [log] [blame]
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/* @file
* @brief wpa_cli implementation for Zephyr OS
*/
#include <stdlib.h>
#include <sys/types.h>
#include <zephyr/kernel.h>
#include <zephyr/shell/shell.h>
#include <zephyr/net/net_if.h>
#include <zephyr/net/socket.h>
#include <zephyr/init.h>
#include "supp_main.h"
#include "common.h"
#include "wpa_supplicant_i.h"
#include "wpa_cli_zephyr.h"
#ifdef CONFIG_WIFI_NM_HOSTAPD_AP
#include "hostapd.h"
#include "hapd_main.h"
#include "hostapd_cli_zephyr.h"
#endif
static int cmd_wpa_cli(const struct shell *sh, size_t argc, const char *argv[])
{
struct net_if *iface = NULL;
char if_name[CONFIG_NET_INTERFACE_NAME_LEN + 1];
struct wpa_supplicant *wpa_s = NULL;
size_t arg_offset = 1;
int idx = -1;
bool iface_found = false;
if (argc > 2 &&
((strcmp(argv[1], "-i") == 0) ||
(strncmp(argv[1], "-i", 2) == 0 && argv[1][2] != '\0'))) {
/* Handle both "-i 2" and "-i2" */
if (strcmp(argv[1], "-i") == 0) {
idx = strtol(argv[2], NULL, 10);
arg_offset = 3;
} else {
idx = strtol(&argv[1][2], NULL, 10);
arg_offset = 2;
}
iface = net_if_get_by_index(idx);
if (!iface) {
shell_error(sh, "Interface index %d not found", idx);
return -ENODEV;
}
net_if_get_name(iface, if_name, sizeof(if_name));
if_name[sizeof(if_name) - 1] = '\0';
iface_found = true;
} else {
/* Default to first Wi-Fi interface */
iface = net_if_get_first_wifi();
if (!iface) {
shell_error(sh, "No Wi-Fi interface found");
return -ENOENT;
}
net_if_get_name(iface, if_name, sizeof(if_name));
if_name[sizeof(if_name) - 1] = '\0';
arg_offset = 1;
iface_found = true;
}
if (!iface_found) {
shell_error(sh, "No interface found");
return -ENODEV;
}
wpa_s = zephyr_get_handle_by_ifname(if_name);
if (!wpa_s) {
shell_error(sh, "No wpa_supplicant context for interface '%s'", if_name);
return -ENODEV;
}
if (argc <= arg_offset) {
shell_error(sh, "Missing argument");
return -EINVAL;
}
argv[argc] = "interactive";
argc++;
/* Remove wpa_cli from the argument list */
return zephyr_wpa_ctrl_zephyr_cmd(wpa_s->ctrl_conn, argc - arg_offset, &argv[arg_offset]);
}
#ifdef CONFIG_WIFI_NM_HOSTAPD_AP
static int cmd_hostapd_cli(const struct shell *sh, size_t argc, const char *argv[])
{
struct net_if *iface = NULL;
size_t arg_offset = 1;
struct hostapd_iface *hapd_iface;
int idx = -1;
bool iface_found = false;
char if_name[CONFIG_NET_INTERFACE_NAME_LEN + 1];
int ret;
if (argc > 2 &&
((strcmp(argv[1], "-i") == 0) ||
(strncmp(argv[1], "-i", 2) == 0 && argv[1][2] != '\0'))) {
/* Handle both "-i 2" and "-i2" */
if (strcmp(argv[1], "-i") == 0) {
idx = strtol(argv[2], NULL, 10);
arg_offset = 3;
} else {
idx = strtol(&argv[1][2], NULL, 10);
arg_offset = 2;
}
iface = net_if_get_by_index(idx);
if (!iface) {
shell_error(sh, "Interface index %d not found", idx);
return -ENODEV;
}
iface_found = true;
} else {
iface = net_if_get_first_wifi();
if (!iface) {
shell_error(sh, "No Wi-Fi interface found");
return -ENOENT;
}
arg_offset = 1;
iface_found = true;
}
if (!iface_found) {
shell_error(sh, "No interface found");
return -ENODEV;
}
ret = net_if_get_name(iface, if_name, sizeof(if_name));
if (!ret) {
shell_error(sh, "Cannot get interface name (%d)", ret);
return -ENODEV;
}
hapd_iface = zephyr_get_hapd_handle_by_ifname(if_name);
if (!hapd_iface) {
shell_error(sh, "No hostapd context for interface '%s'", if_name);
return -ENODEV;
}
if (argc <= arg_offset) {
shell_error(sh, "Missing argument");
return -EINVAL;
}
argv[argc] = "interactive";
argc++;
/* Remove hostapd_cli from the argument list */
return zephyr_hostapd_ctrl_zephyr_cmd(hapd_iface->ctrl_conn, argc - arg_offset,
&argv[arg_offset]);
}
#endif
/* Persisting with "wpa_cli" naming for compatibility with Wi-Fi
* certification applications and scripts.
*/
SHELL_CMD_REGISTER(wpa_cli,
NULL,
"wpa_cli [-i idx] <command> (only for internal use)",
cmd_wpa_cli);
#ifdef CONFIG_WIFI_NM_HOSTAPD_AP
SHELL_CMD_REGISTER(hostapd_cli, NULL,
"hostapd_cli [-i idx] <command> (only for internal use)",
cmd_hostapd_cli);
#endif