1 /*
2  * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or
3  * an affiliate of Cypress Semiconductor Corporation
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /**
9  * @brief AIROC Wi-Fi driver.
10  */
11 
12 #include <zephyr/logging/log.h>
13 #include <zephyr/net/conn_mgr/connectivity_wifi_mgmt.h>
14 #include <airoc_wifi.h>
15 #include <airoc_whd_hal_common.h>
16 
17 LOG_MODULE_REGISTER(infineon_airoc_wifi, CONFIG_WIFI_LOG_LEVEL);
18 
19 #ifndef AIROC_WIFI_TX_PACKET_POOL_COUNT
20 #define AIROC_WIFI_TX_PACKET_POOL_COUNT (10)
21 #endif
22 
23 #ifndef AIROC_WIFI_RX_PACKET_POOL_COUNT
24 #define AIROC_WIFI_RX_PACKET_POOL_COUNT (10)
25 #endif
26 
27 #ifndef AIROC_WIFI_PACKET_POOL_SIZE
28 #define AIROC_WIFI_PACKET_POOL_SIZE     (1600)
29 #endif
30 
31 #define AIROC_WIFI_PACKET_POOL_COUNT                                                               \
32 	(AIROC_WIFI_TX_PACKET_POOL_COUNT + AIROC_WIFI_RX_PACKET_POOL_COUNT)
33 
34 #define AIROC_WIFI_WAIT_SEMA_MS    (30 * 1000)
35 #define AIROC_WIFI_SCAN_TIMEOUT_MS (12 * 1000)
36 
37 /* AIROC private functions */
38 static whd_result_t airoc_wifi_host_buffer_get(whd_buffer_t *buffer, whd_buffer_dir_t direction,
39 					       uint16_t size, uint32_t timeout_ms);
40 static void airoc_wifi_buffer_release(whd_buffer_t buffer, whd_buffer_dir_t direction);
41 static uint8_t *airoc_wifi_buffer_get_current_piece_data_pointer(whd_buffer_t buffer);
42 static uint16_t airoc_wifi_buffer_get_current_piece_size(whd_buffer_t buffer);
43 static whd_result_t airoc_wifi_buffer_set_size(whd_buffer_t buffer, unsigned short size);
44 static whd_result_t airoc_wifi_buffer_add_remove_at_front(whd_buffer_t *buffer,
45 							  int32_t add_remove_amount);
46 static void airoc_wifi_network_process_ethernet_data(whd_interface_t interface,
47 						     whd_buffer_t buffer);
48 int airoc_wifi_init_primary(const struct device *dev, whd_interface_t *interface,
49 			    whd_netif_funcs_t *netif_funcs, whd_buffer_funcs_t *buffer_if);
50 
51 /* Allocate network pool */
52 NET_BUF_POOL_FIXED_DEFINE(airoc_pool, AIROC_WIFI_PACKET_POOL_COUNT,
53 				AIROC_WIFI_PACKET_POOL_SIZE, 0, NULL);
54 
55 /* AIROC globals */
56 static uint16_t ap_event_handler_index = 0xFF;
57 
58 /* Use global iface pointer to support any Ethernet driver */
59 /* necessary for wifi callback functions */
60 static struct net_if *airoc_wifi_iface;
61 
62 static whd_interface_t airoc_if;
63 static whd_interface_t airoc_sta_if;
64 static whd_interface_t airoc_ap_if;
65 
66 static const whd_event_num_t sta_link_events[] = {
67 	WLC_E_LINK,    WLC_E_DEAUTH_IND,       WLC_E_DISASSOC_IND,
68 	WLC_E_PSK_SUP, WLC_E_CSA_COMPLETE_IND, WLC_E_NONE};
69 
70 static const whd_event_num_t ap_link_events[] = {WLC_E_DISASSOC_IND, WLC_E_DEAUTH_IND,
71 						 WLC_E_ASSOC_IND,    WLC_E_REASSOC_IND,
72 						 WLC_E_AUTHORIZED,   WLC_E_NONE};
73 
74 static uint16_t sta_event_handler_index = 0xFF;
75 static void airoc_event_task(void);
76 static struct airoc_wifi_data airoc_wifi_data = {0};
77 
78 #if defined(SPI_DATA_IRQ_SHARED)
79 PINCTRL_DT_INST_DEFINE(0);
80 #endif
81 
82 static struct airoc_wifi_config airoc_wifi_config = {
83 #if defined(CONFIG_AIROC_WIFI_BUS_SDIO)
84 	.bus_dev.bus_sdio = DEVICE_DT_GET(DT_INST_PARENT(0)),
85 #elif defined(CONFIG_AIROC_WIFI_BUS_SPI)
86 	.bus_dev.bus_spi = SPI_DT_SPEC_GET(DT_DRV_INST(0), AIROC_WIFI_SPI_OPERATION, 0),
87 	.bus_select_gpio = GPIO_DT_SPEC_GET_OR(DT_DRV_INST(0), bus_select_gpios, {0}),
88 #if defined(SPI_DATA_IRQ_SHARED)
89 	.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
90 #endif
91 #endif
92 	.wifi_reg_on_gpio = GPIO_DT_SPEC_GET_OR(DT_DRV_INST(0), wifi_reg_on_gpios, {0}),
93 	.wifi_host_wake_gpio = GPIO_DT_SPEC_GET_OR(DT_DRV_INST(0), wifi_host_wake_gpios, {0}),
94 	.wifi_dev_wake_gpio = GPIO_DT_SPEC_GET_OR(DT_DRV_INST(0), wifi_dev_wake_gpios, {0}),
95 };
96 
97 static whd_buffer_funcs_t airoc_wifi_buffer_if_default = {
98 	.whd_host_buffer_get = airoc_wifi_host_buffer_get,
99 	.whd_buffer_release = airoc_wifi_buffer_release,
100 	.whd_buffer_get_current_piece_data_pointer =
101 		airoc_wifi_buffer_get_current_piece_data_pointer,
102 	.whd_buffer_get_current_piece_size = airoc_wifi_buffer_get_current_piece_size,
103 	.whd_buffer_set_size = airoc_wifi_buffer_set_size,
104 	.whd_buffer_add_remove_at_front = airoc_wifi_buffer_add_remove_at_front,
105 };
106 
107 static whd_netif_funcs_t airoc_wifi_netif_if_default = {
108 	.whd_network_process_ethernet_data = airoc_wifi_network_process_ethernet_data,
109 };
110 
111 K_MSGQ_DEFINE(airoc_wifi_msgq, sizeof(whd_event_header_t), 10, 4);
112 K_THREAD_STACK_DEFINE(airoc_wifi_event_stack, CONFIG_AIROC_WIFI_EVENT_TASK_STACK_SIZE);
113 static struct k_thread airoc_wifi_event_thread;
114 
115 struct airoc_wifi_event_t {
116 	uint8_t is_ap_event;
117 	uint32_t event_type;
118 };
119 
120 /*
121  * AIROC Wi-Fi helper functions
122  */
airoc_wifi_get_whd_interface(void)123 whd_interface_t airoc_wifi_get_whd_interface(void)
124 {
125 	return airoc_if;
126 }
127 
airoc_wifi_scan_cb_search(whd_scan_result_t ** result_ptr,void * user_data,whd_scan_status_t status)128 static void airoc_wifi_scan_cb_search(whd_scan_result_t **result_ptr, void *user_data,
129 				      whd_scan_status_t status)
130 {
131 	if (status == WHD_SCAN_ABORTED) {
132 		k_sem_give(&airoc_wifi_data.sema_scan);
133 		return;
134 	}
135 
136 	if (status == WHD_SCAN_COMPLETED_SUCCESSFULLY) {
137 		k_sem_give(&airoc_wifi_data.sema_scan);
138 	} else if ((status == WHD_SCAN_INCOMPLETE) && (user_data != NULL) &&
139 		   ((**result_ptr).SSID.length == ((whd_scan_result_t *)user_data)->SSID.length)) {
140 		if (strncmp(((whd_scan_result_t *)user_data)->SSID.value, (**result_ptr).SSID.value,
141 			    (**result_ptr).SSID.length) == 0) {
142 			memcpy(user_data, *result_ptr, sizeof(whd_scan_result_t));
143 		}
144 	}
145 }
146 
convert_whd_security_to_zephyr(whd_security_t security)147 static int convert_whd_security_to_zephyr(whd_security_t security)
148 {
149 	int zephyr_security = WIFI_SECURITY_TYPE_UNKNOWN;
150 
151 	switch (security) {
152 	case WHD_SECURITY_OPEN:
153 		zephyr_security = WIFI_SECURITY_TYPE_NONE;
154 		break;
155 	case WHD_SECURITY_WEP_PSK:
156 		zephyr_security = WIFI_SECURITY_TYPE_WEP;
157 		break;
158 
159 	case WHD_SECURITY_WPA3_WPA2_PSK:
160 	case WHD_SECURITY_WPA2_AES_PSK:
161 		zephyr_security = WIFI_SECURITY_TYPE_PSK;
162 		break;
163 
164 	case WHD_SECURITY_WPA2_AES_PSK_SHA256:
165 		zephyr_security = WIFI_SECURITY_TYPE_PSK_SHA256;
166 		break;
167 
168 	case WHD_SECURITY_WPA3_SAE:
169 		zephyr_security = WIFI_SECURITY_TYPE_SAE;
170 		break;
171 
172 	case WHD_SECURITY_WPA_AES_PSK:
173 		zephyr_security = WIFI_SECURITY_TYPE_WPA_PSK;
174 		break;
175 
176 	default:
177 		if ((security & ENTERPRISE_ENABLED) != 0) {
178 			zephyr_security = WIFI_SECURITY_TYPE_EAP;
179 		}
180 		break;
181 	}
182 	return zephyr_security;
183 }
184 
parse_scan_result(whd_scan_result_t * p_whd_result,struct wifi_scan_result * p_zy_result)185 static void parse_scan_result(whd_scan_result_t *p_whd_result, struct wifi_scan_result *p_zy_result)
186 {
187 	if (p_whd_result->SSID.length != 0) {
188 		p_zy_result->ssid_length = p_whd_result->SSID.length;
189 		strncpy(p_zy_result->ssid, p_whd_result->SSID.value, p_whd_result->SSID.length);
190 		p_zy_result->channel = p_whd_result->channel;
191 		p_zy_result->security = convert_whd_security_to_zephyr(p_whd_result->security);
192 		p_zy_result->rssi = (int8_t)p_whd_result->signal_strength;
193 		p_zy_result->mac_length = 6;
194 		memcpy(p_zy_result->mac, &p_whd_result->BSSID, 6);
195 	}
196 }
197 
scan_callback(whd_scan_result_t ** result_ptr,void * user_data,whd_scan_status_t status)198 static void scan_callback(whd_scan_result_t **result_ptr, void *user_data, whd_scan_status_t status)
199 {
200 	struct airoc_wifi_data *data = user_data;
201 	whd_scan_result_t whd_scan_result;
202 	struct wifi_scan_result zephyr_scan_result;
203 
204 	if (status == WHD_SCAN_COMPLETED_SUCCESSFULLY || status == WHD_SCAN_ABORTED) {
205 		data->scan_rslt_cb(data->iface, 0, NULL);
206 		data->scan_rslt_cb = NULL;
207 		/* NOTE: It is complete of scan packet, do not need to clean result_ptr,
208 		 * WHD will release result_ptr buffer
209 		 */
210 		return;
211 	}
212 
213 	/* We recived scan data so process it */
214 	if ((result_ptr != NULL) && (*result_ptr != NULL)) {
215 		memcpy(&whd_scan_result, *result_ptr, sizeof(whd_scan_result_t));
216 		parse_scan_result(&whd_scan_result, &zephyr_scan_result);
217 		data->scan_rslt_cb(data->iface, 0, &zephyr_scan_result);
218 	}
219 	memset(*result_ptr, 0, sizeof(whd_scan_result_t));
220 }
221 
222 /*
223  * Implement WHD network buffers functions
224  */
airoc_wifi_host_buffer_get(whd_buffer_t * buffer,whd_buffer_dir_t direction,uint16_t size,uint32_t timeout_ms)225 static whd_result_t airoc_wifi_host_buffer_get(whd_buffer_t *buffer, whd_buffer_dir_t direction,
226 					       uint16_t size, uint32_t timeout_ms)
227 {
228 	ARG_UNUSED(direction);
229 	ARG_UNUSED(timeout_ms);
230 	struct net_buf *buf;
231 
232 	buf = net_buf_alloc_len(&airoc_pool, size, K_NO_WAIT);
233 	if ((buf == NULL) || (buf->size < size)) {
234 		return WHD_BUFFER_ALLOC_FAIL;
235 	}
236 	*buffer = buf;
237 
238 	/* Set buffer size */
239 	(void) airoc_wifi_buffer_set_size(*buffer, size);
240 
241 	return WHD_SUCCESS;
242 }
243 
airoc_wifi_buffer_release(whd_buffer_t buffer,whd_buffer_dir_t direction)244 static void airoc_wifi_buffer_release(whd_buffer_t buffer, whd_buffer_dir_t direction)
245 {
246 	CY_UNUSED_PARAMETER(direction);
247 	(void)net_buf_destroy((struct net_buf *)buffer);
248 }
249 
airoc_wifi_buffer_get_current_piece_data_pointer(whd_buffer_t buffer)250 static uint8_t *airoc_wifi_buffer_get_current_piece_data_pointer(whd_buffer_t buffer)
251 {
252 	CY_ASSERT(buffer != NULL);
253 	struct net_buf *buf = (struct net_buf *)buffer;
254 
255 	return (uint8_t *)buf->data;
256 }
257 
airoc_wifi_buffer_get_current_piece_size(whd_buffer_t buffer)258 static uint16_t airoc_wifi_buffer_get_current_piece_size(whd_buffer_t buffer)
259 {
260 	CY_ASSERT(buffer != NULL);
261 	struct net_buf *buf = (struct net_buf *)buffer;
262 
263 	return (uint16_t)buf->size;
264 }
265 
airoc_wifi_buffer_set_size(whd_buffer_t buffer,unsigned short size)266 static whd_result_t airoc_wifi_buffer_set_size(whd_buffer_t buffer, unsigned short size)
267 {
268 	CY_ASSERT(buffer != NULL);
269 	struct net_buf *buf = (struct net_buf *)buffer;
270 
271 	buf->size = size;
272 	return CY_RSLT_SUCCESS;
273 }
274 
airoc_wifi_buffer_add_remove_at_front(whd_buffer_t * buffer,int32_t add_remove_amount)275 static whd_result_t airoc_wifi_buffer_add_remove_at_front(whd_buffer_t *buffer,
276 							  int32_t add_remove_amount)
277 {
278 	CY_ASSERT(buffer != NULL);
279 	struct net_buf **buf = (struct net_buf **)buffer;
280 
281 	if (add_remove_amount > 0) {
282 		(*buf)->len = (*buf)->size;
283 		(*buf)->data = net_buf_pull(*buf, add_remove_amount);
284 	} else {
285 		(*buf)->data = net_buf_push(*buf, -add_remove_amount);
286 		(*buf)->len = (*buf)->size;
287 	}
288 	return WHD_SUCCESS;
289 }
290 
airoc_mgmt_send(const struct device * dev,struct net_pkt * pkt)291 static int airoc_mgmt_send(const struct device *dev, struct net_pkt *pkt)
292 {
293 	struct airoc_wifi_data *data = dev->data;
294 	cy_rslt_t ret;
295 	size_t pkt_len = net_pkt_get_len(pkt);
296 	struct net_buf *buf = NULL;
297 
298 	/* Read the packet payload */
299 	if (net_pkt_read(pkt, data->frame_buf, pkt_len) < 0) {
300 		LOG_ERR("net_pkt_read failed");
301 		return -EIO;
302 	}
303 
304 	/* Allocate Network Buffer from pool with Packet Length + Data Header */
305 	ret = airoc_wifi_host_buffer_get((whd_buffer_t *) &buf, WHD_NETWORK_TX,
306 					 pkt_len + sizeof(data_header_t), 0);
307 	if ((ret != WHD_SUCCESS) || (buf == NULL)) {
308 		return -EIO;
309 	}
310 
311 	/* Reserve the buffer Headroom for WHD Data header */
312 	net_buf_reserve(buf, sizeof(data_header_t));
313 
314 	/* Copy the buffer to network Buffer pointer */
315 	(void)memcpy(buf->data, data->frame_buf, pkt_len);
316 
317 	/* Call WHD API to send out the Packet */
318 	ret = whd_network_send_ethernet_data(airoc_if, (void *)buf);
319 	if (ret != CY_RSLT_SUCCESS) {
320 		LOG_ERR("whd_network_send_ethernet_data failed");
321 #if defined(CONFIG_NET_STATISTICS_WIFI)
322 		data->stats.errors.tx++;
323 #endif
324 		return -EIO;
325 	}
326 
327 #if defined(CONFIG_NET_STATISTICS_WIFI)
328 	data->stats.bytes.sent += pkt_len;
329 	data->stats.pkts.tx++;
330 #endif
331 
332 	return 0;
333 }
334 
airoc_wifi_network_process_ethernet_data(whd_interface_t interface,whd_buffer_t buffer)335 static void airoc_wifi_network_process_ethernet_data(whd_interface_t interface, whd_buffer_t buffer)
336 {
337 	struct net_pkt *pkt;
338 	uint8_t *data = whd_buffer_get_current_piece_data_pointer(interface->whd_driver, buffer);
339 	uint32_t len = whd_buffer_get_current_piece_size(interface->whd_driver, buffer);
340 	bool net_pkt_unref_flag = false;
341 
342 	if ((airoc_wifi_iface != NULL) && net_if_flag_is_set(airoc_wifi_iface, NET_IF_UP)) {
343 
344 		pkt = net_pkt_rx_alloc_with_buffer(airoc_wifi_iface, len, AF_UNSPEC, 0, K_NO_WAIT);
345 
346 		if (pkt != NULL) {
347 			if (net_pkt_write(pkt, data, len) < 0) {
348 				LOG_ERR("Failed to write pkt");
349 				net_pkt_unref_flag = true;
350 			}
351 
352 			if ((net_pkt_unref_flag) || (net_recv_data(airoc_wifi_iface, pkt) < 0)) {
353 				LOG_ERR("Failed to push received data");
354 				net_pkt_unref_flag = true;
355 			}
356 		} else {
357 			LOG_ERR("Failed to get net buffer");
358 		}
359 	}
360 
361 	/* Release a packet buffer */
362 	airoc_wifi_buffer_release(buffer, WHD_NETWORK_RX);
363 
364 #if defined(CONFIG_NET_STATISTICS_WIFI)
365 	airoc_wifi_data.stats.bytes.received += len;
366 	airoc_wifi_data.stats.pkts.rx++;
367 #endif
368 
369 	if (net_pkt_unref_flag) {
370 		net_pkt_unref(pkt);
371 #if defined(CONFIG_NET_STATISTICS_WIFI)
372 		airoc_wifi_data.stats.errors.rx++;
373 #endif
374 	}
375 }
376 
airoc_get_capabilities(const struct device * dev)377 static enum ethernet_hw_caps airoc_get_capabilities(const struct device *dev)
378 {
379 	ARG_UNUSED(dev);
380 
381 	return ETHERNET_HW_FILTERING;
382 }
383 
airoc_set_config(const struct device * dev,enum ethernet_config_type type,const struct ethernet_config * config)384 static int airoc_set_config(const struct device *dev,
385 			    enum ethernet_config_type type,
386 			    const struct ethernet_config *config)
387 {
388 	ARG_UNUSED(dev);
389 	whd_mac_t whd_mac_addr;
390 
391 	switch (type) {
392 	case ETHERNET_CONFIG_TYPE_FILTER:
393 		for (int i = 0; i < WHD_ETHER_ADDR_LEN; i++) {
394 			whd_mac_addr.octet[i] = config->filter.mac_address.addr[i];
395 		}
396 		if (config->filter.set) {
397 			whd_wifi_register_multicast_address(airoc_if, &whd_mac_addr);
398 		} else {
399 			whd_wifi_unregister_multicast_address(airoc_if, &whd_mac_addr);
400 		}
401 		return 0;
402 	default:
403 		break;
404 	}
405 	return -ENOTSUP;
406 }
407 
link_events_handler(whd_interface_t ifp,const whd_event_header_t * event_header,const uint8_t * event_data,void * handler_user_data)408 static void *link_events_handler(whd_interface_t ifp, const whd_event_header_t *event_header,
409 				 const uint8_t *event_data, void *handler_user_data)
410 {
411 	ARG_UNUSED(ifp);
412 	ARG_UNUSED(event_data);
413 	ARG_UNUSED(handler_user_data);
414 
415 	k_msgq_put(&airoc_wifi_msgq, event_header, K_FOREVER);
416 	return NULL;
417 }
418 
airoc_event_task(void)419 static void airoc_event_task(void)
420 {
421 	whd_event_header_t event_header;
422 
423 	while (1) {
424 		k_msgq_get(&airoc_wifi_msgq, &event_header, K_FOREVER);
425 
426 		switch ((whd_event_num_t)event_header.event_type) {
427 		case WLC_E_LINK:
428 			break;
429 
430 		case WLC_E_DEAUTH_IND:
431 		case WLC_E_DISASSOC_IND:
432 			net_if_dormant_on(airoc_wifi_iface);
433 			break;
434 
435 		default:
436 			break;
437 		}
438 	}
439 }
440 
airoc_mgmt_init(struct net_if * iface)441 static void airoc_mgmt_init(struct net_if *iface)
442 {
443 	const struct device *dev = net_if_get_device(iface);
444 	struct airoc_wifi_data *data = dev->data;
445 	struct ethernet_context *eth_ctx = net_if_l2_data(iface);
446 
447 	eth_ctx->eth_if_type = L2_ETH_IF_TYPE_WIFI;
448 	data->iface = iface;
449 	airoc_wifi_iface = iface;
450 
451 	/* Read WLAN MAC Address */
452 	if (whd_wifi_get_mac_address(airoc_sta_if, &airoc_sta_if->mac_addr) != WHD_SUCCESS) {
453 		LOG_ERR("Failed to get mac address");
454 	} else {
455 		(void)memcpy(&data->mac_addr, &airoc_sta_if->mac_addr,
456 			     sizeof(airoc_sta_if->mac_addr));
457 	}
458 
459 	/* Assign link local address. */
460 	if (net_if_set_link_addr(iface, data->mac_addr, 6, NET_LINK_ETHERNET)) {
461 		LOG_ERR("Failed to set link addr");
462 	}
463 
464 	/* Initialize Ethernet L2 stack */
465 	ethernet_init(iface);
466 
467 	/* Not currently connected to a network */
468 	net_if_dormant_on(iface);
469 
470 	/* L1 network layer (physical layer) is up */
471 	net_if_carrier_on(data->iface);
472 }
473 
airoc_mgmt_scan(const struct device * dev,struct wifi_scan_params * params,scan_result_cb_t cb)474 static int airoc_mgmt_scan(const struct device *dev, struct wifi_scan_params *params,
475 			   scan_result_cb_t cb)
476 {
477 	struct airoc_wifi_data *data = dev->data;
478 
479 	if (data->scan_rslt_cb != NULL) {
480 		LOG_INF("Scan callback in progress");
481 		return -EINPROGRESS;
482 	}
483 
484 	if (k_sem_take(&data->sema_common, K_MSEC(AIROC_WIFI_WAIT_SEMA_MS)) != 0) {
485 		return -EAGAIN;
486 	}
487 
488 	data->scan_rslt_cb = cb;
489 
490 	/* Connect to the network */
491 	if (whd_wifi_scan(airoc_sta_if, params->scan_type, WHD_BSS_TYPE_ANY, &(data->ssid), NULL,
492 			  NULL, NULL, scan_callback, &(data->scan_result), data) != WHD_SUCCESS) {
493 		LOG_ERR("Failed to start scan");
494 		k_sem_give(&data->sema_common);
495 		return -EAGAIN;
496 	}
497 
498 	k_sem_give(&data->sema_common);
499 	return 0;
500 }
501 
airoc_mgmt_connect(const struct device * dev,struct wifi_connect_req_params * params)502 static int airoc_mgmt_connect(const struct device *dev, struct wifi_connect_req_params *params)
503 {
504 	struct airoc_wifi_data *data = (struct airoc_wifi_data *)dev->data;
505 	whd_ssid_t ssid = {0};
506 	int ret = 0;
507 
508 	if (k_sem_take(&data->sema_common, K_MSEC(AIROC_WIFI_WAIT_SEMA_MS)) != 0) {
509 		return -EAGAIN;
510 	}
511 
512 	if (data->is_sta_connected) {
513 		LOG_ERR("Already connected");
514 		ret = -EALREADY;
515 		goto error;
516 	}
517 
518 	if (data->is_ap_up) {
519 		LOG_ERR("Network interface is busy AP. Please first disable AP.");
520 		ret = -EBUSY;
521 		goto error;
522 	}
523 
524 	ssid.length = params->ssid_length;
525 	memcpy(ssid.value, params->ssid, params->ssid_length);
526 
527 	whd_scan_result_t scan_result;
528 	whd_scan_result_t usr_result = {0};
529 
530 	usr_result.SSID.length = ssid.length;
531 	memcpy(usr_result.SSID.value, ssid.value, ssid.length);
532 
533 	if (whd_wifi_scan(airoc_sta_if, WHD_SCAN_TYPE_ACTIVE, WHD_BSS_TYPE_ANY, NULL, NULL, NULL,
534 			  NULL, airoc_wifi_scan_cb_search, &scan_result,
535 			  &(usr_result)) != WHD_SUCCESS) {
536 		LOG_ERR("Failed start scan");
537 		ret = -EAGAIN;
538 		goto error;
539 	}
540 
541 	if (k_sem_take(&airoc_wifi_data.sema_scan, K_MSEC(AIROC_WIFI_SCAN_TIMEOUT_MS)) != 0) {
542 		whd_wifi_stop_scan(airoc_sta_if);
543 		ret = -EAGAIN;
544 		goto error;
545 	}
546 
547 	if (usr_result.security == WHD_SECURITY_UNKNOWN) {
548 		ret = -EAGAIN;
549 		LOG_ERR("Could not scan device");
550 		goto error;
551 	}
552 
553 	/* Connect to the network */
554 	if (whd_wifi_join(airoc_sta_if, &usr_result.SSID, usr_result.security, params->psk,
555 			  params->psk_length) != WHD_SUCCESS) {
556 		LOG_ERR("Failed to connect with network");
557 
558 		ret = -EAGAIN;
559 		goto error;
560 	}
561 
562 error:
563 	if (ret < 0) {
564 		net_if_dormant_on(data->iface);
565 	} else {
566 		net_if_dormant_off(data->iface);
567 		data->is_sta_connected = true;
568 #if defined(CONFIG_NET_DHCPV4)
569 		net_dhcpv4_restart(data->iface);
570 #endif /* defined(CONFIG_NET_DHCPV4) */
571 	}
572 
573 	wifi_mgmt_raise_connect_result_event(data->iface, ret);
574 	k_sem_give(&data->sema_common);
575 	return ret;
576 }
577 
airoc_mgmt_disconnect(const struct device * dev)578 static int airoc_mgmt_disconnect(const struct device *dev)
579 {
580 	int ret = 0;
581 	struct airoc_wifi_data *data = (struct airoc_wifi_data *)dev->data;
582 
583 	if (k_sem_take(&data->sema_common, K_MSEC(AIROC_WIFI_WAIT_SEMA_MS)) != 0) {
584 		return -EAGAIN;
585 	}
586 
587 	if (whd_wifi_leave(airoc_sta_if) != WHD_SUCCESS) {
588 		k_sem_give(&data->sema_common);
589 		ret = -EAGAIN;
590 	} else {
591 		data->is_sta_connected = false;
592 		net_if_dormant_on(data->iface);
593 	}
594 
595 	wifi_mgmt_raise_disconnect_result_event(data->iface, ret);
596 	k_sem_give(&data->sema_common);
597 
598 	return ret;
599 }
600 
airoc_wifi_ap_link_events_handler(whd_interface_t ifp,const whd_event_header_t * event_header,const uint8_t * event_data,void * handler_user_data)601 static void *airoc_wifi_ap_link_events_handler(whd_interface_t ifp,
602 					       const whd_event_header_t *event_header,
603 					       const uint8_t *event_data, void *handler_user_data)
604 {
605 	struct airoc_wifi_event_t airoc_event = {
606 		.is_ap_event = 1,
607 		.event_type = event_header->event_type
608 	};
609 
610 	k_msgq_put(&airoc_wifi_msgq, &airoc_event, K_FOREVER);
611 
612 	return NULL;
613 }
614 
airoc_mgmt_ap_enable(const struct device * dev,struct wifi_connect_req_params * params)615 static int airoc_mgmt_ap_enable(const struct device *dev, struct wifi_connect_req_params *params)
616 {
617 	struct airoc_wifi_data *data = dev->data;
618 	whd_security_t security;
619 	whd_ssid_t ssid;
620 	uint8_t channel;
621 	int ret = 0;
622 
623 	if (k_sem_take(&data->sema_common, K_MSEC(AIROC_WIFI_WAIT_SEMA_MS)) != 0) {
624 		return -EAGAIN;
625 	}
626 
627 	if (data->is_sta_connected) {
628 		LOG_ERR("Network interface is busy in STA mode. Please first disconnect STA.");
629 		ret = -EBUSY;
630 		goto error;
631 	}
632 
633 	if (data->is_ap_up) {
634 		LOG_ERR("Already AP is on - first disable");
635 		ret = -EAGAIN;
636 		goto error;
637 	}
638 
639 	if (!data->second_interface_init) {
640 		if (whd_add_secondary_interface(data->whd_drv, NULL, &airoc_ap_if) !=
641 		    CY_RSLT_SUCCESS) {
642 			LOG_ERR("Error Unable to bring up the whd secondary interface");
643 			ret = -EAGAIN;
644 			goto error;
645 		}
646 		data->second_interface_init = true;
647 	}
648 
649 	ssid.length = params->ssid_length;
650 	memcpy(ssid.value, params->ssid, ssid.length);
651 
652 	/* make sure to set valid channels for 2G and 5G:
653 	 * - 2G channels from 1 to 11,
654 	 * - 5G channels from 36 to 165
655 	 */
656 	if (((params->channel > 0) && (params->channel < 12)) ||
657 	    ((params->channel > 35) && (params->channel < 166))) {
658 		channel = params->channel;
659 	} else {
660 		channel = 1;
661 		LOG_WRN("Discard of setting unsupported channel: %u (will set 1)",
662 			params->channel);
663 	}
664 
665 	switch (params->security) {
666 	case WIFI_SECURITY_TYPE_NONE:
667 		security = WHD_SECURITY_OPEN;
668 		break;
669 	case WIFI_SECURITY_TYPE_PSK:
670 		security = WHD_SECURITY_WPA2_AES_PSK;
671 		break;
672 	case WIFI_SECURITY_TYPE_SAE:
673 		security = WHD_SECURITY_WPA3_SAE;
674 		break;
675 	default:
676 		goto error;
677 	}
678 
679 	if (whd_wifi_init_ap(airoc_ap_if, &ssid, security, (const uint8_t *)params->psk,
680 			     params->psk_length, channel) != 0) {
681 		LOG_ERR("Failed to init whd ap interface");
682 		ret = -EAGAIN;
683 		goto error;
684 	}
685 
686 	if (whd_wifi_start_ap(airoc_ap_if) != 0) {
687 		LOG_ERR("Failed to start whd ap interface");
688 		ret = -EAGAIN;
689 		goto error;
690 	}
691 
692 	/* set event handler */
693 	if (whd_management_set_event_handler(airoc_ap_if, ap_link_events,
694 					     airoc_wifi_ap_link_events_handler, NULL,
695 					     &ap_event_handler_index) != 0) {
696 		whd_wifi_stop_ap(airoc_ap_if);
697 		ret = -EAGAIN;
698 		goto error;
699 	}
700 
701 	data->is_ap_up = true;
702 	airoc_if = airoc_ap_if;
703 	net_if_dormant_off(data->iface);
704 error:
705 
706 	k_sem_give(&data->sema_common);
707 	return ret;
708 }
709 
710 #if defined(CONFIG_NET_STATISTICS_WIFI)
airoc_mgmt_wifi_stats(const struct device * dev,struct net_stats_wifi * stats)711 static int airoc_mgmt_wifi_stats(const struct device *dev, struct net_stats_wifi *stats)
712 {
713 	struct airoc_wifi_data *data = dev->data;
714 
715 	stats->bytes.received = data->stats.bytes.received;
716 	stats->bytes.sent = data->stats.bytes.sent;
717 	stats->pkts.rx = data->stats.pkts.rx;
718 	stats->pkts.tx = data->stats.pkts.tx;
719 	stats->errors.rx = data->stats.errors.rx;
720 	stats->errors.tx = data->stats.errors.tx;
721 	stats->broadcast.rx = data->stats.broadcast.rx;
722 	stats->broadcast.tx = data->stats.broadcast.tx;
723 	stats->multicast.rx = data->stats.multicast.rx;
724 	stats->multicast.tx = data->stats.multicast.tx;
725 	stats->sta_mgmt.beacons_rx = data->stats.sta_mgmt.beacons_rx;
726 	stats->sta_mgmt.beacons_miss = data->stats.sta_mgmt.beacons_miss;
727 
728 	return 0;
729 }
730 #endif
731 
airoc_mgmt_ap_disable(const struct device * dev)732 static int airoc_mgmt_ap_disable(const struct device *dev)
733 {
734 	cy_rslt_t whd_ret;
735 	struct airoc_wifi_data *data = dev->data;
736 
737 	if (k_sem_take(&data->sema_common, K_MSEC(AIROC_WIFI_WAIT_SEMA_MS)) != 0) {
738 		return -EAGAIN;
739 	}
740 
741 	if (whd_wifi_deregister_event_handler(airoc_ap_if, ap_event_handler_index)) {
742 		LOG_ERR("Can't whd_wifi_deregister_event_handler");
743 	}
744 
745 	whd_ret = whd_wifi_stop_ap(airoc_ap_if);
746 	if (whd_ret == CY_RSLT_SUCCESS) {
747 		data->is_ap_up = false;
748 		airoc_if = airoc_sta_if;
749 		net_if_dormant_on(data->iface);
750 	} else {
751 		LOG_ERR("Can't stop wifi ap: %u", whd_ret);
752 	}
753 
754 	k_sem_give(&data->sema_common);
755 
756 	if (whd_ret != CY_RSLT_SUCCESS) {
757 		return -ENODEV;
758 	}
759 
760 	return 0;
761 }
762 
airoc_init(const struct device * dev)763 static int airoc_init(const struct device *dev)
764 {
765 	int ret;
766 	cy_rslt_t whd_ret;
767 	struct airoc_wifi_data *data = dev->data;
768 
769 	k_tid_t tid = k_thread_create(
770 		&airoc_wifi_event_thread, airoc_wifi_event_stack,
771 		CONFIG_AIROC_WIFI_EVENT_TASK_STACK_SIZE, (k_thread_entry_t)airoc_event_task, NULL,
772 		NULL, NULL, CONFIG_AIROC_WIFI_EVENT_TASK_PRIO, K_INHERIT_PERMS, K_NO_WAIT);
773 
774 	if (!tid) {
775 		LOG_ERR("ERROR spawning tx thread");
776 		return -EAGAIN;
777 	}
778 	k_thread_name_set(tid, "airoc_event");
779 
780 	whd_ret = airoc_wifi_init_primary(dev, &airoc_sta_if, &airoc_wifi_netif_if_default,
781 					  &airoc_wifi_buffer_if_default);
782 	if (whd_ret != CY_RSLT_SUCCESS) {
783 		LOG_ERR("airoc_wifi_init_primary failed ret = %d \r\n", whd_ret);
784 		return -EAGAIN;
785 	}
786 	airoc_if = airoc_sta_if;
787 
788 	whd_ret = whd_management_set_event_handler(airoc_sta_if, sta_link_events,
789 				link_events_handler, NULL, &sta_event_handler_index);
790 	if (whd_ret != CY_RSLT_SUCCESS) {
791 		LOG_ERR("whd_management_set_event_handler failed ret = %d \r\n", whd_ret);
792 		return -EAGAIN;
793 	}
794 
795 	ret = k_sem_init(&data->sema_common, 1, 1);
796 	if (ret != 0) {
797 		LOG_ERR("k_sem_init(sema_common) failure");
798 		return ret;
799 	}
800 
801 	ret = k_sem_init(&data->sema_scan, 0, 1);
802 	if (ret != 0) {
803 		LOG_ERR("k_sem_init(sema_scan) failure");
804 		return ret;
805 	}
806 
807 	return 0;
808 }
809 
810 static const struct wifi_mgmt_ops airoc_wifi_mgmt = {
811 	.scan = airoc_mgmt_scan,
812 	.connect = airoc_mgmt_connect,
813 	.disconnect = airoc_mgmt_disconnect,
814 	.ap_enable = airoc_mgmt_ap_enable,
815 	.ap_disable = airoc_mgmt_ap_disable,
816 #if defined(CONFIG_NET_STATISTICS_WIFI)
817 	.get_stats = airoc_mgmt_wifi_stats,
818 #endif
819 };
820 
821 static const struct net_wifi_mgmt_offload airoc_api = {
822 	.wifi_iface.iface_api.init = airoc_mgmt_init,
823 	.wifi_iface.send = airoc_mgmt_send,
824 	.wifi_iface.get_capabilities = airoc_get_capabilities,
825 	.wifi_iface.set_config = airoc_set_config,
826 	.wifi_mgmt_api = &airoc_wifi_mgmt,
827 };
828 
829 NET_DEVICE_DT_INST_DEFINE(0, airoc_init, NULL, &airoc_wifi_data, &airoc_wifi_config,
830 			  CONFIG_WIFI_INIT_PRIORITY, &airoc_api, ETHERNET_L2,
831 			  NET_L2_GET_CTX_TYPE(ETHERNET_L2), WHD_LINK_MTU);
832 
833 CONNECTIVITY_WIFI_MGMT_BIND(Z_DEVICE_DT_DEV_ID(DT_DRV_INST(0)));
834