1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /* @file
8 * @brief wpa_cli implementation for Zephyr OS
9 */
10
11 #include <stdlib.h>
12 #include <sys/types.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/shell/shell.h>
15 #include <zephyr/net/net_if.h>
16 #include <zephyr/net/socket.h>
17 #include <zephyr/init.h>
18
19
20 #include "supp_main.h"
21
22 #include "common.h"
23 #include "wpa_supplicant_i.h"
24 #include "wpa_cli_zephyr.h"
25 #ifdef CONFIG_WIFI_NM_HOSTAPD_AP
26 #include "hostapd.h"
27 #include "hapd_main.h"
28 #include "hostapd_cli_zephyr.h"
29 #endif
30
cmd_wpa_cli(const struct shell * sh,size_t argc,const char * argv[])31 static int cmd_wpa_cli(const struct shell *sh, size_t argc, const char *argv[])
32 {
33 struct net_if *iface = NULL;
34 char if_name[CONFIG_NET_INTERFACE_NAME_LEN + 1];
35 struct wpa_supplicant *wpa_s = NULL;
36 size_t arg_offset = 1;
37 int idx = -1;
38 bool iface_found = false;
39
40 if (argc > 2 &&
41 ((strcmp(argv[1], "-i") == 0) ||
42 (strncmp(argv[1], "-i", 2) == 0 && argv[1][2] != '\0'))) {
43 /* Handle both "-i 2" and "-i2" */
44 if (strcmp(argv[1], "-i") == 0) {
45 idx = strtol(argv[2], NULL, 10);
46 arg_offset = 3;
47 } else {
48 idx = strtol(&argv[1][2], NULL, 10);
49 arg_offset = 2;
50 }
51 iface = net_if_get_by_index(idx);
52 if (!iface) {
53 shell_error(sh, "Interface index %d not found", idx);
54 return -ENODEV;
55 }
56 net_if_get_name(iface, if_name, sizeof(if_name));
57 if_name[sizeof(if_name) - 1] = '\0';
58 iface_found = true;
59 } else {
60 /* Default to first Wi-Fi interface */
61 iface = net_if_get_first_wifi();
62 if (!iface) {
63 shell_error(sh, "No Wi-Fi interface found");
64 return -ENOENT;
65 }
66 net_if_get_name(iface, if_name, sizeof(if_name));
67 if_name[sizeof(if_name) - 1] = '\0';
68 arg_offset = 1;
69 iface_found = true;
70 }
71
72 if (!iface_found) {
73 shell_error(sh, "No interface found");
74 return -ENODEV;
75 }
76
77 wpa_s = zephyr_get_handle_by_ifname(if_name);
78 if (!wpa_s) {
79 shell_error(sh, "No wpa_supplicant context for interface '%s'", if_name);
80 return -ENODEV;
81 }
82
83 if (argc <= arg_offset) {
84 shell_error(sh, "Missing argument");
85 return -EINVAL;
86 }
87
88 argv[argc] = "interactive";
89 argc++;
90
91 /* Remove wpa_cli from the argument list */
92 return zephyr_wpa_ctrl_zephyr_cmd(wpa_s->ctrl_conn, argc - arg_offset, &argv[arg_offset]);
93 }
94
95 #ifdef CONFIG_WIFI_NM_HOSTAPD_AP
cmd_hostapd_cli(const struct shell * sh,size_t argc,const char * argv[])96 static int cmd_hostapd_cli(const struct shell *sh, size_t argc, const char *argv[])
97 {
98 struct net_if *iface = NULL;
99 size_t arg_offset = 1;
100 struct hostapd_iface *hapd_iface;
101 int idx = -1;
102 bool iface_found = false;
103 char if_name[CONFIG_NET_INTERFACE_NAME_LEN + 1];
104 int ret;
105
106 if (argc > 2 &&
107 ((strcmp(argv[1], "-i") == 0) ||
108 (strncmp(argv[1], "-i", 2) == 0 && argv[1][2] != '\0'))) {
109 /* Handle both "-i 2" and "-i2" */
110 if (strcmp(argv[1], "-i") == 0) {
111 idx = strtol(argv[2], NULL, 10);
112 arg_offset = 3;
113 } else {
114 idx = strtol(&argv[1][2], NULL, 10);
115 arg_offset = 2;
116 }
117 iface = net_if_get_by_index(idx);
118 if (!iface) {
119 shell_error(sh, "Interface index %d not found", idx);
120 return -ENODEV;
121 }
122 iface_found = true;
123 } else {
124 iface = net_if_get_wifi_sap();
125 if (!iface) {
126 shell_error(sh, "No Wi-Fi interface found");
127 return -ENOENT;
128 }
129 arg_offset = 1;
130 iface_found = true;
131 }
132
133 if (!iface_found) {
134 shell_error(sh, "No interface found");
135 return -ENODEV;
136 }
137
138 ret = net_if_get_name(iface, if_name, sizeof(if_name));
139 if (!ret) {
140 shell_error(sh, "Cannot get interface name (%d)", ret);
141 return -ENODEV;
142 }
143
144 hapd_iface = zephyr_get_hapd_handle_by_ifname(if_name);
145 if (!hapd_iface) {
146 shell_error(sh, "No hostapd context for interface '%s'", if_name);
147 return -ENODEV;
148 }
149
150 if (argc <= arg_offset) {
151 shell_error(sh, "Missing argument");
152 return -EINVAL;
153 }
154
155 argv[argc] = "interactive";
156 argc++;
157
158 /* Remove hostapd_cli from the argument list */
159 return zephyr_hostapd_ctrl_zephyr_cmd(hapd_iface->ctrl_conn, argc - arg_offset,
160 &argv[arg_offset]);
161 }
162 #endif
163
164 /* Persisting with "wpa_cli" naming for compatibility with Wi-Fi
165 * certification applications and scripts.
166 */
167 SHELL_CMD_REGISTER(wpa_cli,
168 NULL,
169 "wpa_cli [-i idx] <command> (only for internal use)",
170 cmd_wpa_cli);
171 #ifdef CONFIG_WIFI_NM_HOSTAPD_AP
172 SHELL_CMD_REGISTER(hostapd_cli, NULL,
173 "hostapd_cli [-i idx] <command> (only for internal use)",
174 cmd_hostapd_cli);
175 #endif
176