1 /**
2  * Copyright 2023-2024 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/net/wifi_mgmt.h>
8 #include <zephyr/net/wifi_nm.h>
9 #include "includes.h"
10 #include "common.h"
11 #include "eloop.h"
12 #include "wpa_supplicant_i.h"
13 #include "hostapd.h"
14 #include "hostapd_cli_zephyr.h"
15 #include "eap_register.h"
16 #include "ap_drv_ops.h"
17 #include "l2_packet/l2_packet.h"
18 #include "supp_main.h"
19 #include "hapd_main.h"
20 #include "supp_api.h"
21 #include "hapd_api.h"
22 #include "hapd_events.h"
23 
24 static const struct wifi_mgmt_ops mgmt_ap_ops = {
25 	.ap_enable = hostapd_ap_enable,
26 	.ap_disable = hostapd_ap_disable,
27 	.ap_sta_disconnect = hostapd_ap_sta_disconnect,
28 	.iface_status = hostapd_ap_status,
29 #ifdef CONFIG_WIFI_NM_HOSTAPD_WPS
30 	.wps_config = hostapd_ap_wps_config,
31 #endif
32 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_DPP
33 	.dpp_dispatch = hostapd_dpp_dispatch,
34 #endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_DPP */
35 	.ap_config_params = hostapd_ap_config_params,
36 	.set_rts_threshold = supplicant_set_rts_threshold,
37 #ifdef CONFIG_WIFI_NM_HOSTAPD_CRYPTO_ENTERPRISE
38 	.enterprise_creds = hostapd_add_enterprise_creds,
39 #endif
40 	.set_btwt = supplicant_set_btwt,
41 };
42 
43 DEFINE_WIFI_NM_INSTANCE(hostapd, &mgmt_ap_ops);
44 
45 struct hapd_global {
46 	void **drv_priv;
47 	size_t drv_count;
48 };
49 
50 static struct hapd_global hglobal;
51 
52 #ifndef HOSTAPD_CLEANUP_INTERVAL
53 #define HOSTAPD_CLEANUP_INTERVAL 10
54 #endif /* HOSTAPD_CLEANUP_INTERVAL */
55 
hostapd_periodic_call(struct hostapd_iface * iface,void * ctx)56 static int hostapd_periodic_call(struct hostapd_iface *iface, void *ctx)
57 {
58 	hostapd_periodic_iface(iface);
59 	return 0;
60 }
61 
62 /* Periodic cleanup tasks */
hostapd_periodic(void * eloop_ctx,void * timeout_ctx)63 static void hostapd_periodic(void *eloop_ctx, void *timeout_ctx)
64 {
65 	struct hapd_interfaces *interfaces = eloop_ctx;
66 
67 	eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0,
68 			       hostapd_periodic, interfaces, NULL);
69 	hostapd_for_each_interface(interfaces, hostapd_periodic_call, NULL);
70 }
71 
zephyr_get_hapd_handle_by_ifname(const char * ifname)72 struct hostapd_iface *zephyr_get_hapd_handle_by_ifname(const char *ifname)
73 {
74 	struct hapd_interfaces *interfaces = zephyr_get_default_hapd_context();
75 	struct hostapd_data *hapd = NULL;
76 
77 	hapd = hostapd_get_iface(interfaces, ifname);
78 	if (!hapd) {
79 		wpa_printf(MSG_ERROR, "%s: Unable to get hapd handle for %s\n", __func__, ifname);
80 		return NULL;
81 	}
82 
83 	return hapd->iface;
84 }
85 
hostapd_event_eapol_rx_cb(void * ctx,const u8 * src_addr,const u8 * buf,size_t len)86 static void hostapd_event_eapol_rx_cb(void *ctx, const u8 *src_addr,
87 				      const u8 *buf, size_t len)
88 {
89 	hostapd_event_eapol_rx(ctx, src_addr, buf, len, FRAME_ENCRYPTION_UNKNOWN, -1);
90 }
91 
hostapd_get_interface(const char * ifname)92 struct hostapd_iface *hostapd_get_interface(const char *ifname)
93 {
94 	struct hapd_interfaces *interfaces = zephyr_get_default_hapd_context();
95 
96 	return interfaces->iface[0];
97 }
98 
hostapd_enable_iface_cb(struct hostapd_iface * hapd_iface)99 static int hostapd_enable_iface_cb(struct hostapd_iface *hapd_iface)
100 {
101 	struct hostapd_data *bss;
102 
103 	wpa_printf(MSG_DEBUG, "Enable interface %s", hapd_iface->conf->bss[0]->iface);
104 
105 	bss = hapd_iface->bss[0];
106 
107 	bss->conf->start_disabled = 0;
108 
109 	if (hostapd_config_check(hapd_iface->conf, 1) < 0) {
110 		wpa_printf(MSG_INFO, "Invalid configuration - cannot enable");
111 		return -1;
112 	}
113 
114 	l2_packet_deinit(bss->l2);
115 	bss->l2 = l2_packet_init(bss->conf->iface, bss->conf->bssid, ETH_P_EAPOL,
116 				 &hostapd_event_eapol_rx_cb, bss, 0);
117 	if (bss->l2 == NULL) {
118 		wpa_printf(MSG_ERROR, "Failed to initialize l2 for hostapd interface");
119 		return -1;
120 	}
121 
122 	if (hostapd_setup_interface(hapd_iface)) {
123 		wpa_printf(MSG_ERROR, "Failed to initialize hostapd interface");
124 		return -1;
125 	}
126 
127 	return 0;
128 }
129 
hostapd_disable_iface_cb(struct hostapd_iface * hapd_iface)130 static int hostapd_disable_iface_cb(struct hostapd_iface *hapd_iface)
131 {
132 	size_t j;
133 	struct hostapd_data *hapd = NULL;
134 
135 	wpa_msg(hapd_iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
136 
137 	hapd_iface->driver_ap_teardown = !!(hapd_iface->drv_flags
138 					    & WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
139 
140 #ifdef NEED_AP_MLME
141 	for (j = 0; j < hapd_iface->num_bss; j++) {
142 		hostapd_cleanup_cs_params(hapd_iface->bss[j]);
143 	}
144 #endif /* NEED_AP_MLME */
145 
146 	/* Same as hostapd_interface_deinit() without deinitializing control
147 	 * interface
148 	 */
149 	for (j = 0; j < hapd_iface->num_bss; j++) {
150 		hapd = hapd_iface->bss[j];
151 		hostapd_bss_deinit_no_free(hapd);
152 		hostapd_free_hapd_data(hapd);
153 	}
154 
155 	hostapd_drv_stop_ap(hapd);
156 
157 	hostapd_cleanup_iface_partial(hapd_iface);
158 
159 	wpa_printf(MSG_DEBUG, "Interface %s disabled", hapd_iface->bss[0]->conf->iface);
160 	hostapd_set_state(hapd_iface, HAPD_IFACE_DISABLED);
161 	hostapd_send_wifi_mgmt_ap_status(hapd_iface,
162 					 NET_EVENT_WIFI_CMD_AP_DISABLE_RESULT,
163 					 WIFI_STATUS_AP_SUCCESS);
164 	hostapd_config_free(hapd_iface->conf);
165 	hapd_iface->conf = hapd_iface->interfaces->config_read_cb(hapd_iface->config_fname);
166 	for (j = 0; j < hapd_iface->num_bss; j++) {
167 		hapd = hapd_iface->bss[j];
168 		hapd->iconf = hapd_iface->conf;
169 		hapd->conf = hapd_iface->conf->bss[j];
170 		hapd->driver = hapd_iface->conf->driver;
171 	}
172 
173 	return 0;
174 }
175 
hostapd_global_init(struct hapd_interfaces * interfaces,const char * entropy_file)176 static int hostapd_global_init(struct hapd_interfaces *interfaces, const char *entropy_file)
177 {
178 	int i;
179 
180 	os_memset(&hglobal, 0, sizeof(struct hapd_global));
181 
182 	if (eap_server_register_methods()) {
183 		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
184 		return -1;
185 	}
186 
187 	interfaces->eloop_initialized = 1;
188 
189 	for (i = 0; wpa_drivers[i]; i++) {
190 		hglobal.drv_count++;
191 	}
192 
193 	if (hglobal.drv_count == 0) {
194 		wpa_printf(MSG_ERROR, "No drivers enabled");
195 		return -1;
196 	}
197 	hglobal.drv_priv = os_calloc(hglobal.drv_count, sizeof(void *));
198 	if (hglobal.drv_priv == NULL) {
199 		return -1;
200 	}
201 
202 	return 0;
203 }
204 
hostapd_driver_init(struct hostapd_iface * iface)205 static int hostapd_driver_init(struct hostapd_iface *iface)
206 {
207 	struct wpa_init_params params;
208 	size_t i;
209 	struct hostapd_data *hapd       = iface->bss[0];
210 	struct hostapd_bss_config *conf = hapd->conf;
211 	u8 *b                           = conf->bssid;
212 	struct wpa_driver_capa capa;
213 
214 	if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
215 		wpa_printf(MSG_ERROR, "No hostapd driver wrapper available");
216 		return -1;
217 	}
218 
219 	/* Initialize the driver interface */
220 	if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5])) {
221 		b = NULL;
222 	}
223 
224 	os_memset(&params, 0, sizeof(params));
225 	for (i = 0; wpa_drivers[i]; i++) {
226 		if (wpa_drivers[i] != hapd->driver) {
227 			continue;
228 		}
229 
230 		if (hglobal.drv_priv[i] == NULL && wpa_drivers[i]->global_init) {
231 			hglobal.drv_priv[i] = wpa_drivers[i]->global_init(iface->interfaces);
232 			if (hglobal.drv_priv[i] == NULL) {
233 				wpa_printf(MSG_ERROR, "Failed to initialize driver '%s'",
234 					   wpa_drivers[i]->name);
235 				return -1;
236 			}
237 			hglobal.drv_count++;
238 		}
239 
240 		params.global_priv = hglobal.drv_priv[i];
241 		break;
242 	}
243 	params.bssid              = b;
244 	params.ifname             = hapd->conf->iface;
245 	params.driver_params      = hapd->iconf->driver_params;
246 	params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
247 	params.num_bridge         = hapd->iface->num_bss;
248 	params.bridge             = os_calloc(hapd->iface->num_bss, sizeof(char *));
249 	if (params.bridge == NULL) {
250 		return -1;
251 	}
252 	for (i = 0; i < hapd->iface->num_bss; i++) {
253 		struct hostapd_data *bss = hapd->iface->bss[i];
254 
255 		if (bss->conf->bridge[0]) {
256 			params.bridge[i] = bss->conf->bridge;
257 		}
258 	}
259 
260 	params.own_addr = hapd->own_addr;
261 
262 	hapd->drv_priv = hapd->driver->hapd_init(hapd, &params);
263 	os_free(params.bridge);
264 	if (hapd->drv_priv == NULL) {
265 		wpa_printf(MSG_ERROR, "%s driver initialization failed.",
266 			   hapd->driver->name);
267 		hapd->driver = NULL;
268 		return -1;
269 	}
270 
271 	if (hapd->driver->get_capa && hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
272 		struct wowlan_triggers *triggs;
273 
274 		iface->drv_flags           = capa.flags;
275 		iface->drv_flags2          = capa.flags2;
276 		iface->probe_resp_offloads = capa.probe_resp_offloads;
277 		/*
278 		 * Use default extended capa values from per-radio information
279 		 */
280 		iface->extended_capa         = capa.extended_capa;
281 		iface->extended_capa_mask    = capa.extended_capa_mask;
282 		iface->extended_capa_len     = capa.extended_capa_len;
283 		iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
284 
285 		/*
286 		 * Override extended capa with per-interface type (AP), if
287 		 * available from the driver.
288 		 */
289 		hostapd_get_ext_capa(iface);
290 
291 		triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa);
292 		if (triggs && hapd->driver->set_wowlan) {
293 			if (hapd->driver->set_wowlan(hapd->drv_priv, triggs)) {
294 				wpa_printf(MSG_ERROR, "set_wowlan failed");
295 			}
296 		}
297 		os_free(triggs);
298 	}
299 
300 	return 0;
301 }
302 
hostapd_config_read2(const char * fname)303 struct hostapd_config *hostapd_config_read2(const char *fname)
304 {
305 	struct hostapd_config *conf;
306 	const struct device *dev;
307 	char ifname[IFNAMSIZ + 1] = {0};
308 	int errors = 0;
309 	size_t i;
310 	int aCWmin = 4, aCWmax = 10;
311 	/* background traffic */
312 	struct hostapd_wmm_ac_params ac_bk = {aCWmin, aCWmax, 9, 0, 0};
313 	/* best effort traffic */
314 	struct hostapd_wmm_ac_params ac_be = {aCWmin, aCWmax - 4, 5, 0, 0};
315 	/* video traffic */
316 	struct hostapd_wmm_ac_params ac_vi = {aCWmin - 1, aCWmin, 3,
317 					      3008 / 32, 0};
318 	/* voice traffic */
319 	struct hostapd_wmm_ac_params ac_vo = {aCWmin - 2, aCWmin - 1, 3,
320 					      1504 / 32, 0};
321 
322 	dev = net_if_get_device(net_if_get_wifi_sap());
323 	strncpy(ifname, dev->name, IFNAMSIZ);
324 	ifname[IFNAMSIZ] = '\0';
325 
326 	conf = hostapd_config_defaults();
327 	if (conf == NULL) {
328 		return NULL;
329 	}
330 
331 	conf->wmm_ac_params[0] = ac_be;
332 	conf->wmm_ac_params[1] = ac_bk;
333 	conf->wmm_ac_params[2] = ac_vi;
334 	conf->wmm_ac_params[3] = ac_vo;
335 
336 	/* set default driver based on configuration */
337 	conf->driver = wpa_drivers[0];
338 	if (conf->driver == NULL) {
339 		wpa_printf(MSG_ERROR, "No driver wrappers registered!");
340 		hostapd_config_free(conf);
341 		return NULL;
342 	}
343 	conf->last_bss = conf->bss[0];
344 	struct hostapd_bss_config *bss;
345 
346 	bss                 = conf->last_bss;
347 	bss->start_disabled = 1;
348 	bss->max_num_sta    = CONFIG_WIFI_MGMT_AP_MAX_NUM_STA;
349 	bss->dtim_period    = 1;
350 	os_strlcpy(conf->bss[0]->iface, ifname, sizeof(conf->bss[0]->iface));
351 	bss->logger_stdout_level = HOSTAPD_LEVEL_INFO;
352 	bss->logger_stdout       = 0xffff;
353 	bss->nas_identifier      = os_strdup("ap.example.com");
354 	/* Set regulatory domain */
355 	os_memcpy(conf->country, CONFIG_WIFI_NM_HOSTAPD_REGULATORY_REGION, 2);
356 	/* Set regulatory environment */
357 	conf->country[2]     = CONFIG_WIFI_NM_HOSTAPD_REGULATORY_ENV;
358 	conf->hw_mode        = HOSTAPD_MODE_IEEE80211G;
359 	bss->wps_state       = WPS_STATE_CONFIGURED;
360 	bss->eap_server      = 1;
361 #ifdef CONFIG_WPS
362 	bss->ap_setup_locked = 1;
363 #endif
364 	conf->channel        = 1;
365 	conf->acs            = conf->channel == 0;
366 #ifdef CONFIG_ACS
367 	conf->acs_num_scans  = 1;
368 #endif
369 	conf->ieee80211n     = 1;
370 	conf->ieee80211h     = 0;
371 	conf->ieee80211d     = 1;
372 	conf->acs_exclude_dfs = 1;
373 	conf->ht_capab |= HT_CAP_INFO_SHORT_GI20MHZ;
374 	bss->auth_algs = 1;
375 	bss->okc = 1;
376 	conf->no_pri_sec_switch = 1;
377 	conf->ht_op_mode_fixed  = 1;
378 #if CONFIG_WIFI_NM_WPA_SUPPLICANT_11AC
379 	conf->ieee80211ac       = 1;
380 	conf->vht_oper_chwidth  = CHANWIDTH_USE_HT;
381 	conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX;
382 #endif
383 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_11AX
384 	conf->ieee80211ax       = 1;
385 	conf->he_oper_chwidth   = CHANWIDTH_USE_HT;
386 	conf->he_phy_capab.he_su_beamformer = 0;
387 	conf->he_phy_capab.he_su_beamformee = 1;
388 	conf->he_phy_capab.he_mu_beamformer = 0;
389 	conf->he_op.he_bss_color = 1;
390 	conf->he_op.he_default_pe_duration  = 0;
391 	/* Set default basic MCS/NSS set to single stream MCS 0-7 */
392 	conf->he_op.he_basic_mcs_nss_set    = 0xfffc;
393 #endif
394 
395 	for (i = 0; i < conf->num_bss; i++) {
396 		hostapd_set_security_params(conf->bss[i], 1);
397 	}
398 
399 	if (hostapd_config_check(conf, 1)) {
400 		errors++;
401 	}
402 
403 #ifndef WPA_IGNORE_CONFIG_ERRORS
404 	if (errors) {
405 		wpa_printf(MSG_ERROR, "%d errors found in configuration file '%s'",
406 			   errors, fname);
407 		hostapd_config_free(conf);
408 		conf = NULL;
409 	}
410 #endif /* WPA_IGNORE_CONFIG_ERRORS */
411 	return conf;
412 }
413 
hostapd_interface_init(struct hapd_interfaces * interfaces,const char * if_name,const char * config_fname,int debug)414 static struct hostapd_iface *hostapd_interface_init(struct hapd_interfaces *interfaces,
415 						    const char *if_name,
416 						    const char *config_fname,
417 						    int debug)
418 {
419 	struct hostapd_iface *iface;
420 	int k;
421 
422 	wpa_printf(MSG_DEBUG, "Configuration file: %s", config_fname);
423 	iface = hostapd_init(interfaces, config_fname);
424 	if (!iface) {
425 		return NULL;
426 	}
427 
428 	if (if_name) {
429 		os_strlcpy(iface->conf->bss[0]->iface, if_name,
430 			   sizeof(iface->conf->bss[0]->iface));
431 	}
432 
433 	iface->interfaces = interfaces;
434 
435 	for (k = 0; k < debug; k++) {
436 		if (iface->bss[0]->conf->logger_stdout_level > 0) {
437 			iface->bss[0]->conf->logger_stdout_level--;
438 		}
439 	}
440 
441 	if (iface->conf->bss[0]->iface[0] == '\0' &&
442 	    !hostapd_drv_none(iface->bss[0])) {
443 		wpa_printf(MSG_ERROR,
444 			   "Interface name not specified in %s, nor by '-i' parameter",
445 			   config_fname);
446 		hostapd_interface_deinit_free(iface);
447 		return NULL;
448 	}
449 
450 	iface->bss[0]->is_hostapd = 1;
451 
452 	return iface;
453 }
454 
zephyr_hostapd_init(struct hapd_interfaces * interfaces)455 void zephyr_hostapd_init(struct hapd_interfaces *interfaces)
456 {
457 	size_t i;
458 	int ret, debug = 0;
459 	struct net_if *iface;
460 	char ifname[IFNAMSIZ + 1] = { 0 };
461 	const char *entropy_file = NULL;
462 	size_t num_bss_configs = 0;
463 	int start_ifaces_in_sync = 0;
464 #ifdef CONFIG_DPP
465 	struct dpp_global_config dpp_conf;
466 #endif /* CONFIG_DPP */
467 
468 	os_memset(interfaces, 0, sizeof(struct hapd_interfaces));
469 	interfaces->reload_config      = hostapd_reload_config;
470 	interfaces->config_read_cb     = hostapd_config_read2;
471 	interfaces->for_each_interface = hostapd_for_each_interface;
472 	interfaces->driver_init        = hostapd_driver_init;
473 	interfaces->global_ctrl_sock   = -1;
474 	dl_list_init(&interfaces->global_ctrl_dst);
475 #ifdef CONFIG_DPP
476 	os_memset(&dpp_conf, 0, sizeof(dpp_conf));
477 	dpp_conf.cb_ctx = interfaces;
478 	interfaces->dpp = dpp_global_init(&dpp_conf);
479 	if (!interfaces->dpp) {
480 		return;
481 	}
482 #endif /* CONFIG_DPP */
483 
484 	interfaces->count = 1;
485 	if (interfaces->count || num_bss_configs) {
486 		interfaces->iface = os_calloc(interfaces->count + num_bss_configs,
487 					      sizeof(struct hostapd_iface *));
488 		if (interfaces->iface == NULL) {
489 			wpa_printf(MSG_ERROR, "malloc failed");
490 			return;
491 		}
492 	}
493 
494 	if (hostapd_global_init(interfaces, entropy_file)) {
495 		wpa_printf(MSG_ERROR, "Failed to initialize global context");
496 		return;
497 	}
498 
499 	eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0,
500 			       hostapd_periodic, interfaces, NULL);
501 
502 	iface = net_if_get_wifi_sap();
503 	ret = net_if_get_name(iface, ifname, sizeof(ifname) - 1);
504 	if (ret < 0) {
505 		wpa_printf(MSG_ERROR, "Cannot get interface %d (%p) name",
506 			   net_if_get_by_iface(iface), iface);
507 		goto out;
508 	}
509 
510 	for (i = 0; i < interfaces->count; i++) {
511 		interfaces->iface[i] = hostapd_interface_init(interfaces, ifname,
512 							      "hostapd.conf", debug);
513 		if (!interfaces->iface[i]) {
514 			wpa_printf(MSG_ERROR, "Failed to initialize interface");
515 			goto out;
516 		}
517 		if (start_ifaces_in_sync) {
518 			interfaces->iface[i]->need_to_start_in_sync = 0;
519 		}
520 	}
521 
522 	/*
523 	 * Enable configured interfaces. Depending on channel configuration,
524 	 * this may complete full initialization before returning or use a
525 	 * callback mechanism to complete setup in case of operations like HT
526 	 * co-ex scans, ACS, or DFS are needed to determine channel parameters.
527 	 * In such case, the interface will be enabled from eloop context within
528 	 * hostapd_global_run().
529 	 */
530 	interfaces->terminate_on_error = 0;
531 	for (i = 0; i < interfaces->count; i++) {
532 		if (hostapd_driver_init(interfaces->iface[i])) {
533 			goto out;
534 		}
535 		interfaces->iface[i]->enable_iface_cb  = hostapd_enable_iface_cb;
536 		interfaces->iface[i]->disable_iface_cb = hostapd_disable_iface_cb;
537 		zephyr_hostapd_ctrl_init((void *)interfaces->iface[i]->bss[0]);
538 	}
539 
540 out:
541 	return;
542 }
543 
zephyr_hostapd_msg(void * ctx,const char * txt,size_t len)544 void zephyr_hostapd_msg(void *ctx, const char *txt, size_t len)
545 {
546 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_DPP
547 	struct hostapd_data *hapd = (struct hostapd_data *)ctx;
548 #endif
549 
550 	if (!ctx || !txt) {
551 		return;
552 	}
553 
554 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_DPP
555 	if (strncmp(txt, "DPP", 3) == 0) {
556 		hostapd_handle_dpp_event(hapd, (char *)txt, len);
557 	}
558 #endif
559 }
560