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(¶ms, 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, ¶ms);
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