zephyr/subsys/net/l2/wifi/wifi_shell.c

283 lines
6.5 KiB
C

/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/** @file
* @brief WiFi shell module
*/
#include <zephyr.h>
#include <stdio.h>
#include <stdlib.h>
#include <shell/shell.h>
#include <shell/shell_uart.h>
#include <misc/printk.h>
#include <init.h>
#include <net/net_if.h>
#include <net/wifi_mgmt.h>
#include <net/net_event.h>
#define WIFI_SHELL_MODULE "wifi"
#define WIFI_SHELL_MGMT_EVENTS (NET_EVENT_WIFI_SCAN_RESULT | \
NET_EVENT_WIFI_SCAN_DONE | \
NET_EVENT_WIFI_CONNECT_RESULT | \
NET_EVENT_WIFI_DISCONNECT_RESULT)
static union {
struct {
const struct shell *shell;
u8_t connecting : 1;
u8_t disconnecting : 1;
u8_t _unused : 6;
};
u8_t all;
} context;
static u32_t scan_result;
static struct net_mgmt_event_callback wifi_shell_mgmt_cb;
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;
scan_result++;
if (scan_result == 1) {
shell_fprintf(context.shell, SHELL_NORMAL,
"%-4s | %-32s %-5s | %-4s | %-4s | %-5s\n",
"Num", "SSID", "(len)", "Chan", "RSSI", "Sec");
}
shell_fprintf(context.shell, SHELL_NORMAL,
"%-4d | %-32s %-5u | %-4u | %-4d | %-5s\n",
scan_result, entry->ssid, entry->ssid_length,
entry->channel, entry->rssi,
(entry->security == WIFI_SECURITY_TYPE_PSK ?
"WPA/WPA2" : "Open"));
}
static void handle_wifi_scan_done(struct net_mgmt_event_callback *cb)
{
const struct wifi_status *status =
(const struct wifi_status *)cb->info;
if (status->status) {
shell_fprintf(context.shell, SHELL_WARNING,
"Scan request failed (%d)\n", status->status);
} else {
shell_fprintf(context.shell, SHELL_NORMAL,
"Scan request done\n");
}
scan_result = 0;
}
static void handle_wifi_connect_result(struct net_mgmt_event_callback *cb)
{
const struct wifi_status *status =
(const struct wifi_status *) cb->info;
if (status->status) {
shell_fprintf(context.shell, SHELL_WARNING,
"Connection request failed (%d)\n",
status->status);
} else {
shell_fprintf(context.shell, SHELL_NORMAL, "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;
if (context.disconnecting) {
shell_fprintf(context.shell,
status->status ? SHELL_WARNING : SHELL_NORMAL,
"Disconnection request %s (%d)\n",
status->status ? "failed" : "done",
status->status);
context.disconnecting = false;
} else {
shell_fprintf(context.shell, SHELL_NORMAL, "Disconnected\n");
}
}
static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb,
u32_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;
case NET_EVENT_WIFI_CONNECT_RESULT:
handle_wifi_connect_result(cb);
break;
case NET_EVENT_WIFI_DISCONNECT_RESULT:
handle_wifi_disconnect_result(cb);
break;
default:
break;
}
}
static int cmd_wifi_connect(const struct shell *shell, size_t argc,
char *argv[])
{
struct net_if *iface = net_if_get_default();
static struct wifi_connect_req_params cnx_params;
int idx = 3;
if (shell_help_requested(shell) || argc < 2) {
shell_help_print(shell, NULL, 0);
return -ENOEXEC;
}
cnx_params.ssid_length = atoi(argv[2]);
if (cnx_params.ssid_length <= 2) {
shell_help_print(shell, NULL, 0);
return -ENOEXEC;
}
cnx_params.ssid = &argv[1][1];
argv[1][cnx_params.ssid_length + 1] = '\0';
if ((idx < argc) && (strlen(argv[idx]) <= 2)) {
cnx_params.channel = atoi(argv[2]);
if (cnx_params.channel == 0) {
cnx_params.channel = WIFI_CHANNEL_ANY;
}
idx++;
} else {
cnx_params.channel = WIFI_CHANNEL_ANY;
}
if (idx < argc) {
cnx_params.psk = argv[idx];
cnx_params.psk_length = strlen(argv[idx]);
cnx_params.security = WIFI_SECURITY_TYPE_PSK;
} else {
cnx_params.security = WIFI_SECURITY_TYPE_NONE;
}
context.connecting = true;
context.shell = shell;
if (net_mgmt(NET_REQUEST_WIFI_CONNECT, iface,
&cnx_params, sizeof(struct wifi_connect_req_params))) {
shell_fprintf(shell, SHELL_WARNING,
"Connection request failed\n");
context.connecting = false;
return -ENOEXEC;
} else {
shell_fprintf(shell, SHELL_NORMAL,
"Connection requested\n");
}
return 0;
}
static int cmd_wifi_disconnect(const struct shell *shell, size_t argc,
char *argv[])
{
struct net_if *iface = net_if_get_default();
int status;
if (shell_help_requested(shell)) {
shell_help_print(shell, NULL, 0);
return -ENOEXEC;
}
context.disconnecting = true;
context.shell = shell;
status = net_mgmt(NET_REQUEST_WIFI_DISCONNECT, iface, NULL, 0);
if (status) {
context.disconnecting = false;
if (status == -EALREADY) {
shell_fprintf(shell, SHELL_INFO,
"Already disconnected\n");
} else {
shell_fprintf(shell, SHELL_WARNING,
"Disconnect request failed\n");
return -ENOEXEC;
}
} else {
shell_fprintf(shell, SHELL_NORMAL,
"Disconnect requested\n");
}
return 0;
}
static int cmd_wifi_scan(const struct shell *shell, size_t argc, char *argv[])
{
struct net_if *iface = net_if_get_default();
if (shell_help_requested(shell)) {
shell_help_print(shell, NULL, 0);
return -ENOEXEC;
}
if (net_mgmt(NET_REQUEST_WIFI_SCAN, iface, NULL, 0)) {
shell_fprintf(shell, SHELL_WARNING, "Scan request failed\n");
return -ENOEXEC;
} else {
shell_fprintf(shell, SHELL_NORMAL, "Scan requested\n");
}
return 0;
}
SHELL_CREATE_STATIC_SUBCMD_SET(wifi_commands)
{
SHELL_CMD(connect, NULL,
"\"<SSID>\"\n<SSID length>\n<channel number (optional), "
"0 means all>\n"
"<PSK (optional: valid only for secured SSIDs)>",
cmd_wifi_connect),
SHELL_CMD(disconnect, NULL, "Disconnect from Wifi AP",
cmd_wifi_disconnect),
SHELL_CMD(scan, NULL, "Scan Wifi AP", cmd_wifi_scan),
SHELL_SUBCMD_SET_END
};
SHELL_CMD_REGISTER(wifi, &wifi_commands, "Wifi commands", NULL);
static int wifi_shell_init(struct device *unused)
{
ARG_UNUSED(unused);
context.shell = NULL;
context.all = 0;
scan_result = 0;
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);
return 0;
}
SYS_INIT(wifi_shell_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);