Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4311 lines
118 KiB

/*
* Copyright (c) 2018 Intel Corporation
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
/** @file
* @brief WiFi shell module
*/
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF);
#include <zephyr/kernel.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <zephyr/shell/shell.h>
#include <zephyr/sys/printk.h>
#include <zephyr/init.h>
#include <zephyr/net/net_if.h>
#include <zephyr/net/net_event.h>
#include <zephyr/net/wifi_mgmt.h>
#include <zephyr/net/wifi_utils.h>
#include <zephyr/posix/unistd.h>
#include <zephyr/sys/slist.h>
#include "net_shell_private.h"
#include <math.h>
#if defined CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE || \
defined CONFIG_WIFI_NM_HOSTAPD_CRYPTO_ENTERPRISE
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
#include <zephyr/net/tls_credentials.h>
enum wifi_enterprise_cert_sec_tags {
WIFI_CERT_CA_SEC_TAG = 0x1020001,
WIFI_CERT_CLIENT_KEY_SEC_TAG,
WIFI_CERT_SERVER_KEY_SEC_TAG,
WIFI_CERT_CLIENT_SEC_TAG,
WIFI_CERT_SERVER_SEC_TAG,
/* Phase 2 */
WIFI_CERT_CA_P2_SEC_TAG,
WIFI_CERT_CLIENT_KEY_P2_SEC_TAG,
WIFI_CERT_CLIENT_P2_SEC_TAG,
};
struct wifi_cert_data {
enum tls_credential_type type;
uint32_t sec_tag;
uint8_t **data;
size_t *len;
};
#else
static const char ca_cert_test[] = {
#include <wifi_enterprise_test_certs/ca.pem.inc>
'\0'
};
static const char client_cert_test[] = {
#include <wifi_enterprise_test_certs/client.pem.inc>
'\0'
};
static const char client_key_test[] = {
#include <wifi_enterprise_test_certs/client-key.pem.inc>
'\0'
};
static const char ca_cert2_test[] = {
#include <wifi_enterprise_test_certs/ca2.pem.inc>
'\0'};
static const char client_cert2_test[] = {
#include <wifi_enterprise_test_certs/client2.pem.inc>
'\0'};
static const char client_key2_test[] = {
#include <wifi_enterprise_test_certs/client-key2.pem.inc>
'\0'};
static const char server_cert_test[] = {
#include <wifi_enterprise_test_certs/server.pem.inc>
'\0'
};
static const char server_key_test[] = {
#include <wifi_enterprise_test_certs/server-key.pem.inc>
'\0'
};
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE */
#define WIFI_SHELL_MODULE "wifi"
#define WIFI_SHELL_MGMT_EVENTS ( \
NET_EVENT_WIFI_CONNECT_RESULT |\
NET_EVENT_WIFI_DISCONNECT_RESULT |\
NET_EVENT_WIFI_TWT |\
NET_EVENT_WIFI_AP_ENABLE_RESULT |\
NET_EVENT_WIFI_AP_DISABLE_RESULT |\
NET_EVENT_WIFI_AP_STA_CONNECTED |\
NET_EVENT_WIFI_AP_STA_DISCONNECTED)
#ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS_ONLY
#define WIFI_SHELL_SCAN_EVENTS ( \
NET_EVENT_WIFI_SCAN_DONE |\
NET_EVENT_WIFI_RAW_SCAN_RESULT)
#else
#define WIFI_SHELL_SCAN_EVENTS ( \
NET_EVENT_WIFI_SCAN_RESULT |\
NET_EVENT_WIFI_SCAN_DONE |\
NET_EVENT_WIFI_RAW_SCAN_RESULT)
#endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS_ONLY */
#define MAX_BANDS_STR_LEN 64
static struct {
const struct shell *sh;
uint32_t scan_result;
union {
struct {
uint8_t connecting: 1;
uint8_t disconnecting: 1;
uint8_t _unused: 6;
};
uint8_t all;
};
#if defined CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE || \
defined CONFIG_WIFI_NM_HOSTAPD_CRYPTO_ENTERPRISE
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
struct wifi_enterprise_creds_params enterprise_creds_params;
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE */
} context;
static struct net_mgmt_event_callback wifi_shell_mgmt_cb;
static struct net_mgmt_event_callback wifi_shell_scan_cb;
static struct wifi_reg_chan_info chan_info[MAX_REG_CHAN_NUM];
static K_MUTEX_DEFINE(wifi_ap_sta_list_lock);
struct wifi_ap_sta_node {
bool valid;
struct wifi_ap_sta_info sta_info;
};
static struct wifi_ap_sta_node sta_list[CONFIG_WIFI_SHELL_MAX_AP_STA];
enum iface_type {
IFACE_TYPE_STA,
IFACE_TYPE_SAP,
};
static struct net_if *get_iface(enum iface_type type, int argc, char *argv[])
{
struct net_if *iface = NULL;
int iface_index = -1;
/* Parse arguments manually to find -i or --iface,
* it's intentional not to use getopt() here to avoid
* permuting the arguments.
*/
for (int i = 1; i < argc; i++) {
if ((strcmp(argv[i], "-i") == 0 ||
strcmp(argv[i], "--iface") == 0) &&
(i + 1 < argc)) {
int err = 0;
iface_index = shell_strtol(argv[i + 1], 10, &err);
if (err || iface_index < 0) {
LOG_ERR("Invalid interface index: %s", argv[i + 1]);
return NULL;
}
break;
}
}
if (iface_index != -1) {
iface = net_if_get_by_index(iface_index);
if (iface == NULL) {
LOG_WRN("Invalid interface index: %d, using default", iface_index);
}
}
if (iface == NULL) {
/* Fallback to STA or SAP if user didn't specify a valid interface */
if (type == IFACE_TYPE_STA) {
iface = net_if_get_wifi_sta();
} else if (type == IFACE_TYPE_SAP) {
iface = net_if_get_wifi_sap();
}
if (iface == NULL) {
LOG_ERR("No default interface found for type: %s",
type == IFACE_TYPE_STA ? "STA" : "SAP");
return NULL;
}
}
return iface;
}
#if defined CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE || \
defined CONFIG_WIFI_NM_HOSTAPD_CRYPTO_ENTERPRISE
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
static int process_certificates(struct wifi_cert_data *certs, size_t cert_count)
{
for (size_t i = 0; i < cert_count; i++) {
int err;
size_t len = 0;
uint8_t *cert_tmp;
err = tls_credential_get(certs[i].sec_tag, certs[i].type, NULL, &len);
if (err != -EFBIG) {
LOG_ERR("Failed to get credential tag: %d length, err: %d",
certs[i].sec_tag, err);
return err;
}
cert_tmp = k_malloc(len);
if (!cert_tmp) {
LOG_ERR("Failed to allocate memory for credential tag: %d",
certs[i].sec_tag);
return -ENOMEM;
}
err = tls_credential_get(certs[i].sec_tag, certs[i].type, cert_tmp, &len);
if (err) {
LOG_ERR("Failed to get credential tag: %d", certs[i].sec_tag);
k_free(cert_tmp);
return err;
}
*certs[i].data = cert_tmp;
*certs[i].len = len;
}
return 0;
}
static void set_enterprise_creds_params(struct wifi_enterprise_creds_params *params,
bool is_ap)
{
struct wifi_cert_data certs_common[] = {
{
.type = TLS_CREDENTIAL_CA_CERTIFICATE,
.sec_tag = WIFI_CERT_CA_SEC_TAG,
.data = &params->ca_cert,
.len = &params->ca_cert_len,
},
};
struct wifi_cert_data certs_sta[] = {
{
.type = TLS_CREDENTIAL_PRIVATE_KEY,
.sec_tag = WIFI_CERT_CLIENT_KEY_SEC_TAG,
.data = &params->client_key,
.len = &params->client_key_len,
},
{
.type = TLS_CREDENTIAL_PUBLIC_CERTIFICATE,
.sec_tag = WIFI_CERT_CLIENT_SEC_TAG,
.data = &params->client_cert,
.len = &params->client_cert_len,
},
{
.type = TLS_CREDENTIAL_CA_CERTIFICATE,
.sec_tag = WIFI_CERT_CA_P2_SEC_TAG,
.data = &params->ca_cert2,
.len = &params->ca_cert2_len,
},
{
.type = TLS_CREDENTIAL_PRIVATE_KEY,
.sec_tag = WIFI_CERT_CLIENT_KEY_P2_SEC_TAG,
.data = &params->client_key2,
.len = &params->client_key2_len,
},
{
.type = TLS_CREDENTIAL_PUBLIC_CERTIFICATE,
.sec_tag = WIFI_CERT_CLIENT_P2_SEC_TAG,
.data = &params->client_cert2,
.len = &params->client_cert2_len,
},
};
struct wifi_cert_data certs_ap[] = {
{
.type = TLS_CREDENTIAL_PUBLIC_CERTIFICATE,
.sec_tag = WIFI_CERT_SERVER_SEC_TAG,
.data = &params->server_cert,
.len = &params->server_cert_len,
},
{
.type = TLS_CREDENTIAL_PRIVATE_KEY,
.sec_tag = WIFI_CERT_SERVER_KEY_SEC_TAG,
.data = &params->server_key,
.len = &params->server_key_len,
},
};
memset(params, 0, sizeof(*params));
/* Process common certificates */
if (process_certificates(certs_common, ARRAY_SIZE(certs_common)) != 0) {
goto cleanup;
}
/* Process STA-specific certificates */
if (!is_ap) {
if (process_certificates(certs_sta, ARRAY_SIZE(certs_sta)) != 0) {
goto cleanup;
}
}
/* Process AP-specific certificates if is_ap is true */
if (is_ap) {
if (process_certificates(certs_ap, ARRAY_SIZE(certs_ap)) != 0) {
goto cleanup;
}
}
memcpy(&context.enterprise_creds_params, params, sizeof(*params));
return;
cleanup:
for (size_t i = 0; i < ARRAY_SIZE(certs_common); i++) {
if (certs_common[i].data) {
k_free(*certs_common[i].data);
}
}
if (!is_ap) {
for (size_t i = 0; i < ARRAY_SIZE(certs_sta); i++) {
if (certs_sta[i].data) {
k_free(*certs_sta[i].data);
}
}
}
if (is_ap) {
for (size_t i = 0; i < ARRAY_SIZE(certs_ap); i++) {
if (certs_ap[i].data) {
k_free(*certs_ap[i].data);
}
}
}
}
static void clear_enterprise_creds_params(struct wifi_enterprise_creds_params *params)
{
size_t i;
if (!params) {
return;
}
const uint8_t *certs[] = {
params->ca_cert,
params->client_cert,
params->client_key,
params->server_cert,
params->server_key,
params->ca_cert2,
params->client_cert2,
params->client_key2,
};
for (i = 0; i < ARRAY_SIZE(certs); i++) {
k_free((void *)certs[i]);
}
memset(params, 0, sizeof(*params));
}
#else
static void set_enterprise_creds_params(struct wifi_enterprise_creds_params *params,
bool is_ap)
{
params->ca_cert = (uint8_t *)ca_cert_test;
params->ca_cert_len = ARRAY_SIZE(ca_cert_test);
if (!is_ap) {
params->client_cert = (uint8_t *)client_cert_test;
params->client_cert_len = ARRAY_SIZE(client_cert_test);
params->client_key = (uint8_t *)client_key_test;
params->client_key_len = ARRAY_SIZE(client_key_test);
params->ca_cert2 = (uint8_t *)ca_cert2_test;
params->ca_cert2_len = ARRAY_SIZE(ca_cert2_test);
params->client_cert2 = (uint8_t *)client_cert2_test;
params->client_cert2_len = ARRAY_SIZE(client_cert2_test);
params->client_key2 = (uint8_t *)client_key2_test;
params->client_key2_len = ARRAY_SIZE(client_key2_test);
return;
}
params->server_cert = (uint8_t *)server_cert_test;
params->server_cert_len = ARRAY_SIZE(server_cert_test);
params->server_key = (uint8_t *)server_key_test;
params->server_key_len = ARRAY_SIZE(server_key_test);
}
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
static int wifi_set_enterprise_creds(const struct shell *sh, struct net_if *iface,
bool is_ap)
{
struct wifi_enterprise_creds_params params = {0};
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
clear_enterprise_creds_params(&context.enterprise_creds_params);
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
set_enterprise_creds_params(&params, is_ap);
if (net_mgmt(NET_REQUEST_WIFI_ENTERPRISE_CREDS, iface, &params, sizeof(params))) {
PR_WARNING("Set enterprise credentials failed\n");
return -1;
}
return 0;
}
#endif
static bool parse_number(const struct shell *sh, long *param, char *str,
char *pname, long min, long max)
{
char *endptr;
char *str_tmp = str;
long num;
if ((str_tmp[0] == '0') && (str_tmp[1] == 'x')) {
/* Hexadecimal numbers take base 0 in strtol */
num = strtol(str_tmp, &endptr, 0);
} else {
num = strtol(str_tmp, &endptr, 10);
}
if (*endptr != '\0') {
PR_ERROR("Invalid number: %s\n", str_tmp);
return false;
}
if ((num) < (min) || (num) > (max)) {
if (pname) {
PR_WARNING("%s value out of range: %s, (%ld-%ld)\n",
pname, str_tmp, min, max);
} else {
PR_WARNING("Value out of range: %s, (%ld-%ld)\n",
str_tmp, min, max);
}
return false;
}
*param = num;
return true;
}
static void handle_wifi_scan_result(struct net_mgmt_event_callback *cb)
{
const struct wifi_scan_result *entry =
(const struct wifi_scan_result *)cb->info;
uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")];
const struct shell *sh = context.sh;
uint8_t ssid_print[WIFI_SSID_MAX_LEN + 1];
context.scan_result++;
if (context.scan_result == 1U) {
PR("\n%-4s | %-32s %-5s | %-13s | %-4s | %-20s | %-17s | %-8s\n",
"Num", "SSID", "(len)", "Chan (Band)", "RSSI", "Security", "BSSID", "MFP");
}
strncpy(ssid_print, entry->ssid, sizeof(ssid_print) - 1);
ssid_print[sizeof(ssid_print) - 1] = '\0';
PR("%-4d | %-32s %-5u | %-4u (%-6s) | %-4d | %-20s | %-17s | %-8s\n",
context.scan_result, ssid_print, entry->ssid_length, entry->channel,
wifi_band_txt(entry->band),
entry->rssi,
((entry->wpa3_ent_type) ?
wifi_wpa3_enterprise_txt(entry->wpa3_ent_type)
: (entry->security == WIFI_SECURITY_TYPE_EAP ? "WPA2 Enterprise"
: wifi_security_txt(entry->security))),
((entry->mac_length) ?
net_sprint_ll_addr_buf(entry->mac, WIFI_MAC_ADDR_LEN,
mac_string_buf,
sizeof(mac_string_buf)) : ""),
wifi_mfp_txt(entry->mfp));
}
static int wifi_freq_to_channel(int frequency)
{
int channel;
if (frequency == 2484) { /* channel 14 */
channel = 14;
} else if ((frequency <= 2472) && (frequency >= 2412)) {
channel = ((frequency - 2412) / 5) + 1;
} else if ((frequency <= 5320) && (frequency >= 5180)) {
channel = ((frequency - 5180) / 5) + 36;
} else if ((frequency <= 5720) && (frequency >= 5500)) {
channel = ((frequency - 5500) / 5) + 100;
} else if ((frequency <= 5895) && (frequency >= 5745)) {
channel = ((frequency - 5745) / 5) + 149;
} else {
channel = frequency;
}
return channel;
}
#ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS
static enum wifi_frequency_bands wifi_freq_to_band(int frequency)
{
enum wifi_frequency_bands band = WIFI_FREQ_BAND_2_4_GHZ;
if ((frequency >= 2401) && (frequency <= 2495)) {
band = WIFI_FREQ_BAND_2_4_GHZ;
} else if ((frequency >= 5170) && (frequency <= 5895)) {
band = WIFI_FREQ_BAND_5_GHZ;
} else {
band = WIFI_FREQ_BAND_6_GHZ;
}
return band;
}
static void handle_wifi_raw_scan_result(struct net_mgmt_event_callback *cb)
{
struct wifi_raw_scan_result *raw =
(struct wifi_raw_scan_result *)cb->info;
int channel;
int band;
int rssi;
uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")];
const struct shell *sh = context.sh;
context.scan_result++;
if (context.scan_result == 1U) {
PR("\n%-4s | %-13s | %-4s | %-15s | %-15s | %-32s\n",
"Num", "Channel (Band)", "RSSI", "BSSID", "Frame length", "Frame Body");
}
rssi = raw->rssi;
channel = wifi_freq_to_channel(raw->frequency);
band = wifi_freq_to_band(raw->frequency);
PR("%-4d | %-4u (%-6s) | %-4d | %s | %-4d ",
context.scan_result,
channel,
wifi_band_txt(band),
rssi,
net_sprint_ll_addr_buf(raw->data + 10, WIFI_MAC_ADDR_LEN, mac_string_buf,
sizeof(mac_string_buf)), raw->frame_length);
for (int i = 0; i < 32; i++) {
PR("%02X ", *(raw->data + i));
}
PR("\n");
}
#endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */
static void handle_wifi_scan_done(struct net_mgmt_event_callback *cb)
{
const struct wifi_status *status =
(const struct wifi_status *)cb->info;
const struct shell *sh = context.sh;
if (status->status) {
PR_WARNING("Scan request failed (%d)\n", status->status);
} else {
PR("Scan request done\n");
}
net_mgmt_del_event_callback(&wifi_shell_scan_cb);
context.scan_result = 0U;
}
static void handle_wifi_connect_result(struct net_mgmt_event_callback *cb)
{
const struct wifi_status *status =
(const struct wifi_status *) cb->info;
const struct shell *sh = context.sh;
int st = status->status;
if (st) {
if (st < 0) {
/* Errno values are negative, try to map to
* wifi status values.
*/
if (st == -ETIMEDOUT) {
st = WIFI_STATUS_CONN_TIMEOUT;
}
}
PR_WARNING("Connection request failed (%s/%d)\n",
wifi_conn_status_txt(st), st);
} else {
PR("Connected\n");
}
context.connecting = false;
}
static void handle_wifi_disconnect_result(struct net_mgmt_event_callback *cb)
{
const struct wifi_status *status =
(const struct wifi_status *) cb->info;
const struct shell *sh = context.sh;
if (context.disconnecting) {
if (status->status) {
PR_WARNING("Disconnection request failed (%d)\n", status->status);
} else {
PR("Disconnection request done (%d)\n", status->status);
}
context.disconnecting = false;
} else {
PR("Disconnected\n");
}
}
static void print_twt_params(uint8_t dialog_token, uint8_t flow_id,
enum wifi_twt_negotiation_type negotiation_type,
bool responder, bool implicit, bool announce,
bool trigger, uint32_t twt_wake_interval,
uint64_t twt_interval)
{
const struct shell *sh = context.sh;
PR("TWT Dialog token: %d\n",
dialog_token);
PR("TWT flow ID: %d\n",
flow_id);
PR("TWT negotiation type: %s\n",
wifi_twt_negotiation_type_txt(negotiation_type));
PR("TWT responder: %s\n",
responder ? "true" : "false");
PR("TWT implicit: %s\n",
implicit ? "true" : "false");
PR("TWT announce: %s\n",
announce ? "true" : "false");
PR("TWT trigger: %s\n",
trigger ? "true" : "false");
PR("TWT wake interval: %d us\n",
twt_wake_interval);
PR("TWT interval: %lld us\n",
twt_interval);
PR("========================\n");
}
static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb)
{
const struct wifi_twt_params *resp =
(const struct wifi_twt_params *)cb->info;
const struct shell *sh = context.sh;
if (resp->operation == WIFI_TWT_TEARDOWN) {
if (resp->teardown_status == WIFI_TWT_TEARDOWN_SUCCESS) {
PR("TWT teardown succeeded for flow ID %d\n",
resp->flow_id);
} else {
PR("TWT teardown failed for flow ID %d\n",
resp->flow_id);
}
return;
}
if (resp->resp_status == WIFI_TWT_RESP_RECEIVED) {
PR("TWT response: %s\n",
wifi_twt_setup_cmd_txt(resp->setup_cmd));
PR("== TWT negotiated parameters ==\n");
print_twt_params(resp->dialog_token,
resp->flow_id,
resp->negotiation_type,
resp->setup.responder,
resp->setup.implicit,
resp->setup.announce,
resp->setup.trigger,
resp->setup.twt_wake_interval,
resp->setup.twt_interval);
} else {
PR("TWT response timed out\n");
}
}
static void handle_wifi_ap_enable_result(struct net_mgmt_event_callback *cb)
{
const struct wifi_status *status =
(const struct wifi_status *)cb->info;
const struct shell *sh = context.sh;
if (status->status) {
PR_WARNING("AP enable request failed (%d)\n", status->status);
} else {
PR("AP enabled\n");
}
}
static void handle_wifi_ap_disable_result(struct net_mgmt_event_callback *cb)
{
const struct wifi_status *status =
(const struct wifi_status *)cb->info;
const struct shell *sh = context.sh;
if (status->status) {
PR_WARNING("AP disable request failed (%d)\n", status->status);
} else {
PR("AP disabled\n");
}
k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER);
memset(&sta_list, 0, sizeof(sta_list));
k_mutex_unlock(&wifi_ap_sta_list_lock);
}
static void handle_wifi_ap_sta_connected(struct net_mgmt_event_callback *cb)
{
const struct wifi_ap_sta_info *sta_info =
(const struct wifi_ap_sta_info *)cb->info;
const struct shell *sh = context.sh;
uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")];
int i;
PR("Station connected: %s\n",
net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN,
mac_string_buf, sizeof(mac_string_buf)));
k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER);
for (i = 0; i < CONFIG_WIFI_SHELL_MAX_AP_STA; i++) {
if (!sta_list[i].valid) {
sta_list[i].sta_info = *sta_info;
sta_list[i].valid = true;
break;
}
}
if (i == CONFIG_WIFI_SHELL_MAX_AP_STA) {
PR_WARNING("No space to store station info: "
"Increase CONFIG_WIFI_SHELL_MAX_AP_STA\n");
}
k_mutex_unlock(&wifi_ap_sta_list_lock);
}
static void handle_wifi_ap_sta_disconnected(struct net_mgmt_event_callback *cb)
{
const struct wifi_ap_sta_info *sta_info =
(const struct wifi_ap_sta_info *)cb->info;
const struct shell *sh = context.sh;
uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")];
PR("Station disconnected: %s\n",
net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN,
mac_string_buf, sizeof(mac_string_buf)));
k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER);
for (int i = 0; i < CONFIG_WIFI_SHELL_MAX_AP_STA; i++) {
if (!sta_list[i].valid) {
continue;
}
if (!memcmp(sta_list[i].sta_info.mac, sta_info->mac,
WIFI_MAC_ADDR_LEN)) {
sta_list[i].valid = false;
break;
}
}
k_mutex_unlock(&wifi_ap_sta_list_lock);
}
#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_ROAMING
static void handle_wifi_signal_change(struct net_mgmt_event_callback *cb, struct net_if *iface)
{
const struct shell *sh = context.sh;
int ret;
ret = net_mgmt(NET_REQUEST_WIFI_START_ROAMING, iface, NULL, 0);
if (ret) {
PR_WARNING("Start roaming failed\n");
return;
}
PR("Start roaming requested\n");
}
static void handle_wifi_neighbor_rep_complete(struct net_mgmt_event_callback *cb,
struct net_if *iface)
{
const struct shell *sh = context.sh;
int ret;
ret = net_mgmt(NET_REQUEST_WIFI_NEIGHBOR_REP_COMPLETE, iface, NULL, 0);
if (ret) {
PR_WARNING("Neighbor report complete failed\n");
return;
}
PR("Neighbor report complete requested\n");
}
#endif
static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb,
uint64_t mgmt_event, struct net_if *iface)
{
switch (mgmt_event) {
case NET_EVENT_WIFI_CONNECT_RESULT:
handle_wifi_connect_result(cb);
break;
case NET_EVENT_WIFI_DISCONNECT_RESULT:
handle_wifi_disconnect_result(cb);
break;
case NET_EVENT_WIFI_TWT:
handle_wifi_twt_event(cb);
break;
case NET_EVENT_WIFI_AP_ENABLE_RESULT:
handle_wifi_ap_enable_result(cb);
break;
case NET_EVENT_WIFI_AP_DISABLE_RESULT:
handle_wifi_ap_disable_result(cb);
break;
case NET_EVENT_WIFI_AP_STA_CONNECTED:
handle_wifi_ap_sta_connected(cb);
break;
case NET_EVENT_WIFI_AP_STA_DISCONNECTED:
handle_wifi_ap_sta_disconnected(cb);
break;
#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_ROAMING
case NET_EVENT_WIFI_SIGNAL_CHANGE:
handle_wifi_signal_change(cb, iface);
break;
case NET_EVENT_WIFI_NEIGHBOR_REP_COMP:
handle_wifi_neighbor_rep_complete(cb, iface);
break;
#endif
default:
break;
}
}
static void wifi_mgmt_scan_event_handler(struct net_mgmt_event_callback *cb,
uint64_t mgmt_event, struct net_if *iface)
{
switch (mgmt_event) {
case NET_EVENT_WIFI_SCAN_RESULT:
handle_wifi_scan_result(cb);
break;
case NET_EVENT_WIFI_SCAN_DONE:
handle_wifi_scan_done(cb);
break;
#ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS
case NET_EVENT_WIFI_RAW_SCAN_RESULT:
handle_wifi_raw_scan_result(cb);
break;
#endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */
default:
break;
}
}
static int __wifi_args_to_params(const struct shell *sh, size_t argc, char *argv[],
struct wifi_connect_req_params *params,
enum wifi_iface_mode iface_mode)
{
int opt;
int opt_index = 0;
struct getopt_state *state;
static const struct option long_options[] = {
{"ssid", required_argument, 0, 's'},
{"passphrase", required_argument, 0, 'p'},
{"key-mgmt", required_argument, 0, 'k'},
{"ieee-80211w", required_argument, 0, 'w'},
{"bssid", required_argument, 0, 'm'},
{"band", required_argument, 0, 'b'},
{"channel", required_argument, 0, 'c'},
{"timeout", required_argument, 0, 't'},
{"anon-id", required_argument, 0, 'a'},
{"bandwidth", required_argument, 0, 'B'},
{"key1-pwd", required_argument, 0, 'K'},
{"key2-pwd", required_argument, 0, 'K'},
{"wpa3-enterprise", required_argument, 0, 'S'},
{"TLS-cipher", required_argument, 0, 'T'},
{"verify-peer-cert", required_argument, 0, 'A'},
{"eap-version", required_argument, 0, 'V'},
{"eap-id1", required_argument, 0, 'I'},
{"eap-id2", required_argument, 0, 'I'},
{"eap-id3", required_argument, 0, 'I'},
{"eap-id4", required_argument, 0, 'I'},
{"eap-id5", required_argument, 0, 'I'},
{"eap-id6", required_argument, 0, 'I'},
{"eap-id7", required_argument, 0, 'I'},
{"eap-id8", required_argument, 0, 'I'},
{"eap-pwd1", required_argument, 0, 'P'},
{"eap-pwd2", required_argument, 0, 'P'},
{"eap-pwd3", required_argument, 0, 'P'},
{"eap-pwd4", required_argument, 0, 'P'},
{"eap-pwd5", required_argument, 0, 'P'},
{"eap-pwd6", required_argument, 0, 'P'},
{"eap-pwd7", required_argument, 0, 'P'},
{"eap-pwd8", required_argument, 0, 'P'},
{"ignore-broadcast-ssid", required_argument, 0, 'g'},
{"ieee-80211r", no_argument, 0, 'R'},
{"iface", required_argument, 0, 'i'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}};
char *endptr;
int idx = 1;
bool secure_connection = false;
uint8_t band;
const uint8_t all_bands[] = {
WIFI_FREQ_BAND_2_4_GHZ,
WIFI_FREQ_BAND_5_GHZ,
WIFI_FREQ_BAND_6_GHZ
};
bool found = false;
char bands_str[MAX_BANDS_STR_LEN] = {0};
size_t offset = 0;
long channel;
int key_passwd_cnt = 0;
int ret = 0;
/* Defaults */
params->band = WIFI_FREQ_BAND_UNKNOWN;
params->channel = WIFI_CHANNEL_ANY;
params->security = WIFI_SECURITY_TYPE_NONE;
params->mfp = WIFI_MFP_OPTIONAL;
params->eap_ver = 1;
params->ignore_broadcast_ssid = 0;
params->bandwidth = WIFI_FREQ_BANDWIDTH_20MHZ;
params->verify_peer_cert = false;
while ((opt = getopt_long(argc, argv, "s:p:k:e:w:b:c:m:t:a:B:K:S:T:A:V:I:P:g:Rh:i:",
long_options, &opt_index)) != -1) {
state = getopt_state_get();
switch (opt) {
case 's':
params->ssid = state->optarg;
params->ssid_length = strlen(params->ssid);
if (params->ssid_length > WIFI_SSID_MAX_LEN) {
PR_WARNING("SSID too long (max %d characters)\n",
WIFI_SSID_MAX_LEN);
return -EINVAL;
}
break;
case 'k':
params->security = atoi(state->optarg);
if (params->security) {
secure_connection = true;
}
break;
case 'p':
params->psk = state->optarg;
params->psk_length = strlen(params->psk);
break;
case 'c':
channel = strtol(state->optarg, &endptr, 10);
if (iface_mode == WIFI_MODE_AP && channel == 0) {
params->channel = channel;
break;
}
for (band = 0; band < ARRAY_SIZE(all_bands); band++) {
offset += snprintf(bands_str + offset,
sizeof(bands_str) - offset,
"%s%s",
band ? "," : "",
wifi_band_txt(all_bands[band]));
if (offset >= sizeof(bands_str)) {
PR_ERROR("Failed to parse channel: %s: "
"band string too long\n",
argv[idx]);
return -EINVAL;
}
if (wifi_utils_validate_chan(all_bands[band],
channel)) {
found = true;
break;
}
}
if (!found) {
PR_ERROR("Invalid channel: %ld, checked bands: %s\n",
channel,
bands_str);
return -EINVAL;
}
params->channel = channel;
break;
case 'b':
if (iface_mode == WIFI_MODE_INFRA ||
iface_mode == WIFI_MODE_AP) {
switch (atoi(state->optarg)) {
case 2:
params->band = WIFI_FREQ_BAND_2_4_GHZ;
break;
case 5:
params->band = WIFI_FREQ_BAND_5_GHZ;
break;
case 6:
params->band = WIFI_FREQ_BAND_6_GHZ;
break;
case 0:
/* Allow default value when connecting */
if (iface_mode == WIFI_MODE_INFRA) {
params->band = WIFI_FREQ_BAND_UNKNOWN;
break;
}
__fallthrough;
default:
PR_ERROR("Invalid band: %d\n", atoi(state->optarg));
return -EINVAL;
}
}
break;
case 'w':
if (params->security == WIFI_SECURITY_TYPE_NONE ||
params->security == WIFI_SECURITY_TYPE_WPA_PSK) {
PR_ERROR("MFP not supported for security type %s\n",
wifi_security_txt(params->security));
return -EINVAL;
}
params->mfp = atoi(state->optarg);
break;
case 'm':
if (net_bytes_from_str(params->bssid, sizeof(params->bssid),
state->optarg) < 0) {
PR_WARNING("Invalid MAC address\n");
return -EINVAL;
}
break;
case 't':
if (iface_mode == WIFI_MODE_INFRA) {
params->timeout = strtol(state->optarg, &endptr, 10);
if (*endptr != '\0') {
PR_ERROR("Invalid timeout: %s\n", state->optarg);
return -EINVAL;
}
}
break;
case 'a':
params->anon_id = state->optarg;
params->aid_length = strlen(params->anon_id);
if (params->aid_length > WIFI_ENT_IDENTITY_MAX_LEN) {
PR_WARNING("anon_id too long (max %d characters)\n",
WIFI_ENT_IDENTITY_MAX_LEN);
return -EINVAL;
}
break;
case 'B':
if (iface_mode == WIFI_MODE_AP) {
switch (atoi(state->optarg)) {
case 1:
params->bandwidth = WIFI_FREQ_BANDWIDTH_20MHZ;
break;
case 2:
params->bandwidth = WIFI_FREQ_BANDWIDTH_40MHZ;
break;
case 3:
params->bandwidth = WIFI_FREQ_BANDWIDTH_80MHZ;
break;
default:
PR_ERROR("Invalid bandwidth: %d\n", atoi(state->optarg));
return -EINVAL;
}
}
break;
case 'K':
if (key_passwd_cnt >= 2) {
PR_WARNING("too many key_passwd (max 2 key_passwd)\n");
return -EINVAL;
}
if (key_passwd_cnt == 0) {
params->key_passwd = state->optarg;
params->key_passwd_length = strlen(params->key_passwd);
if (params->key_passwd_length > WIFI_ENT_PSWD_MAX_LEN) {
PR_WARNING("key_passwd too long (max %d characters)\n",
WIFI_ENT_PSWD_MAX_LEN);
return -EINVAL;
}
} else if (key_passwd_cnt == 1) {
params->key2_passwd = state->optarg;
params->key2_passwd_length = strlen(params->key2_passwd);
if (params->key2_passwd_length > WIFI_ENT_PSWD_MAX_LEN) {
PR_WARNING("key2_passwd too long (max %d characters)\n",
WIFI_ENT_PSWD_MAX_LEN);
return -EINVAL;
}
}
key_passwd_cnt++;
break;
case 'S':
params->wpa3_ent_mode = atoi(state->optarg);
break;
case 'T':
params->TLS_cipher = atoi(state->optarg);
break;
case 'A':
if (iface_mode == WIFI_MODE_INFRA) {
params->verify_peer_cert = !!atoi(state->optarg);
}
break;
case 'V':
params->eap_ver = atoi(state->optarg);
if (params->eap_ver != 0U && params->eap_ver != 1U) {
PR_WARNING("eap_ver error %d\n", params->eap_ver);
return -EINVAL;
}
break;
case 'I':
if (params->nusers >= WIFI_ENT_IDENTITY_MAX_USERS) {
PR_WARNING("too many eap identities (max %d identities)\n",
WIFI_ENT_IDENTITY_MAX_USERS);
return -EINVAL;
}
params->eap_identity = state->optarg;
params->eap_id_length = strlen(params->eap_identity);
params->identities[params->nusers] = state->optarg;
params->nusers++;
if (params->eap_id_length > WIFI_ENT_IDENTITY_MAX_LEN) {
PR_WARNING("eap identity too long (max %d characters)\n",
WIFI_ENT_IDENTITY_MAX_LEN);
return -EINVAL;
}
break;
case 'P':
if (params->passwds >= WIFI_ENT_IDENTITY_MAX_USERS) {
PR_WARNING("too many eap passwds (max %d passwds)\n",
WIFI_ENT_IDENTITY_MAX_USERS);
return -EINVAL;
}
params->eap_password = state->optarg;
params->eap_passwd_length = strlen(params->eap_password);
params->passwords[params->passwds] = state->optarg;
params->passwds++;
if (params->eap_passwd_length > WIFI_ENT_PSWD_MAX_LEN) {
PR_WARNING("eap password length too long (max %d characters)\n",
WIFI_ENT_PSWD_MAX_LEN);
return -EINVAL;
}
break;
case 'R':
params->ft_used = true;
break;
case 'g':
params->ignore_broadcast_ssid = shell_strtol(state->optarg, 10, &ret);
break;
case 'i':
/* Unused, but parsing to avoid unknown option error */
break;
case 'h':
return -ENOEXEC;
default:
PR_ERROR("Invalid option %c\n", state->optopt);
return -EINVAL;
}
if (ret) {
PR_ERROR("Invalid argument %d ret %d\n", opt_index, ret);
return -EINVAL;
}
}
if (params->psk && !secure_connection) {
PR_WARNING("Passphrase provided without security configuration\n");
}
if (!params->ssid) {
PR_ERROR("SSID not provided\n");
return -EINVAL;
}
if (params->security == WIFI_SECURITY_TYPE_SAE_HNP
|| params->security == WIFI_SECURITY_TYPE_SAE_H2E
|| params->security == WIFI_SECURITY_TYPE_SAE_AUTO
|| params->wpa3_ent_mode != WIFI_WPA3_ENTERPRISE_NA) {
if (params->mfp != WIFI_MFP_REQUIRED) {
PR_ERROR("MFP is required for WPA3 mode\n");
return -EINVAL;
}
}
if (iface_mode == WIFI_MODE_AP && params->channel == WIFI_CHANNEL_ANY) {
PR_ERROR("Channel not provided\n");
return -EINVAL;
}
#ifdef CONFIG_WIFI_NM_HOSTAPD_AP
if (iface_mode == WIFI_MODE_AP) {
if (params->channel == 0 && params->band == WIFI_FREQ_BAND_UNKNOWN) {
PR_ERROR("Band not provided when channel is 0\n");
return -EINVAL;
}
if (params->channel > 0 && params->channel <= 14 &&
(params->band != WIFI_FREQ_BAND_2_4_GHZ &&
params->band != WIFI_FREQ_BAND_UNKNOWN)) {
PR_ERROR("Band and channel mismatch\n");
return -EINVAL;
}
if (params->channel >= 36 &&
(params->band != WIFI_FREQ_BAND_5_GHZ &&
params->band != WIFI_FREQ_BAND_UNKNOWN)) {
PR_ERROR("Band and channel mismatch\n");
return -EINVAL;
}
}
#endif
if (params->ignore_broadcast_ssid > 2) {
PR_ERROR("Invalid ignore_broadcast_ssid value\n");
return -EINVAL;
}
return 0;
}
static int cmd_wifi_connect(const struct shell *sh, size_t argc,
char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_connect_req_params cnx_params = { 0 };
int ret;
context.sh = sh;
if (__wifi_args_to_params(sh, argc, argv, &cnx_params, WIFI_MODE_INFRA)) {
shell_help(sh);
return -ENOEXEC;
}
#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
/* Load the enterprise credentials if needed */
if (cnx_params.security == WIFI_SECURITY_TYPE_EAP_TLS ||
cnx_params.security == WIFI_SECURITY_TYPE_EAP_PEAP_MSCHAPV2 ||
cnx_params.security == WIFI_SECURITY_TYPE_EAP_PEAP_GTC ||
cnx_params.security == WIFI_SECURITY_TYPE_EAP_TTLS_MSCHAPV2 ||
cnx_params.security == WIFI_SECURITY_TYPE_EAP_PEAP_TLS) {
wifi_set_enterprise_creds(sh, iface, 0);
}
#endif
context.connecting = true;
ret = net_mgmt(NET_REQUEST_WIFI_CONNECT, iface,
&cnx_params, sizeof(struct wifi_connect_req_params));
if (ret) {
printk("Connection request failed with error: %d\n", ret);
context.connecting = false;
return -ENOEXEC;
}
PR("Connection requested\n");
return 0;
}
static int cmd_wifi_disconnect(const struct shell *sh, size_t argc,
char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
int status;
context.disconnecting = true;
context.sh = sh;
status = net_mgmt(NET_REQUEST_WIFI_DISCONNECT, iface, NULL, 0);
if (status) {
context.disconnecting = false;
if (status == -EALREADY) {
PR_INFO("Already disconnected\n");
} else {
PR_WARNING("Disconnect request failed: %d\n", status);
return -ENOEXEC;
}
} else {
PR("Disconnect requested\n");
}
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
/* Clear the certificates */
clear_enterprise_creds_params(&context.enterprise_creds_params);
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
return 0;
}
static int wifi_scan_args_to_params(const struct shell *sh,
size_t argc,
char *argv[],
struct wifi_scan_params *params,
bool *do_scan)
{
int opt;
int opt_index = 0;
struct getopt_state *state;
static const struct option long_options[] = {
{"type", required_argument, 0, 't'},
{"bands", required_argument, 0, 'b'},
{"dwell_time_active", required_argument, 0, 'a'},
{"dwell_time_passive", required_argument, 0, 'p'},
{"ssid", required_argument, 0, 's'},
{"max_bss", required_argument, 0, 'm'},
{"chans", required_argument, 0, 'c'},
{"iface", required_argument, 0, 'i'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}};
int val;
int opt_num = 0;
*do_scan = true;
while ((opt = getopt_long(argc, argv, "t:b:a:p:s:m:c:i:h",
long_options, &opt_index)) != -1) {
state = getopt_state_get();
switch (opt) {
case 't':
if (!strncasecmp(state->optarg, "passive", 7)) {
params->scan_type = WIFI_SCAN_TYPE_PASSIVE;
} else if (!strncasecmp(state->optarg, "active", 6)) {
params->scan_type = WIFI_SCAN_TYPE_ACTIVE;
} else {
PR_ERROR("Invalid scan type %s\n", state->optarg);
return -ENOEXEC;
}
opt_num++;
break;
case 'b':
if (wifi_utils_parse_scan_bands(state->optarg, &params->bands)) {
PR_ERROR("Invalid band value(s)\n");
return -ENOEXEC;
}
opt_num++;
break;
case 'a':
val = atoi(state->optarg);
if (val < 0) {
PR_ERROR("Invalid dwell_time_active val\n");
return -ENOEXEC;
}
params->dwell_time_active = val;
opt_num++;
break;
case 'p':
val = atoi(state->optarg);
if (val < 0) {
PR_ERROR("Invalid dwell_time_passive val\n");
return -ENOEXEC;
}
params->dwell_time_passive = val;
opt_num++;
break;
case 's':
if (wifi_utils_parse_scan_ssids(state->optarg,
params->ssids,
ARRAY_SIZE(params->ssids))) {
PR_ERROR("Invalid SSID(s)\n");
return -ENOEXEC;
}
opt_num++;
break;
case 'm':
val = atoi(state->optarg);
if ((val < 0) || (val > WIFI_MGMT_SCAN_MAX_BSS_CNT)) {
PR_ERROR("Invalid max_bss val\n");
return -ENOEXEC;
}
params->max_bss_cnt = val;
opt_num++;
break;
case 'c':
if (wifi_utils_parse_scan_chan(state->optarg,
params->band_chan,
ARRAY_SIZE(params->band_chan))) {
PR_ERROR("Invalid band or channel value(s)\n");
return -ENOEXEC;
}
opt_num++;
break;
case 'h':
shell_help(sh);
*do_scan = false;
opt_num++;
break;
case 'i':
/* Unused, but parsing to avoid unknown option error */
opt_num++;
break;
case '?':
default:
PR_ERROR("Invalid option or option usage: %s\n",
argv[opt_index + 1]);
return -ENOEXEC;
}
}
return opt_num;
}
static int cmd_wifi_scan(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_scan_params params = { 0 };
bool do_scan = true;
int opt_num;
context.sh = sh;
if (argc > 1) {
opt_num = wifi_scan_args_to_params(sh, argc, argv, &params, &do_scan);
if (opt_num < 0) {
shell_help(sh);
return -ENOEXEC;
} else if (!opt_num) {
PR_WARNING("No valid option(s) found\n");
do_scan = false;
}
}
if (do_scan) {
net_mgmt_add_event_callback(&wifi_shell_scan_cb);
if (net_mgmt(NET_REQUEST_WIFI_SCAN, iface, &params, sizeof(params))) {
PR_WARNING("Scan request failed\n");
return -ENOEXEC;
}
PR("Scan requested\n");
return 0;
}
PR_WARNING("Scan not initiated\n");
return -ENOEXEC;
}
static int cmd_wifi_status(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_iface_status status = { 0 };
context.sh = sh;
if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, iface, &status,
sizeof(struct wifi_iface_status))) {
PR_WARNING("Status request failed\n");
return -ENOEXEC;
}
PR("Status: successful\n");
PR("==================\n");
PR("State: %s\n", wifi_state_txt(status.state));
if (status.state >= WIFI_STATE_ASSOCIATED) {
uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")];
PR("Interface Mode: %s\n", wifi_mode_txt(status.iface_mode));
PR("Link Mode: %s\n", wifi_link_mode_txt(status.link_mode));
PR("SSID: %.32s\n", status.ssid);
PR("BSSID: %s\n",
net_sprint_ll_addr_buf(status.bssid,
WIFI_MAC_ADDR_LEN, mac_string_buf,
sizeof(mac_string_buf)));
PR("Band: %s\n", wifi_band_txt(status.band));
PR("Channel: %d\n", status.channel);
PR("Security: %s %s\n", wifi_wpa3_enterprise_txt(status.wpa3_ent_type),
wifi_security_txt(status.security));
PR("MFP: %s\n", wifi_mfp_txt(status.mfp));
if (status.iface_mode == WIFI_MODE_INFRA) {
PR("RSSI: %d\n", status.rssi);
}
PR("Beacon Interval: %d\n", status.beacon_interval);
PR("DTIM: %d\n", status.dtim_period);
PR("TWT: %s\n",
status.twt_capable ? "Supported" : "Not supported");
PR("Current PHY TX rate (Mbps) : %d\n", status.current_phy_tx_rate);
}
return 0;
}
static int cmd_wifi_ap_status(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_SAP, argc, argv);
struct wifi_iface_status status = {0};
uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")];
context.sh = sh;
if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, iface, &status,
sizeof(struct wifi_iface_status))) {
PR_WARNING("Status request failed\n");
return -ENOEXEC;
}
switch (status.state) {
case WIFI_SAP_IFACE_UNINITIALIZED:
PR("State: %s\n", "UNINITIALIZED");
return 0;
case WIFI_SAP_IFACE_DISABLED:
PR("State: %s\n", "DISABLED");
return 0;
case WIFI_SAP_IFACE_COUNTRY_UPDATE:
PR("State: %s\n", "COUNTRY_UPDATE");
return 0;
case WIFI_SAP_IFACE_ACS:
PR("State: %s\n", "ACS");
return 0;
case WIFI_SAP_IFACE_HT_SCAN:
PR("State: %s\n", "HT_SCAN");
return 0;
case WIFI_SAP_IFACE_DFS:
PR("State: %s\n", "DFS");
break;
case WIFI_SAP_IFACE_NO_IR:
PR("State: %s\n", "NO_IR");
break;
case WIFI_SAP_IFACE_ENABLED:
PR("State: %s\n", "ENABLED");
break;
default:
return 0;
}
PR("Interface Mode: %s\n", wifi_mode_txt(status.iface_mode));
PR("Link Mode: %s\n", wifi_link_mode_txt(status.link_mode));
PR("SSID: %.32s\n", status.ssid);
PR("BSSID: %s\n", net_sprint_ll_addr_buf(status.bssid, WIFI_MAC_ADDR_LEN, mac_string_buf,
sizeof(mac_string_buf)));
PR("Band: %s\n", wifi_band_txt(status.band));
PR("Channel: %d\n", status.channel);
PR("Security: %s %s\n", wifi_wpa3_enterprise_txt(status.wpa3_ent_type),
wifi_security_txt(status.security));
PR("MFP: %s\n", wifi_mfp_txt(status.mfp));
if (status.iface_mode == WIFI_MODE_INFRA) {
PR("RSSI: %d\n", status.rssi);
}
PR("Beacon Interval: %d\n", status.beacon_interval);
PR("DTIM: %d\n", status.dtim_period);
PR("TWT: %s\n", status.twt_capable ? "Supported" : "Not supported");
return 0;
}
#if defined(CONFIG_NET_STATISTICS_WIFI) && \
defined(CONFIG_NET_STATISTICS_USER_API)
static void print_wifi_stats(struct net_if *iface, struct net_stats_wifi *data,
const struct shell *sh)
{
PR("Statistics for Wi-Fi interface %p [%d]\n", iface,
net_if_get_by_iface(iface));
PR("Bytes received : %llu\n", data->bytes.received);
PR("Bytes sent : %llu\n", data->bytes.sent);
PR("Packets received : %u\n", data->pkts.rx);
PR("Packets sent : %u\n", data->pkts.tx);
PR("Receive errors : %u\n", data->errors.rx);
PR("Send errors : %u\n", data->errors.tx);
PR("Bcast received : %u\n", data->broadcast.rx);
PR("Bcast sent : %u\n", data->broadcast.tx);
PR("Mcast received : %u\n", data->multicast.rx);
PR("Mcast sent : %u\n", data->multicast.tx);
PR("Beacons received : %u\n", data->sta_mgmt.beacons_rx);
PR("Beacons missed : %u\n", data->sta_mgmt.beacons_miss);
PR("Unicast received : %u\n", data->unicast.rx);
PR("Unicast sent : %u\n", data->unicast.tx);
PR("Overrun count : %u\n", data->overrun_count);
}
#endif /* CONFIG_NET_STATISTICS_WIFI && CONFIG_NET_STATISTICS_USER_API */
static int cmd_wifi_stats(const struct shell *sh, size_t argc, char *argv[])
{
#if defined(CONFIG_NET_STATISTICS_WIFI) && \
defined(CONFIG_NET_STATISTICS_USER_API)
struct net_if *iface = net_if_get_wifi_sta();
struct net_stats_wifi stats = { 0 };
int ret;
context.sh = sh;
if (argc == 1) {
ret = net_mgmt(NET_REQUEST_STATS_GET_WIFI, iface,
&stats, sizeof(stats));
if (!ret) {
print_wifi_stats(iface, &stats, sh);
}
}
if (argc > 1) {
if (!strncasecmp(argv[1], "reset", 5)) {
ret = net_mgmt(NET_REQUEST_STATS_RESET_WIFI, iface,
&stats, sizeof(stats));
if (!ret) {
PR("Wi-Fi interface statistics have been reset.\n");
}
} else if (!strncasecmp(argv[1], "help", 4)) {
shell_help(sh);
} else {
PR_WARNING("Invalid argument\n");
shell_help(sh);
return -ENOEXEC;
}
}
#else
ARG_UNUSED(argc);
ARG_UNUSED(argv);
PR_INFO("Set %s to enable %s support.\n",
"CONFIG_NET_STATISTICS_WIFI and CONFIG_NET_STATISTICS_USER_API",
"statistics");
#endif /* CONFIG_NET_STATISTICS_WIFI && CONFIG_NET_STATISTICS_USER_API */
return 0;
}
static int cmd_wifi_11k(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_11k_params params = { 0 };
context.sh = sh;
if (argc > 2) {
PR_WARNING("Invalid number of arguments\n");
return -ENOEXEC;
}
if (argc == 1) {
params.oper = WIFI_MGMT_GET;
} else {
params.oper = WIFI_MGMT_SET;
if (!strncasecmp(argv[1], "enable", 2)) {
params.enable_11k = true;
} else if (!strncasecmp(argv[1], "disable", 3)) {
params.enable_11k = false;
} else {
PR_WARNING("Invalid argument\n");
return -ENOEXEC;
}
}
if (net_mgmt(NET_REQUEST_WIFI_11K_CONFIG, iface, &params, sizeof(params))) {
PR_WARNING("11k enable/disable failed\n");
return -ENOEXEC;
}
if (params.oper == WIFI_MGMT_GET) {
PR("11k is %s\n", params.enable_11k ? "enabled" : "disabled");
} else {
PR("%s %s requested\n", argv[0], argv[1]);
}
return 0;
}
static int cmd_wifi_11k_neighbor_request(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_11k_params params = { 0 };
context.sh = sh;
if ((argc != 1 && argc != 3) || (argc == 3 && strncasecmp("ssid", argv[1], 4))) {
PR_WARNING("Invalid input arguments\n");
PR_WARNING("Usage: %s\n", argv[0]);
PR_WARNING("or %s ssid <ssid>\n", argv[0]);
return -ENOEXEC;
}
if (argc == 3) {
if (strlen(argv[2]) > (sizeof(params.ssid) - 1)) {
PR_WARNING("Error: ssid too long\n");
return -ENOEXEC;
}
(void)memcpy((void *)params.ssid, (const void *)argv[2],
(size_t)strlen(argv[2]));
}
if (net_mgmt(NET_REQUEST_WIFI_11K_NEIGHBOR_REQUEST, iface, &params, sizeof(params))) {
PR_WARNING("11k neighbor request failed\n");
return -ENOEXEC;
}
if (argc == 3) {
PR("%s %s %s requested\n", argv[0], argv[1], argv[2]);
} else {
PR("%s requested\n", argv[0]);
}
return 0;
}
static int cmd_wifi_ps(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_ps_params params = { 0 };
context.sh = sh;
if (argc > 2) {
PR_WARNING("Invalid number of arguments\n");
return -ENOEXEC;
}
if (argc == 1) {
struct wifi_ps_config config = { 0 };
if (net_mgmt(NET_REQUEST_WIFI_PS_CONFIG, iface,
&config, sizeof(config))) {
PR_WARNING("Failed to get PS config\n");
return -ENOEXEC;
}
PR("PS status: %s\n",
wifi_ps_txt(config.ps_params.enabled));
if (config.ps_params.enabled) {
PR("PS mode: %s\n",
wifi_ps_mode_txt(config.ps_params.mode));
}
PR("PS listen_interval: %d\n",
config.ps_params.listen_interval);
PR("PS wake up mode: %s\n",
config.ps_params.wakeup_mode ? "Listen interval" : "DTIM");
if (config.ps_params.timeout_ms) {
PR("PS timeout: %d ms\n",
config.ps_params.timeout_ms);
} else {
PR("PS timeout: disabled\n");
}
shell_fprintf(sh, SHELL_NORMAL, "PS exit strategy: %s\n",
wifi_ps_exit_strategy_txt(config.ps_params.exit_strategy));
if (config.num_twt_flows == 0) {
PR("No TWT flows\n");
} else {
for (int i = 0; i < config.num_twt_flows; i++) {
print_twt_params(
config.twt_flows[i].dialog_token,
config.twt_flows[i].flow_id,
config.twt_flows[i].negotiation_type,
config.twt_flows[i].responder,
config.twt_flows[i].implicit,
config.twt_flows[i].announce,
config.twt_flows[i].trigger,
config.twt_flows[i].twt_wake_interval,
config.twt_flows[i].twt_interval);
PR("TWT Wake ahead duration : %d us\n",
config.twt_flows[i].twt_wake_ahead_duration);
}
}
return 0;
}
if (!strncasecmp(argv[1], "on", 2)) {
params.enabled = WIFI_PS_ENABLED;
} else if (!strncasecmp(argv[1], "off", 3)) {
params.enabled = WIFI_PS_DISABLED;
} else {
PR_WARNING("Invalid argument\n");
return -ENOEXEC;
}
params.type = WIFI_PS_PARAM_STATE;
if (net_mgmt(NET_REQUEST_WIFI_PS, iface, &params, sizeof(params))) {
PR_WARNING("PS %s failed. Reason: %s\n",
params.enabled ? "enable" : "disable",
wifi_ps_get_config_err_code_str(params.fail_reason));
return -ENOEXEC;
}
PR("%s\n", wifi_ps_txt(params.enabled));
return 0;
}
static int cmd_wifi_ps_mode(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_ps_params params = { 0 };
context.sh = sh;
if (!strncasecmp(argv[1], "legacy", 6)) {
params.mode = WIFI_PS_MODE_LEGACY;
} else if (!strncasecmp(argv[1], "WMM", 3)) {
params.mode = WIFI_PS_MODE_WMM;
} else {
PR_WARNING("Invalid PS mode\n");
return -ENOEXEC;
}
params.type = WIFI_PS_PARAM_MODE;
if (net_mgmt(NET_REQUEST_WIFI_PS, iface, &params, sizeof(params))) {
PR_WARNING("%s failed Reason : %s\n",
wifi_ps_mode_txt(params.mode),
wifi_ps_get_config_err_code_str(params.fail_reason));
return -ENOEXEC;
}
PR("%s\n", wifi_ps_mode_txt(params.mode));
return 0;
}
static int cmd_wifi_ps_timeout(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_ps_params params = { 0 };
long timeout_ms = 0;
int err = 0;
context.sh = sh;
timeout_ms = shell_strtol(argv[1], 10, &err);
if (err) {
shell_error(sh, "Unable to parse input (err %d)", err);
return err;
}
params.timeout_ms = timeout_ms;
params.type = WIFI_PS_PARAM_TIMEOUT;
if (net_mgmt(NET_REQUEST_WIFI_PS, iface, &params, sizeof(params))) {
PR_WARNING("Setting PS timeout failed. Reason : %s\n",
wifi_ps_get_config_err_code_str(params.fail_reason));
return -ENOEXEC;
}
if (params.timeout_ms) {
PR("PS timeout: %d ms\n", params.timeout_ms);
} else {
PR("PS timeout: disabled\n");
}
return 0;
}
static int cmd_wifi_twt_setup_quick(const struct shell *sh, size_t argc,
char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_twt_params params = { 0 };
int idx = 1;
long value;
double twt_mantissa_scale = 0.0;
double twt_interval_scale = 0.0;
uint16_t scale = 1000;
int exponent = 0;
context.sh = sh;
/* Sensible defaults */
params.operation = WIFI_TWT_SETUP;
params.negotiation_type = WIFI_TWT_INDIVIDUAL;
params.setup_cmd = WIFI_TWT_SETUP_CMD_REQUEST;
params.dialog_token = 1;
params.flow_id = 0;
params.setup.responder = 0;
params.setup.implicit = 1;
params.setup.trigger = 0;
params.setup.announce = 0;
if (!parse_number(sh, &value, argv[idx++], NULL, 1, WIFI_MAX_TWT_WAKE_INTERVAL_US)) {
return -EINVAL;
}
params.setup.twt_wake_interval = (uint32_t)value;
if (!parse_number(sh, &value, argv[idx++], NULL, 1, WIFI_MAX_TWT_INTERVAL_US)) {
return -EINVAL;
}
params.setup.twt_interval = (uint64_t)value;
/* control the region of mantissa filed */
twt_interval_scale = (double)(params.setup.twt_interval / scale);
/* derive mantissa and exponent from interval */
twt_mantissa_scale = frexp(twt_interval_scale, &exponent);
params.setup.twt_mantissa = ceil(twt_mantissa_scale * scale);
params.setup.twt_exponent = exponent;
if (net_mgmt(NET_REQUEST_WIFI_TWT, iface, &params, sizeof(params))) {
PR_WARNING("%s with %s failed, reason : %s\n",
wifi_twt_operation_txt(params.operation),
wifi_twt_negotiation_type_txt(params.negotiation_type),
wifi_twt_get_err_code_str(params.fail_reason));
return -ENOEXEC;
}
PR("TWT operation %s with dg: %d, flow_id: %d requested\n",
wifi_twt_operation_txt(params.operation),
params.dialog_token, params.flow_id);
return 0;
}
static int cmd_wifi_btwt_setup(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_SAP, argc, argv);
struct wifi_twt_params params = {0};
int idx = 1;
int err = 0;
context.sh = sh;
params.btwt.btwt_sta_wait = (uint8_t)shell_strtol(argv[idx++], 10, &err);
if (err) {
PR_ERROR("Parse btwt sta_wait (err %d)\n", err);
return -EINVAL;
}
params.btwt.btwt_offset = (uint16_t)shell_strtol(argv[idx++], 10, &err);
if (err) {
PR_ERROR("Parse btwt offset (err %d)\n", err);
return -EINVAL;
}
params.btwt.btwt_li = (uint8_t)shell_strtol(argv[idx++], 10, &err);
if (err) {
PR_ERROR("Parse btwt_li (err %d)\n", err);
return -EINVAL;
}
params.btwt.btwt_count = (uint8_t)shell_strtol(argv[idx++], 10, &err);
if (err) {
PR_ERROR("Parse btwt count (err %d)\n", err);
return -EINVAL;
}
if (params.btwt.btwt_count < 2 || params.btwt.btwt_count > 5) {
PR_ERROR("Invalid broadcast twt count. Count rang: 2-5.\n");
return -EINVAL;
}
if (argc != 5 + params.btwt.btwt_count * 4) {
PR_ERROR("Invalid number of broadcast parameters.\n");
return -EINVAL;
}
for (int i = 0; i < params.btwt.btwt_count; i++) {
params.btwt.btwt_set_cfg[i].btwt_id
= (uint8_t)shell_strtol(argv[idx++], 10, &err);
if (err) {
PR_ERROR("Parse btwt [%d] id (err %d)\n", i, err);
return -EINVAL;
}
params.btwt.btwt_set_cfg[i].btwt_mantissa
= (uint16_t)shell_strtol(argv[idx++], 10, &err);
if (err) {
PR_ERROR("Parse btwt [%d] mantissa (err %d)\n", i, err);
return -EINVAL;
}
params.btwt.btwt_set_cfg[i].btwt_exponent
= (uint8_t)shell_strtol(argv[idx++], 10, &err);
if (err) {
PR_ERROR("Parse btwt [%d] exponent (err %d)\n", i, err);
return -EINVAL;
}
params.btwt.btwt_set_cfg[i].btwt_nominal_wake
= (uint8_t)shell_strtol(argv[idx++], 10, &err);
if (err) {
PR_ERROR("Parse btwt [%d] nominal_wake (err %d)\n", i, err);
return -EINVAL;
}
}
if (net_mgmt(NET_REQUEST_WIFI_BTWT, iface, &params, sizeof(params))) {
PR_WARNING("Failed reason : %s\n",
wifi_twt_get_err_code_str(params.fail_reason));
return -ENOEXEC;
}
PR("BTWT setup\n");
return 0;
}
static int twt_args_to_params(const struct shell *sh, size_t argc, char *argv[],
struct wifi_twt_params *params)
{
int opt;
int opt_index = 0;
struct getopt_state *state;
long value;
double twt_mantissa_scale = 0.0;
double twt_interval_scale = 0.0;
uint16_t scale = 1000;
int exponent = 0;
static const struct option long_options[] = {
{"negotiation-type", required_argument, 0, 'n'},
{"setup-cmd", required_argument, 0, 'c'},
{"dialog-token", required_argument, 0, 't'},
{"flow-id", required_argument, 0, 'f'},
{"responder", required_argument, 0, 'r'},
{"trigger", required_argument, 0, 'T'},
{"implicit", required_argument, 0, 'I'},
{"announce", required_argument, 0, 'a'},
{"wake-interval", required_argument, 0, 'w'},
{"interval", required_argument, 0, 'p'},
{"wake-ahead-duration", required_argument, 0, 'D'},
{"info-disable", required_argument, 0, 'd'},
{"exponent", required_argument, 0, 'e'},
{"mantissa", required_argument, 0, 'm'},
{"iface", required_argument, 0, 'i'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}};
params->operation = WIFI_TWT_SETUP;
while ((opt = getopt_long(argc, argv, "n:c:t:f:r:T:I:a:t:w:p:D:d:e:m:i:h",
long_options, &opt_index)) != -1) {
state = getopt_state_get();
switch (opt) {
case 'n':
if (!parse_number(sh, &value, state->optarg, NULL,
WIFI_TWT_INDIVIDUAL,
WIFI_TWT_WAKE_TBTT)) {
return -EINVAL;
}
params->negotiation_type = (enum wifi_twt_negotiation_type)value;
break;
case 'c':
if (!parse_number(sh, &value, state->optarg, NULL,
WIFI_TWT_SETUP_CMD_REQUEST,
WIFI_TWT_SETUP_CMD_DEMAND)) {
return -EINVAL;
}
params->setup_cmd = (enum wifi_twt_setup_cmd)value;
break;
case 't':
if (!parse_number(sh, &value, state->optarg, NULL, 1, 255)) {
return -EINVAL;
}
params->dialog_token = (uint8_t)value;
break;
case 'f':
if (!parse_number(sh, &value, state->optarg, NULL, 0,
(WIFI_MAX_TWT_FLOWS - 1))) {
return -EINVAL;
}
params->flow_id = (uint8_t)value;
break;
case 'r':
if (!parse_number(sh, &value, state->optarg, NULL, 0, 1)) {
return -EINVAL;
}
params->setup.responder = (bool)value;
break;
case 'T':
if (!parse_number(sh, &value, state->optarg, NULL, 0, 1)) {
return -EINVAL;
}
params->setup.trigger = (bool)value;
break;
case 'I':
if (!parse_number(sh, &value, state->optarg, NULL, 0, 1)) {
return -EINVAL;
}
params->setup.implicit = (bool)value;
break;
case 'a':
if (!parse_number(sh, &value, state->optarg, NULL, 0, 1)) {
return -EINVAL;
}
params->setup.announce = (bool)value;
break;
case 'w':
if (!parse_number(sh, &value, state->optarg, NULL, 1,
WIFI_MAX_TWT_WAKE_INTERVAL_US)) {
return -EINVAL;
}
params->setup.twt_wake_interval = (uint32_t)value;
break;
case 'p':
if (!parse_number(sh, &value, state->optarg, NULL, 1,
WIFI_MAX_TWT_INTERVAL_US)) {
return -EINVAL;
}
params->setup.twt_interval = (uint64_t)value;
break;
case 'D':
if (!parse_number(sh, &value, state->optarg, NULL, 0,
WIFI_MAX_TWT_WAKE_AHEAD_DURATION_US)) {
return -EINVAL;
}
params->setup.twt_wake_ahead_duration = (uint32_t)value;
break;
case 'd':
if (!parse_number(sh, &value, state->optarg, NULL, 0, 1)) {
return -EINVAL;
}
params->setup.twt_info_disable = (bool)value;
break;
case 'e':
if (!parse_number(sh, &value, state->optarg, NULL, 0,
WIFI_MAX_TWT_EXPONENT)) {
return -EINVAL;
}
params->setup.twt_exponent = (uint8_t)value;
break;
case 'm':
if (!parse_number(sh, &value, state->optarg, NULL, 0, 0xFFFF)) {
return -EINVAL;
}
params->setup.twt_mantissa = (uint16_t)value;
break;
case 'i':
/* Unused, but parsing to avoid unknown option error */
break;
case 'h':
return -ENOEXEC;
}
}
if ((params->setup.twt_interval != 0) &&
((params->setup.twt_exponent != 0) ||
(params->setup.twt_mantissa != 0))) {
PR_ERROR("Only one of TWT internal or (mantissa, exponent) should be used\n");
return -EINVAL;
}
if (params->setup.twt_interval) {
/* control the region of mantissa filed */
twt_interval_scale = (double)(params->setup.twt_interval / scale);
/* derive mantissa and exponent from interval */
twt_mantissa_scale = frexp(twt_interval_scale, &exponent);
params->setup.twt_mantissa = ceil(twt_mantissa_scale * scale);
params->setup.twt_exponent = exponent;
} else if ((params->setup.twt_exponent != 0) ||
(params->setup.twt_mantissa != 0)) {
params->setup.twt_interval = floor(ldexp(params->setup.twt_mantissa,
params->setup.twt_exponent));
} else {
PR_ERROR("Either TWT interval or (mantissa, exponent) is needed\n");
return -EINVAL;
}
return 0;
}
static int cmd_wifi_twt_setup(const struct shell *sh, size_t argc,
char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_twt_params params = { 0 };
context.sh = sh;
if (twt_args_to_params(sh, argc, argv, &params)) {
shell_help(sh);
return -ENOEXEC;
}
if (net_mgmt(NET_REQUEST_WIFI_TWT, iface, &params, sizeof(params))) {
PR_WARNING("%s with %s failed. reason : %s\n",
wifi_twt_operation_txt(params.operation),
wifi_twt_negotiation_type_txt(params.negotiation_type),
wifi_twt_get_err_code_str(params.fail_reason));
return -ENOEXEC;
}
PR("TWT operation %s with dg: %d, flow_id: %d requested\n",
wifi_twt_operation_txt(params.operation),
params.dialog_token, params.flow_id);
return 0;
}
static int cmd_wifi_twt_teardown(const struct shell *sh, size_t argc,
char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_twt_params params = { 0 };
long value;
context.sh = sh;
int idx = 1;
params.operation = WIFI_TWT_TEARDOWN;
if (!parse_number(sh, &value, argv[idx++], NULL, WIFI_TWT_INDIVIDUAL,
WIFI_TWT_WAKE_TBTT)) {
return -EINVAL;
}
params.negotiation_type = (enum wifi_twt_negotiation_type)value;
if (!parse_number(sh, &value, argv[idx++], NULL, WIFI_TWT_SETUP_CMD_REQUEST,
WIFI_TWT_SETUP_CMD_DEMAND)) {
return -EINVAL;
}
params.setup_cmd = (enum wifi_twt_setup_cmd)value;
if (!parse_number(sh, &value, argv[idx++], NULL, 1, 255)) {
return -EINVAL;
}
params.dialog_token = (uint8_t)value;
if (!parse_number(sh, &value, argv[idx++], NULL, 0, (WIFI_MAX_TWT_FLOWS - 1))) {
return -EINVAL;
}
params.flow_id = (uint8_t)value;
if (net_mgmt(NET_REQUEST_WIFI_TWT, iface, &params, sizeof(params))) {
PR_WARNING("%s with %s failed, reason : %s\n",
wifi_twt_operation_txt(params.operation),
wifi_twt_negotiation_type_txt(params.negotiation_type),
wifi_twt_get_err_code_str(params.fail_reason));
return -ENOEXEC;
}
PR("TWT operation %s with dg: %d, flow_id: %d success\n",
wifi_twt_operation_txt(params.operation),
params.dialog_token, params.flow_id);
return 0;
}
static int cmd_wifi_twt_teardown_all(const struct shell *sh, size_t argc,
char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_twt_params params = { 0 };
context.sh = sh;
params.operation = WIFI_TWT_TEARDOWN;
params.teardown.teardown_all = 1;
if (net_mgmt(NET_REQUEST_WIFI_TWT, iface, &params, sizeof(params))) {
PR_WARNING("%s with %s failed, reason : %s\n",
wifi_twt_operation_txt(params.operation),
wifi_twt_negotiation_type_txt(params.negotiation_type),
wifi_twt_get_err_code_str(params.fail_reason));
return -ENOEXEC;
}
PR("TWT operation %s all flows success\n",
wifi_twt_operation_txt(params.operation));
return 0;
}
static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc,
char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_SAP, argc, argv);
struct wifi_connect_req_params cnx_params = {0};
int ret;
context.sh = sh;
if (__wifi_args_to_params(sh, argc, &argv[0], &cnx_params, WIFI_MODE_AP)) {
shell_help(sh);
return -ENOEXEC;
}
#ifdef CONFIG_WIFI_NM_HOSTAPD_CRYPTO_ENTERPRISE
/* Load the enterprise credentials if needed */
if (cnx_params.security == WIFI_SECURITY_TYPE_EAP_TLS ||
cnx_params.security == WIFI_SECURITY_TYPE_EAP_PEAP_MSCHAPV2 ||
cnx_params.security == WIFI_SECURITY_TYPE_EAP_PEAP_GTC ||
cnx_params.security == WIFI_SECURITY_TYPE_EAP_TTLS_MSCHAPV2 ||
cnx_params.security == WIFI_SECURITY_TYPE_EAP_PEAP_TLS) {
wifi_set_enterprise_creds(sh, iface, 1);
}
#endif
k_mutex_init(&wifi_ap_sta_list_lock);
ret = net_mgmt(NET_REQUEST_WIFI_AP_ENABLE, iface, &cnx_params,
sizeof(struct wifi_connect_req_params));
if (ret) {
PR_WARNING("AP mode enable failed: %s\n", strerror(-ret));
return -ENOEXEC;
}
PR("AP mode enable requested\n");
return 0;
}
static int cmd_wifi_ap_disable(const struct shell *sh, size_t argc,
char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_SAP, argc, argv);
int ret;
ret = net_mgmt(NET_REQUEST_WIFI_AP_DISABLE, iface, NULL, 0);
if (ret) {
PR_WARNING("AP mode disable failed: %s\n", strerror(-ret));
return -ENOEXEC;
}
PR("AP mode disable requested\n");
#ifdef CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES
/* Clear the certificates */
clear_enterprise_creds_params(&context.enterprise_creds_params);
#endif /* CONFIG_WIFI_SHELL_RUNTIME_CERTIFICATES */
return 0;
}
static int cmd_wifi_ap_stations(const struct shell *sh, size_t argc,
char *argv[])
{
size_t id = 1;
ARG_UNUSED(argv);
ARG_UNUSED(argc);
PR("AP stations:\n");
PR("============\n");
k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER);
for (int i = 0; i < CONFIG_WIFI_SHELL_MAX_AP_STA; i++) {
struct wifi_ap_sta_info *sta;
uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")];
if (!sta_list[i].valid) {
continue;
}
sta = &sta_list[i].sta_info;
PR("Station %zu:\n", id++);
PR("==========\n");
PR("MAC: %s\n",
net_sprint_ll_addr_buf(sta->mac,
WIFI_MAC_ADDR_LEN,
mac_string_buf,
sizeof(mac_string_buf)));
PR("Link mode: %s\n",
wifi_link_mode_txt(sta->link_mode));
PR("TWT: %s\n",
sta->twt_capable ? "Supported" : "Not supported");
}
if (id == 1) {
PR("No stations connected\n");
}
k_mutex_unlock(&wifi_ap_sta_list_lock);
return 0;
}
static int cmd_wifi_ap_sta_disconnect(const struct shell *sh, size_t argc,
char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_SAP, argc, argv);
uint8_t mac[6];
int ret;
if (net_bytes_from_str(mac, sizeof(mac), argv[1]) < 0) {
PR_WARNING("Invalid MAC address\n");
return -ENOEXEC;
}
ret = net_mgmt(NET_REQUEST_WIFI_AP_STA_DISCONNECT, iface, mac, sizeof(mac));
if (ret) {
PR_WARNING("AP station disconnect failed: %s\n",
strerror(-ret));
return -ENOEXEC;
}
PR("AP station disconnect requested\n");
return 0;
}
static int wifi_ap_config_args_to_params(const struct shell *sh, size_t argc, char *argv[],
struct wifi_ap_config_params *params)
{
int opt;
int opt_index = 0;
struct getopt_state *state;
static const struct option long_options[] = {
{"max_inactivity", required_argument, 0, 't'},
{"max_num_sta", required_argument, 0, 's'},
#if defined(CONFIG_WIFI_NM_HOSTAPD_AP)
{"ht_capab", required_argument, 0, 'n'},
{"vht_capab", required_argument, 0, 'c'},
#endif
{"iface", required_argument, 0, 'i'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}};
long val;
while ((opt = getopt_long(argc, argv, "t:s:n:c:i:h",
long_options, &opt_index)) != -1) {
state = getopt_state_get();
switch (opt) {
case 't':
if (!parse_number(sh, &val, state->optarg, "max_inactivity",
0, WIFI_AP_STA_MAX_INACTIVITY)) {
return -EINVAL;
}
params->max_inactivity = (uint32_t)val;
params->type |= WIFI_AP_CONFIG_PARAM_MAX_INACTIVITY;
break;
case 's':
if (!parse_number(sh, &val, state->optarg, "max_num_sta",
0, CONFIG_WIFI_MGMT_AP_MAX_NUM_STA)) {
return -EINVAL;
}
params->max_num_sta = (uint32_t)val;
params->type |= WIFI_AP_CONFIG_PARAM_MAX_NUM_STA;
break;
#if defined(CONFIG_WIFI_NM_HOSTAPD_AP)
case 'n':
strncpy(params->ht_capab, state->optarg, WIFI_AP_IEEE_80211_CAPAB_MAX_LEN);
params->type |= WIFI_AP_CONFIG_PARAM_HT_CAPAB;
break;
case 'c':
strncpy(params->vht_capab, state->optarg, WIFI_AP_IEEE_80211_CAPAB_MAX_LEN);
params->type |= WIFI_AP_CONFIG_PARAM_VHT_CAPAB;
break;
#endif
case 'i':
/* Unused, but parsing to avoid unknown option error */
break;
case 'h':
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
default:
PR_ERROR("Invalid option %c\n", state->optopt);
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
}
return 0;
}
static int cmd_wifi_ap_config_params(const struct shell *sh, size_t argc,
char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_SAP, argc, argv);
struct wifi_ap_config_params ap_config_params = { 0 };
int ret = -1;
context.sh = sh;
if (wifi_ap_config_args_to_params(sh, argc, argv, &ap_config_params)) {
return -ENOEXEC;
}
ret = net_mgmt(NET_REQUEST_WIFI_AP_CONFIG_PARAM, iface,
&ap_config_params, sizeof(struct wifi_ap_config_params));
if (ret) {
PR_WARNING("Setting AP parameter failed: %s\n",
strerror(-ret));
return -ENOEXEC;
}
return 0;
}
static int cmd_wifi_ap_set_rts_threshold(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_SAP, argc, argv);
unsigned int rts_threshold = -1; /* Default value if user supplies "off" argument */
int err = 0;
context.sh = sh;
if (strcmp(argv[1], "off") != 0) {
long rts_val = shell_strtol(argv[1], 10, &err);
if (err) {
shell_error(sh, "Unable to parse input (err %d)", err);
return err;
}
rts_threshold = (unsigned int)rts_val;
}
if (net_mgmt(NET_REQUEST_WIFI_AP_RTS_THRESHOLD, iface,
&rts_threshold, sizeof(rts_threshold))) {
shell_fprintf(sh, SHELL_WARNING,
"Setting RTS threshold failed.\n");
return -ENOEXEC;
}
if ((int)rts_threshold >= 0)
shell_fprintf(sh, SHELL_NORMAL, "RTS threshold: %d\n", rts_threshold);
else
shell_fprintf(sh, SHELL_NORMAL, "RTS threshold is off\n");
return 0;
}
static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc,
char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_reg_domain regd = {0};
int ret, chan_idx = 0;
int opt;
bool force = false;
bool verbose = false;
int opt_index = 0;
static const struct option long_options[] = {
{"force", no_argument, 0, 'f'},
{"verbose", no_argument, 0, 'v'},
{"iface", required_argument, 0, 'i'},
{NULL, 0, NULL, 0}
};
while ((opt = getopt_long(argc, argv, "fvi:", long_options, &opt_index)) != -1) {
switch (opt) {
case 'f':
force = true;
break;
case 'v':
verbose = true;
break;
case 'i':
/* Unused, but parsing to avoid unknown option error */
break;
default:
return -ENOEXEC;
}
}
if (optind == argc) {
regd.chan_info = &chan_info[0];
regd.oper = WIFI_MGMT_GET;
} else if (optind == argc - 1) {
if (strlen(argv[optind]) != 2) {
PR_WARNING("Invalid reg domain: Length should be two letters/digits\n");
return -ENOEXEC;
}
/* Two letter country code with special case of 00 for WORLD */
if (((argv[optind][0] < 'A' || argv[optind][0] > 'Z') ||
(argv[optind][1] < 'A' || argv[optind][1] > 'Z')) &&
(argv[optind][0] != '0' || argv[optind][1] != '0')) {
PR_WARNING("Invalid reg domain %c%c\n", argv[optind][0], argv[optind][1]);
return -ENOEXEC;
}
regd.country_code[0] = argv[optind][0];
regd.country_code[1] = argv[optind][1];
regd.force = force;
regd.oper = WIFI_MGMT_SET;
} else {
return -ENOEXEC;
}
ret = net_mgmt(NET_REQUEST_WIFI_REG_DOMAIN, iface,
&regd, sizeof(regd));
if (ret) {
PR_WARNING("Cannot %s Regulatory domain: %d\n",
regd.oper == WIFI_MGMT_GET ? "get" : "set", ret);
return -ENOEXEC;
}
if (regd.oper == WIFI_MGMT_GET) {
PR("Wi-Fi Regulatory domain is: %c%c\n",
regd.country_code[0], regd.country_code[1]);
if (!verbose) {
return 0;
}
PR("<channel>\t<center frequency>\t<supported(y/n)>\t"
"<max power(dBm)>\t<passive transmission only(y/n)>\t<DFS supported(y/n)>\n");
for (chan_idx = 0; chan_idx < regd.num_channels; chan_idx++) {
PR(" %d\t\t\t%d\t\t\t%s\t\t\t%d\t\t\t%s\t\t\t\t%s\n",
wifi_freq_to_channel(chan_info[chan_idx].center_frequency),
chan_info[chan_idx].center_frequency,
chan_info[chan_idx].supported ? "y" : "n",
chan_info[chan_idx].max_power,
chan_info[chan_idx].passive_only ? "y" : "n",
chan_info[chan_idx].dfs ? "y" : "n");
}
} else {
PR("Wi-Fi Regulatory domain set to: %c%c\n",
regd.country_code[0], regd.country_code[1]);
}
return 0;
}
static int cmd_wifi_listen_interval(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_ps_params params = { 0 };
long interval;
context.sh = sh;
if (!parse_number(sh, &interval, argv[1], NULL,
WIFI_LISTEN_INTERVAL_MIN,
WIFI_LISTEN_INTERVAL_MAX)) {
return -EINVAL;
}
params.listen_interval = interval;
params.type = WIFI_PS_PARAM_LISTEN_INTERVAL;
if (net_mgmt(NET_REQUEST_WIFI_PS, iface, &params, sizeof(params))) {
if (params.fail_reason ==
WIFI_PS_PARAM_LISTEN_INTERVAL_RANGE_INVALID) {
PR_WARNING("Setting listen interval failed. Reason :%s\n",
wifi_ps_get_config_err_code_str(params.fail_reason));
} else {
PR_WARNING("Setting listen interval failed. Reason :%s\n",
wifi_ps_get_config_err_code_str(params.fail_reason));
}
return -ENOEXEC;
}
PR("Listen interval %hu\n", params.listen_interval);
return 0;
}
static int cmd_wifi_btm_query(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
uint8_t query_reason = 0;
long tmp = 0;
context.sh = sh;
if (!parse_number(sh, &tmp, argv[1], NULL,
WIFI_BTM_QUERY_REASON_UNSPECIFIED, WIFI_BTM_QUERY_REASON_LEAVING_ESS)) {
return -EINVAL;
}
query_reason = tmp;
if (net_mgmt(NET_REQUEST_WIFI_BTM_QUERY, iface, &query_reason, sizeof(query_reason))) {
PR_WARNING("Setting BTM query Reason failed. Reason : %d\n", query_reason);
return -ENOEXEC;
}
PR("Query reason %d\n", query_reason);
return 0;
}
static int cmd_wifi_wps_pbc(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_wps_config_params params = {0};
context.sh = sh;
if (argc == 1) {
params.oper = WIFI_WPS_PBC;
} else {
shell_help(sh);
return -ENOEXEC;
}
if (net_mgmt(NET_REQUEST_WIFI_WPS_CONFIG, iface, &params, sizeof(params))) {
PR_WARNING("Start wps pbc connection failed\n");
return -ENOEXEC;
}
return 0;
}
static int cmd_wifi_wps_pin(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_wps_config_params params = {0};
context.sh = sh;
if (argc == 1) {
params.oper = WIFI_WPS_PIN_GET;
} else if (argc == 2) {
params.oper = WIFI_WPS_PIN_SET;
strncpy(params.pin, argv[1], WIFI_WPS_PIN_MAX_LEN);
} else {
shell_help(sh);
return -ENOEXEC;
}
if (net_mgmt(NET_REQUEST_WIFI_WPS_CONFIG, iface, &params, sizeof(params))) {
PR_WARNING("Start wps pin connection failed\n");
return -ENOEXEC;
}
if (params.oper == WIFI_WPS_PIN_GET) {
PR("WPS PIN is: %s\n", params.pin);
}
return 0;
}
static int cmd_wifi_ap_wps_pbc(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_SAP, argc, argv);
struct wifi_wps_config_params params = {0};
context.sh = sh;
if (argc == 1) {
params.oper = WIFI_WPS_PBC;
} else {
shell_help(sh);
return -ENOEXEC;
}
if (net_mgmt(NET_REQUEST_WIFI_WPS_CONFIG, iface, &params, sizeof(params))) {
PR_WARNING("Start AP WPS PBC failed\n");
return -ENOEXEC;
}
return 0;
}
static int cmd_wifi_ap_wps_pin(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_SAP, argc, argv);
struct wifi_wps_config_params params = {0};
context.sh = sh;
if (argc == 1) {
params.oper = WIFI_WPS_PIN_GET;
} else if (argc == 2) {
params.oper = WIFI_WPS_PIN_SET;
strncpy(params.pin, argv[1], WIFI_WPS_PIN_MAX_LEN);
} else {
shell_help(sh);
return -ENOEXEC;
}
if (net_mgmt(NET_REQUEST_WIFI_WPS_CONFIG, iface, &params, sizeof(params))) {
PR_WARNING("Start AP WPS PIN failed\n");
return -ENOEXEC;
}
if (params.oper == WIFI_WPS_PIN_GET) {
PR("WPS PIN is: %s\n", params.pin);
}
return 0;
}
static int cmd_wifi_ps_wakeup_mode(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_ps_params params = { 0 };
context.sh = sh;
if (!strncasecmp(argv[1], "dtim", 4)) {
params.wakeup_mode = WIFI_PS_WAKEUP_MODE_DTIM;
} else if (!strncasecmp(argv[1], "listen_interval", 15)) {
params.wakeup_mode = WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL;
} else {
PR_WARNING("Invalid argument\n");
PR_INFO("Valid argument : <dtim> / <listen_interval>\n");
return -ENOEXEC;
}
params.type = WIFI_PS_PARAM_WAKEUP_MODE;
if (net_mgmt(NET_REQUEST_WIFI_PS, iface, &params, sizeof(params))) {
PR_WARNING("Setting PS wake up mode to %s failed..Reason :%s\n",
params.wakeup_mode ? "Listen interval" : "DTIM interval",
wifi_ps_get_config_err_code_str(params.fail_reason));
return -ENOEXEC;
}
PR("%s\n", wifi_ps_wakeup_mode_txt(params.wakeup_mode));
return 0;
}
static int cmd_wifi_set_rts_threshold(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
unsigned int rts_threshold = -1; /* Default value if user supplies "off" argument */
int err = 0;
context.sh = sh;
if (argc > 2) {
PR_WARNING("Invalid number of arguments\n");
return -ENOEXEC;
}
if (argc == 1) {
if (net_mgmt(NET_REQUEST_WIFI_RTS_THRESHOLD_CONFIG, iface,
&rts_threshold, sizeof(rts_threshold))) {
PR_WARNING("Failed to get rts_threshold\n");
return -ENOEXEC;
}
if ((int)rts_threshold < 0) {
PR("RTS threshold is off\n");
} else {
PR("RTS threshold: %d\n", rts_threshold);
}
}
if (argc == 2) {
if (strcmp(argv[1], "off") != 0) {
long rts_val = shell_strtol(argv[1], 10, &err);
if (err) {
shell_error(sh, "Unable to parse input (err %d)", err);
return err;
}
rts_threshold = (unsigned int)rts_val;
}
if (net_mgmt(NET_REQUEST_WIFI_RTS_THRESHOLD, iface,
&rts_threshold, sizeof(rts_threshold))) {
shell_fprintf(sh, SHELL_WARNING,
"Setting RTS threshold failed.\n");
return -ENOEXEC;
}
if ((int)rts_threshold >= 0) {
shell_fprintf(sh, SHELL_NORMAL, "RTS threshold: %d\n", rts_threshold);
} else {
shell_fprintf(sh, SHELL_NORMAL, "RTS threshold is off\n");
}
}
return 0;
}
static int cmd_wifi_ps_exit_strategy(const struct shell *sh, size_t argc,
char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_ps_params params = { 0 };
context.sh = sh;
if (!strncmp(argv[1], "tim", 3)) {
params.exit_strategy = WIFI_PS_EXIT_EVERY_TIM;
} else if (!strncmp(argv[1], "custom", 6)) {
params.exit_strategy = WIFI_PS_EXIT_CUSTOM_ALGO;
} else {
shell_fprintf(sh, SHELL_WARNING, "Invalid argument\n");
shell_fprintf(sh, SHELL_INFO, "Valid argument : <tim> / <custom>\n");
return -ENOEXEC;
}
params.type = WIFI_PS_PARAM_EXIT_STRATEGY;
if (net_mgmt(NET_REQUEST_WIFI_PS, iface, &params, sizeof(params))) {
shell_fprintf(sh, SHELL_WARNING,
"Setting PS exit strategy to %s failed..Reason :%s\n",
wifi_ps_exit_strategy_txt(params.exit_strategy),
wifi_ps_get_config_err_code_str(params.fail_reason));
return -ENOEXEC;
}
shell_fprintf(sh, SHELL_NORMAL, "%s\n",
wifi_ps_exit_strategy_txt(params.exit_strategy));
return 0;
}
void parse_mode_args_to_params(const struct shell *sh, int argc,
char *argv[], struct wifi_mode_info *mode,
bool *do_mode_oper)
{
int opt;
int opt_index = 0;
int opt_num = 0;
struct getopt_state *state;
static const struct option long_options[] = {
{"iface", required_argument, 0, 'i'},
{"sta", no_argument, 0, 's'},
{"monitor", no_argument, 0, 'm'},
{"ap", no_argument, 0, 'a'},
{"softap", no_argument, 0, 'k'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}};
mode->oper = WIFI_MGMT_GET;
while ((opt = getopt_long(argc, argv, "i:smtpakh",
long_options, &opt_index)) != -1) {
state = getopt_state_get();
switch (opt) {
case 's':
mode->mode |= WIFI_STA_MODE;
opt_num++;
break;
case 'm':
mode->mode |= WIFI_MONITOR_MODE;
opt_num++;
break;
case 'a':
mode->mode |= WIFI_AP_MODE;
opt_num++;
break;
case 'k':
mode->mode |= WIFI_SOFTAP_MODE;
opt_num++;
break;
case 'i':
mode->if_index = (uint8_t)atoi(state->optarg);
/* Don't count iface as it's common for both get and set */
break;
case 'h':
shell_help(sh);
*do_mode_oper = false;
opt_num++;
break;
case '?':
default:
break;
}
}
if (opt_num != 0) {
mode->oper = WIFI_MGMT_SET;
}
}
static int cmd_wifi_mode(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface;
struct wifi_mode_info mode_info = {0};
int ret;
bool do_mode_oper = true;
parse_mode_args_to_params(sh, argc, argv, &mode_info, &do_mode_oper);
if (do_mode_oper) {
/* Check interface index value. Mode validation must be performed by
* lower layer
*/
if (mode_info.if_index == 0) {
iface = net_if_get_wifi_sta();
if (iface == NULL) {
PR_ERROR("Cannot find the default wifi interface\n");
return -ENOEXEC;
}
mode_info.if_index = net_if_get_by_iface(iface);
} else {
iface = net_if_get_by_index(mode_info.if_index);
if (iface == NULL) {
PR_ERROR("Cannot find interface for if_index %d\n",
mode_info.if_index);
return -ENOEXEC;
}
}
ret = net_mgmt(NET_REQUEST_WIFI_MODE, iface, &mode_info, sizeof(mode_info));
if (ret) {
PR_ERROR("mode %s operation failed with reason %d\n",
mode_info.oper == WIFI_MGMT_GET ? "get" : "set", ret);
return -ENOEXEC;
}
if (mode_info.oper == WIFI_MGMT_GET) {
PR("Wi-Fi current mode is %x\n", mode_info.mode);
} else {
PR("Wi-Fi mode set to %x\n", mode_info.mode);
}
}
return 0;
}
void parse_channel_args_to_params(const struct shell *sh, int argc,
char *argv[], struct wifi_channel_info *channel,
bool *do_channel_oper)
{
int opt;
int opt_index = 0;
struct getopt_state *state;
static const struct option long_options[] = {
{"iface", optional_argument, 0, 'i'},
{"channel", required_argument, 0, 'c'},
{"get", no_argument, 0, 'g'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}};
while ((opt = getopt_long(argc, argv, "i:c:gh",
long_options, &opt_index)) != -1) {
state = getopt_state_get();
switch (opt) {
case 'c':
channel->channel = (uint16_t)atoi(state->optarg);
break;
case 'i':
channel->if_index = (uint8_t)atoi(state->optarg);
break;
case 'g':
channel->oper = WIFI_MGMT_GET;
break;
case 'h':
shell_help(sh);
*do_channel_oper = false;
break;
case '?':
default:
break;
}
}
}
static int cmd_wifi_channel(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface;
struct wifi_channel_info channel_info = {0};
int ret;
bool do_channel_oper = true;
channel_info.oper = WIFI_MGMT_SET;
parse_channel_args_to_params(sh, argc, argv, &channel_info, &do_channel_oper);
if (do_channel_oper) {
/*
* Validate parameters before sending to lower layer.
* Do it here instead of parse_channel_args_to_params
* as this is right before sending the parameters to
* the lower layer.
*/
if (channel_info.if_index == 0) {
iface = net_if_get_wifi_sta();
if (iface == NULL) {
PR_ERROR("Cannot find the default wifi interface\n");
return -ENOEXEC;
}
channel_info.if_index = net_if_get_by_iface(iface);
} else {
iface = net_if_get_by_index(channel_info.if_index);
if (iface == NULL) {
PR_ERROR("Cannot find interface for if_index %d\n",
channel_info.if_index);
return -ENOEXEC;
}
}
if (channel_info.oper == WIFI_MGMT_SET) {
if ((channel_info.channel < WIFI_CHANNEL_MIN) ||
(channel_info.channel > WIFI_CHANNEL_MAX)) {
PR_ERROR("Invalid channel number. Range is (1-233)\n");
return -ENOEXEC;
}
}
ret = net_mgmt(NET_REQUEST_WIFI_CHANNEL, iface, &channel_info,
sizeof(channel_info));
if (ret) {
PR_ERROR("channel %s operation failed with reason %d\n",
channel_info.oper == WIFI_MGMT_GET ? "get" : "set", ret);
return -ENOEXEC;
}
if (channel_info.oper == WIFI_MGMT_GET) {
PR("Wi-Fi current channel is: %d\n", channel_info.channel);
} else {
PR("Wi-Fi channel set to %d\n", channel_info.channel);
}
}
return 0;
}
void parse_filter_args_to_params(const struct shell *sh, int argc,
char *argv[], struct wifi_filter_info *filter,
bool *do_filter_oper)
{
int opt;
int opt_index = 0;
struct getopt_state *state;
static const struct option long_options[] = {
{"iface", required_argument, 0, 'i'},
{"capture-len", optional_argument, 0, 'b'},
{"all", no_argument, 0, 'a'},
{"mgmt", no_argument, 0, 'm'},
{"ctrl", no_argument, 0, 'c'},
{"data", no_argument, 0, 'd'},
{"get", no_argument, 0, 'g'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}};
while ((opt = getopt_long(argc, argv, "i:b:amcdgh",
long_options, &opt_index)) != -1) {
state = getopt_state_get();
switch (opt) {
case 'a':
filter->filter |= WIFI_PACKET_FILTER_ALL;
break;
case 'm':
filter->filter |= WIFI_PACKET_FILTER_MGMT;
break;
case 'c':
filter->filter |= WIFI_PACKET_FILTER_CTRL;
break;
case 'd':
filter->filter |= WIFI_PACKET_FILTER_DATA;
break;
case 'i':
filter->if_index = (uint8_t)atoi(state->optarg);
break;
case 'b':
filter->buffer_size = (uint16_t)atoi(state->optarg);
break;
case 'h':
shell_help(sh);
*do_filter_oper = false;
break;
case 'g':
filter->oper = WIFI_MGMT_GET;
break;
case '?':
default:
break;
}
}
}
static int cmd_wifi_packet_filter(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface;
struct wifi_filter_info packet_filter = {0};
int ret;
bool do_filter_oper = true;
packet_filter.oper = WIFI_MGMT_SET;
parse_filter_args_to_params(sh, argc, argv, &packet_filter, &do_filter_oper);
if (do_filter_oper) {
/*
* Validate parameters before sending to lower layer.
* Do it here instead of parse_filter_args_to_params
* as this is right before sending the parameters to
* the lower layer. filter and packet capture length
* value to be verified by the lower layer.
*/
if (packet_filter.if_index == 0) {
iface = net_if_get_wifi_sta();
if (iface == NULL) {
PR_ERROR("Cannot find the default wifi interface\n");
return -ENOEXEC;
}
packet_filter.if_index = net_if_get_by_iface(iface);
} else {
iface = net_if_get_by_index(packet_filter.if_index);
if (iface == NULL) {
PR_ERROR("Cannot find interface for if_index %d\n",
packet_filter.if_index);
return -ENOEXEC;
}
}
ret = net_mgmt(NET_REQUEST_WIFI_PACKET_FILTER, iface, &packet_filter,
sizeof(packet_filter));
if (ret) {
PR_ERROR("Wi-Fi packet filter %s operation failed with reason %d\n",
packet_filter.oper == WIFI_MGMT_GET ? "get" : "set", ret);
return -ENOEXEC;
}
if (packet_filter.oper == WIFI_MGMT_GET) {
PR("Wi-Fi current mode packet filter is %d\n",
packet_filter.filter);
} else {
PR("Wi-Fi mode packet filter set to %d\n",
packet_filter.filter);
}
}
return 0;
}
static int cmd_wifi_version(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_version version = {0};
if (net_mgmt(NET_REQUEST_WIFI_VERSION, iface, &version, sizeof(version))) {
PR_WARNING("Failed to get Wi-Fi versions\n");
return -ENOEXEC;
}
PR("Wi-Fi Driver Version: %s\n", version.drv_version);
PR("Wi-Fi Firmware Version: %s\n", version.fw_version);
return 0;
}
#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_DPP
static int parse_dpp_args_auth_init(const struct shell *sh, size_t argc, char *argv[],
struct wifi_dpp_params *params)
{
int opt;
int opt_index = 0;
struct getopt_state *state;
static const struct option long_options[] = {
{"peer", required_argument, 0, 'p'},
{"role", required_argument, 0, 'r'},
{"configurator", required_argument, 0, 'c'},
{"mode", required_argument, 0, 'm'},
{"ssid", required_argument, 0, 's'},
{"iface", required_argument, 0, 'i'},
{0, 0, 0, 0}};
int ret = 0;
while ((opt = getopt_long(argc, argv, "p:r:c:m:s:i:",
long_options, &opt_index)) != -1) {
state = getopt_state_get();
switch (opt) {
case 'p':
params->auth_init.peer = shell_strtol(state->optarg, 10, &ret);
break;
case 'r':
params->auth_init.role = shell_strtol(state->optarg, 10, &ret);
break;
case 'c':
params->auth_init.configurator = shell_strtol(state->optarg, 10, &ret);
break;
case 'm':
params->auth_init.conf = shell_strtol(state->optarg, 10, &ret);
break;
case 's':
strncpy(params->auth_init.ssid, state->optarg, WIFI_SSID_MAX_LEN);
break;
case 'i':
/* Unused, but parsing to avoid unknown option error */
break;
default:
PR_ERROR("Invalid option %c\n", state->optopt);
return -EINVAL;
}
if (ret) {
PR_ERROR("Invalid argument %d ret %d\n", opt_index, ret);
return -EINVAL;
}
}
return 0;
}
static int parse_dpp_args_chirp(const struct shell *sh, size_t argc, char *argv[],
struct wifi_dpp_params *params)
{
int opt;
int opt_index = 0;
struct getopt_state *state;
static const struct option long_options[] = {
{"own", required_argument, 0, 'o'},
{"freq", required_argument, 0, 'f'},
{"iface", required_argument, 0, 'i'},
{0, 0, 0, 0}};
int ret = 0;
while ((opt = getopt_long(argc, argv, "o:f:i:",
long_options, &opt_index)) != -1) {
state = getopt_state_get();
switch (opt) {
case 'o':
params->chirp.id = shell_strtol(state->optarg, 10, &ret);
break;
case 'f':
params->chirp.freq = shell_strtol(state->optarg, 10, &ret);
break;
case 'i':
/* Unused, but parsing to avoid unknown option error */
break;
default:
PR_ERROR("Invalid option %c\n", state->optopt);
return -EINVAL;
}
if (ret) {
PR_ERROR("Invalid argument %d ret %d\n", opt_index, ret);
return -EINVAL;
}
}
return 0;
}
static int parse_dpp_args_listen(const struct shell *sh, size_t argc, char *argv[],
struct wifi_dpp_params *params)
{
int opt;
int opt_index = 0;
struct getopt_state *state;
static const struct option long_options[] = {
{"role", required_argument, 0, 'r'},
{"freq", required_argument, 0, 'f'},
{"iface", required_argument, 0, 'i'},
{0, 0, 0, 0}};
int ret = 0;
while ((opt = getopt_long(argc, argv, "r:f:i:",
long_options, &opt_index)) != -1) {
state = getopt_state_get();
switch (opt) {
case 'r':
params->listen.role = shell_strtol(state->optarg, 10, &ret);
break;
case 'f':
params->listen.freq = shell_strtol(state->optarg, 10, &ret);
break;
case 'i':
/* Unused, but parsing to avoid unknown option error */
break;
default:
PR_ERROR("Invalid option %c\n", state->optopt);
return -EINVAL;
}
if (ret) {
PR_ERROR("Invalid argument %d ret %d\n", opt_index, ret);
return -EINVAL;
}
}
return 0;
}
static int parse_dpp_args_btstrap_gen(const struct shell *sh, size_t argc, char *argv[],
struct wifi_dpp_params *params)
{
int opt;
int opt_index = 0;
struct getopt_state *state;
static const struct option long_options[] = {
{"type", required_argument, 0, 't'},
{"opclass", required_argument, 0, 'o'},
{"channel", required_argument, 0, 'h'},
{"mac", required_argument, 0, 'a'},
{"iface", required_argument, 0, 'i'},
{0, 0, 0, 0}};
int ret = 0;
while ((opt = getopt_long(argc, argv, "t:o:h:a:i:",
long_options, &opt_index)) != -1) {
state = getopt_state_get();
switch (opt) {
case 't':
params->bootstrap_gen.type = shell_strtol(state->optarg, 10, &ret);
break;
case 'o':
params->bootstrap_gen.op_class = shell_strtol(state->optarg, 10, &ret);
break;
case 'h':
params->bootstrap_gen.chan = shell_strtol(state->optarg, 10, &ret);
break;
case 'a':
ret = net_bytes_from_str(params->bootstrap_gen.mac,
WIFI_MAC_ADDR_LEN, state->optarg);
break;
case 'i':
/* Unused, but parsing to avoid unknown option error */
break;
default:
PR_ERROR("Invalid option %c\n", state->optopt);
return -EINVAL;
}
if (ret) {
PR_ERROR("Invalid argument %d ret %d\n", opt_index, ret);
return -EINVAL;
}
}
/* DPP bootstrap type currently only support qr_code */
if (params->bootstrap_gen.type == 0) {
params->bootstrap_gen.type = WIFI_DPP_BOOTSTRAP_TYPE_QRCODE;
}
if (params->bootstrap_gen.type != WIFI_DPP_BOOTSTRAP_TYPE_QRCODE) {
PR_ERROR("DPP bootstrap type currently only support qr_code\n");
return -ENOTSUP;
}
/* operating class should be set alongside with channel */
if ((params->bootstrap_gen.op_class && !params->bootstrap_gen.chan) ||
(!params->bootstrap_gen.op_class && params->bootstrap_gen.chan)) {
PR_ERROR("Operating class should be set alongside with channel\n");
return -EINVAL;
}
return 0;
}
static int parse_dpp_args_set_config_param(const struct shell *sh, size_t argc, char *argv[],
struct wifi_dpp_params *params)
{
int opt;
int opt_index = 0;
struct getopt_state *state;
static const struct option long_options[] = {
{"configurator", required_argument, 0, 'c'},
{"mode", required_argument, 0, 'm'},
{"ssid", required_argument, 0, 's'},
{"iface", required_argument, 0, 'i'},
{0, 0, 0, 0}};
int ret = 0;
while ((opt = getopt_long(argc, argv, "p:r:c:m:s:i:",
long_options, &opt_index)) != -1) {
state = getopt_state_get();
switch (opt) {
case 'c':
params->configurator_set.configurator =
shell_strtol(state->optarg, 10, &ret);
break;
case 'm':
params->configurator_set.conf = shell_strtol(state->optarg, 10, &ret);
break;
case 's':
strncpy(params->configurator_set.ssid, state->optarg, WIFI_SSID_MAX_LEN);
break;
case 'i':
/* Unused, but parsing to avoid unknown option error */
break;
default:
PR_ERROR("Invalid option %c\n", state->optopt);
return -EINVAL;
}
if (ret) {
PR_ERROR("Invalid argument %d ret %d\n", opt_index, ret);
return -EINVAL;
}
}
return 0;
}
static int cmd_wifi_dpp_configurator_add(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_dpp_params params = {0};
params.action = WIFI_DPP_CONFIGURATOR_ADD;
if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, &params, sizeof(params))) {
PR_WARNING("Failed to request DPP action\n");
return -ENOEXEC;
}
return 0;
}
static int cmd_wifi_dpp_auth_init(const struct shell *sh, size_t argc, char *argv[])
{
int ret;
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_dpp_params params = {0};
params.action = WIFI_DPP_AUTH_INIT;
ret = parse_dpp_args_auth_init(sh, argc, argv, &params);
if (ret) {
PR_ERROR("parse DPP args fail\n");
return -EINVAL;
}
if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, &params, sizeof(params))) {
PR_WARNING("Failed to request DPP action\n");
return -ENOEXEC;
}
return 0;
}
static int cmd_wifi_dpp_qr_code(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_dpp_params params = {0};
params.action = WIFI_DPP_QR_CODE;
if (argc >= 2) {
strncpy(params.dpp_qr_code, argv[1], WIFI_DPP_QRCODE_MAX_LEN);
}
if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, &params, sizeof(params))) {
PR_WARNING("Failed to request DPP action\n");
return -ENOEXEC;
}
return 0;
}
static int cmd_wifi_dpp_chirp(const struct shell *sh, size_t argc, char *argv[])
{
int ret;
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_dpp_params params = {0};
params.action = WIFI_DPP_CHIRP;
ret = parse_dpp_args_chirp(sh, argc, argv, &params);
if (ret) {
PR_ERROR("parse DPP args fail\n");
return -EINVAL;
}
if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, &params, sizeof(params))) {
PR_WARNING("Failed to request DPP action\n");
return -ENOEXEC;
}
return 0;
}
static int cmd_wifi_dpp_listen(const struct shell *sh, size_t argc, char *argv[])
{
int ret;
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_dpp_params params = {0};
params.action = WIFI_DPP_LISTEN;
ret = parse_dpp_args_listen(sh, argc, argv, &params);
if (ret) {
PR_ERROR("parse DPP args fail\n");
return -EINVAL;
}
if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, &params, sizeof(params))) {
PR_WARNING("Failed to request DPP action\n");
return -ENOEXEC;
}
return 0;
}
static int cmd_wifi_dpp_btstrap_gen(const struct shell *sh, size_t argc, char *argv[])
{
int ret;
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_dpp_params params = {0};
params.action = WIFI_DPP_BOOTSTRAP_GEN;
ret = parse_dpp_args_btstrap_gen(sh, argc, argv, &params);
if (ret) {
PR_ERROR("parse DPP args fail\n");
return -EINVAL;
}
if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, &params, sizeof(params))) {
PR_WARNING("Failed to request DPP action\n");
return -ENOEXEC;
}
return 0;
}
static int cmd_wifi_dpp_btstrap_get_uri(const struct shell *sh, size_t argc, char *argv[])
{
int ret = 0;
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_dpp_params params = {0};
params.action = WIFI_DPP_BOOTSTRAP_GET_URI;
if (argc >= 2) {
params.id = shell_strtol(argv[1], 10, &ret);
}
if (ret) {
PR_ERROR("parse DPP args fail\n");
return -EINVAL;
}
if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, &params, sizeof(params))) {
PR_WARNING("Failed to request DPP action\n");
return -ENOEXEC;
}
return 0;
}
static int cmd_wifi_dpp_configurator_set(const struct shell *sh, size_t argc, char *argv[])
{
int ret;
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_dpp_params params = {0};
params.action = WIFI_DPP_SET_CONF_PARAM;
ret = parse_dpp_args_set_config_param(sh, argc, argv, &params);
if (ret) {
PR_ERROR("parse DPP args fail\n");
return -EINVAL;
}
if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, &params, sizeof(params))) {
PR_WARNING("Failed to request DPP action\n");
return -ENOEXEC;
}
return 0;
}
static int cmd_wifi_dpp_resp_timeout_set(const struct shell *sh, size_t argc, char *argv[])
{
int ret = 0;
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_dpp_params params = {0};
params.action = WIFI_DPP_SET_WAIT_RESP_TIME;
if (argc >= 2) {
params.dpp_resp_wait_time = shell_strtol(argv[1], 10, &ret);
}
if (ret) {
PR_ERROR("parse DPP args fail");
return -EINVAL;
}
if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, &params, sizeof(params))) {
PR_WARNING("Failed to request DPP action\n");
return -ENOEXEC;
}
return 0;
}
static int cmd_wifi_dpp_ap_btstrap_gen(const struct shell *sh, size_t argc, char *argv[])
{
int ret;
struct net_if *iface = get_iface(IFACE_TYPE_SAP, argc, argv);
struct wifi_dpp_params params = {0};
params.action = WIFI_DPP_BOOTSTRAP_GEN;
ret = parse_dpp_args_btstrap_gen(sh, argc, argv, &params);
if (ret) {
PR_ERROR("parse DPP args fail\n");
return -EINVAL;
}
if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, &params, sizeof(params))) {
PR_WARNING("Failed to request DPP action\n");
return -ENOEXEC;
}
return 0;
}
static int cmd_wifi_dpp_ap_btstrap_get_uri(const struct shell *sh, size_t argc, char *argv[])
{
int ret = 0;
struct net_if *iface = get_iface(IFACE_TYPE_SAP, argc, argv);
struct wifi_dpp_params params = {0};
params.action = WIFI_DPP_BOOTSTRAP_GET_URI;
if (argc >= 2) {
params.id = shell_strtol(argv[1], 10, &ret);
}
if (ret) {
PR_ERROR("parse DPP args fail\n");
return -EINVAL;
}
if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, &params, sizeof(params))) {
PR_WARNING("Failed to request DPP action\n");
return -ENOEXEC;
}
return 0;
}
static int cmd_wifi_dpp_ap_qr_code(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_SAP, argc, argv);
struct wifi_dpp_params params = {0};
params.action = WIFI_DPP_QR_CODE;
if (argc >= 2) {
strncpy(params.dpp_qr_code, argv[1], WIFI_DPP_QRCODE_MAX_LEN);
}
if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, &params, sizeof(params))) {
PR_WARNING("Failed to request DPP action\n");
return -ENOEXEC;
}
return 0;
}
static int cmd_wifi_dpp_ap_auth_init(const struct shell *sh, size_t argc, char *argv[])
{
int opt;
int opt_index = 0;
struct getopt_state *state;
static const struct option long_options[] = {
{"peer", required_argument, 0, 'p'},
{"iface", required_argument, 0, 'i'},
{0, 0, 0, 0}};
int ret = 0;
struct net_if *iface = get_iface(IFACE_TYPE_SAP, argc, argv);
struct wifi_dpp_params params = {0};
params.action = WIFI_DPP_AUTH_INIT;
while ((opt = getopt_long(argc, argv, "p:i:",
long_options, &opt_index)) != -1) {
state = getopt_state_get();
switch (opt) {
case 'p':
params.auth_init.peer = shell_strtol(state->optarg, 10, &ret);
break;
case 'i':
/* Unused, but parsing to avoid unknown option error */
break;
default:
PR_ERROR("Invalid option %c\n", state->optopt);
return -EINVAL;
}
if (ret) {
PR_ERROR("Invalid argument %d ret %d\n", opt_index, ret);
return -EINVAL;
}
}
/* AP DPP auth only act as enrollee */
params.auth_init.role = WIFI_DPP_ROLE_ENROLLEE;
if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, &params, sizeof(params))) {
PR_WARNING("Failed to request DPP action\n");
return -ENOEXEC;
}
return 0;
}
static int cmd_wifi_dpp_reconfig(const struct shell *sh, size_t argc, char *argv[])
{
int ret = 0;
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
struct wifi_dpp_params params = {0};
params.action = WIFI_DPP_RECONFIG;
if (argc >= 2) {
params.network_id = shell_strtol(argv[1], 10, &ret);
}
if (ret) {
PR_ERROR("parse DPP args fail\n");
return -EINVAL;
}
if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, &params, sizeof(params))) {
PR_WARNING("Failed to request DPP action\n");
return -ENOEXEC;
}
return 0;
}
#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_DPP */
static int cmd_wifi_pmksa_flush(const struct shell *sh, size_t argc, char *argv[])
{
struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv);
context.sh = sh;
if (net_mgmt(NET_REQUEST_WIFI_PMKSA_FLUSH, iface, NULL, 0)) {
PR_WARNING("Flush PMKSA cache entries failed\n");
return -ENOEXEC;
}
return 0;
}
SHELL_STATIC_SUBCMD_SET_CREATE(
wifi_cmd_ap,
SHELL_CMD_ARG(disable, NULL, "Disable Access Point mode.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_ap_disable, 1, 2),
SHELL_CMD_ARG(enable, NULL,
"-s --ssid=<SSID>\n"
"-c --channel=<channel number>\n"
"-p --passphrase=<PSK> (valid only for secure SSIDs)\n"
"-k --key-mgmt=<Security type> (valid only for secure SSIDs)\n"
"0:None, 1:WPA2-PSK, 2:WPA2-PSK-256, 3:SAE-HNP, 4:SAE-H2E, 5:SAE-AUTO, 6:WAPI,"
"7:EAP-TLS, 8:WEP, 9: WPA-PSK, 10: WPA-Auto-Personal, 11: DPP\n"
"12: EAP-PEAP-MSCHAPv2, 13: EAP-PEAP-GTC, 14: EAP-TTLS-MSCHAPv2,\n"
"15: EAP-PEAP-TLS, 20: SAE-EXT-KEY\n"
"-w --ieee-80211w=<MFP> (optional: needs security type to be specified)\n"
"0:Disable, 1:Optional, 2:Required\n"
"-b --band=<band> (2 -2.6GHz, 5 - 5Ghz, 6 - 6GHz)\n"
"-m --bssid=<BSSID>\n"
"-g --ignore-broadcast-ssid=<type>. Hide SSID in AP mode.\n"
"0: disabled (default)\n"
"1: send empty (length=0) SSID in beacon and ignore probe request for "
"broadcast SSID.\n"
"2: clear SSID (ASCII 0), but keep the original length and ignore "
"probe requests for broadcast SSID.\n"
"[-B, --bandwidth=<bandwidth>]: 1:20MHz, 2:40MHz, 3:80MHz\n"
"[-K, --key1-pwd for eap phase1 or --key2-pwd for eap phase2]:\n"
"Private key passwd for enterprise mode. Default no password for private key.\n"
"[-S, --wpa3-enterprise]: WPA3 enterprise mode:\n"
"Default 0: Not WPA3 enterprise mode.\n"
"1:Suite-b mode, 2:Suite-b-192-bit mode, 3:WPA3-enterprise-only mode.\n"
"[-V, --eap-version]: 0 or 1. Default 1: eap version 1.\n"
"[-I, --eap-id1...--eap-id8]: Client Identity. Default no eap identity.\n"
"[-P, --eap-pwd1...--eap-pwd8]: Client Password.\n"
"Default no password for eap user.\n"
"[-i, --iface=<interface index>] : Interface index.\n"
"-h --help (prints help)",
cmd_wifi_ap_enable, 2, 47),
SHELL_CMD_ARG(stations, NULL, "List stations connected to the AP\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_ap_stations, 1, 2),
SHELL_CMD_ARG(disconnect, NULL,
"Disconnect a station from the AP\n"
"[-i, --iface=<interface index>] : Interface index.\n"
"<MAC address of the station>\n",
cmd_wifi_ap_sta_disconnect, 2, 3),
SHELL_CMD_ARG(config, NULL,
"Configure AP parameters.\n"
"[-i, --iface=<interface index>] : Interface index.\n"
"-t --max_inactivity=<time duration (in seconds)>\n"
"-s --max_num_sta=<maximum number of stations>\n"
#if defined(CONFIG_WIFI_NM_HOSTAPD_AP)
"Please refer to hostapd.conf to set the following options,\n"
"============ IEEE 802.11 related configuration ============\n"
"-n --ht_capab=<HT capabilities (string)>\n"
"(e.g. \"ht_capab=[HT40+]\" is that \"-n [HT40+]\")\n"
"-c --vht_capab=<VHT capabilities (string)>\n"
"(e.g. \"vht_capab=[SU-BEAMFORMEE][BF-ANTENNA-4]\" is that\n"
"\"-c [SU-BEAMFORMEE][BF-ANTENNA-4]\")\n"
"===========================================================\n"
#endif
"-h --help (prints help)",
cmd_wifi_ap_config_params, 3, 12),
SHELL_CMD_ARG(wps_pbc, NULL,
"Start AP WPS PBC session.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_ap_wps_pbc, 1, 2),
SHELL_CMD_ARG(wps_pin, NULL,
"Get or Set AP WPS PIN.\n"
"[-i, --iface=<interface index>] : Interface index.\n"
"[pin] Only applicable for set.\n",
cmd_wifi_ap_wps_pin, 1, 3),
SHELL_CMD_ARG(status, NULL, "Status of Wi-Fi SAP\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_ap_status, 1, 2),
SHELL_CMD_ARG(rts_threshold,
NULL,
"<rts_threshold: rts threshold/off>.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_ap_set_rts_threshold,
3,
2),
SHELL_SUBCMD_SET_END);
SHELL_SUBCMD_ADD((wifi), ap, &wifi_cmd_ap,
"Access Point mode commands.",
NULL,
0, 0);
SHELL_STATIC_SUBCMD_SET_CREATE(wifi_twt_ops,
SHELL_CMD_ARG(quick_setup, NULL, " Start a TWT flow with defaults:\n"
"<twt_wake_interval: 1-262144us> <twt_interval: 1us-2^31us>.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_twt_setup_quick,
3, 2),
SHELL_CMD_ARG(setup, NULL, " Start a TWT flow:\n"
"<-n --negotiation-type>: 0: Individual, 1: Broadcast, 2: Wake TBTT\n"
"<-c --setup-cmd>: 0: Request, 1: Suggest, 2: Demand\n"
"<-t --dialog-token>: 1-255\n"
"<-f --flow-id>: 0-7\n"
"<-r --responder>: 0/1\n"
"<-T --trigger>: 0/1\n"
"<-I --implicit>:0/1\n"
"<-a --announce>: 0/1\n"
"<-w --wake-interval>: 1-262144us\n"
"<-p --interval>: 1us-2^31us\n"
"<-D --wake-ahead-duration>: 0us-2^31us\n"
"<-d --info-disable>: 0/1\n"
"<-e --exponent>: 0-31\n"
"<-m --mantissa>: 1-2^16\n"
"[-i, --iface=<interface index>] : Interface index.\n"
"[-h, --help]: Print out command usage.\n",
cmd_wifi_twt_setup,
25, 7),
SHELL_CMD_ARG(
btwt_setup, NULL,
" Start a BTWT flow:\n"
"<sta_wait> <offset> <twtli> <session_num>: 2-5\n"
"<id0> <mantissa0> <exponent0> <nominal_wake0>: 64-255\n"
"<id1> <mantissa1> <exponent1> <nominal_wake1>: 64-255\n"
"<idx> <mantissax> <exponentx> <nominal_wakex>: 64-255\n"
" The total number of '0, 1, ..., x' is session_num\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_btwt_setup,
13, 2),
SHELL_CMD_ARG(teardown, NULL, " Teardown a TWT flow:\n"
"<negotiation_type, 0: Individual, 1: Broadcast, 2: Wake TBTT>\n"
"<setup_cmd: 0: Request, 1: Suggest, 2: Demand>\n"
"<dialog_token: 1-255> <flow_id: 0-7>.\n",
cmd_wifi_twt_teardown,
5, 0),
SHELL_CMD_ARG(teardown_all, NULL, " Teardown all TWT flows.\n",
cmd_wifi_twt_teardown_all,
1, 0),
SHELL_SUBCMD_SET_END
);
SHELL_SUBCMD_ADD((wifi), twt, &wifi_twt_ops,
"Manage TWT flows.",
NULL,
0, 0);
#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_DPP
SHELL_STATIC_SUBCMD_SET_CREATE(
wifi_cmd_dpp,
SHELL_CMD_ARG(configurator_add, NULL,
" Add DPP configurator\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_dpp_configurator_add, 1, 2),
SHELL_CMD_ARG(auth_init, NULL,
"DPP start auth request:\n"
"-p --peer <peer_bootstrap_id>\n"
"[-r --role <1/2>]: DPP role default 1. 1: configurator, 2: enrollee\n"
"Optional args for configurator:\n"
"[-c --configurator <configurator_id>]\n"
"[-m --mode <1/2>]: Peer mode. 1: STA, 2: AP\n"
"[-s --ssid <SSID>]: SSID\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_dpp_auth_init, 3, 10),
SHELL_CMD_ARG(qr_code, NULL,
" Input QR code:\n"
"<qr_code_string>\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_dpp_qr_code, 2, 2),
SHELL_CMD_ARG(chirp, NULL,
" DPP chirp:\n"
"-o --own <own_bootstrap_id>\n"
"-f --freq <listen_freq>\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_dpp_chirp, 5, 2),
SHELL_CMD_ARG(listen, NULL,
" DPP listen:\n"
"-f --freq <listen_freq>\n"
"-r --role <1/2>: DPP role. 1: configurator, 2: enrollee\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_dpp_listen, 5, 2),
SHELL_CMD_ARG(btstrap_gen, NULL,
" DPP bootstrap generate:\n"
"[-t --type <1/2/3>]: Bootstrap type. 1: qr_code, 2: pkex, 3: nfc."
" Currently only support qr_code\n"
"[-o --opclass <operating_class>]\n"
"[-h --channel <channel>]\n"
"[-a --mac <mac_addr>]\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_dpp_btstrap_gen, 1, 10),
SHELL_CMD_ARG(btstrap_get_uri, NULL,
" Get DPP bootstrap uri by id:\n"
"<bootstrap_id>\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_dpp_btstrap_get_uri, 2, 2),
SHELL_CMD_ARG(configurator_set, NULL,
" Set DPP configurator parameters:\n"
"-c --configurator <configurator_id>\n"
"[-m --mode <1/2>]: Peer mode. 1: STA, 2: AP\n"
"[-s --ssid <SSID>]: SSID\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_dpp_configurator_set, 3, 6),
SHELL_CMD_ARG(resp_timeout_set, NULL,
" Set DPP RX response wait timeout ms:\n"
"<timeout_ms>\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_dpp_resp_timeout_set, 2, 2),
SHELL_CMD_ARG(ap_btstrap_gen, NULL,
" AP DPP bootstrap generate:\n"
"[-t --type <1/2/3>]: Bootstrap type. 1: qr_code, 2: pkex, 3: nfc."
" Currently only support qr_code\n"
"[-o --opclass <operating_class>]\n"
"[-h --channel <channel>]\n"
"[-a --mac <mac_addr>]\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_dpp_ap_btstrap_gen, 1, 10),
SHELL_CMD_ARG(ap_btstrap_get_uri, NULL,
" AP get DPP bootstrap uri by id:\n"
"<bootstrap_id>\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_dpp_ap_btstrap_get_uri, 2, 2),
SHELL_CMD_ARG(ap_qr_code, NULL,
" AP Input QR code:\n"
"<qr_code_string>\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_dpp_ap_qr_code, 2, 2),
SHELL_CMD_ARG(ap_auth_init, NULL,
"AP DPP start auth request as enrollee:\n"
"-p --peer <peer_bootstrap_id>\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_dpp_ap_auth_init, 3, 2),
SHELL_CMD_ARG(reconfig, NULL,
" reconfig network by id:\n"
"<network_id>\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_dpp_reconfig, 2, 2),
SHELL_SUBCMD_SET_END
);
SHELL_SUBCMD_ADD((wifi), dpp, &wifi_cmd_dpp,
"DPP actions.",
NULL,
0, 0);
#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_DPP */
SHELL_SUBCMD_SET_CREATE(wifi_commands, (wifi));
SHELL_SUBCMD_ADD((wifi), 11k, NULL,
"Configure 11k or get 11k status.\n"
"[enable/disable]\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_11k,
1, 3);
SHELL_SUBCMD_ADD((wifi), 11k_neighbor_request, NULL,
"Send Neighbor Report Request frame.\n"
"[ssid <ssid>]\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_11k_neighbor_request,
1, 4);
SHELL_SUBCMD_ADD((wifi), 11v_btm_query, NULL,
"<query_reason: The reason code for a BSS transition management query>.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_btm_query,
2, 2);
SHELL_SUBCMD_ADD((wifi), channel, NULL,
"wifi channel setting\n"
"This command is used to set the channel when\n"
"monitor or TX-Injection mode is enabled\n"
"Currently 20 MHz is only supported and no BW parameter is provided\n"
"[-i, --iface=<interface index>] : Interface index.\n"
"[-c, --channel <chan>] : Set a specific channel number to the lower layer\n"
"[-g, --get] : Get current set channel number from the lower layer\n"
"[-h, --help] : Help\n"
"Usage: Get operation example for interface index 1\n"
"wifi channel -g -i1\n"
"Set operation example for interface index 1 (setting channel 5)\n"
"wifi -i1 -c5.\n",
cmd_wifi_channel,
2, 6);
SHELL_SUBCMD_ADD((wifi), connect, NULL,
"Connect to a Wi-Fi AP\n"
"<-s --ssid \"<SSID>\">: SSID.\n"
"[-c --channel]: Channel that needs to be scanned for connection. "
"0:any channel.\n"
"[-b, --band] 0: any band (2:2.4GHz, 5:5GHz, 6:6GHz]\n"
"[-p, --passphrase]: Passphrase (valid only for secure SSIDs)\n"
"[-k, --key-mgmt]: Key Management type (valid only for secure SSIDs)\n"
"0:None, 1:WPA2-PSK, 2:WPA2-PSK-256, 3:SAE-HNP, 4:SAE-H2E, 5:SAE-AUTO, 6:WAPI,"
"7:EAP-TLS, 8:WEP, 9: WPA-PSK, 10: WPA-Auto-Personal, 11: DPP\n"
"12: EAP-PEAP-MSCHAPv2, 13: EAP-PEAP-GTC, 14: EAP-TTLS-MSCHAPv2,\n"
"15: EAP-PEAP-TLS, 20: SAE-EXT-KEY\n"
"[-w, --ieee-80211w]: MFP (optional: needs security type to be specified)\n"
": 0:Disable, 1:Optional, 2:Required.\n"
"[-m, --bssid]: MAC address of the AP (BSSID).\n"
"[-t, --timeout]: Timeout for the connection attempt (in seconds).\n"
"[-a, --anon-id]: Anonymous identity for enterprise mode.\n"
"[-K, --key1-pwd for eap phase1 or --key2-pwd for eap phase2]:\n"
"Private key passwd for enterprise mode. Default no password for private key.\n"
"[-S, --wpa3-enterprise]: WPA3 enterprise mode:\n"
"Default 0: Not WPA3 enterprise mode.\n"
"1:Suite-b mode, 2:Suite-b-192-bit mode, 3:WPA3-enterprise-only mode.\n"
"[-T, --TLS-cipher]: 0:TLS-NONE, 1:TLS-ECC-P384, 2:TLS-RSA-3K.\n"
"[-A, --verify-peer-cert]: apply for EAP-PEAP-MSCHAPv2 and EAP-TTLS-MSCHAPv2\n"
"Default 0. 0:not use CA to verify peer, 1:use CA to verify peer.\n"
"[-V, --eap-version]: 0 or 1. Default 1: eap version 1.\n"
"[-I, --eap-id1]: Client Identity. Default no eap identity.\n"
"[-P, --eap-pwd1]: Client Password.\n"
"Default no password for eap user.\n"
"[-R, --ieee-80211r]: Use IEEE80211R fast BSS transition connect."
"[-h, --help]: Print out the help for the connect command.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_connect,
2, 42);
SHELL_SUBCMD_ADD((wifi), disconnect, NULL,
"Disconnect from the Wi-Fi AP.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_disconnect,
1, 2);
SHELL_SUBCMD_ADD((wifi), mode, NULL,
"mode operational setting\n"
"This command may be used to set the Wi-Fi device into a specific "
"mode of operation\n"
"[-i, --iface=<interface index>] : Interface index.\n"
"[-s, --sta] : Station mode\n"
"[-m, --monitor] : Monitor mode\n"
"[-a, --ap] : AP mode\n"
"[-k, --softap] : Softap mode\n"
"[-h, --help] : Help\n"
"Usage: Get operation example for interface index 1\n"
"wifi mode -i1\n"
"Set operation example for interface index 1 - set station+promiscuous\n"
"wifi mode -i1 -sp.\n",
cmd_wifi_mode,
1, 11);
SHELL_SUBCMD_ADD((wifi), packet_filter, NULL,
"mode filter setting\n"
"This command is used to set packet filter setting when\n"
"monitor, TX-Injection and promiscuous mode is enabled\n"
"The different packet filter modes are control, management, "
"data and enable all filters\n"
"[-i, --iface=<interface index>] : Interface index.\n"
"[-a, --all] : Enable all packet filter modes\n"
"[-m, --mgmt] : Enable management packets to allowed up the stack\n"
"[-c, --ctrl] : Enable control packets to be allowed up the stack\n"
"[-d, --data] : Enable Data packets to be allowed up the stack\n"
"[-g, --get] : Get current filter settings for a specific interface index\n"
"[-b, --capture-len <len>] : Capture length buffer size for each packet "
"to be captured\n"
"[-h, --help] : Help\n"
"Usage: Get operation example for interface index 1\n"
"wifi packet_filter -g -i1\n"
"Set operation example for interface index 1 - set data+management frame filter\n"
"wifi packet_filter -i1 -md.\n",
cmd_wifi_packet_filter,
2, 10);
SHELL_SUBCMD_ADD((wifi), pmksa_flush, NULL,
"Flush PMKSA cache entries.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_pmksa_flush,
1, 2);
SHELL_SUBCMD_ADD((wifi), ps, NULL,
"Configure or display Wi-Fi power save state.\n[on/off]\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_ps,
1, 2);
SHELL_SUBCMD_ADD((wifi), ps_listen_interval, NULL,
"<val> - Listen interval in the range of <0-65535>.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_listen_interval,
2, 2);
SHELL_SUBCMD_ADD((wifi), ps_mode, NULL,
"<mode: legacy/WMM>.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_ps_mode,
2, 2);
SHELL_SUBCMD_ADD((wifi), ps_timeout, NULL,
"<val> - PS inactivity timer(in ms).\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_ps_timeout,
2, 2);
SHELL_SUBCMD_ADD((wifi), ps_wakeup_mode, NULL,
"<wakeup_mode: DTIM/Listen Interval>.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_ps_wakeup_mode,
2, 2);
SHELL_SUBCMD_ADD((wifi), reg_domain, NULL,
"Set or Get Wi-Fi regulatory domain\n"
"[ISO/IEC 3166-1 alpha2]: Regulatory domain\n"
"[-f]: Force to use this regulatory hint over any other regulatory hints\n"
"Note1: The behavior of this command is dependent on the Wi-Fi driver/chipset implementation\n"
"Note2: This may cause regulatory compliance issues, use it at your own risk.\n"
"[-v]: Verbose, display the per-channel regulatory information\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_reg_domain,
1, 5);
SHELL_SUBCMD_ADD((wifi), rts_threshold, NULL,
"<rts_threshold: rts threshold/off>.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_set_rts_threshold,
2, 2);
SHELL_SUBCMD_ADD((wifi), scan, NULL,
"Scan for Wi-Fi APs\n"
"[-t, --type <active/passive>] : Preferred mode of scan. "
"The actual mode of scan can depend on factors such as the Wi-Fi chip "
"implementation, regulatory domain restrictions. Default type is active\n"
"[-b, --bands <Comma separated list of band values (2/5/6)>] : "
"Bands to be scanned where 2: 2.4 GHz, 5: 5 GHz, 6: 6 GHz\n"
"[-a, --dwell_time_active <val_in_ms>] : "
"Active scan dwell time (in ms) on a channel. Range 5 ms to 1000 ms\n"
"[-p, --dwell_time_passive <val_in_ms>] : "
"Passive scan dwell time (in ms) on a channel. Range 10 ms to 1000 ms\n"
"[-s, --ssid] : SSID to scan for. Can be provided multiple times\n"
"[-m, --max_bss <val>] : Maximum BSSes to scan for. Range 1 - 65535\n"
"[-c, --chans <Comma separated list of channel ranges>] : "
"Channels to be scanned. The channels must be specified in the form "
"band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band "
"values and chan1, chan2, chan3 must be specified as a list of comma "
"separated values where each value is either a single channel or a "
"channel range specified as chan_start-chan_end. Each band channel "
"set has to be separated by a _. For example, a valid channel "
"specification can be 2:1,6_5:36 or 2:1,6-11,14_5:36,163-177,52. "
"Care should be taken to ensure that configured channels don't exceed "
"CONFIG_WIFI_MGMT_SCAN_CHAN_MAX_MANUAL\n"
"[-h, --help] : Print out the help for the scan command.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_scan,
1, 10);
SHELL_SUBCMD_ADD((wifi), statistics, NULL,
"Wi-Fi interface statistics.\n"
"[reset] : Reset Wi-Fi interface statistics\n"
"[help] : Print out the help for the statistics command.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_stats,
1, 3);
SHELL_SUBCMD_ADD((wifi), status, NULL,
"Status of the Wi-Fi interface.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_status,
1, 2);
SHELL_SUBCMD_ADD((wifi), version, NULL,
"Print Wi-Fi Driver and Firmware versions\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_version,
1, 2);
SHELL_SUBCMD_ADD((wifi), wps_pbc, NULL,
"Start a WPS PBC connection.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_wps_pbc,
1, 2);
SHELL_SUBCMD_ADD((wifi), wps_pin, NULL,
"Set and get WPS pin.\n"
"[pin] Only applicable for set.\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_wps_pin,
1, 3);
SHELL_SUBCMD_ADD((wifi), ps_exit_strategy, NULL,
"<tim> : Set PS exit strategy to Every TIM\n"
"<custom> : Set PS exit strategy to Custom\n"
"[-i, --iface=<interface index>] : Interface index.\n",
cmd_wifi_ps_exit_strategy,
2, 2);
SHELL_CMD_REGISTER(wifi, &wifi_commands, "Wi-Fi commands", NULL);
static int wifi_shell_init(void)
{
context.sh = NULL;
context.all = 0U;
context.scan_result = 0U;
net_mgmt_init_event_callback(&wifi_shell_mgmt_cb,
wifi_mgmt_event_handler,
WIFI_SHELL_MGMT_EVENTS);
net_mgmt_add_event_callback(&wifi_shell_mgmt_cb);
net_mgmt_init_event_callback(&wifi_shell_scan_cb,
wifi_mgmt_scan_event_handler,
WIFI_SHELL_SCAN_EVENTS);
return 0;
}
SYS_INIT(wifi_shell_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);