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