1 /**
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <stdarg.h>
7
8 #include <zephyr/logging/log.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/net/wifi_mgmt.h>
11
12 #include "includes.h"
13 #include "common.h"
14 #include "common/defs.h"
15 #include "wpa_supplicant/config.h"
16 #include "wpa_supplicant_i.h"
17 #include "driver_i.h"
18
19 #include "supp_main.h"
20 #include "supp_api.h"
21 #include "wpa_cli_zephyr.h"
22 #include "supp_events.h"
23
24 extern struct k_sem wpa_supplicant_ready_sem;
25 extern struct wpa_global *global;
26
27 enum requested_ops {
28 CONNECT = 0,
29 DISCONNECT
30 };
31
32 enum status_thread_state {
33 STATUS_THREAD_STOPPED = 0,
34 STATUS_THREAD_RUNNING,
35 };
36
37 #define OP_STATUS_POLLING_INTERVAL 1
38
39 #define CONNECTION_SUCCESS 0
40 #define CONNECTION_FAILURE 1
41 #define CONNECTION_TERMINATED 2
42
43 #define DISCONNECT_TIMEOUT_MS 5000
44
45 K_MUTEX_DEFINE(wpa_supplicant_mutex);
46
47 extern struct k_work_q *get_workq(void);
48
49 struct wpa_supp_api_ctrl {
50 const struct device *dev;
51 enum requested_ops requested_op;
52 enum status_thread_state status_thread_state;
53 int connection_timeout; /* in seconds */
54 struct k_work_sync sync;
55 bool terminate;
56 };
57
58 static struct wpa_supp_api_ctrl wpas_api_ctrl;
59
60 static void supp_shell_connect_status(struct k_work *work);
61
62 static K_WORK_DELAYABLE_DEFINE(wpa_supp_status_work,
63 supp_shell_connect_status);
64
65 #define wpa_cli_cmd_v(cmd, ...) ({ \
66 bool status; \
67 \
68 if (zephyr_wpa_cli_cmd_v(cmd, ##__VA_ARGS__) < 0) { \
69 wpa_printf(MSG_ERROR, \
70 "Failed to execute wpa_cli command: %s", \
71 cmd); \
72 status = false; \
73 } else { \
74 status = true; \
75 } \
76 \
77 status; \
78 })
79
get_wpa_s_handle(const struct device * dev)80 static struct wpa_supplicant *get_wpa_s_handle(const struct device *dev)
81 {
82 struct net_if *iface = net_if_lookup_by_dev(dev);
83 char if_name[CONFIG_NET_INTERFACE_NAME_LEN + 1];
84 struct wpa_supplicant *wpa_s;
85 int ret;
86
87 if (!iface) {
88 wpa_printf(MSG_ERROR, "Interface for device %s not found", dev->name);
89 return NULL;
90 }
91
92 ret = net_if_get_name(iface, if_name, sizeof(if_name));
93 if (!ret) {
94 wpa_printf(MSG_ERROR, "Cannot get interface name (%d)", ret);
95 return NULL;
96 }
97
98 wpa_s = zephyr_get_handle_by_ifname(if_name);
99 if (!wpa_s) {
100 wpa_printf(MSG_ERROR, "Interface %s not found", if_name);
101 return NULL;
102 }
103
104 return wpa_s;
105 }
106
107 #define WPA_SUPP_STATE_POLLING_MS 10
wait_for_disconnect_complete(const struct device * dev)108 static int wait_for_disconnect_complete(const struct device *dev)
109 {
110 int ret = 0;
111 int attempts = 0;
112 struct wpa_supplicant *wpa_s = get_wpa_s_handle(dev);
113 unsigned int max_attempts = DISCONNECT_TIMEOUT_MS / WPA_SUPP_STATE_POLLING_MS;
114
115 if (!wpa_s) {
116 ret = -ENODEV;
117 wpa_printf(MSG_ERROR, "Failed to get wpa_s handle");
118 goto out;
119 }
120
121 while (wpa_s->wpa_state != WPA_DISCONNECTED) {
122 if (attempts++ > max_attempts) {
123 ret = -ETIMEDOUT;
124 wpa_printf(MSG_WARNING, "Failed to disconnect from network");
125 break;
126 }
127
128 k_sleep(K_MSEC(WPA_SUPP_STATE_POLLING_MS));
129 }
130 out:
131 return ret;
132 }
133
supp_shell_connect_status(struct k_work * work)134 static void supp_shell_connect_status(struct k_work *work)
135 {
136 static int seconds_counter;
137 int status = CONNECTION_SUCCESS;
138 int conn_result = CONNECTION_FAILURE;
139 struct wpa_supplicant *wpa_s;
140 struct wpa_supp_api_ctrl *ctrl = &wpas_api_ctrl;
141
142 k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER);
143
144 if (ctrl->status_thread_state == STATUS_THREAD_RUNNING && ctrl->terminate) {
145 status = CONNECTION_TERMINATED;
146 goto out;
147 }
148
149 wpa_s = get_wpa_s_handle(ctrl->dev);
150 if (!wpa_s) {
151 status = CONNECTION_FAILURE;
152 goto out;
153 }
154
155 if (ctrl->requested_op == CONNECT && wpa_s->wpa_state != WPA_COMPLETED) {
156 if (ctrl->connection_timeout > 0 &&
157 seconds_counter++ > ctrl->connection_timeout) {
158 if (!wpa_cli_cmd_v("disconnect")) {
159 goto out;
160 }
161
162 conn_result = -ETIMEDOUT;
163 supplicant_send_wifi_mgmt_event(wpa_s->ifname,
164 NET_EVENT_WIFI_CMD_CONNECT_RESULT,
165 (void *)&conn_result, sizeof(int));
166 status = CONNECTION_FAILURE;
167 goto out;
168 }
169
170 k_work_reschedule_for_queue(get_workq(), &wpa_supp_status_work,
171 K_SECONDS(OP_STATUS_POLLING_INTERVAL));
172 ctrl->status_thread_state = STATUS_THREAD_RUNNING;
173 k_mutex_unlock(&wpa_supplicant_mutex);
174 return;
175 }
176 out:
177 seconds_counter = 0;
178
179 ctrl->status_thread_state = STATUS_THREAD_STOPPED;
180 k_mutex_unlock(&wpa_supplicant_mutex);
181 }
182
get_mode_by_band(struct wpa_supplicant * wpa_s,uint8_t band)183 static struct hostapd_hw_modes *get_mode_by_band(struct wpa_supplicant *wpa_s, uint8_t band)
184 {
185 enum hostapd_hw_mode hw_mode;
186 bool is_6ghz = (band == WIFI_FREQ_BAND_6_GHZ) ? true : false;
187
188 if (band == WIFI_FREQ_BAND_2_4_GHZ) {
189 hw_mode = HOSTAPD_MODE_IEEE80211G;
190 } else if ((band == WIFI_FREQ_BAND_5_GHZ) ||
191 (band == WIFI_FREQ_BAND_6_GHZ)) {
192 hw_mode = HOSTAPD_MODE_IEEE80211A;
193 } else {
194 return NULL;
195 }
196
197 return get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode, is_6ghz);
198 }
199
wpa_supp_supported_channels(struct wpa_supplicant * wpa_s,uint8_t band,char ** chan_list)200 static int wpa_supp_supported_channels(struct wpa_supplicant *wpa_s, uint8_t band, char **chan_list)
201 {
202 struct hostapd_hw_modes *mode = NULL;
203 int i;
204 int offset, retval;
205 int size;
206 char *_chan_list;
207
208 mode = get_mode_by_band(wpa_s, band);
209 if (!mode) {
210 wpa_printf(MSG_ERROR, "Unsupported or invalid band: %d", band);
211 return -EINVAL;
212 }
213
214 size = ((mode->num_channels) * CHAN_NUM_LEN) + 1;
215 _chan_list = k_malloc(size);
216 if (!_chan_list) {
217 wpa_printf(MSG_ERROR, "Mem alloc failed for channel list");
218 return -ENOMEM;
219 }
220
221 retval = 0;
222 offset = 0;
223 for (i = 0; i < mode->num_channels; i++) {
224 retval = snprintf(_chan_list + offset, CHAN_NUM_LEN, " %d",
225 mode->channels[i].freq);
226 offset += retval;
227 }
228 *chan_list = _chan_list;
229
230 return 0;
231 }
232
wpa_supp_band_chan_compat(struct wpa_supplicant * wpa_s,uint8_t band,uint8_t channel)233 static int wpa_supp_band_chan_compat(struct wpa_supplicant *wpa_s, uint8_t band, uint8_t channel)
234 {
235 struct hostapd_hw_modes *mode = NULL;
236 int i;
237
238 mode = get_mode_by_band(wpa_s, band);
239 if (!mode) {
240 wpa_printf(MSG_ERROR, "Unsupported or invalid band: %d", band);
241 return -EINVAL;
242 }
243
244 for (i = 0; i < mode->num_channels; i++) {
245 if (mode->channels[i].chan == channel) {
246 return mode->channels[i].freq;
247 }
248 }
249
250 wpa_printf(MSG_ERROR, "Channel %d not supported for band %d", channel, band);
251
252 return -EINVAL;
253 }
254
wpa_supp_restart_status_work(void)255 static inline void wpa_supp_restart_status_work(void)
256 {
257 /* Terminate synchronously */
258 wpas_api_ctrl.terminate = 1;
259 k_work_flush_delayable(&wpa_supp_status_work, &wpas_api_ctrl.sync);
260 wpas_api_ctrl.terminate = 0;
261
262 /* Start afresh */
263 k_work_reschedule_for_queue(get_workq(), &wpa_supp_status_work, K_MSEC(10));
264 }
265
chan_to_freq(int chan)266 static inline int chan_to_freq(int chan)
267 {
268 /* We use global channel list here and also use the widest
269 * op_class for 5GHz channels as there is no user input
270 * for these (yet).
271 */
272 int freq = -1;
273 int op_classes[] = {81, 82, 128};
274 int op_classes_size = ARRAY_SIZE(op_classes);
275
276 for (int i = 0; i < op_classes_size; i++) {
277 freq = ieee80211_chan_to_freq(NULL, op_classes[i], chan);
278 if (freq > 0) {
279 break;
280 }
281 }
282
283 if (freq <= 0) {
284 wpa_printf(MSG_ERROR, "Invalid channel %d", chan);
285 return -1;
286 }
287
288 return freq;
289 }
290
wpas_band_to_zephyr(enum wpa_radio_work_band band)291 static inline enum wifi_frequency_bands wpas_band_to_zephyr(enum wpa_radio_work_band band)
292 {
293 switch (band) {
294 case BAND_2_4_GHZ:
295 return WIFI_FREQ_BAND_2_4_GHZ;
296 case BAND_5_GHZ:
297 return WIFI_FREQ_BAND_5_GHZ;
298 default:
299 return WIFI_FREQ_BAND_UNKNOWN;
300 }
301 }
302
wpas_key_mgmt_to_zephyr(int key_mgmt,int proto)303 static inline enum wifi_security_type wpas_key_mgmt_to_zephyr(int key_mgmt, int proto)
304 {
305 switch (key_mgmt) {
306 case WPA_KEY_MGMT_NONE:
307 return WIFI_SECURITY_TYPE_NONE;
308 case WPA_KEY_MGMT_PSK:
309 if (proto == WPA_PROTO_RSN) {
310 return WIFI_SECURITY_TYPE_PSK;
311 } else {
312 return WIFI_SECURITY_TYPE_WPA_PSK;
313 }
314 case WPA_KEY_MGMT_PSK_SHA256:
315 return WIFI_SECURITY_TYPE_PSK_SHA256;
316 case WPA_KEY_MGMT_SAE:
317 return WIFI_SECURITY_TYPE_SAE;
318 default:
319 return WIFI_SECURITY_TYPE_UNKNOWN;
320 }
321 }
322
wpas_add_and_config_network(struct wpa_supplicant * wpa_s,struct wifi_connect_req_params * params,bool mode_ap)323 static int wpas_add_and_config_network(struct wpa_supplicant *wpa_s,
324 struct wifi_connect_req_params *params,
325 bool mode_ap)
326 {
327 struct add_network_resp resp = {0};
328 char *chan_list = NULL;
329 struct net_eth_addr mac = {0};
330 int ret = 0;
331
332 if (!wpa_cli_cmd_v("remove_network all")) {
333 goto out;
334 }
335
336 ret = z_wpa_ctrl_add_network(&resp);
337 if (ret) {
338 wpa_printf(MSG_ERROR, "Failed to add network");
339 goto out;
340 }
341
342 wpa_printf(MSG_DEBUG, "NET added: %d", resp.network_id);
343
344 if (mode_ap) {
345 if (!wpa_cli_cmd_v("set_network %d mode 2", resp.network_id)) {
346 goto out;
347 }
348 }
349
350 if (!wpa_cli_cmd_v("set_network %d ssid \"%s\"",
351 resp.network_id, params->ssid)) {
352 goto out;
353 }
354
355 if (!wpa_cli_cmd_v("set_network %d scan_ssid 1", resp.network_id)) {
356 goto out;
357 }
358
359 if (!wpa_cli_cmd_v("set_network %d key_mgmt NONE", resp.network_id)) {
360 goto out;
361 }
362
363 if (!wpa_cli_cmd_v("set_network %d ieee80211w 0", resp.network_id)) {
364 goto out;
365 }
366
367 if (params->band != WIFI_FREQ_BAND_UNKNOWN) {
368 ret = wpa_supp_supported_channels(wpa_s, params->band, &chan_list);
369 if (ret < 0) {
370 goto rem_net;
371 }
372
373 if (chan_list) {
374 if (!wpa_cli_cmd_v("set_network %d scan_freq%s", resp.network_id,
375 chan_list)) {
376 k_free(chan_list);
377 goto out;
378 }
379
380 k_free(chan_list);
381 }
382 }
383
384 if (params->security != WIFI_SECURITY_TYPE_NONE) {
385 /* SAP - only open and WPA2-PSK are supported for now */
386 if (mode_ap && params->security != WIFI_SECURITY_TYPE_PSK) {
387 ret = -1;
388 wpa_printf(MSG_ERROR, "Unsupported security type: %d",
389 params->security);
390 goto rem_net;
391 }
392
393 /* Except for WPA-PSK, rest all are under WPA2 */
394 if (params->security != WIFI_SECURITY_TYPE_WPA_PSK) {
395 if (!wpa_cli_cmd_v("set_network %d proto RSN",
396 resp.network_id)) {
397 goto out;
398 }
399 }
400
401 if (params->security == WIFI_SECURITY_TYPE_SAE) {
402 if (params->sae_password) {
403 if (!wpa_cli_cmd_v("set_network %d sae_password \"%s\"",
404 resp.network_id, params->sae_password)) {
405 goto out;
406 }
407 } else {
408 if (!wpa_cli_cmd_v("set_network %d sae_password \"%s\"",
409 resp.network_id, params->psk)) {
410 goto out;
411 }
412 }
413
414 if (!wpa_cli_cmd_v("set_network %d key_mgmt SAE", resp.network_id)) {
415 goto out;
416 }
417 } else if (params->security == WIFI_SECURITY_TYPE_PSK_SHA256) {
418 if (!wpa_cli_cmd_v("set_network %d psk \"%s\"",
419 resp.network_id, params->psk)) {
420 goto out;
421 }
422
423 if (!wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK-SHA256",
424 resp.network_id)) {
425 goto out;
426 }
427 } else if (params->security == WIFI_SECURITY_TYPE_PSK ||
428 params->security == WIFI_SECURITY_TYPE_WPA_PSK) {
429 if (!wpa_cli_cmd_v("set_network %d psk \"%s\"",
430 resp.network_id, params->psk)) {
431 goto out;
432 }
433
434 if (!wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK",
435 resp.network_id)) {
436 goto out;
437 }
438
439 if (params->security == WIFI_SECURITY_TYPE_WPA_PSK) {
440 if (!wpa_cli_cmd_v("set_network %d proto WPA",
441 resp.network_id)) {
442 goto out;
443 }
444 }
445 } else {
446 ret = -1;
447 wpa_printf(MSG_ERROR, "Unsupported security type: %d",
448 params->security);
449 goto rem_net;
450 }
451
452 if (params->mfp) {
453 if (!wpa_cli_cmd_v("set_network %d ieee80211w %d",
454 resp.network_id, params->mfp)) {
455 goto out;
456 }
457 }
458 }
459
460 if (params->channel != WIFI_CHANNEL_ANY) {
461 int freq;
462
463 if (params->band != WIFI_FREQ_BAND_UNKNOWN) {
464 freq = wpa_supp_band_chan_compat(wpa_s, params->band, params->channel);
465 if (freq < 0) {
466 goto rem_net;
467 }
468 } else {
469 freq = chan_to_freq(params->channel);
470 if (freq < 0) {
471 ret = -1;
472 wpa_printf(MSG_ERROR, "Invalid channel %d",
473 params->channel);
474 goto rem_net;
475 }
476 }
477
478 if (mode_ap) {
479 if (!wpa_cli_cmd_v("set_network %d frequency %d",
480 resp.network_id, freq)) {
481 goto out;
482 }
483 } else {
484 if (!wpa_cli_cmd_v("set_network %d scan_freq %d",
485 resp.network_id, freq)) {
486 goto out;
487 }
488 }
489 }
490
491 memcpy((void *)&mac, params->bssid, WIFI_MAC_ADDR_LEN);
492 if (net_eth_is_addr_broadcast(&mac) ||
493 net_eth_is_addr_multicast(&mac)) {
494 wpa_printf(MSG_ERROR, "Invalid BSSID. Configuration "
495 "of multicast or broadcast MAC is not allowed.");
496 ret = -EINVAL;
497 goto rem_net;
498 }
499
500 if (!net_eth_is_addr_unspecified(&mac)) {
501 char bssid_str[MAC_STR_LEN] = {0};
502
503 snprintf(bssid_str, MAC_STR_LEN, "%02x:%02x:%02x:%02x:%02x:%02x",
504 params->bssid[0], params->bssid[1], params->bssid[2],
505 params->bssid[3], params->bssid[4], params->bssid[5]);
506
507 if (!wpa_cli_cmd_v("set_network %d bssid %s",
508 resp.network_id, bssid_str)) {
509 goto out;
510 }
511 }
512
513 /* enable and select network */
514 if (!wpa_cli_cmd_v("enable_network %d", resp.network_id)) {
515 goto out;
516 }
517
518 if (!wpa_cli_cmd_v("select_network %d", resp.network_id)) {
519 goto out;
520 }
521
522 return 0;
523
524 rem_net:
525 if (!wpa_cli_cmd_v("remove_network %d", resp.network_id)) {
526 goto out;
527 }
528
529 out:
530 return ret;
531 }
532
wpas_disconnect_network(const struct device * dev,int cur_mode)533 static int wpas_disconnect_network(const struct device *dev, int cur_mode)
534 {
535 struct net_if *iface = net_if_lookup_by_dev(dev);
536 struct wpa_supplicant *wpa_s;
537 bool is_ap = false;
538 int ret = 0;
539
540 if (!iface) {
541 ret = -ENOENT;
542 wpa_printf(MSG_ERROR, "Interface for device %s not found", dev->name);
543 return ret;
544 }
545
546 wpa_s = get_wpa_s_handle(dev);
547 if (!wpa_s) {
548 ret = -1;
549 wpa_printf(MSG_ERROR, "Interface %s not found", dev->name);
550 goto out;
551 }
552
553 k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER);
554
555 if (wpa_s->current_ssid && wpa_s->current_ssid->mode != cur_mode) {
556 ret = -EBUSY;
557 wpa_printf(MSG_ERROR, "Interface %s is not in %s mode", dev->name,
558 cur_mode == WPAS_MODE_INFRA ? "STA" : "AP");
559 goto out;
560 }
561
562 is_ap = (cur_mode == WPAS_MODE_AP);
563
564 wpas_api_ctrl.dev = dev;
565 wpas_api_ctrl.requested_op = DISCONNECT;
566
567 if (!wpa_cli_cmd_v("disconnect")) {
568 goto out;
569 }
570
571 out:
572 k_mutex_unlock(&wpa_supplicant_mutex);
573
574 if (ret) {
575 wpa_printf(MSG_ERROR, "Disconnect failed: %s", strerror(-ret));
576 return ret;
577 }
578
579 wpa_supp_restart_status_work();
580
581 ret = wait_for_disconnect_complete(dev);
582 #ifdef CONFIG_AP
583 if (is_ap) {
584 supplicant_send_wifi_mgmt_ap_status(wpa_s,
585 NET_EVENT_WIFI_CMD_AP_DISABLE_RESULT,
586 ret == 0 ? WIFI_STATUS_AP_SUCCESS : WIFI_STATUS_AP_FAIL);
587 } else {
588 #else
589 {
590 #endif /* CONFIG_AP */
591 wifi_mgmt_raise_disconnect_complete_event(iface, ret);
592 }
593
594 return ret;
595 }
596
597 /* Public API */
598 int supplicant_connect(const struct device *dev, struct wifi_connect_req_params *params)
599 {
600 struct wpa_supplicant *wpa_s;
601 int ret = 0;
602
603 if (!net_if_is_admin_up(net_if_lookup_by_dev(dev))) {
604 wpa_printf(MSG_ERROR,
605 "Interface %s is down, dropping connect",
606 dev->name);
607 return -1;
608 }
609
610 k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER);
611
612 wpa_s = get_wpa_s_handle(dev);
613 if (!wpa_s) {
614 ret = -1;
615 wpa_printf(MSG_ERROR, "Device %s not found", dev->name);
616 goto out;
617 }
618
619 /* Allow connect in STA mode only even if we are connected already */
620 if (wpa_s->current_ssid && wpa_s->current_ssid->mode != WPAS_MODE_INFRA) {
621 ret = -EBUSY;
622 wpa_printf(MSG_ERROR, "Interface %s is not in STA mode", dev->name);
623 goto out;
624 }
625
626 ret = wpas_add_and_config_network(wpa_s, params, false);
627 if (ret) {
628 wpa_printf(MSG_ERROR, "Failed to add and configure network for STA mode: %d", ret);
629 goto out;
630 }
631
632 wpas_api_ctrl.dev = dev;
633 wpas_api_ctrl.requested_op = CONNECT;
634 wpas_api_ctrl.connection_timeout = params->timeout;
635
636 out:
637 k_mutex_unlock(&wpa_supplicant_mutex);
638
639 if (!ret) {
640 wpa_supp_restart_status_work();
641 }
642
643 return ret;
644 }
645
646 int supplicant_disconnect(const struct device *dev)
647 {
648 return wpas_disconnect_network(dev, WPAS_MODE_INFRA);
649 }
650
651 int supplicant_status(const struct device *dev, struct wifi_iface_status *status)
652 {
653 struct net_if *iface = net_if_lookup_by_dev(dev);
654 struct wpa_supplicant *wpa_s;
655 int ret = -1;
656 struct wpa_signal_info *si = NULL;
657 struct wpa_conn_info *conn_info = NULL;
658
659 if (!iface) {
660 ret = -ENOENT;
661 wpa_printf(MSG_ERROR, "Interface for device %s not found", dev->name);
662 return ret;
663 }
664
665 k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER);
666
667 wpa_s = get_wpa_s_handle(dev);
668 if (!wpa_s) {
669 wpa_printf(MSG_ERROR, "Device %s not found", dev->name);
670 goto out;
671 }
672
673 si = os_zalloc(sizeof(struct wpa_signal_info));
674 if (!si) {
675 wpa_printf(MSG_ERROR, "Failed to allocate memory for signal info");
676 goto out;
677 }
678
679 status->state = wpa_s->wpa_state; /* 1-1 Mapping */
680
681 if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
682 struct wpa_ssid *ssid = wpa_s->current_ssid;
683 u8 channel;
684 struct signal_poll_resp signal_poll;
685 u8 *_ssid = ssid->ssid;
686 size_t ssid_len = ssid->ssid_len;
687 struct status_resp cli_status;
688 bool is_ap;
689 int proto;
690 int key_mgmt;
691
692 if (!ssid) {
693 wpa_printf(MSG_ERROR, "Failed to get current ssid");
694 goto out;
695 }
696
697 is_ap = ssid->mode == WPAS_MODE_AP;
698 /* For AP its always the configured one */
699 proto = is_ap ? ssid->proto : wpa_s->wpa_proto;
700 key_mgmt = is_ap ? ssid->key_mgmt : wpa_s->key_mgmt;
701 os_memcpy(status->bssid, wpa_s->bssid, WIFI_MAC_ADDR_LEN);
702 status->band = wpas_band_to_zephyr(wpas_freq_to_band(wpa_s->assoc_freq));
703 status->security = wpas_key_mgmt_to_zephyr(key_mgmt, proto);
704 status->mfp = ssid->ieee80211w; /* Same mapping */
705 ieee80211_freq_to_chan(wpa_s->assoc_freq, &channel);
706 status->channel = channel;
707
708 if (ssid_len == 0) {
709 int _res = z_wpa_ctrl_status(&cli_status);
710
711 if (_res < 0) {
712 ssid_len = 0;
713 } else {
714 ssid_len = cli_status.ssid_len;
715 }
716
717 _ssid = cli_status.ssid;
718 }
719
720 os_memcpy(status->ssid, _ssid, ssid_len);
721 status->ssid_len = ssid_len;
722 status->iface_mode = ssid->mode;
723
724 if (wpa_s->connection_set == 1) {
725 status->link_mode = wpa_s->connection_he ? WIFI_6 :
726 wpa_s->connection_vht ? WIFI_5 :
727 wpa_s->connection_ht ? WIFI_4 :
728 wpa_s->connection_g ? WIFI_3 :
729 wpa_s->connection_a ? WIFI_2 :
730 wpa_s->connection_b ? WIFI_1 :
731 WIFI_0;
732 } else {
733 status->link_mode = WIFI_LINK_MODE_UNKNOWN;
734 }
735
736 status->rssi = -WPA_INVALID_NOISE;
737 if (status->iface_mode == WIFI_MODE_INFRA) {
738 ret = z_wpa_ctrl_signal_poll(&signal_poll);
739 if (!ret) {
740 status->rssi = signal_poll.rssi;
741 } else {
742 wpa_printf(MSG_WARNING, "%s:Failed to read RSSI", __func__);
743 }
744 }
745
746 conn_info = os_zalloc(sizeof(struct wpa_conn_info));
747 if (!conn_info) {
748 wpa_printf(MSG_ERROR, "%s:Failed to allocate memory\n",
749 __func__);
750 ret = -ENOMEM;
751 goto out;
752 }
753
754 ret = wpa_drv_get_conn_info(wpa_s, conn_info);
755 if (!ret) {
756 status->beacon_interval = conn_info->beacon_interval;
757 status->dtim_period = conn_info->dtim_period;
758 status->twt_capable = conn_info->twt_capable;
759 } else {
760 wpa_printf(MSG_WARNING, "%s: Failed to get connection info\n",
761 __func__);
762
763 status->beacon_interval = 0;
764 status->dtim_period = 0;
765 status->twt_capable = false;
766 ret = 0;
767 }
768
769 os_free(conn_info);
770 } else {
771 ret = 0;
772 }
773
774 out:
775 os_free(si);
776 k_mutex_unlock(&wpa_supplicant_mutex);
777 return ret;
778 }
779
780 /* Below APIs are not natively supported by WPA supplicant, so,
781 * these are just wrappers around driver offload APIs. But it is
782 * transparent to the user.
783 *
784 * In the future these might be implemented natively by the WPA
785 * supplicant.
786 */
787
788 static const struct wifi_mgmt_ops *const get_wifi_mgmt_api(const struct device *dev)
789 {
790 struct net_wifi_mgmt_offload *api = (struct net_wifi_mgmt_offload *)dev->api;
791
792 return api ? api->wifi_mgmt_api : NULL;
793 }
794
795 int supplicant_scan(const struct device *dev, struct wifi_scan_params *params,
796 scan_result_cb_t cb)
797 {
798 const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev);
799
800 if (!wifi_mgmt_api || !wifi_mgmt_api->scan) {
801 wpa_printf(MSG_ERROR, "Scan not supported");
802 return -ENOTSUP;
803 }
804
805 return wifi_mgmt_api->scan(dev, params, cb);
806 }
807
808 #ifdef CONFIG_NET_STATISTICS_WIFI
809 int supplicant_get_stats(const struct device *dev, struct net_stats_wifi *stats)
810 {
811 const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev);
812
813 if (!wifi_mgmt_api || !wifi_mgmt_api->get_stats) {
814 wpa_printf(MSG_ERROR, "Get stats not supported");
815 return -ENOTSUP;
816 }
817
818 return wifi_mgmt_api->get_stats(dev, stats);
819 }
820 #endif /* CONFIG_NET_STATISTICS_WIFI */
821
822 int supplicant_set_power_save(const struct device *dev, struct wifi_ps_params *params)
823 {
824 const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev);
825
826 if (!wifi_mgmt_api || !wifi_mgmt_api->set_power_save) {
827 wpa_printf(MSG_ERROR, "Set power save not supported");
828 return -ENOTSUP;
829 }
830
831 return wifi_mgmt_api->set_power_save(dev, params);
832 }
833
834 int supplicant_set_twt(const struct device *dev, struct wifi_twt_params *params)
835 {
836 const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev);
837
838 if (!wifi_mgmt_api || !wifi_mgmt_api->set_twt) {
839 wpa_printf(MSG_ERROR, "Set TWT not supported");
840 return -ENOTSUP;
841 }
842
843 return wifi_mgmt_api->set_twt(dev, params);
844 }
845
846 int supplicant_get_power_save_config(const struct device *dev,
847 struct wifi_ps_config *config)
848 {
849 const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev);
850
851 if (!wifi_mgmt_api || !wifi_mgmt_api->get_power_save_config) {
852 wpa_printf(MSG_ERROR, "Get power save config not supported");
853 return -ENOTSUP;
854 }
855
856 return wifi_mgmt_api->get_power_save_config(dev, config);
857 }
858
859 int supplicant_reg_domain(const struct device *dev,
860 struct wifi_reg_domain *reg_domain)
861 {
862 const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev);
863
864 if (!wifi_mgmt_api || !wifi_mgmt_api->reg_domain) {
865 wpa_printf(MSG_ERROR, "Regulatory domain not supported");
866 return -ENOTSUP;
867 }
868
869 return wifi_mgmt_api->reg_domain(dev, reg_domain);
870 }
871
872 int supplicant_mode(const struct device *dev, struct wifi_mode_info *mode)
873 {
874 const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev);
875
876 if (!wifi_mgmt_api || !wifi_mgmt_api->mode) {
877 wpa_printf(MSG_ERROR, "Setting mode not supported");
878 return -ENOTSUP;
879 }
880
881 return wifi_mgmt_api->mode(dev, mode);
882 }
883
884 int supplicant_filter(const struct device *dev, struct wifi_filter_info *filter)
885 {
886 const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev);
887
888 if (!wifi_mgmt_api || !wifi_mgmt_api->filter) {
889 wpa_printf(MSG_ERROR, "Setting filter not supported");
890 return -ENOTSUP;
891 }
892
893 return wifi_mgmt_api->filter(dev, filter);
894 }
895
896 int supplicant_channel(const struct device *dev, struct wifi_channel_info *channel)
897 {
898 const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev);
899
900 if (!wifi_mgmt_api || !wifi_mgmt_api->channel) {
901 wpa_printf(MSG_ERROR, "Setting channel not supported");
902 return -ENOTSUP;
903 }
904
905 return wifi_mgmt_api->channel(dev, channel);
906 }
907
908 #ifdef CONFIG_AP
909 int supplicant_ap_enable(const struct device *dev,
910 struct wifi_connect_req_params *params)
911 {
912 struct wpa_supplicant *wpa_s;
913 int ret;
914
915 if (!net_if_is_admin_up(net_if_lookup_by_dev(dev))) {
916 wpa_printf(MSG_ERROR,
917 "Interface %s is down, dropping connect",
918 dev->name);
919 return -1;
920 }
921
922 k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER);
923
924 wpa_s = get_wpa_s_handle(dev);
925 if (!wpa_s) {
926 ret = -1;
927 wpa_printf(MSG_ERROR, "Interface %s not found", dev->name);
928 goto out;
929 }
930
931 if (wpa_s->wpa_state != WPA_DISCONNECTED) {
932 ret = -EBUSY;
933 wpa_printf(MSG_ERROR, "Interface %s is not in disconnected state", dev->name);
934 goto out;
935 }
936
937 /* No need to check for existing network to join for SoftAP*/
938 wpa_s->conf->ap_scan = 2;
939
940 ret = wpas_add_and_config_network(wpa_s, params, true);
941 if (ret) {
942 wpa_printf(MSG_ERROR, "Failed to add and configure network for AP mode: %d", ret);
943 goto out;
944 }
945
946 out:
947 k_mutex_unlock(&wpa_supplicant_mutex);
948
949 return ret;
950 }
951
952 int supplicant_ap_disable(const struct device *dev)
953 {
954 struct wpa_supplicant *wpa_s;
955 int ret = -1;
956
957 k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER);
958
959 wpa_s = get_wpa_s_handle(dev);
960 if (!wpa_s) {
961 ret = -1;
962 wpa_printf(MSG_ERROR, "Interface %s not found", dev->name);
963 goto out;
964 }
965
966 ret = wpas_disconnect_network(dev, WPAS_MODE_AP);
967 if (ret) {
968 wpa_printf(MSG_ERROR, "Failed to disconnect from network");
969 goto out;
970 }
971
972 /* Restore ap_scan to default value */
973 wpa_s->conf->ap_scan = 1;
974
975 out:
976 k_mutex_unlock(&wpa_supplicant_mutex);
977 return ret;
978 }
979
980 int supplicant_ap_sta_disconnect(const struct device *dev,
981 const uint8_t *mac_addr)
982 {
983 struct wpa_supplicant *wpa_s;
984 int ret = -1;
985
986 k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER);
987
988 wpa_s = get_wpa_s_handle(dev);
989 if (!wpa_s) {
990 ret = -1;
991 wpa_printf(MSG_ERROR, "Interface %s not found", dev->name);
992 goto out;
993 }
994
995 if (!mac_addr) {
996 ret = -EINVAL;
997 wpa_printf(MSG_ERROR, "Invalid MAC address");
998 goto out;
999 }
1000
1001 if (!wpa_cli_cmd_v("disassociate %02x:%02x:%02x:%02x:%02x:%02x",
1002 mac_addr[0], mac_addr[1], mac_addr[2],
1003 mac_addr[3], mac_addr[4], mac_addr[5])) {
1004 goto out;
1005 }
1006
1007 ret = 0;
1008
1009 out:
1010 k_mutex_unlock(&wpa_supplicant_mutex);
1011
1012 return ret;
1013 }
1014 #endif /* CONFIG_AP */
1015