1214501Srpaulo/* 2214501Srpaulo * hostapd / Initialization and configuration 3346981Scy * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "utils/includes.h" 10351611Scy#ifdef CONFIG_SQLITE 11351611Scy#include <sqlite3.h> 12351611Scy#endif /* CONFIG_SQLITE */ 13214501Srpaulo 14214501Srpaulo#include "utils/common.h" 15214501Srpaulo#include "utils/eloop.h" 16214501Srpaulo#include "common/ieee802_11_defs.h" 17281806Srpaulo#include "common/wpa_ctrl.h" 18337817Scy#include "common/hw_features_common.h" 19214501Srpaulo#include "radius/radius_client.h" 20252726Srpaulo#include "radius/radius_das.h" 21281806Srpaulo#include "eap_server/tncs.h" 22281806Srpaulo#include "eapol_auth/eapol_auth_sm.h" 23281806Srpaulo#include "eapol_auth/eapol_auth_sm_i.h" 24289549Srpaulo#include "fst/fst.h" 25214501Srpaulo#include "hostapd.h" 26214501Srpaulo#include "authsrv.h" 27214501Srpaulo#include "sta_info.h" 28214501Srpaulo#include "accounting.h" 29214501Srpaulo#include "ap_list.h" 30214501Srpaulo#include "beacon.h" 31214501Srpaulo#include "iapp.h" 32214501Srpaulo#include "ieee802_1x.h" 33214501Srpaulo#include "ieee802_11_auth.h" 34214501Srpaulo#include "vlan_init.h" 35214501Srpaulo#include "wpa_auth.h" 36214501Srpaulo#include "wps_hostapd.h" 37346981Scy#include "dpp_hostapd.h" 38346981Scy#include "gas_query_ap.h" 39214501Srpaulo#include "hw_features.h" 40214501Srpaulo#include "wpa_auth_glue.h" 41214501Srpaulo#include "ap_drv_ops.h" 42214501Srpaulo#include "ap_config.h" 43252726Srpaulo#include "p2p_hostapd.h" 44252726Srpaulo#include "gas_serv.h" 45281806Srpaulo#include "dfs.h" 46281806Srpaulo#include "ieee802_11.h" 47281806Srpaulo#include "bss_load.h" 48281806Srpaulo#include "x_snoop.h" 49281806Srpaulo#include "dhcp_snoop.h" 50281806Srpaulo#include "ndisc_snoop.h" 51337817Scy#include "neighbor_db.h" 52337817Scy#include "rrm.h" 53346981Scy#include "fils_hlp.h" 54346981Scy#include "acs.h" 55346981Scy#include "hs20.h" 56351611Scy#include "airtime_policy.h" 57351611Scy#include "wpa_auth_kay.h" 58214501Srpaulo 59214501Srpaulo 60252726Srpaulostatic int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason); 61214501Srpaulostatic int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd); 62252726Srpaulostatic int hostapd_broadcast_wep_clear(struct hostapd_data *hapd); 63281806Srpaulostatic int setup_interface2(struct hostapd_iface *iface); 64281806Srpaulostatic void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx); 65346981Scystatic void hostapd_interface_setup_failure_handler(void *eloop_ctx, 66346981Scy void *timeout_ctx); 67214501Srpaulo 68214501Srpaulo 69252726Srpauloint hostapd_for_each_interface(struct hapd_interfaces *interfaces, 70252726Srpaulo int (*cb)(struct hostapd_iface *iface, 71252726Srpaulo void *ctx), void *ctx) 72214501Srpaulo{ 73252726Srpaulo size_t i; 74252726Srpaulo int ret; 75214501Srpaulo 76252726Srpaulo for (i = 0; i < interfaces->count; i++) { 77252726Srpaulo ret = cb(interfaces->iface[i], ctx); 78252726Srpaulo if (ret) 79252726Srpaulo return ret; 80252726Srpaulo } 81214501Srpaulo 82252726Srpaulo return 0; 83252726Srpaulo} 84214501Srpaulo 85252726Srpaulo 86346981Scyvoid hostapd_reconfig_encryption(struct hostapd_data *hapd) 87346981Scy{ 88346981Scy if (hapd->wpa_auth) 89346981Scy return; 90346981Scy 91346981Scy hostapd_set_privacy(hapd, 0); 92346981Scy hostapd_setup_encryption(hapd->conf->iface, hapd); 93346981Scy} 94346981Scy 95346981Scy 96252726Srpaulostatic void hostapd_reload_bss(struct hostapd_data *hapd) 97252726Srpaulo{ 98281806Srpaulo struct hostapd_ssid *ssid; 99281806Srpaulo 100346981Scy if (!hapd->started) 101346981Scy return; 102346981Scy 103346981Scy if (hapd->conf->wmm_enabled < 0) 104346981Scy hapd->conf->wmm_enabled = hapd->iconf->ieee80211n; 105346981Scy 106214501Srpaulo#ifndef CONFIG_NO_RADIUS 107252726Srpaulo radius_client_reconfig(hapd->radius, hapd->conf->radius); 108214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 109214501Srpaulo 110281806Srpaulo ssid = &hapd->conf->ssid; 111281806Srpaulo if (!ssid->wpa_psk_set && ssid->wpa_psk && !ssid->wpa_psk->next && 112281806Srpaulo ssid->wpa_passphrase_set && ssid->wpa_passphrase) { 113281806Srpaulo /* 114281806Srpaulo * Force PSK to be derived again since SSID or passphrase may 115281806Srpaulo * have changed. 116281806Srpaulo */ 117281806Srpaulo hostapd_config_clear_wpa_psk(&hapd->conf->ssid.wpa_psk); 118281806Srpaulo } 119214501Srpaulo if (hostapd_setup_wpa_psk(hapd->conf)) { 120214501Srpaulo wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK " 121214501Srpaulo "after reloading configuration"); 122214501Srpaulo } 123214501Srpaulo 124214501Srpaulo if (hapd->conf->ieee802_1x || hapd->conf->wpa) 125252726Srpaulo hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1); 126214501Srpaulo else 127252726Srpaulo hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); 128214501Srpaulo 129281806Srpaulo if ((hapd->conf->wpa || hapd->conf->osen) && hapd->wpa_auth == NULL) { 130214501Srpaulo hostapd_setup_wpa(hapd); 131252726Srpaulo if (hapd->wpa_auth) 132252726Srpaulo wpa_init_keys(hapd->wpa_auth); 133252726Srpaulo } else if (hapd->conf->wpa) { 134214501Srpaulo const u8 *wpa_ie; 135214501Srpaulo size_t wpa_ie_len; 136214501Srpaulo hostapd_reconfig_wpa(hapd); 137214501Srpaulo wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len); 138214501Srpaulo if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) 139214501Srpaulo wpa_printf(MSG_ERROR, "Failed to configure WPA IE for " 140214501Srpaulo "the kernel driver."); 141214501Srpaulo } else if (hapd->wpa_auth) { 142214501Srpaulo wpa_deinit(hapd->wpa_auth); 143214501Srpaulo hapd->wpa_auth = NULL; 144214501Srpaulo hostapd_set_privacy(hapd, 0); 145214501Srpaulo hostapd_setup_encryption(hapd->conf->iface, hapd); 146214501Srpaulo hostapd_set_generic_elem(hapd, (u8 *) "", 0); 147214501Srpaulo } 148214501Srpaulo 149214501Srpaulo ieee802_11_set_beacon(hapd); 150214501Srpaulo hostapd_update_wps(hapd); 151214501Srpaulo 152214501Srpaulo if (hapd->conf->ssid.ssid_set && 153252726Srpaulo hostapd_set_ssid(hapd, hapd->conf->ssid.ssid, 154214501Srpaulo hapd->conf->ssid.ssid_len)) { 155214501Srpaulo wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); 156214501Srpaulo /* try to continue */ 157214501Srpaulo } 158252726Srpaulo wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface); 159252726Srpaulo} 160214501Srpaulo 161252726Srpaulo 162281806Srpaulostatic void hostapd_clear_old(struct hostapd_iface *iface) 163252726Srpaulo{ 164252726Srpaulo size_t j; 165252726Srpaulo 166252726Srpaulo /* 167252726Srpaulo * Deauthenticate all stations since the new configuration may not 168252726Srpaulo * allow them to use the BSS anymore. 169252726Srpaulo */ 170252726Srpaulo for (j = 0; j < iface->num_bss; j++) { 171252726Srpaulo hostapd_flush_old_stations(iface->bss[j], 172252726Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 173252726Srpaulo hostapd_broadcast_wep_clear(iface->bss[j]); 174252726Srpaulo 175252726Srpaulo#ifndef CONFIG_NO_RADIUS 176252726Srpaulo /* TODO: update dynamic data based on changed configuration 177252726Srpaulo * items (e.g., open/close sockets, etc.) */ 178252726Srpaulo radius_client_flush(iface->bss[j]->radius, 0); 179252726Srpaulo#endif /* CONFIG_NO_RADIUS */ 180252726Srpaulo } 181281806Srpaulo} 182252726Srpaulo 183281806Srpaulo 184346981Scystatic int hostapd_iface_conf_changed(struct hostapd_config *newconf, 185346981Scy struct hostapd_config *oldconf) 186346981Scy{ 187346981Scy size_t i; 188346981Scy 189346981Scy if (newconf->num_bss != oldconf->num_bss) 190346981Scy return 1; 191346981Scy 192346981Scy for (i = 0; i < newconf->num_bss; i++) { 193346981Scy if (os_strcmp(newconf->bss[i]->iface, 194346981Scy oldconf->bss[i]->iface) != 0) 195346981Scy return 1; 196346981Scy } 197346981Scy 198346981Scy return 0; 199346981Scy} 200346981Scy 201346981Scy 202281806Srpauloint hostapd_reload_config(struct hostapd_iface *iface) 203281806Srpaulo{ 204346981Scy struct hapd_interfaces *interfaces = iface->interfaces; 205281806Srpaulo struct hostapd_data *hapd = iface->bss[0]; 206281806Srpaulo struct hostapd_config *newconf, *oldconf; 207281806Srpaulo size_t j; 208281806Srpaulo 209281806Srpaulo if (iface->config_fname == NULL) { 210281806Srpaulo /* Only in-memory config in use - assume it has been updated */ 211281806Srpaulo hostapd_clear_old(iface); 212281806Srpaulo for (j = 0; j < iface->num_bss; j++) 213281806Srpaulo hostapd_reload_bss(iface->bss[j]); 214281806Srpaulo return 0; 215281806Srpaulo } 216281806Srpaulo 217281806Srpaulo if (iface->interfaces == NULL || 218281806Srpaulo iface->interfaces->config_read_cb == NULL) 219281806Srpaulo return -1; 220281806Srpaulo newconf = iface->interfaces->config_read_cb(iface->config_fname); 221281806Srpaulo if (newconf == NULL) 222281806Srpaulo return -1; 223281806Srpaulo 224281806Srpaulo hostapd_clear_old(iface); 225281806Srpaulo 226252726Srpaulo oldconf = hapd->iconf; 227346981Scy if (hostapd_iface_conf_changed(newconf, oldconf)) { 228346981Scy char *fname; 229346981Scy int res; 230346981Scy 231346981Scy wpa_printf(MSG_DEBUG, 232346981Scy "Configuration changes include interface/BSS modification - force full disable+enable sequence"); 233346981Scy fname = os_strdup(iface->config_fname); 234346981Scy if (!fname) { 235346981Scy hostapd_config_free(newconf); 236346981Scy return -1; 237346981Scy } 238346981Scy hostapd_remove_iface(interfaces, hapd->conf->iface); 239346981Scy iface = hostapd_init(interfaces, fname); 240346981Scy os_free(fname); 241346981Scy hostapd_config_free(newconf); 242346981Scy if (!iface) { 243346981Scy wpa_printf(MSG_ERROR, 244346981Scy "Failed to initialize interface on config reload"); 245346981Scy return -1; 246346981Scy } 247346981Scy iface->interfaces = interfaces; 248346981Scy interfaces->iface[interfaces->count] = iface; 249346981Scy interfaces->count++; 250346981Scy res = hostapd_enable_iface(iface); 251346981Scy if (res < 0) 252346981Scy wpa_printf(MSG_ERROR, 253346981Scy "Failed to enable interface on config reload"); 254346981Scy return res; 255346981Scy } 256252726Srpaulo iface->conf = newconf; 257252726Srpaulo 258252726Srpaulo for (j = 0; j < iface->num_bss; j++) { 259252726Srpaulo hapd = iface->bss[j]; 260252726Srpaulo hapd->iconf = newconf; 261281806Srpaulo hapd->iconf->channel = oldconf->channel; 262289549Srpaulo hapd->iconf->acs = oldconf->acs; 263281806Srpaulo hapd->iconf->secondary_channel = oldconf->secondary_channel; 264281806Srpaulo hapd->iconf->ieee80211n = oldconf->ieee80211n; 265281806Srpaulo hapd->iconf->ieee80211ac = oldconf->ieee80211ac; 266281806Srpaulo hapd->iconf->ht_capab = oldconf->ht_capab; 267281806Srpaulo hapd->iconf->vht_capab = oldconf->vht_capab; 268351611Scy hostapd_set_oper_chwidth(hapd->iconf, 269351611Scy hostapd_get_oper_chwidth(oldconf)); 270351611Scy hostapd_set_oper_centr_freq_seg0_idx( 271351611Scy hapd->iconf, 272351611Scy hostapd_get_oper_centr_freq_seg0_idx(oldconf)); 273351611Scy hostapd_set_oper_centr_freq_seg1_idx( 274351611Scy hapd->iconf, 275351611Scy hostapd_get_oper_centr_freq_seg1_idx(oldconf)); 276281806Srpaulo hapd->conf = newconf->bss[j]; 277252726Srpaulo hostapd_reload_bss(hapd); 278252726Srpaulo } 279252726Srpaulo 280214501Srpaulo hostapd_config_free(oldconf); 281214501Srpaulo 282214501Srpaulo 283214501Srpaulo return 0; 284214501Srpaulo} 285214501Srpaulo 286214501Srpaulo 287214501Srpaulostatic void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd, 288337817Scy const char *ifname) 289214501Srpaulo{ 290214501Srpaulo int i; 291214501Srpaulo 292346981Scy if (!ifname || !hapd->drv_priv) 293337817Scy return; 294214501Srpaulo for (i = 0; i < NUM_WEP_KEYS; i++) { 295252726Srpaulo if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, 296252726Srpaulo 0, NULL, 0, NULL, 0)) { 297214501Srpaulo wpa_printf(MSG_DEBUG, "Failed to clear default " 298214501Srpaulo "encryption keys (ifname=%s keyidx=%d)", 299214501Srpaulo ifname, i); 300214501Srpaulo } 301214501Srpaulo } 302214501Srpaulo#ifdef CONFIG_IEEE80211W 303214501Srpaulo if (hapd->conf->ieee80211w) { 304214501Srpaulo for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) { 305252726Srpaulo if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, 306252726Srpaulo NULL, i, 0, NULL, 307252726Srpaulo 0, NULL, 0)) { 308214501Srpaulo wpa_printf(MSG_DEBUG, "Failed to clear " 309214501Srpaulo "default mgmt encryption keys " 310214501Srpaulo "(ifname=%s keyidx=%d)", ifname, i); 311214501Srpaulo } 312214501Srpaulo } 313214501Srpaulo } 314214501Srpaulo#endif /* CONFIG_IEEE80211W */ 315214501Srpaulo} 316214501Srpaulo 317214501Srpaulo 318214501Srpaulostatic int hostapd_broadcast_wep_clear(struct hostapd_data *hapd) 319214501Srpaulo{ 320214501Srpaulo hostapd_broadcast_key_clear_iface(hapd, hapd->conf->iface); 321214501Srpaulo return 0; 322214501Srpaulo} 323214501Srpaulo 324214501Srpaulo 325214501Srpaulostatic int hostapd_broadcast_wep_set(struct hostapd_data *hapd) 326214501Srpaulo{ 327214501Srpaulo int errors = 0, idx; 328214501Srpaulo struct hostapd_ssid *ssid = &hapd->conf->ssid; 329214501Srpaulo 330214501Srpaulo idx = ssid->wep.idx; 331214501Srpaulo if (ssid->wep.default_len && 332252726Srpaulo hostapd_drv_set_key(hapd->conf->iface, 333252726Srpaulo hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, 334252726Srpaulo 1, NULL, 0, ssid->wep.key[idx], 335252726Srpaulo ssid->wep.len[idx])) { 336214501Srpaulo wpa_printf(MSG_WARNING, "Could not set WEP encryption."); 337214501Srpaulo errors++; 338214501Srpaulo } 339214501Srpaulo 340214501Srpaulo return errors; 341214501Srpaulo} 342214501Srpaulo 343252726Srpaulo 344252726Srpaulostatic void hostapd_free_hapd_data(struct hostapd_data *hapd) 345214501Srpaulo{ 346281806Srpaulo os_free(hapd->probereq_cb); 347281806Srpaulo hapd->probereq_cb = NULL; 348289549Srpaulo hapd->num_probereq_cb = 0; 349281806Srpaulo 350281806Srpaulo#ifdef CONFIG_P2P 351281806Srpaulo wpabuf_free(hapd->p2p_beacon_ie); 352281806Srpaulo hapd->p2p_beacon_ie = NULL; 353281806Srpaulo wpabuf_free(hapd->p2p_probe_resp_ie); 354281806Srpaulo hapd->p2p_probe_resp_ie = NULL; 355281806Srpaulo#endif /* CONFIG_P2P */ 356281806Srpaulo 357281806Srpaulo if (!hapd->started) { 358281806Srpaulo wpa_printf(MSG_ERROR, "%s: Interface %s wasn't started", 359346981Scy __func__, hapd->conf ? hapd->conf->iface : "N/A"); 360281806Srpaulo return; 361281806Srpaulo } 362281806Srpaulo hapd->started = 0; 363346981Scy hapd->beacon_set_done = 0; 364281806Srpaulo 365281806Srpaulo wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface); 366214501Srpaulo iapp_deinit(hapd->iapp); 367214501Srpaulo hapd->iapp = NULL; 368214501Srpaulo accounting_deinit(hapd); 369214501Srpaulo hostapd_deinit_wpa(hapd); 370214501Srpaulo vlan_deinit(hapd); 371214501Srpaulo hostapd_acl_deinit(hapd); 372214501Srpaulo#ifndef CONFIG_NO_RADIUS 373214501Srpaulo radius_client_deinit(hapd->radius); 374214501Srpaulo hapd->radius = NULL; 375252726Srpaulo radius_das_deinit(hapd->radius_das); 376252726Srpaulo hapd->radius_das = NULL; 377214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 378214501Srpaulo 379214501Srpaulo hostapd_deinit_wps(hapd); 380351611Scy ieee802_1x_dealloc_kay_sm_hapd(hapd); 381346981Scy#ifdef CONFIG_DPP 382346981Scy hostapd_dpp_deinit(hapd); 383346981Scy gas_query_ap_deinit(hapd->gas); 384346981Scy#endif /* CONFIG_DPP */ 385214501Srpaulo 386214501Srpaulo authsrv_deinit(hapd); 387214501Srpaulo 388281806Srpaulo if (hapd->interface_added) { 389281806Srpaulo hapd->interface_added = 0; 390281806Srpaulo if (hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) { 391281806Srpaulo wpa_printf(MSG_WARNING, 392281806Srpaulo "Failed to remove BSS interface %s", 393281806Srpaulo hapd->conf->iface); 394281806Srpaulo hapd->interface_added = 1; 395281806Srpaulo } else { 396281806Srpaulo /* 397281806Srpaulo * Since this was a dynamically added interface, the 398281806Srpaulo * driver wrapper may have removed its internal instance 399281806Srpaulo * and hapd->drv_priv is not valid anymore. 400281806Srpaulo */ 401281806Srpaulo hapd->drv_priv = NULL; 402281806Srpaulo } 403214501Srpaulo } 404214501Srpaulo 405252726Srpaulo wpabuf_free(hapd->time_adv); 406252726Srpaulo 407252726Srpaulo#ifdef CONFIG_INTERWORKING 408252726Srpaulo gas_serv_deinit(hapd); 409252726Srpaulo#endif /* CONFIG_INTERWORKING */ 410252726Srpaulo 411281806Srpaulo bss_load_update_deinit(hapd); 412281806Srpaulo ndisc_snoop_deinit(hapd); 413281806Srpaulo dhcp_snoop_deinit(hapd); 414281806Srpaulo x_snoop_deinit(hapd); 415281806Srpaulo 416252726Srpaulo#ifdef CONFIG_SQLITE 417281806Srpaulo bin_clear_free(hapd->tmp_eap_user.identity, 418281806Srpaulo hapd->tmp_eap_user.identity_len); 419281806Srpaulo bin_clear_free(hapd->tmp_eap_user.password, 420281806Srpaulo hapd->tmp_eap_user.password_len); 421252726Srpaulo#endif /* CONFIG_SQLITE */ 422281806Srpaulo 423281806Srpaulo#ifdef CONFIG_MESH 424281806Srpaulo wpabuf_free(hapd->mesh_pending_auth); 425281806Srpaulo hapd->mesh_pending_auth = NULL; 426281806Srpaulo#endif /* CONFIG_MESH */ 427337817Scy 428337817Scy hostapd_clean_rrm(hapd); 429346981Scy fils_hlp_deinit(hapd); 430346981Scy 431346981Scy#ifdef CONFIG_SAE 432346981Scy { 433346981Scy struct hostapd_sae_commit_queue *q; 434346981Scy 435346981Scy while ((q = dl_list_first(&hapd->sae_commit_queue, 436346981Scy struct hostapd_sae_commit_queue, 437346981Scy list))) { 438346981Scy dl_list_del(&q->list); 439346981Scy os_free(q); 440346981Scy } 441346981Scy } 442346981Scy eloop_cancel_timeout(auth_sae_process_commit, hapd, NULL); 443346981Scy#endif /* CONFIG_SAE */ 444214501Srpaulo} 445214501Srpaulo 446214501Srpaulo 447214501Srpaulo/** 448252726Srpaulo * hostapd_cleanup - Per-BSS cleanup (deinitialization) 449252726Srpaulo * @hapd: Pointer to BSS data 450252726Srpaulo * 451252726Srpaulo * This function is used to free all per-BSS data structures and resources. 452281806Srpaulo * Most of the modules that are initialized in hostapd_setup_bss() are 453281806Srpaulo * deinitialized here. 454252726Srpaulo */ 455252726Srpaulostatic void hostapd_cleanup(struct hostapd_data *hapd) 456252726Srpaulo{ 457281806Srpaulo wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd, 458346981Scy hapd->conf ? hapd->conf->iface : "N/A"); 459252726Srpaulo if (hapd->iface->interfaces && 460346981Scy hapd->iface->interfaces->ctrl_iface_deinit) { 461346981Scy wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_TERMINATING); 462252726Srpaulo hapd->iface->interfaces->ctrl_iface_deinit(hapd); 463346981Scy } 464252726Srpaulo hostapd_free_hapd_data(hapd); 465252726Srpaulo} 466252726Srpaulo 467252726Srpaulo 468289549Srpaulostatic void sta_track_deinit(struct hostapd_iface *iface) 469289549Srpaulo{ 470289549Srpaulo struct hostapd_sta_info *info; 471289549Srpaulo 472289549Srpaulo if (!iface->num_sta_seen) 473289549Srpaulo return; 474289549Srpaulo 475289549Srpaulo while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info, 476289549Srpaulo list))) { 477289549Srpaulo dl_list_del(&info->list); 478289549Srpaulo iface->num_sta_seen--; 479337817Scy sta_track_del(info); 480289549Srpaulo } 481289549Srpaulo} 482289549Srpaulo 483289549Srpaulo 484252726Srpaulostatic void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) 485252726Srpaulo{ 486281806Srpaulo wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); 487281806Srpaulo#ifdef CONFIG_IEEE80211N 488281806Srpaulo#ifdef NEED_AP_MLME 489281806Srpaulo hostapd_stop_setup_timers(iface); 490281806Srpaulo#endif /* NEED_AP_MLME */ 491281806Srpaulo#endif /* CONFIG_IEEE80211N */ 492346981Scy if (iface->current_mode) 493346981Scy acs_cleanup(iface); 494252726Srpaulo hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); 495252726Srpaulo iface->hw_features = NULL; 496346981Scy iface->current_mode = NULL; 497252726Srpaulo os_free(iface->current_rates); 498252726Srpaulo iface->current_rates = NULL; 499252726Srpaulo os_free(iface->basic_rates); 500252726Srpaulo iface->basic_rates = NULL; 501252726Srpaulo ap_list_deinit(iface); 502289549Srpaulo sta_track_deinit(iface); 503351611Scy airtime_policy_update_deinit(iface); 504252726Srpaulo} 505252726Srpaulo 506252726Srpaulo 507214501Srpaulo/** 508214501Srpaulo * hostapd_cleanup_iface - Complete per-interface cleanup 509214501Srpaulo * @iface: Pointer to interface data 510214501Srpaulo * 511214501Srpaulo * This function is called after per-BSS data structures are deinitialized 512214501Srpaulo * with hostapd_cleanup(). 513214501Srpaulo */ 514214501Srpaulostatic void hostapd_cleanup_iface(struct hostapd_iface *iface) 515214501Srpaulo{ 516281806Srpaulo wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); 517281806Srpaulo eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); 518346981Scy eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface, 519346981Scy NULL); 520281806Srpaulo 521252726Srpaulo hostapd_cleanup_iface_partial(iface); 522214501Srpaulo hostapd_config_free(iface->conf); 523214501Srpaulo iface->conf = NULL; 524214501Srpaulo 525214501Srpaulo os_free(iface->config_fname); 526214501Srpaulo os_free(iface->bss); 527281806Srpaulo wpa_printf(MSG_DEBUG, "%s: free iface=%p", __func__, iface); 528214501Srpaulo os_free(iface); 529214501Srpaulo} 530214501Srpaulo 531214501Srpaulo 532252726Srpaulostatic void hostapd_clear_wep(struct hostapd_data *hapd) 533252726Srpaulo{ 534346981Scy if (hapd->drv_priv && !hapd->iface->driver_ap_teardown && hapd->conf) { 535252726Srpaulo hostapd_set_privacy(hapd, 0); 536252726Srpaulo hostapd_broadcast_wep_clear(hapd); 537252726Srpaulo } 538252726Srpaulo} 539252726Srpaulo 540252726Srpaulo 541214501Srpaulostatic int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd) 542214501Srpaulo{ 543214501Srpaulo int i; 544214501Srpaulo 545214501Srpaulo hostapd_broadcast_wep_set(hapd); 546214501Srpaulo 547214501Srpaulo if (hapd->conf->ssid.wep.default_len) { 548214501Srpaulo hostapd_set_privacy(hapd, 1); 549214501Srpaulo return 0; 550214501Srpaulo } 551214501Srpaulo 552252726Srpaulo /* 553252726Srpaulo * When IEEE 802.1X is not enabled, the driver may need to know how to 554252726Srpaulo * set authentication algorithms for static WEP. 555252726Srpaulo */ 556252726Srpaulo hostapd_drv_set_authmode(hapd, hapd->conf->auth_algs); 557252726Srpaulo 558214501Srpaulo for (i = 0; i < 4; i++) { 559214501Srpaulo if (hapd->conf->ssid.wep.key[i] && 560252726Srpaulo hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i, 561252726Srpaulo i == hapd->conf->ssid.wep.idx, NULL, 0, 562252726Srpaulo hapd->conf->ssid.wep.key[i], 563252726Srpaulo hapd->conf->ssid.wep.len[i])) { 564214501Srpaulo wpa_printf(MSG_WARNING, "Could not set WEP " 565214501Srpaulo "encryption."); 566214501Srpaulo return -1; 567214501Srpaulo } 568214501Srpaulo if (hapd->conf->ssid.wep.key[i] && 569214501Srpaulo i == hapd->conf->ssid.wep.idx) 570214501Srpaulo hostapd_set_privacy(hapd, 1); 571214501Srpaulo } 572214501Srpaulo 573214501Srpaulo return 0; 574214501Srpaulo} 575214501Srpaulo 576214501Srpaulo 577252726Srpaulostatic int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason) 578214501Srpaulo{ 579214501Srpaulo int ret = 0; 580252726Srpaulo u8 addr[ETH_ALEN]; 581214501Srpaulo 582214501Srpaulo if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL) 583214501Srpaulo return 0; 584214501Srpaulo 585281806Srpaulo if (!hapd->iface->driver_ap_teardown) { 586281806Srpaulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, 587281806Srpaulo "Flushing old station entries"); 588281806Srpaulo 589281806Srpaulo if (hostapd_flush(hapd)) { 590281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_WARNING, 591281806Srpaulo "Could not connect to kernel driver"); 592281806Srpaulo ret = -1; 593281806Srpaulo } 594214501Srpaulo } 595346981Scy if (hapd->conf && hapd->conf->broadcast_deauth) { 596346981Scy wpa_dbg(hapd->msg_ctx, MSG_DEBUG, 597346981Scy "Deauthenticate all stations"); 598346981Scy os_memset(addr, 0xff, ETH_ALEN); 599346981Scy hostapd_drv_sta_deauth(hapd, addr, reason); 600346981Scy } 601252726Srpaulo hostapd_free_stas(hapd); 602214501Srpaulo 603214501Srpaulo return ret; 604214501Srpaulo} 605214501Srpaulo 606214501Srpaulo 607281806Srpaulostatic void hostapd_bss_deinit_no_free(struct hostapd_data *hapd) 608281806Srpaulo{ 609281806Srpaulo hostapd_free_stas(hapd); 610281806Srpaulo hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING); 611281806Srpaulo hostapd_clear_wep(hapd); 612281806Srpaulo} 613281806Srpaulo 614281806Srpaulo 615214501Srpaulo/** 616214501Srpaulo * hostapd_validate_bssid_configuration - Validate BSSID configuration 617214501Srpaulo * @iface: Pointer to interface data 618214501Srpaulo * Returns: 0 on success, -1 on failure 619214501Srpaulo * 620214501Srpaulo * This function is used to validate that the configured BSSIDs are valid. 621214501Srpaulo */ 622214501Srpaulostatic int hostapd_validate_bssid_configuration(struct hostapd_iface *iface) 623214501Srpaulo{ 624214501Srpaulo u8 mask[ETH_ALEN] = { 0 }; 625214501Srpaulo struct hostapd_data *hapd = iface->bss[0]; 626214501Srpaulo unsigned int i = iface->conf->num_bss, bits = 0, j; 627214501Srpaulo int auto_addr = 0; 628214501Srpaulo 629214501Srpaulo if (hostapd_drv_none(hapd)) 630214501Srpaulo return 0; 631214501Srpaulo 632337817Scy if (iface->conf->use_driver_iface_addr) 633337817Scy return 0; 634337817Scy 635214501Srpaulo /* Generate BSSID mask that is large enough to cover the BSSIDs. */ 636214501Srpaulo 637214501Srpaulo /* Determine the bits necessary to cover the number of BSSIDs. */ 638214501Srpaulo for (i--; i; i >>= 1) 639214501Srpaulo bits++; 640214501Srpaulo 641214501Srpaulo /* Determine the bits necessary to any configured BSSIDs, 642214501Srpaulo if they are higher than the number of BSSIDs. */ 643214501Srpaulo for (j = 0; j < iface->conf->num_bss; j++) { 644337817Scy if (is_zero_ether_addr(iface->conf->bss[j]->bssid)) { 645214501Srpaulo if (j) 646214501Srpaulo auto_addr++; 647214501Srpaulo continue; 648214501Srpaulo } 649214501Srpaulo 650214501Srpaulo for (i = 0; i < ETH_ALEN; i++) { 651214501Srpaulo mask[i] |= 652281806Srpaulo iface->conf->bss[j]->bssid[i] ^ 653214501Srpaulo hapd->own_addr[i]; 654214501Srpaulo } 655214501Srpaulo } 656214501Srpaulo 657214501Srpaulo if (!auto_addr) 658214501Srpaulo goto skip_mask_ext; 659214501Srpaulo 660214501Srpaulo for (i = 0; i < ETH_ALEN && mask[i] == 0; i++) 661214501Srpaulo ; 662214501Srpaulo j = 0; 663214501Srpaulo if (i < ETH_ALEN) { 664214501Srpaulo j = (5 - i) * 8; 665214501Srpaulo 666214501Srpaulo while (mask[i] != 0) { 667214501Srpaulo mask[i] >>= 1; 668214501Srpaulo j++; 669214501Srpaulo } 670214501Srpaulo } 671214501Srpaulo 672214501Srpaulo if (bits < j) 673214501Srpaulo bits = j; 674214501Srpaulo 675214501Srpaulo if (bits > 40) { 676214501Srpaulo wpa_printf(MSG_ERROR, "Too many bits in the BSSID mask (%u)", 677214501Srpaulo bits); 678214501Srpaulo return -1; 679214501Srpaulo } 680214501Srpaulo 681214501Srpaulo os_memset(mask, 0xff, ETH_ALEN); 682214501Srpaulo j = bits / 8; 683214501Srpaulo for (i = 5; i > 5 - j; i--) 684214501Srpaulo mask[i] = 0; 685214501Srpaulo j = bits % 8; 686346981Scy while (j) { 687346981Scy j--; 688214501Srpaulo mask[i] <<= 1; 689346981Scy } 690214501Srpaulo 691214501Srpauloskip_mask_ext: 692214501Srpaulo wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)", 693214501Srpaulo (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits); 694214501Srpaulo 695214501Srpaulo if (!auto_addr) 696214501Srpaulo return 0; 697214501Srpaulo 698214501Srpaulo for (i = 0; i < ETH_ALEN; i++) { 699214501Srpaulo if ((hapd->own_addr[i] & mask[i]) != hapd->own_addr[i]) { 700214501Srpaulo wpa_printf(MSG_ERROR, "Invalid BSSID mask " MACSTR 701214501Srpaulo " for start address " MACSTR ".", 702214501Srpaulo MAC2STR(mask), MAC2STR(hapd->own_addr)); 703214501Srpaulo wpa_printf(MSG_ERROR, "Start address must be the " 704214501Srpaulo "first address in the block (i.e., addr " 705214501Srpaulo "AND mask == addr)."); 706214501Srpaulo return -1; 707214501Srpaulo } 708214501Srpaulo } 709214501Srpaulo 710214501Srpaulo return 0; 711214501Srpaulo} 712214501Srpaulo 713214501Srpaulo 714214501Srpaulostatic int mac_in_conf(struct hostapd_config *conf, const void *a) 715214501Srpaulo{ 716214501Srpaulo size_t i; 717214501Srpaulo 718214501Srpaulo for (i = 0; i < conf->num_bss; i++) { 719281806Srpaulo if (hostapd_mac_comp(conf->bss[i]->bssid, a) == 0) { 720214501Srpaulo return 1; 721214501Srpaulo } 722214501Srpaulo } 723214501Srpaulo 724214501Srpaulo return 0; 725214501Srpaulo} 726214501Srpaulo 727214501Srpaulo 728252726Srpaulo#ifndef CONFIG_NO_RADIUS 729214501Srpaulo 730252726Srpaulostatic int hostapd_das_nas_mismatch(struct hostapd_data *hapd, 731252726Srpaulo struct radius_das_attrs *attr) 732252726Srpaulo{ 733281806Srpaulo if (attr->nas_identifier && 734281806Srpaulo (!hapd->conf->nas_identifier || 735281806Srpaulo os_strlen(hapd->conf->nas_identifier) != 736281806Srpaulo attr->nas_identifier_len || 737281806Srpaulo os_memcmp(hapd->conf->nas_identifier, attr->nas_identifier, 738281806Srpaulo attr->nas_identifier_len) != 0)) { 739281806Srpaulo wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-Identifier mismatch"); 740281806Srpaulo return 1; 741281806Srpaulo } 742281806Srpaulo 743281806Srpaulo if (attr->nas_ip_addr && 744281806Srpaulo (hapd->conf->own_ip_addr.af != AF_INET || 745281806Srpaulo os_memcmp(&hapd->conf->own_ip_addr.u.v4, attr->nas_ip_addr, 4) != 746281806Srpaulo 0)) { 747281806Srpaulo wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-IP-Address mismatch"); 748281806Srpaulo return 1; 749281806Srpaulo } 750281806Srpaulo 751281806Srpaulo#ifdef CONFIG_IPV6 752281806Srpaulo if (attr->nas_ipv6_addr && 753281806Srpaulo (hapd->conf->own_ip_addr.af != AF_INET6 || 754281806Srpaulo os_memcmp(&hapd->conf->own_ip_addr.u.v6, attr->nas_ipv6_addr, 16) 755281806Srpaulo != 0)) { 756281806Srpaulo wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-IPv6-Address mismatch"); 757281806Srpaulo return 1; 758281806Srpaulo } 759281806Srpaulo#endif /* CONFIG_IPV6 */ 760281806Srpaulo 761252726Srpaulo return 0; 762252726Srpaulo} 763214501Srpaulo 764252726Srpaulo 765252726Srpaulostatic struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd, 766281806Srpaulo struct radius_das_attrs *attr, 767281806Srpaulo int *multi) 768252726Srpaulo{ 769281806Srpaulo struct sta_info *selected, *sta; 770252726Srpaulo char buf[128]; 771281806Srpaulo int num_attr = 0; 772281806Srpaulo int count; 773252726Srpaulo 774281806Srpaulo *multi = 0; 775281806Srpaulo 776281806Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) 777281806Srpaulo sta->radius_das_match = 1; 778281806Srpaulo 779281806Srpaulo if (attr->sta_addr) { 780281806Srpaulo num_attr++; 781252726Srpaulo sta = ap_get_sta(hapd, attr->sta_addr); 782281806Srpaulo if (!sta) { 783281806Srpaulo wpa_printf(MSG_DEBUG, 784281806Srpaulo "RADIUS DAS: No Calling-Station-Id match"); 785281806Srpaulo return NULL; 786281806Srpaulo } 787252726Srpaulo 788281806Srpaulo selected = sta; 789252726Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 790281806Srpaulo if (sta != selected) 791281806Srpaulo sta->radius_das_match = 0; 792281806Srpaulo } 793281806Srpaulo wpa_printf(MSG_DEBUG, "RADIUS DAS: Calling-Station-Id match"); 794281806Srpaulo } 795281806Srpaulo 796281806Srpaulo if (attr->acct_session_id) { 797281806Srpaulo num_attr++; 798337817Scy if (attr->acct_session_id_len != 16) { 799281806Srpaulo wpa_printf(MSG_DEBUG, 800281806Srpaulo "RADIUS DAS: Acct-Session-Id cannot match"); 801281806Srpaulo return NULL; 802281806Srpaulo } 803281806Srpaulo count = 0; 804281806Srpaulo 805281806Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 806281806Srpaulo if (!sta->radius_das_match) 807281806Srpaulo continue; 808337817Scy os_snprintf(buf, sizeof(buf), "%016llX", 809337817Scy (unsigned long long) sta->acct_session_id); 810337817Scy if (os_memcmp(attr->acct_session_id, buf, 16) != 0) 811281806Srpaulo sta->radius_das_match = 0; 812281806Srpaulo else 813281806Srpaulo count++; 814252726Srpaulo } 815281806Srpaulo 816281806Srpaulo if (count == 0) { 817281806Srpaulo wpa_printf(MSG_DEBUG, 818281806Srpaulo "RADIUS DAS: No matches remaining after Acct-Session-Id check"); 819281806Srpaulo return NULL; 820281806Srpaulo } 821281806Srpaulo wpa_printf(MSG_DEBUG, "RADIUS DAS: Acct-Session-Id match"); 822252726Srpaulo } 823252726Srpaulo 824281806Srpaulo if (attr->acct_multi_session_id) { 825281806Srpaulo num_attr++; 826337817Scy if (attr->acct_multi_session_id_len != 16) { 827281806Srpaulo wpa_printf(MSG_DEBUG, 828281806Srpaulo "RADIUS DAS: Acct-Multi-Session-Id cannot match"); 829281806Srpaulo return NULL; 830281806Srpaulo } 831281806Srpaulo count = 0; 832281806Srpaulo 833252726Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 834281806Srpaulo if (!sta->radius_das_match) 835281806Srpaulo continue; 836281806Srpaulo if (!sta->eapol_sm || 837337817Scy !sta->eapol_sm->acct_multi_session_id) { 838281806Srpaulo sta->radius_das_match = 0; 839281806Srpaulo continue; 840281806Srpaulo } 841337817Scy os_snprintf(buf, sizeof(buf), "%016llX", 842337817Scy (unsigned long long) 843337817Scy sta->eapol_sm->acct_multi_session_id); 844337817Scy if (os_memcmp(attr->acct_multi_session_id, buf, 16) != 845281806Srpaulo 0) 846281806Srpaulo sta->radius_das_match = 0; 847281806Srpaulo else 848281806Srpaulo count++; 849281806Srpaulo } 850281806Srpaulo 851281806Srpaulo if (count == 0) { 852281806Srpaulo wpa_printf(MSG_DEBUG, 853281806Srpaulo "RADIUS DAS: No matches remaining after Acct-Multi-Session-Id check"); 854281806Srpaulo return NULL; 855281806Srpaulo } 856281806Srpaulo wpa_printf(MSG_DEBUG, 857281806Srpaulo "RADIUS DAS: Acct-Multi-Session-Id match"); 858281806Srpaulo } 859281806Srpaulo 860281806Srpaulo if (attr->cui) { 861281806Srpaulo num_attr++; 862281806Srpaulo count = 0; 863281806Srpaulo 864281806Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 865252726Srpaulo struct wpabuf *cui; 866281806Srpaulo 867281806Srpaulo if (!sta->radius_das_match) 868281806Srpaulo continue; 869252726Srpaulo cui = ieee802_1x_get_radius_cui(sta->eapol_sm); 870281806Srpaulo if (!cui || wpabuf_len(cui) != attr->cui_len || 871252726Srpaulo os_memcmp(wpabuf_head(cui), attr->cui, 872281806Srpaulo attr->cui_len) != 0) 873281806Srpaulo sta->radius_das_match = 0; 874281806Srpaulo else 875281806Srpaulo count++; 876252726Srpaulo } 877281806Srpaulo 878281806Srpaulo if (count == 0) { 879281806Srpaulo wpa_printf(MSG_DEBUG, 880281806Srpaulo "RADIUS DAS: No matches remaining after Chargeable-User-Identity check"); 881281806Srpaulo return NULL; 882281806Srpaulo } 883281806Srpaulo wpa_printf(MSG_DEBUG, 884281806Srpaulo "RADIUS DAS: Chargeable-User-Identity match"); 885252726Srpaulo } 886252726Srpaulo 887281806Srpaulo if (attr->user_name) { 888281806Srpaulo num_attr++; 889281806Srpaulo count = 0; 890281806Srpaulo 891252726Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 892252726Srpaulo u8 *identity; 893252726Srpaulo size_t identity_len; 894281806Srpaulo 895281806Srpaulo if (!sta->radius_das_match) 896281806Srpaulo continue; 897252726Srpaulo identity = ieee802_1x_get_identity(sta->eapol_sm, 898252726Srpaulo &identity_len); 899281806Srpaulo if (!identity || 900281806Srpaulo identity_len != attr->user_name_len || 901252726Srpaulo os_memcmp(identity, attr->user_name, identity_len) 902281806Srpaulo != 0) 903281806Srpaulo sta->radius_das_match = 0; 904281806Srpaulo else 905281806Srpaulo count++; 906252726Srpaulo } 907281806Srpaulo 908281806Srpaulo if (count == 0) { 909281806Srpaulo wpa_printf(MSG_DEBUG, 910281806Srpaulo "RADIUS DAS: No matches remaining after User-Name check"); 911281806Srpaulo return NULL; 912281806Srpaulo } 913281806Srpaulo wpa_printf(MSG_DEBUG, 914281806Srpaulo "RADIUS DAS: User-Name match"); 915252726Srpaulo } 916252726Srpaulo 917281806Srpaulo if (num_attr == 0) { 918281806Srpaulo /* 919281806Srpaulo * In theory, we could match all current associations, but it 920281806Srpaulo * seems safer to just reject requests that do not include any 921281806Srpaulo * session identification attributes. 922281806Srpaulo */ 923281806Srpaulo wpa_printf(MSG_DEBUG, 924281806Srpaulo "RADIUS DAS: No session identification attributes included"); 925281806Srpaulo return NULL; 926281806Srpaulo } 927281806Srpaulo 928281806Srpaulo selected = NULL; 929281806Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 930281806Srpaulo if (sta->radius_das_match) { 931281806Srpaulo if (selected) { 932281806Srpaulo *multi = 1; 933281806Srpaulo return NULL; 934281806Srpaulo } 935281806Srpaulo selected = sta; 936281806Srpaulo } 937281806Srpaulo } 938281806Srpaulo 939281806Srpaulo return selected; 940252726Srpaulo} 941252726Srpaulo 942252726Srpaulo 943281806Srpaulostatic int hostapd_das_disconnect_pmksa(struct hostapd_data *hapd, 944281806Srpaulo struct radius_das_attrs *attr) 945281806Srpaulo{ 946281806Srpaulo if (!hapd->wpa_auth) 947281806Srpaulo return -1; 948281806Srpaulo return wpa_auth_radius_das_disconnect_pmksa(hapd->wpa_auth, attr); 949281806Srpaulo} 950281806Srpaulo 951281806Srpaulo 952252726Srpaulostatic enum radius_das_res 953252726Srpaulohostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr) 954252726Srpaulo{ 955252726Srpaulo struct hostapd_data *hapd = ctx; 956252726Srpaulo struct sta_info *sta; 957281806Srpaulo int multi; 958252726Srpaulo 959252726Srpaulo if (hostapd_das_nas_mismatch(hapd, attr)) 960252726Srpaulo return RADIUS_DAS_NAS_MISMATCH; 961252726Srpaulo 962281806Srpaulo sta = hostapd_das_find_sta(hapd, attr, &multi); 963281806Srpaulo if (sta == NULL) { 964281806Srpaulo if (multi) { 965281806Srpaulo wpa_printf(MSG_DEBUG, 966281806Srpaulo "RADIUS DAS: Multiple sessions match - not supported"); 967281806Srpaulo return RADIUS_DAS_MULTI_SESSION_MATCH; 968281806Srpaulo } 969281806Srpaulo if (hostapd_das_disconnect_pmksa(hapd, attr) == 0) { 970281806Srpaulo wpa_printf(MSG_DEBUG, 971281806Srpaulo "RADIUS DAS: PMKSA cache entry matched"); 972281806Srpaulo return RADIUS_DAS_SUCCESS; 973281806Srpaulo } 974281806Srpaulo wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found"); 975252726Srpaulo return RADIUS_DAS_SESSION_NOT_FOUND; 976281806Srpaulo } 977252726Srpaulo 978281806Srpaulo wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR 979281806Srpaulo " - disconnecting", MAC2STR(sta->addr)); 980281806Srpaulo wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr); 981281806Srpaulo 982252726Srpaulo hostapd_drv_sta_deauth(hapd, sta->addr, 983252726Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 984252726Srpaulo ap_sta_deauthenticate(hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID); 985252726Srpaulo 986252726Srpaulo return RADIUS_DAS_SUCCESS; 987252726Srpaulo} 988252726Srpaulo 989346981Scy 990346981Scy#ifdef CONFIG_HS20 991346981Scystatic enum radius_das_res 992346981Scyhostapd_das_coa(void *ctx, struct radius_das_attrs *attr) 993346981Scy{ 994346981Scy struct hostapd_data *hapd = ctx; 995346981Scy struct sta_info *sta; 996346981Scy int multi; 997346981Scy 998346981Scy if (hostapd_das_nas_mismatch(hapd, attr)) 999346981Scy return RADIUS_DAS_NAS_MISMATCH; 1000346981Scy 1001346981Scy sta = hostapd_das_find_sta(hapd, attr, &multi); 1002346981Scy if (!sta) { 1003346981Scy if (multi) { 1004346981Scy wpa_printf(MSG_DEBUG, 1005346981Scy "RADIUS DAS: Multiple sessions match - not supported"); 1006346981Scy return RADIUS_DAS_MULTI_SESSION_MATCH; 1007346981Scy } 1008346981Scy wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found"); 1009346981Scy return RADIUS_DAS_SESSION_NOT_FOUND; 1010346981Scy } 1011346981Scy 1012346981Scy wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR 1013346981Scy " - CoA", MAC2STR(sta->addr)); 1014346981Scy 1015346981Scy if (attr->hs20_t_c_filtering) { 1016346981Scy if (attr->hs20_t_c_filtering[0] & BIT(0)) { 1017346981Scy wpa_printf(MSG_DEBUG, 1018346981Scy "HS 2.0: Unexpected Terms and Conditions filtering required in CoA-Request"); 1019346981Scy return RADIUS_DAS_COA_FAILED; 1020346981Scy } 1021346981Scy 1022346981Scy hs20_t_c_filtering(hapd, sta, 0); 1023346981Scy } 1024346981Scy 1025346981Scy return RADIUS_DAS_SUCCESS; 1026346981Scy} 1027346981Scy#else /* CONFIG_HS20 */ 1028346981Scy#define hostapd_das_coa NULL 1029346981Scy#endif /* CONFIG_HS20 */ 1030346981Scy 1031351611Scy 1032351611Scy#ifdef CONFIG_SQLITE 1033351611Scy 1034351611Scystatic int db_table_exists(sqlite3 *db, const char *name) 1035351611Scy{ 1036351611Scy char cmd[128]; 1037351611Scy 1038351611Scy os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name); 1039351611Scy return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK; 1040351611Scy} 1041351611Scy 1042351611Scy 1043351611Scystatic int db_table_create_radius_attributes(sqlite3 *db) 1044351611Scy{ 1045351611Scy char *err = NULL; 1046351611Scy const char *sql = 1047351611Scy "CREATE TABLE radius_attributes(" 1048351611Scy " id INTEGER PRIMARY KEY," 1049351611Scy " sta TEXT," 1050351611Scy " reqtype TEXT," 1051351611Scy " attr TEXT" 1052351611Scy ");" 1053351611Scy "CREATE INDEX idx_sta_reqtype ON radius_attributes(sta,reqtype);"; 1054351611Scy 1055351611Scy wpa_printf(MSG_DEBUG, 1056351611Scy "Adding database table for RADIUS attribute information"); 1057351611Scy if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) { 1058351611Scy wpa_printf(MSG_ERROR, "SQLite error: %s", err); 1059351611Scy sqlite3_free(err); 1060351611Scy return -1; 1061351611Scy } 1062351611Scy 1063351611Scy return 0; 1064351611Scy} 1065351611Scy 1066351611Scy#endif /* CONFIG_SQLITE */ 1067351611Scy 1068252726Srpaulo#endif /* CONFIG_NO_RADIUS */ 1069252726Srpaulo 1070252726Srpaulo 1071214501Srpaulo/** 1072214501Srpaulo * hostapd_setup_bss - Per-BSS setup (initialization) 1073214501Srpaulo * @hapd: Pointer to BSS data 1074281806Srpaulo * @first: Whether this BSS is the first BSS of an interface; -1 = not first, 1075281806Srpaulo * but interface may exist 1076214501Srpaulo * 1077214501Srpaulo * This function is used to initialize all per-BSS data structures and 1078214501Srpaulo * resources. This gets called in a loop for each BSS when an interface is 1079214501Srpaulo * initialized. Most of the modules that are initialized here will be 1080214501Srpaulo * deinitialized in hostapd_cleanup(). 1081214501Srpaulo */ 1082214501Srpaulostatic int hostapd_setup_bss(struct hostapd_data *hapd, int first) 1083214501Srpaulo{ 1084214501Srpaulo struct hostapd_bss_config *conf = hapd->conf; 1085289549Srpaulo u8 ssid[SSID_MAX_LEN + 1]; 1086214501Srpaulo int ssid_len, set_ssid; 1087214501Srpaulo char force_ifname[IFNAMSIZ]; 1088214501Srpaulo u8 if_addr[ETH_ALEN]; 1089281806Srpaulo int flush_old_stations = 1; 1090214501Srpaulo 1091281806Srpaulo wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s), first=%d)", 1092281806Srpaulo __func__, hapd, conf->iface, first); 1093281806Srpaulo 1094281806Srpaulo#ifdef EAP_SERVER_TNC 1095281806Srpaulo if (conf->tnc && tncs_global_init() < 0) { 1096281806Srpaulo wpa_printf(MSG_ERROR, "Failed to initialize TNCS"); 1097281806Srpaulo return -1; 1098281806Srpaulo } 1099281806Srpaulo#endif /* EAP_SERVER_TNC */ 1100281806Srpaulo 1101281806Srpaulo if (hapd->started) { 1102281806Srpaulo wpa_printf(MSG_ERROR, "%s: Interface %s was already started", 1103281806Srpaulo __func__, conf->iface); 1104281806Srpaulo return -1; 1105281806Srpaulo } 1106281806Srpaulo hapd->started = 1; 1107281806Srpaulo 1108281806Srpaulo if (!first || first == -1) { 1109337817Scy u8 *addr = hapd->own_addr; 1110337817Scy 1111337817Scy if (!is_zero_ether_addr(conf->bssid)) { 1112214501Srpaulo /* Allocate the configured BSSID. */ 1113281806Srpaulo os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN); 1114214501Srpaulo 1115214501Srpaulo if (hostapd_mac_comp(hapd->own_addr, 1116214501Srpaulo hapd->iface->bss[0]->own_addr) == 1117214501Srpaulo 0) { 1118214501Srpaulo wpa_printf(MSG_ERROR, "BSS '%s' may not have " 1119214501Srpaulo "BSSID set to the MAC address of " 1120281806Srpaulo "the radio", conf->iface); 1121214501Srpaulo return -1; 1122214501Srpaulo } 1123337817Scy } else if (hapd->iconf->use_driver_iface_addr) { 1124337817Scy addr = NULL; 1125337817Scy } else { 1126337817Scy /* Allocate the next available BSSID. */ 1127337817Scy do { 1128337817Scy inc_byte_array(hapd->own_addr, ETH_ALEN); 1129337817Scy } while (mac_in_conf(hapd->iconf, hapd->own_addr)); 1130214501Srpaulo } 1131214501Srpaulo 1132214501Srpaulo hapd->interface_added = 1; 1133214501Srpaulo if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS, 1134337817Scy conf->iface, addr, hapd, 1135252726Srpaulo &hapd->drv_priv, force_ifname, if_addr, 1136281806Srpaulo conf->bridge[0] ? conf->bridge : NULL, 1137281806Srpaulo first == -1)) { 1138214501Srpaulo wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID=" 1139214501Srpaulo MACSTR ")", MAC2STR(hapd->own_addr)); 1140281806Srpaulo hapd->interface_added = 0; 1141214501Srpaulo return -1; 1142214501Srpaulo } 1143337817Scy 1144337817Scy if (!addr) 1145337817Scy os_memcpy(hapd->own_addr, if_addr, ETH_ALEN); 1146214501Srpaulo } 1147214501Srpaulo 1148252726Srpaulo if (conf->wmm_enabled < 0) 1149252726Srpaulo conf->wmm_enabled = hapd->iconf->ieee80211n; 1150252726Srpaulo 1151346981Scy#ifdef CONFIG_IEEE80211R_AP 1152337817Scy if (is_zero_ether_addr(conf->r1_key_holder)) 1153337817Scy os_memcpy(conf->r1_key_holder, hapd->own_addr, ETH_ALEN); 1154346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1155337817Scy 1156281806Srpaulo#ifdef CONFIG_MESH 1157346981Scy if ((hapd->conf->mesh & MESH_ENABLED) && hapd->iface->mconf == NULL) 1158281806Srpaulo flush_old_stations = 0; 1159281806Srpaulo#endif /* CONFIG_MESH */ 1160281806Srpaulo 1161281806Srpaulo if (flush_old_stations) 1162281806Srpaulo hostapd_flush_old_stations(hapd, 1163281806Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 1164214501Srpaulo hostapd_set_privacy(hapd, 0); 1165214501Srpaulo 1166214501Srpaulo hostapd_broadcast_wep_clear(hapd); 1167281806Srpaulo if (hostapd_setup_encryption(conf->iface, hapd)) 1168214501Srpaulo return -1; 1169214501Srpaulo 1170214501Srpaulo /* 1171214501Srpaulo * Fetch the SSID from the system and use it or, 1172214501Srpaulo * if one was specified in the config file, verify they 1173214501Srpaulo * match. 1174214501Srpaulo */ 1175214501Srpaulo ssid_len = hostapd_get_ssid(hapd, ssid, sizeof(ssid)); 1176214501Srpaulo if (ssid_len < 0) { 1177214501Srpaulo wpa_printf(MSG_ERROR, "Could not read SSID from system"); 1178214501Srpaulo return -1; 1179214501Srpaulo } 1180214501Srpaulo if (conf->ssid.ssid_set) { 1181214501Srpaulo /* 1182214501Srpaulo * If SSID is specified in the config file and it differs 1183214501Srpaulo * from what is being used then force installation of the 1184214501Srpaulo * new SSID. 1185214501Srpaulo */ 1186214501Srpaulo set_ssid = (conf->ssid.ssid_len != (size_t) ssid_len || 1187214501Srpaulo os_memcmp(conf->ssid.ssid, ssid, ssid_len) != 0); 1188214501Srpaulo } else { 1189214501Srpaulo /* 1190214501Srpaulo * No SSID in the config file; just use the one we got 1191214501Srpaulo * from the system. 1192214501Srpaulo */ 1193214501Srpaulo set_ssid = 0; 1194214501Srpaulo conf->ssid.ssid_len = ssid_len; 1195214501Srpaulo os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len); 1196214501Srpaulo } 1197214501Srpaulo 1198214501Srpaulo if (!hostapd_drv_none(hapd)) { 1199214501Srpaulo wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR 1200252726Srpaulo " and ssid \"%s\"", 1201281806Srpaulo conf->iface, MAC2STR(hapd->own_addr), 1202281806Srpaulo wpa_ssid_txt(conf->ssid.ssid, conf->ssid.ssid_len)); 1203214501Srpaulo } 1204214501Srpaulo 1205214501Srpaulo if (hostapd_setup_wpa_psk(conf)) { 1206214501Srpaulo wpa_printf(MSG_ERROR, "WPA-PSK setup failed."); 1207214501Srpaulo return -1; 1208214501Srpaulo } 1209214501Srpaulo 1210214501Srpaulo /* Set SSID for the kernel driver (to be used in beacon and probe 1211214501Srpaulo * response frames) */ 1212252726Srpaulo if (set_ssid && hostapd_set_ssid(hapd, conf->ssid.ssid, 1213214501Srpaulo conf->ssid.ssid_len)) { 1214214501Srpaulo wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); 1215214501Srpaulo return -1; 1216214501Srpaulo } 1217214501Srpaulo 1218281806Srpaulo if (wpa_debug_level <= MSG_MSGDUMP) 1219214501Srpaulo conf->radius->msg_dumps = 1; 1220214501Srpaulo#ifndef CONFIG_NO_RADIUS 1221351611Scy 1222351611Scy#ifdef CONFIG_SQLITE 1223351611Scy if (conf->radius_req_attr_sqlite) { 1224351611Scy if (sqlite3_open(conf->radius_req_attr_sqlite, 1225351611Scy &hapd->rad_attr_db)) { 1226351611Scy wpa_printf(MSG_ERROR, "Could not open SQLite file '%s'", 1227351611Scy conf->radius_req_attr_sqlite); 1228351611Scy return -1; 1229351611Scy } 1230351611Scy 1231351611Scy wpa_printf(MSG_DEBUG, "Opening RADIUS attribute database: %s", 1232351611Scy conf->radius_req_attr_sqlite); 1233351611Scy if (!db_table_exists(hapd->rad_attr_db, "radius_attributes") && 1234351611Scy db_table_create_radius_attributes(hapd->rad_attr_db) < 0) 1235351611Scy return -1; 1236351611Scy } 1237351611Scy#endif /* CONFIG_SQLITE */ 1238351611Scy 1239214501Srpaulo hapd->radius = radius_client_init(hapd, conf->radius); 1240214501Srpaulo if (hapd->radius == NULL) { 1241214501Srpaulo wpa_printf(MSG_ERROR, "RADIUS client initialization failed."); 1242214501Srpaulo return -1; 1243214501Srpaulo } 1244252726Srpaulo 1245281806Srpaulo if (conf->radius_das_port) { 1246252726Srpaulo struct radius_das_conf das_conf; 1247252726Srpaulo os_memset(&das_conf, 0, sizeof(das_conf)); 1248281806Srpaulo das_conf.port = conf->radius_das_port; 1249281806Srpaulo das_conf.shared_secret = conf->radius_das_shared_secret; 1250252726Srpaulo das_conf.shared_secret_len = 1251281806Srpaulo conf->radius_das_shared_secret_len; 1252281806Srpaulo das_conf.client_addr = &conf->radius_das_client_addr; 1253281806Srpaulo das_conf.time_window = conf->radius_das_time_window; 1254252726Srpaulo das_conf.require_event_timestamp = 1255281806Srpaulo conf->radius_das_require_event_timestamp; 1256337817Scy das_conf.require_message_authenticator = 1257337817Scy conf->radius_das_require_message_authenticator; 1258252726Srpaulo das_conf.ctx = hapd; 1259252726Srpaulo das_conf.disconnect = hostapd_das_disconnect; 1260346981Scy das_conf.coa = hostapd_das_coa; 1261252726Srpaulo hapd->radius_das = radius_das_init(&das_conf); 1262252726Srpaulo if (hapd->radius_das == NULL) { 1263252726Srpaulo wpa_printf(MSG_ERROR, "RADIUS DAS initialization " 1264252726Srpaulo "failed."); 1265252726Srpaulo return -1; 1266252726Srpaulo } 1267252726Srpaulo } 1268214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 1269214501Srpaulo 1270214501Srpaulo if (hostapd_acl_init(hapd)) { 1271214501Srpaulo wpa_printf(MSG_ERROR, "ACL initialization failed."); 1272214501Srpaulo return -1; 1273214501Srpaulo } 1274214501Srpaulo if (hostapd_init_wps(hapd, conf)) 1275214501Srpaulo return -1; 1276214501Srpaulo 1277346981Scy#ifdef CONFIG_DPP 1278346981Scy hapd->gas = gas_query_ap_init(hapd, hapd->msg_ctx); 1279346981Scy if (!hapd->gas) 1280346981Scy return -1; 1281346981Scy if (hostapd_dpp_init(hapd)) 1282346981Scy return -1; 1283346981Scy#endif /* CONFIG_DPP */ 1284346981Scy 1285214501Srpaulo if (authsrv_init(hapd) < 0) 1286214501Srpaulo return -1; 1287214501Srpaulo 1288214501Srpaulo if (ieee802_1x_init(hapd)) { 1289214501Srpaulo wpa_printf(MSG_ERROR, "IEEE 802.1X initialization failed."); 1290214501Srpaulo return -1; 1291214501Srpaulo } 1292214501Srpaulo 1293281806Srpaulo if ((conf->wpa || conf->osen) && hostapd_setup_wpa(hapd)) 1294214501Srpaulo return -1; 1295214501Srpaulo 1296214501Srpaulo if (accounting_init(hapd)) { 1297214501Srpaulo wpa_printf(MSG_ERROR, "Accounting initialization failed."); 1298214501Srpaulo return -1; 1299214501Srpaulo } 1300214501Srpaulo 1301281806Srpaulo if (conf->ieee802_11f && 1302281806Srpaulo (hapd->iapp = iapp_init(hapd, conf->iapp_iface)) == NULL) { 1303214501Srpaulo wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization " 1304214501Srpaulo "failed."); 1305214501Srpaulo return -1; 1306214501Srpaulo } 1307214501Srpaulo 1308252726Srpaulo#ifdef CONFIG_INTERWORKING 1309252726Srpaulo if (gas_serv_init(hapd)) { 1310252726Srpaulo wpa_printf(MSG_ERROR, "GAS server initialization failed"); 1311252726Srpaulo return -1; 1312252726Srpaulo } 1313281806Srpaulo 1314281806Srpaulo if (conf->qos_map_set_len && 1315281806Srpaulo hostapd_drv_set_qos_map(hapd, conf->qos_map_set, 1316281806Srpaulo conf->qos_map_set_len)) { 1317281806Srpaulo wpa_printf(MSG_ERROR, "Failed to initialize QoS Map"); 1318281806Srpaulo return -1; 1319281806Srpaulo } 1320252726Srpaulo#endif /* CONFIG_INTERWORKING */ 1321252726Srpaulo 1322281806Srpaulo if (conf->bss_load_update_period && bss_load_update_init(hapd)) { 1323281806Srpaulo wpa_printf(MSG_ERROR, "BSS Load initialization failed"); 1324214501Srpaulo return -1; 1325214501Srpaulo } 1326214501Srpaulo 1327281806Srpaulo if (conf->proxy_arp) { 1328281806Srpaulo if (x_snoop_init(hapd)) { 1329281806Srpaulo wpa_printf(MSG_ERROR, 1330281806Srpaulo "Generic snooping infrastructure initialization failed"); 1331281806Srpaulo return -1; 1332281806Srpaulo } 1333281806Srpaulo 1334281806Srpaulo if (dhcp_snoop_init(hapd)) { 1335281806Srpaulo wpa_printf(MSG_ERROR, 1336281806Srpaulo "DHCP snooping initialization failed"); 1337281806Srpaulo return -1; 1338281806Srpaulo } 1339281806Srpaulo 1340281806Srpaulo if (ndisc_snoop_init(hapd)) { 1341281806Srpaulo wpa_printf(MSG_ERROR, 1342281806Srpaulo "Neighbor Discovery snooping initialization failed"); 1343281806Srpaulo return -1; 1344281806Srpaulo } 1345281806Srpaulo } 1346281806Srpaulo 1347214501Srpaulo if (!hostapd_drv_none(hapd) && vlan_init(hapd)) { 1348214501Srpaulo wpa_printf(MSG_ERROR, "VLAN initialization failed."); 1349214501Srpaulo return -1; 1350214501Srpaulo } 1351214501Srpaulo 1352281806Srpaulo if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0) 1353281806Srpaulo return -1; 1354214501Srpaulo 1355252726Srpaulo if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0) 1356252726Srpaulo return -1; 1357252726Srpaulo 1358252726Srpaulo if (hapd->driver && hapd->driver->set_operstate) 1359252726Srpaulo hapd->driver->set_operstate(hapd->drv_priv, 1); 1360252726Srpaulo 1361214501Srpaulo return 0; 1362214501Srpaulo} 1363214501Srpaulo 1364214501Srpaulo 1365214501Srpaulostatic void hostapd_tx_queue_params(struct hostapd_iface *iface) 1366214501Srpaulo{ 1367214501Srpaulo struct hostapd_data *hapd = iface->bss[0]; 1368214501Srpaulo int i; 1369214501Srpaulo struct hostapd_tx_queue_params *p; 1370214501Srpaulo 1371281806Srpaulo#ifdef CONFIG_MESH 1372346981Scy if ((hapd->conf->mesh & MESH_ENABLED) && iface->mconf == NULL) 1373281806Srpaulo return; 1374281806Srpaulo#endif /* CONFIG_MESH */ 1375281806Srpaulo 1376214501Srpaulo for (i = 0; i < NUM_TX_QUEUES; i++) { 1377214501Srpaulo p = &iface->conf->tx_queue[i]; 1378214501Srpaulo 1379214501Srpaulo if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin, 1380214501Srpaulo p->cwmax, p->burst)) { 1381214501Srpaulo wpa_printf(MSG_DEBUG, "Failed to set TX queue " 1382214501Srpaulo "parameters for queue %d.", i); 1383214501Srpaulo /* Continue anyway */ 1384214501Srpaulo } 1385214501Srpaulo } 1386214501Srpaulo} 1387214501Srpaulo 1388214501Srpaulo 1389281806Srpaulostatic int hostapd_set_acl_list(struct hostapd_data *hapd, 1390281806Srpaulo struct mac_acl_entry *mac_acl, 1391281806Srpaulo int n_entries, u8 accept_acl) 1392281806Srpaulo{ 1393281806Srpaulo struct hostapd_acl_params *acl_params; 1394281806Srpaulo int i, err; 1395281806Srpaulo 1396281806Srpaulo acl_params = os_zalloc(sizeof(*acl_params) + 1397281806Srpaulo (n_entries * sizeof(acl_params->mac_acl[0]))); 1398281806Srpaulo if (!acl_params) 1399281806Srpaulo return -ENOMEM; 1400281806Srpaulo 1401281806Srpaulo for (i = 0; i < n_entries; i++) 1402281806Srpaulo os_memcpy(acl_params->mac_acl[i].addr, mac_acl[i].addr, 1403281806Srpaulo ETH_ALEN); 1404281806Srpaulo 1405281806Srpaulo acl_params->acl_policy = accept_acl; 1406281806Srpaulo acl_params->num_mac_acl = n_entries; 1407281806Srpaulo 1408281806Srpaulo err = hostapd_drv_set_acl(hapd, acl_params); 1409281806Srpaulo 1410281806Srpaulo os_free(acl_params); 1411281806Srpaulo 1412281806Srpaulo return err; 1413281806Srpaulo} 1414281806Srpaulo 1415281806Srpaulo 1416281806Srpaulostatic void hostapd_set_acl(struct hostapd_data *hapd) 1417281806Srpaulo{ 1418281806Srpaulo struct hostapd_config *conf = hapd->iconf; 1419281806Srpaulo int err; 1420281806Srpaulo u8 accept_acl; 1421281806Srpaulo 1422281806Srpaulo if (hapd->iface->drv_max_acl_mac_addrs == 0) 1423281806Srpaulo return; 1424281806Srpaulo 1425281806Srpaulo if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) { 1426281806Srpaulo accept_acl = 1; 1427281806Srpaulo err = hostapd_set_acl_list(hapd, conf->bss[0]->accept_mac, 1428281806Srpaulo conf->bss[0]->num_accept_mac, 1429281806Srpaulo accept_acl); 1430281806Srpaulo if (err) { 1431281806Srpaulo wpa_printf(MSG_DEBUG, "Failed to set accept acl"); 1432281806Srpaulo return; 1433281806Srpaulo } 1434281806Srpaulo } else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) { 1435281806Srpaulo accept_acl = 0; 1436281806Srpaulo err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac, 1437281806Srpaulo conf->bss[0]->num_deny_mac, 1438281806Srpaulo accept_acl); 1439281806Srpaulo if (err) { 1440281806Srpaulo wpa_printf(MSG_DEBUG, "Failed to set deny acl"); 1441281806Srpaulo return; 1442281806Srpaulo } 1443281806Srpaulo } 1444281806Srpaulo} 1445281806Srpaulo 1446281806Srpaulo 1447281806Srpaulostatic int start_ctrl_iface_bss(struct hostapd_data *hapd) 1448281806Srpaulo{ 1449281806Srpaulo if (!hapd->iface->interfaces || 1450281806Srpaulo !hapd->iface->interfaces->ctrl_iface_init) 1451281806Srpaulo return 0; 1452281806Srpaulo 1453281806Srpaulo if (hapd->iface->interfaces->ctrl_iface_init(hapd)) { 1454281806Srpaulo wpa_printf(MSG_ERROR, 1455281806Srpaulo "Failed to setup control interface for %s", 1456281806Srpaulo hapd->conf->iface); 1457281806Srpaulo return -1; 1458281806Srpaulo } 1459281806Srpaulo 1460281806Srpaulo return 0; 1461281806Srpaulo} 1462281806Srpaulo 1463281806Srpaulo 1464281806Srpaulostatic int start_ctrl_iface(struct hostapd_iface *iface) 1465281806Srpaulo{ 1466281806Srpaulo size_t i; 1467281806Srpaulo 1468281806Srpaulo if (!iface->interfaces || !iface->interfaces->ctrl_iface_init) 1469281806Srpaulo return 0; 1470281806Srpaulo 1471281806Srpaulo for (i = 0; i < iface->num_bss; i++) { 1472281806Srpaulo struct hostapd_data *hapd = iface->bss[i]; 1473281806Srpaulo if (iface->interfaces->ctrl_iface_init(hapd)) { 1474281806Srpaulo wpa_printf(MSG_ERROR, 1475281806Srpaulo "Failed to setup control interface for %s", 1476281806Srpaulo hapd->conf->iface); 1477281806Srpaulo return -1; 1478281806Srpaulo } 1479281806Srpaulo } 1480281806Srpaulo 1481281806Srpaulo return 0; 1482281806Srpaulo} 1483281806Srpaulo 1484281806Srpaulo 1485281806Srpaulostatic void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx) 1486281806Srpaulo{ 1487281806Srpaulo struct hostapd_iface *iface = eloop_ctx; 1488281806Srpaulo 1489281806Srpaulo if (!iface->wait_channel_update) { 1490281806Srpaulo wpa_printf(MSG_INFO, "Channel list update timeout, but interface was not waiting for it"); 1491281806Srpaulo return; 1492281806Srpaulo } 1493281806Srpaulo 1494281806Srpaulo /* 1495281806Srpaulo * It is possible that the existing channel list is acceptable, so try 1496281806Srpaulo * to proceed. 1497281806Srpaulo */ 1498281806Srpaulo wpa_printf(MSG_DEBUG, "Channel list update timeout - try to continue anyway"); 1499281806Srpaulo setup_interface2(iface); 1500281806Srpaulo} 1501281806Srpaulo 1502281806Srpaulo 1503281806Srpaulovoid hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator) 1504281806Srpaulo{ 1505281806Srpaulo if (!iface->wait_channel_update || initiator != REGDOM_SET_BY_USER) 1506281806Srpaulo return; 1507281806Srpaulo 1508281806Srpaulo wpa_printf(MSG_DEBUG, "Channel list updated - continue setup"); 1509281806Srpaulo eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); 1510281806Srpaulo setup_interface2(iface); 1511281806Srpaulo} 1512281806Srpaulo 1513281806Srpaulo 1514214501Srpaulostatic int setup_interface(struct hostapd_iface *iface) 1515214501Srpaulo{ 1516214501Srpaulo struct hostapd_data *hapd = iface->bss[0]; 1517214501Srpaulo size_t i; 1518214501Srpaulo 1519214501Srpaulo /* 1520281806Srpaulo * It is possible that setup_interface() is called after the interface 1521281806Srpaulo * was disabled etc., in which case driver_ap_teardown is possibly set 1522281806Srpaulo * to 1. Clear it here so any other key/station deletion, which is not 1523281806Srpaulo * part of a teardown flow, would also call the relevant driver 1524281806Srpaulo * callbacks. 1525281806Srpaulo */ 1526281806Srpaulo iface->driver_ap_teardown = 0; 1527281806Srpaulo 1528281806Srpaulo if (!iface->phy[0]) { 1529281806Srpaulo const char *phy = hostapd_drv_get_radio_name(hapd); 1530281806Srpaulo if (phy) { 1531281806Srpaulo wpa_printf(MSG_DEBUG, "phy: %s", phy); 1532281806Srpaulo os_strlcpy(iface->phy, phy, sizeof(iface->phy)); 1533281806Srpaulo } 1534281806Srpaulo } 1535281806Srpaulo 1536281806Srpaulo /* 1537214501Srpaulo * Make sure that all BSSes get configured with a pointer to the same 1538214501Srpaulo * driver interface. 1539214501Srpaulo */ 1540214501Srpaulo for (i = 1; i < iface->num_bss; i++) { 1541214501Srpaulo iface->bss[i]->driver = hapd->driver; 1542214501Srpaulo iface->bss[i]->drv_priv = hapd->drv_priv; 1543214501Srpaulo } 1544214501Srpaulo 1545214501Srpaulo if (hostapd_validate_bssid_configuration(iface)) 1546214501Srpaulo return -1; 1547214501Srpaulo 1548281806Srpaulo /* 1549281806Srpaulo * Initialize control interfaces early to allow external monitoring of 1550281806Srpaulo * channel setup operations that may take considerable amount of time 1551281806Srpaulo * especially for DFS cases. 1552281806Srpaulo */ 1553281806Srpaulo if (start_ctrl_iface(iface)) 1554281806Srpaulo return -1; 1555281806Srpaulo 1556214501Srpaulo if (hapd->iconf->country[0] && hapd->iconf->country[1]) { 1557281806Srpaulo char country[4], previous_country[4]; 1558281806Srpaulo 1559281806Srpaulo hostapd_set_state(iface, HAPD_IFACE_COUNTRY_UPDATE); 1560281806Srpaulo if (hostapd_get_country(hapd, previous_country) < 0) 1561281806Srpaulo previous_country[0] = '\0'; 1562281806Srpaulo 1563214501Srpaulo os_memcpy(country, hapd->iconf->country, 3); 1564214501Srpaulo country[3] = '\0'; 1565214501Srpaulo if (hostapd_set_country(hapd, country) < 0) { 1566214501Srpaulo wpa_printf(MSG_ERROR, "Failed to set country code"); 1567214501Srpaulo return -1; 1568214501Srpaulo } 1569281806Srpaulo 1570281806Srpaulo wpa_printf(MSG_DEBUG, "Previous country code %s, new country code %s", 1571281806Srpaulo previous_country, country); 1572281806Srpaulo 1573281806Srpaulo if (os_strncmp(previous_country, country, 2) != 0) { 1574281806Srpaulo wpa_printf(MSG_DEBUG, "Continue interface setup after channel list update"); 1575281806Srpaulo iface->wait_channel_update = 1; 1576281806Srpaulo eloop_register_timeout(5, 0, 1577281806Srpaulo channel_list_update_timeout, 1578281806Srpaulo iface, NULL); 1579281806Srpaulo return 0; 1580281806Srpaulo } 1581214501Srpaulo } 1582214501Srpaulo 1583281806Srpaulo return setup_interface2(iface); 1584281806Srpaulo} 1585281806Srpaulo 1586281806Srpaulo 1587281806Srpaulostatic int setup_interface2(struct hostapd_iface *iface) 1588281806Srpaulo{ 1589281806Srpaulo iface->wait_channel_update = 0; 1590281806Srpaulo 1591214501Srpaulo if (hostapd_get_hw_features(iface)) { 1592214501Srpaulo /* Not all drivers support this yet, so continue without hw 1593214501Srpaulo * feature data. */ 1594214501Srpaulo } else { 1595214501Srpaulo int ret = hostapd_select_hw_mode(iface); 1596214501Srpaulo if (ret < 0) { 1597214501Srpaulo wpa_printf(MSG_ERROR, "Could not select hw_mode and " 1598214501Srpaulo "channel. (%d)", ret); 1599281806Srpaulo goto fail; 1600214501Srpaulo } 1601281806Srpaulo if (ret == 1) { 1602281806Srpaulo wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback (ACS)"); 1603281806Srpaulo return 0; 1604281806Srpaulo } 1605214501Srpaulo ret = hostapd_check_ht_capab(iface); 1606214501Srpaulo if (ret < 0) 1607281806Srpaulo goto fail; 1608214501Srpaulo if (ret == 1) { 1609214501Srpaulo wpa_printf(MSG_DEBUG, "Interface initialization will " 1610214501Srpaulo "be completed in a callback"); 1611214501Srpaulo return 0; 1612214501Srpaulo } 1613281806Srpaulo 1614281806Srpaulo if (iface->conf->ieee80211h) 1615281806Srpaulo wpa_printf(MSG_DEBUG, "DFS support is enabled"); 1616214501Srpaulo } 1617214501Srpaulo return hostapd_setup_interface_complete(iface, 0); 1618281806Srpaulo 1619281806Srpaulofail: 1620281806Srpaulo hostapd_set_state(iface, HAPD_IFACE_DISABLED); 1621281806Srpaulo wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); 1622281806Srpaulo if (iface->interfaces && iface->interfaces->terminate_on_error) 1623281806Srpaulo eloop_terminate(); 1624281806Srpaulo return -1; 1625214501Srpaulo} 1626214501Srpaulo 1627214501Srpaulo 1628289549Srpaulo#ifdef CONFIG_FST 1629289549Srpaulo 1630289549Srpaulostatic const u8 * fst_hostapd_get_bssid_cb(void *ctx) 1631289549Srpaulo{ 1632289549Srpaulo struct hostapd_data *hapd = ctx; 1633289549Srpaulo 1634289549Srpaulo return hapd->own_addr; 1635289549Srpaulo} 1636289549Srpaulo 1637289549Srpaulo 1638289549Srpaulostatic void fst_hostapd_get_channel_info_cb(void *ctx, 1639289549Srpaulo enum hostapd_hw_mode *hw_mode, 1640289549Srpaulo u8 *channel) 1641289549Srpaulo{ 1642289549Srpaulo struct hostapd_data *hapd = ctx; 1643289549Srpaulo 1644289549Srpaulo *hw_mode = ieee80211_freq_to_chan(hapd->iface->freq, channel); 1645289549Srpaulo} 1646289549Srpaulo 1647289549Srpaulo 1648289549Srpaulostatic void fst_hostapd_set_ies_cb(void *ctx, const struct wpabuf *fst_ies) 1649289549Srpaulo{ 1650289549Srpaulo struct hostapd_data *hapd = ctx; 1651289549Srpaulo 1652289549Srpaulo if (hapd->iface->fst_ies != fst_ies) { 1653289549Srpaulo hapd->iface->fst_ies = fst_ies; 1654289549Srpaulo if (ieee802_11_set_beacon(hapd)) 1655289549Srpaulo wpa_printf(MSG_WARNING, "FST: Cannot set beacon"); 1656289549Srpaulo } 1657289549Srpaulo} 1658289549Srpaulo 1659289549Srpaulo 1660289549Srpaulostatic int fst_hostapd_send_action_cb(void *ctx, const u8 *da, 1661289549Srpaulo struct wpabuf *buf) 1662289549Srpaulo{ 1663289549Srpaulo struct hostapd_data *hapd = ctx; 1664289549Srpaulo 1665289549Srpaulo return hostapd_drv_send_action(hapd, hapd->iface->freq, 0, da, 1666289549Srpaulo wpabuf_head(buf), wpabuf_len(buf)); 1667289549Srpaulo} 1668289549Srpaulo 1669289549Srpaulo 1670289549Srpaulostatic const struct wpabuf * fst_hostapd_get_mb_ie_cb(void *ctx, const u8 *addr) 1671289549Srpaulo{ 1672289549Srpaulo struct hostapd_data *hapd = ctx; 1673289549Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 1674289549Srpaulo 1675289549Srpaulo return sta ? sta->mb_ies : NULL; 1676289549Srpaulo} 1677289549Srpaulo 1678289549Srpaulo 1679289549Srpaulostatic void fst_hostapd_update_mb_ie_cb(void *ctx, const u8 *addr, 1680289549Srpaulo const u8 *buf, size_t size) 1681289549Srpaulo{ 1682289549Srpaulo struct hostapd_data *hapd = ctx; 1683289549Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 1684289549Srpaulo 1685289549Srpaulo if (sta) { 1686289549Srpaulo struct mb_ies_info info; 1687289549Srpaulo 1688289549Srpaulo if (!mb_ies_info_by_ies(&info, buf, size)) { 1689289549Srpaulo wpabuf_free(sta->mb_ies); 1690289549Srpaulo sta->mb_ies = mb_ies_by_info(&info); 1691289549Srpaulo } 1692289549Srpaulo } 1693289549Srpaulo} 1694289549Srpaulo 1695289549Srpaulo 1696289549Srpaulostatic const u8 * fst_hostapd_get_sta(struct fst_get_peer_ctx **get_ctx, 1697289549Srpaulo Boolean mb_only) 1698289549Srpaulo{ 1699289549Srpaulo struct sta_info *s = (struct sta_info *) *get_ctx; 1700289549Srpaulo 1701289549Srpaulo if (mb_only) { 1702289549Srpaulo for (; s && !s->mb_ies; s = s->next) 1703289549Srpaulo ; 1704289549Srpaulo } 1705289549Srpaulo 1706289549Srpaulo if (s) { 1707289549Srpaulo *get_ctx = (struct fst_get_peer_ctx *) s->next; 1708289549Srpaulo 1709289549Srpaulo return s->addr; 1710289549Srpaulo } 1711289549Srpaulo 1712289549Srpaulo *get_ctx = NULL; 1713289549Srpaulo return NULL; 1714289549Srpaulo} 1715289549Srpaulo 1716289549Srpaulo 1717289549Srpaulostatic const u8 * fst_hostapd_get_peer_first(void *ctx, 1718289549Srpaulo struct fst_get_peer_ctx **get_ctx, 1719289549Srpaulo Boolean mb_only) 1720289549Srpaulo{ 1721289549Srpaulo struct hostapd_data *hapd = ctx; 1722289549Srpaulo 1723289549Srpaulo *get_ctx = (struct fst_get_peer_ctx *) hapd->sta_list; 1724289549Srpaulo 1725289549Srpaulo return fst_hostapd_get_sta(get_ctx, mb_only); 1726289549Srpaulo} 1727289549Srpaulo 1728289549Srpaulo 1729289549Srpaulostatic const u8 * fst_hostapd_get_peer_next(void *ctx, 1730289549Srpaulo struct fst_get_peer_ctx **get_ctx, 1731289549Srpaulo Boolean mb_only) 1732289549Srpaulo{ 1733289549Srpaulo return fst_hostapd_get_sta(get_ctx, mb_only); 1734289549Srpaulo} 1735289549Srpaulo 1736289549Srpaulo 1737289549Srpaulovoid fst_hostapd_fill_iface_obj(struct hostapd_data *hapd, 1738289549Srpaulo struct fst_wpa_obj *iface_obj) 1739289549Srpaulo{ 1740289549Srpaulo iface_obj->ctx = hapd; 1741289549Srpaulo iface_obj->get_bssid = fst_hostapd_get_bssid_cb; 1742289549Srpaulo iface_obj->get_channel_info = fst_hostapd_get_channel_info_cb; 1743289549Srpaulo iface_obj->set_ies = fst_hostapd_set_ies_cb; 1744289549Srpaulo iface_obj->send_action = fst_hostapd_send_action_cb; 1745289549Srpaulo iface_obj->get_mb_ie = fst_hostapd_get_mb_ie_cb; 1746289549Srpaulo iface_obj->update_mb_ie = fst_hostapd_update_mb_ie_cb; 1747289549Srpaulo iface_obj->get_peer_first = fst_hostapd_get_peer_first; 1748289549Srpaulo iface_obj->get_peer_next = fst_hostapd_get_peer_next; 1749289549Srpaulo} 1750289549Srpaulo 1751289549Srpaulo#endif /* CONFIG_FST */ 1752289549Srpaulo 1753346981Scy#ifdef CONFIG_OWE 1754289549Srpaulo 1755346981Scystatic int hostapd_owe_iface_iter(struct hostapd_iface *iface, void *ctx) 1756214501Srpaulo{ 1757346981Scy struct hostapd_data *hapd = ctx; 1758346981Scy size_t i; 1759337817Scy 1760346981Scy for (i = 0; i < iface->num_bss; i++) { 1761346981Scy struct hostapd_data *bss = iface->bss[i]; 1762337817Scy 1763346981Scy if (os_strcmp(hapd->conf->owe_transition_ifname, 1764346981Scy bss->conf->iface) != 0) 1765346981Scy continue; 1766337817Scy 1767346981Scy wpa_printf(MSG_DEBUG, 1768346981Scy "OWE: ifname=%s found transition mode ifname=%s BSSID " 1769346981Scy MACSTR " SSID %s", 1770346981Scy hapd->conf->iface, bss->conf->iface, 1771346981Scy MAC2STR(bss->own_addr), 1772346981Scy wpa_ssid_txt(bss->conf->ssid.ssid, 1773346981Scy bss->conf->ssid.ssid_len)); 1774346981Scy if (!bss->conf->ssid.ssid_set || !bss->conf->ssid.ssid_len || 1775346981Scy is_zero_ether_addr(bss->own_addr)) 1776346981Scy continue; 1777337817Scy 1778346981Scy os_memcpy(hapd->conf->owe_transition_bssid, bss->own_addr, 1779346981Scy ETH_ALEN); 1780346981Scy os_memcpy(hapd->conf->owe_transition_ssid, 1781346981Scy bss->conf->ssid.ssid, bss->conf->ssid.ssid_len); 1782346981Scy hapd->conf->owe_transition_ssid_len = bss->conf->ssid.ssid_len; 1783346981Scy wpa_printf(MSG_DEBUG, 1784346981Scy "OWE: Copied transition mode information"); 1785346981Scy return 1; 1786346981Scy } 1787337817Scy 1788346981Scy return 0; 1789346981Scy} 1790337817Scy 1791337817Scy 1792346981Scyint hostapd_owe_trans_get_info(struct hostapd_data *hapd) 1793346981Scy{ 1794346981Scy if (hapd->conf->owe_transition_ssid_len > 0 && 1795346981Scy !is_zero_ether_addr(hapd->conf->owe_transition_bssid)) 1796346981Scy return 0; 1797337817Scy 1798346981Scy /* Find transition mode SSID/BSSID information from a BSS operated by 1799346981Scy * this hostapd instance. */ 1800346981Scy if (!hapd->iface->interfaces || 1801346981Scy !hapd->iface->interfaces->for_each_interface) 1802346981Scy return hostapd_owe_iface_iter(hapd->iface, hapd); 1803346981Scy else 1804346981Scy return hapd->iface->interfaces->for_each_interface( 1805346981Scy hapd->iface->interfaces, hostapd_owe_iface_iter, hapd); 1806346981Scy} 1807337817Scy 1808337817Scy 1809346981Scystatic int hostapd_owe_iface_iter2(struct hostapd_iface *iface, void *ctx) 1810346981Scy{ 1811346981Scy size_t i; 1812337817Scy 1813346981Scy for (i = 0; i < iface->num_bss; i++) { 1814346981Scy struct hostapd_data *bss = iface->bss[i]; 1815346981Scy int res; 1816337817Scy 1817346981Scy if (!bss->conf->owe_transition_ifname[0]) 1818346981Scy continue; 1819346981Scy res = hostapd_owe_trans_get_info(bss); 1820346981Scy if (res == 0) 1821346981Scy continue; 1822346981Scy wpa_printf(MSG_DEBUG, 1823346981Scy "OWE: Matching transition mode interface enabled - update beacon data for %s", 1824346981Scy bss->conf->iface); 1825346981Scy ieee802_11_set_beacon(bss); 1826337817Scy } 1827337817Scy 1828346981Scy return 0; 1829346981Scy} 1830337817Scy 1831346981Scy#endif /* CONFIG_OWE */ 1832337817Scy 1833337817Scy 1834346981Scystatic void hostapd_owe_update_trans(struct hostapd_iface *iface) 1835346981Scy{ 1836346981Scy#ifdef CONFIG_OWE 1837346981Scy /* Check whether the enabled BSS can complete OWE transition mode 1838346981Scy * configuration for any pending interface. */ 1839346981Scy if (!iface->interfaces || 1840346981Scy !iface->interfaces->for_each_interface) 1841346981Scy hostapd_owe_iface_iter2(iface, NULL); 1842346981Scy else 1843346981Scy iface->interfaces->for_each_interface( 1844346981Scy iface->interfaces, hostapd_owe_iface_iter2, NULL); 1845346981Scy#endif /* CONFIG_OWE */ 1846346981Scy} 1847337817Scy 1848337817Scy 1849346981Scystatic void hostapd_interface_setup_failure_handler(void *eloop_ctx, 1850346981Scy void *timeout_ctx) 1851346981Scy{ 1852346981Scy struct hostapd_iface *iface = eloop_ctx; 1853346981Scy struct hostapd_data *hapd; 1854346981Scy 1855346981Scy if (iface->num_bss < 1 || !iface->bss || !iface->bss[0]) 1856346981Scy return; 1857346981Scy hapd = iface->bss[0]; 1858346981Scy if (hapd->setup_complete_cb) 1859346981Scy hapd->setup_complete_cb(hapd->setup_complete_cb_ctx); 1860337817Scy} 1861337817Scy 1862337817Scy 1863337817Scystatic int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface, 1864337817Scy int err) 1865337817Scy{ 1866214501Srpaulo struct hostapd_data *hapd = iface->bss[0]; 1867214501Srpaulo size_t j; 1868214501Srpaulo u8 *prev_addr; 1869281806Srpaulo int delay_apply_cfg = 0; 1870281806Srpaulo int res_dfs_offload = 0; 1871214501Srpaulo 1872281806Srpaulo if (err) 1873281806Srpaulo goto fail; 1874214501Srpaulo 1875214501Srpaulo wpa_printf(MSG_DEBUG, "Completing interface initialization"); 1876281806Srpaulo if (iface->conf->channel) { 1877281806Srpaulo#ifdef NEED_AP_MLME 1878281806Srpaulo int res; 1879281806Srpaulo#endif /* NEED_AP_MLME */ 1880281806Srpaulo 1881281806Srpaulo iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel); 1882214501Srpaulo wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d " 1883214501Srpaulo "Frequency: %d MHz", 1884281806Srpaulo hostapd_hw_mode_txt(iface->conf->hw_mode), 1885281806Srpaulo iface->conf->channel, iface->freq); 1886214501Srpaulo 1887281806Srpaulo#ifdef NEED_AP_MLME 1888281806Srpaulo /* Handle DFS only if it is not offloaded to the driver */ 1889281806Srpaulo if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) { 1890281806Srpaulo /* Check DFS */ 1891281806Srpaulo res = hostapd_handle_dfs(iface); 1892281806Srpaulo if (res <= 0) { 1893281806Srpaulo if (res < 0) 1894281806Srpaulo goto fail; 1895281806Srpaulo return res; 1896281806Srpaulo } 1897281806Srpaulo } else { 1898281806Srpaulo /* If DFS is offloaded to the driver */ 1899281806Srpaulo res_dfs_offload = hostapd_handle_dfs_offload(iface); 1900281806Srpaulo if (res_dfs_offload <= 0) { 1901281806Srpaulo if (res_dfs_offload < 0) 1902281806Srpaulo goto fail; 1903281806Srpaulo } else { 1904281806Srpaulo wpa_printf(MSG_DEBUG, 1905281806Srpaulo "Proceed with AP/channel setup"); 1906281806Srpaulo /* 1907281806Srpaulo * If this is a DFS channel, move to completing 1908281806Srpaulo * AP setup. 1909281806Srpaulo */ 1910281806Srpaulo if (res_dfs_offload == 1) 1911281806Srpaulo goto dfs_offload; 1912281806Srpaulo /* Otherwise fall through. */ 1913281806Srpaulo } 1914281806Srpaulo } 1915281806Srpaulo#endif /* NEED_AP_MLME */ 1916281806Srpaulo 1917281806Srpaulo#ifdef CONFIG_MESH 1918281806Srpaulo if (iface->mconf != NULL) { 1919281806Srpaulo wpa_printf(MSG_DEBUG, 1920281806Srpaulo "%s: Mesh configuration will be applied while joining the mesh network", 1921281806Srpaulo iface->bss[0]->conf->iface); 1922281806Srpaulo delay_apply_cfg = 1; 1923281806Srpaulo } 1924281806Srpaulo#endif /* CONFIG_MESH */ 1925281806Srpaulo 1926281806Srpaulo if (!delay_apply_cfg && 1927281806Srpaulo hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq, 1928214501Srpaulo hapd->iconf->channel, 1929214501Srpaulo hapd->iconf->ieee80211n, 1930281806Srpaulo hapd->iconf->ieee80211ac, 1931351611Scy hapd->iconf->ieee80211ax, 1932281806Srpaulo hapd->iconf->secondary_channel, 1933351611Scy hostapd_get_oper_chwidth(hapd->iconf), 1934351611Scy hostapd_get_oper_centr_freq_seg0_idx( 1935351611Scy hapd->iconf), 1936351611Scy hostapd_get_oper_centr_freq_seg1_idx( 1937351611Scy hapd->iconf))) { 1938214501Srpaulo wpa_printf(MSG_ERROR, "Could not set channel for " 1939214501Srpaulo "kernel driver"); 1940281806Srpaulo goto fail; 1941214501Srpaulo } 1942214501Srpaulo } 1943214501Srpaulo 1944252726Srpaulo if (iface->current_mode) { 1945252726Srpaulo if (hostapd_prepare_rates(iface, iface->current_mode)) { 1946252726Srpaulo wpa_printf(MSG_ERROR, "Failed to prepare rates " 1947252726Srpaulo "table."); 1948252726Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 1949252726Srpaulo HOSTAPD_LEVEL_WARNING, 1950252726Srpaulo "Failed to prepare rates table."); 1951281806Srpaulo goto fail; 1952252726Srpaulo } 1953252726Srpaulo } 1954252726Srpaulo 1955346981Scy if (hapd->iconf->rts_threshold >= -1 && 1956346981Scy hostapd_set_rts(hapd, hapd->iconf->rts_threshold) && 1957346981Scy hapd->iconf->rts_threshold >= -1) { 1958214501Srpaulo wpa_printf(MSG_ERROR, "Could not set RTS threshold for " 1959214501Srpaulo "kernel driver"); 1960281806Srpaulo goto fail; 1961214501Srpaulo } 1962214501Srpaulo 1963346981Scy if (hapd->iconf->fragm_threshold >= -1 && 1964346981Scy hostapd_set_frag(hapd, hapd->iconf->fragm_threshold) && 1965346981Scy hapd->iconf->fragm_threshold != -1) { 1966214501Srpaulo wpa_printf(MSG_ERROR, "Could not set fragmentation threshold " 1967214501Srpaulo "for kernel driver"); 1968281806Srpaulo goto fail; 1969214501Srpaulo } 1970214501Srpaulo 1971214501Srpaulo prev_addr = hapd->own_addr; 1972214501Srpaulo 1973214501Srpaulo for (j = 0; j < iface->num_bss; j++) { 1974214501Srpaulo hapd = iface->bss[j]; 1975214501Srpaulo if (j) 1976214501Srpaulo os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN); 1977281806Srpaulo if (hostapd_setup_bss(hapd, j == 0)) { 1978346981Scy for (;;) { 1979281806Srpaulo hapd = iface->bss[j]; 1980281806Srpaulo hostapd_bss_deinit_no_free(hapd); 1981281806Srpaulo hostapd_free_hapd_data(hapd); 1982346981Scy if (j == 0) 1983346981Scy break; 1984346981Scy j--; 1985346981Scy } 1986281806Srpaulo goto fail; 1987281806Srpaulo } 1988337817Scy if (is_zero_ether_addr(hapd->conf->bssid)) 1989214501Srpaulo prev_addr = hapd->own_addr; 1990214501Srpaulo } 1991281806Srpaulo hapd = iface->bss[0]; 1992214501Srpaulo 1993214501Srpaulo hostapd_tx_queue_params(iface); 1994214501Srpaulo 1995214501Srpaulo ap_list_init(iface); 1996214501Srpaulo 1997281806Srpaulo hostapd_set_acl(hapd); 1998281806Srpaulo 1999214501Srpaulo if (hostapd_driver_commit(hapd) < 0) { 2000214501Srpaulo wpa_printf(MSG_ERROR, "%s: Failed to commit driver " 2001214501Srpaulo "configuration", __func__); 2002281806Srpaulo goto fail; 2003214501Srpaulo } 2004214501Srpaulo 2005252726Srpaulo /* 2006252726Srpaulo * WPS UPnP module can be initialized only when the "upnp_iface" is up. 2007252726Srpaulo * If "interface" and "upnp_iface" are the same (e.g., non-bridge 2008252726Srpaulo * mode), the interface is up only after driver_commit, so initialize 2009252726Srpaulo * WPS after driver_commit. 2010252726Srpaulo */ 2011252726Srpaulo for (j = 0; j < iface->num_bss; j++) { 2012252726Srpaulo if (hostapd_init_wps_complete(iface->bss[j])) 2013281806Srpaulo goto fail; 2014252726Srpaulo } 2015252726Srpaulo 2016281806Srpaulo if ((iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) && 2017281806Srpaulo !res_dfs_offload) { 2018281806Srpaulo /* 2019281806Srpaulo * If freq is DFS, and DFS is offloaded to the driver, then wait 2020281806Srpaulo * for CAC to complete. 2021281806Srpaulo */ 2022281806Srpaulo wpa_printf(MSG_DEBUG, "%s: Wait for CAC to complete", __func__); 2023281806Srpaulo return res_dfs_offload; 2024281806Srpaulo } 2025281806Srpaulo 2026281806Srpaulo#ifdef NEED_AP_MLME 2027281806Srpaulodfs_offload: 2028281806Srpaulo#endif /* NEED_AP_MLME */ 2029289549Srpaulo 2030289549Srpaulo#ifdef CONFIG_FST 2031289549Srpaulo if (hapd->iconf->fst_cfg.group_id[0]) { 2032289549Srpaulo struct fst_wpa_obj iface_obj; 2033289549Srpaulo 2034289549Srpaulo fst_hostapd_fill_iface_obj(hapd, &iface_obj); 2035289549Srpaulo iface->fst = fst_attach(hapd->conf->iface, hapd->own_addr, 2036289549Srpaulo &iface_obj, &hapd->iconf->fst_cfg); 2037289549Srpaulo if (!iface->fst) { 2038289549Srpaulo wpa_printf(MSG_ERROR, "Could not attach to FST %s", 2039289549Srpaulo hapd->iconf->fst_cfg.group_id); 2040289549Srpaulo goto fail; 2041289549Srpaulo } 2042289549Srpaulo } 2043289549Srpaulo#endif /* CONFIG_FST */ 2044289549Srpaulo 2045281806Srpaulo hostapd_set_state(iface, HAPD_IFACE_ENABLED); 2046346981Scy hostapd_owe_update_trans(iface); 2047351611Scy airtime_policy_update_init(iface); 2048281806Srpaulo wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED); 2049252726Srpaulo if (hapd->setup_complete_cb) 2050252726Srpaulo hapd->setup_complete_cb(hapd->setup_complete_cb_ctx); 2051252726Srpaulo 2052214501Srpaulo wpa_printf(MSG_DEBUG, "%s: Setup of interface done.", 2053214501Srpaulo iface->bss[0]->conf->iface); 2054281806Srpaulo if (iface->interfaces && iface->interfaces->terminate_on_error > 0) 2055281806Srpaulo iface->interfaces->terminate_on_error--; 2056214501Srpaulo 2057337817Scy for (j = 0; j < iface->num_bss; j++) 2058346981Scy hostapd_neighbor_set_own_report(iface->bss[j]); 2059337817Scy 2060214501Srpaulo return 0; 2061281806Srpaulo 2062281806Srpaulofail: 2063281806Srpaulo wpa_printf(MSG_ERROR, "Interface initialization failed"); 2064281806Srpaulo hostapd_set_state(iface, HAPD_IFACE_DISABLED); 2065281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); 2066289549Srpaulo#ifdef CONFIG_FST 2067289549Srpaulo if (iface->fst) { 2068289549Srpaulo fst_detach(iface->fst); 2069289549Srpaulo iface->fst = NULL; 2070289549Srpaulo } 2071289549Srpaulo#endif /* CONFIG_FST */ 2072346981Scy 2073346981Scy if (iface->interfaces && iface->interfaces->terminate_on_error) { 2074281806Srpaulo eloop_terminate(); 2075346981Scy } else if (hapd->setup_complete_cb) { 2076346981Scy /* 2077346981Scy * Calling hapd->setup_complete_cb directly may cause iface 2078346981Scy * deinitialization which may be accessed later by the caller. 2079346981Scy */ 2080346981Scy eloop_register_timeout(0, 0, 2081346981Scy hostapd_interface_setup_failure_handler, 2082346981Scy iface, NULL); 2083346981Scy } 2084346981Scy 2085281806Srpaulo return -1; 2086214501Srpaulo} 2087214501Srpaulo 2088214501Srpaulo 2089214501Srpaulo/** 2090337817Scy * hostapd_setup_interface_complete - Complete interface setup 2091337817Scy * 2092337817Scy * This function is called when previous steps in the interface setup has been 2093337817Scy * completed. This can also start operations, e.g., DFS, that will require 2094337817Scy * additional processing before interface is ready to be enabled. Such 2095337817Scy * operations will call this function from eloop callbacks when finished. 2096337817Scy */ 2097337817Scyint hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) 2098337817Scy{ 2099337817Scy struct hapd_interfaces *interfaces = iface->interfaces; 2100337817Scy struct hostapd_data *hapd = iface->bss[0]; 2101337817Scy unsigned int i; 2102337817Scy int not_ready_in_sync_ifaces = 0; 2103337817Scy 2104337817Scy if (!iface->need_to_start_in_sync) 2105337817Scy return hostapd_setup_interface_complete_sync(iface, err); 2106337817Scy 2107337817Scy if (err) { 2108337817Scy wpa_printf(MSG_ERROR, "Interface initialization failed"); 2109337817Scy hostapd_set_state(iface, HAPD_IFACE_DISABLED); 2110337817Scy iface->need_to_start_in_sync = 0; 2111337817Scy wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); 2112337817Scy if (interfaces && interfaces->terminate_on_error) 2113337817Scy eloop_terminate(); 2114337817Scy return -1; 2115337817Scy } 2116337817Scy 2117337817Scy if (iface->ready_to_start_in_sync) { 2118337817Scy /* Already in ready and waiting. should never happpen */ 2119337817Scy return 0; 2120337817Scy } 2121337817Scy 2122337817Scy for (i = 0; i < interfaces->count; i++) { 2123337817Scy if (interfaces->iface[i]->need_to_start_in_sync && 2124337817Scy !interfaces->iface[i]->ready_to_start_in_sync) 2125337817Scy not_ready_in_sync_ifaces++; 2126337817Scy } 2127337817Scy 2128337817Scy /* 2129337817Scy * Check if this is the last interface, if yes then start all the other 2130337817Scy * waiting interfaces. If not, add this interface to the waiting list. 2131337817Scy */ 2132337817Scy if (not_ready_in_sync_ifaces > 1 && iface->state == HAPD_IFACE_DFS) { 2133337817Scy /* 2134337817Scy * If this interface went through CAC, do not synchronize, just 2135337817Scy * start immediately. 2136337817Scy */ 2137337817Scy iface->need_to_start_in_sync = 0; 2138337817Scy wpa_printf(MSG_INFO, 2139337817Scy "%s: Finished CAC - bypass sync and start interface", 2140337817Scy iface->bss[0]->conf->iface); 2141337817Scy return hostapd_setup_interface_complete_sync(iface, err); 2142337817Scy } 2143337817Scy 2144337817Scy if (not_ready_in_sync_ifaces > 1) { 2145337817Scy /* need to wait as there are other interfaces still coming up */ 2146337817Scy iface->ready_to_start_in_sync = 1; 2147337817Scy wpa_printf(MSG_INFO, 2148337817Scy "%s: Interface waiting to sync with other interfaces", 2149337817Scy iface->bss[0]->conf->iface); 2150337817Scy return 0; 2151337817Scy } 2152337817Scy 2153337817Scy wpa_printf(MSG_INFO, 2154337817Scy "%s: Last interface to sync - starting all interfaces", 2155337817Scy iface->bss[0]->conf->iface); 2156337817Scy iface->need_to_start_in_sync = 0; 2157337817Scy hostapd_setup_interface_complete_sync(iface, err); 2158337817Scy for (i = 0; i < interfaces->count; i++) { 2159337817Scy if (interfaces->iface[i]->need_to_start_in_sync && 2160337817Scy interfaces->iface[i]->ready_to_start_in_sync) { 2161337817Scy hostapd_setup_interface_complete_sync( 2162337817Scy interfaces->iface[i], 0); 2163337817Scy /* Only once the interfaces are sync started */ 2164337817Scy interfaces->iface[i]->need_to_start_in_sync = 0; 2165337817Scy } 2166337817Scy } 2167337817Scy 2168337817Scy return 0; 2169337817Scy} 2170337817Scy 2171337817Scy 2172337817Scy/** 2173214501Srpaulo * hostapd_setup_interface - Setup of an interface 2174214501Srpaulo * @iface: Pointer to interface data. 2175214501Srpaulo * Returns: 0 on success, -1 on failure 2176214501Srpaulo * 2177214501Srpaulo * Initializes the driver interface, validates the configuration, 2178214501Srpaulo * and sets driver parameters based on the configuration. 2179214501Srpaulo * Flushes old stations, sets the channel, encryption, 2180214501Srpaulo * beacons, and WDS links based on the configuration. 2181281806Srpaulo * 2182281806Srpaulo * If interface setup requires more time, e.g., to perform HT co-ex scans, ACS, 2183281806Srpaulo * or DFS operations, this function returns 0 before such operations have been 2184281806Srpaulo * completed. The pending operations are registered into eloop and will be 2185281806Srpaulo * completed from eloop callbacks. Those callbacks end up calling 2186281806Srpaulo * hostapd_setup_interface_complete() once setup has been completed. 2187214501Srpaulo */ 2188214501Srpauloint hostapd_setup_interface(struct hostapd_iface *iface) 2189214501Srpaulo{ 2190214501Srpaulo int ret; 2191214501Srpaulo 2192214501Srpaulo ret = setup_interface(iface); 2193214501Srpaulo if (ret) { 2194214501Srpaulo wpa_printf(MSG_ERROR, "%s: Unable to setup interface.", 2195214501Srpaulo iface->bss[0]->conf->iface); 2196214501Srpaulo return -1; 2197214501Srpaulo } 2198214501Srpaulo 2199214501Srpaulo return 0; 2200214501Srpaulo} 2201214501Srpaulo 2202214501Srpaulo 2203214501Srpaulo/** 2204214501Srpaulo * hostapd_alloc_bss_data - Allocate and initialize per-BSS data 2205214501Srpaulo * @hapd_iface: Pointer to interface data 2206214501Srpaulo * @conf: Pointer to per-interface configuration 2207214501Srpaulo * @bss: Pointer to per-BSS configuration for this BSS 2208214501Srpaulo * Returns: Pointer to allocated BSS data 2209214501Srpaulo * 2210214501Srpaulo * This function is used to allocate per-BSS data structure. This data will be 2211214501Srpaulo * freed after hostapd_cleanup() is called for it during interface 2212214501Srpaulo * deinitialization. 2213214501Srpaulo */ 2214214501Srpaulostruct hostapd_data * 2215214501Srpaulohostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, 2216214501Srpaulo struct hostapd_config *conf, 2217214501Srpaulo struct hostapd_bss_config *bss) 2218214501Srpaulo{ 2219214501Srpaulo struct hostapd_data *hapd; 2220214501Srpaulo 2221214501Srpaulo hapd = os_zalloc(sizeof(*hapd)); 2222214501Srpaulo if (hapd == NULL) 2223214501Srpaulo return NULL; 2224214501Srpaulo 2225214501Srpaulo hapd->new_assoc_sta_cb = hostapd_new_assoc_sta; 2226214501Srpaulo hapd->iconf = conf; 2227214501Srpaulo hapd->conf = bss; 2228214501Srpaulo hapd->iface = hapd_iface; 2229346981Scy if (conf) 2230346981Scy hapd->driver = conf->driver; 2231252726Srpaulo hapd->ctrl_sock = -1; 2232337817Scy dl_list_init(&hapd->ctrl_dst); 2233337817Scy dl_list_init(&hapd->nr_db); 2234346981Scy hapd->dhcp_sock = -1; 2235346981Scy#ifdef CONFIG_IEEE80211R_AP 2236346981Scy dl_list_init(&hapd->l2_queue); 2237346981Scy dl_list_init(&hapd->l2_oui_queue); 2238346981Scy#endif /* CONFIG_IEEE80211R_AP */ 2239346981Scy#ifdef CONFIG_SAE 2240346981Scy dl_list_init(&hapd->sae_commit_queue); 2241346981Scy#endif /* CONFIG_SAE */ 2242214501Srpaulo 2243214501Srpaulo return hapd; 2244214501Srpaulo} 2245214501Srpaulo 2246214501Srpaulo 2247281806Srpaulostatic void hostapd_bss_deinit(struct hostapd_data *hapd) 2248281806Srpaulo{ 2249337817Scy if (!hapd) 2250337817Scy return; 2251281806Srpaulo wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__, 2252346981Scy hapd->conf ? hapd->conf->iface : "N/A"); 2253281806Srpaulo hostapd_bss_deinit_no_free(hapd); 2254281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); 2255351611Scy#ifdef CONFIG_SQLITE 2256351611Scy if (hapd->rad_attr_db) { 2257351611Scy sqlite3_close(hapd->rad_attr_db); 2258351611Scy hapd->rad_attr_db = NULL; 2259351611Scy } 2260351611Scy#endif /* CONFIG_SQLITE */ 2261281806Srpaulo hostapd_cleanup(hapd); 2262281806Srpaulo} 2263281806Srpaulo 2264281806Srpaulo 2265214501Srpaulovoid hostapd_interface_deinit(struct hostapd_iface *iface) 2266214501Srpaulo{ 2267281806Srpaulo int j; 2268214501Srpaulo 2269281806Srpaulo wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); 2270214501Srpaulo if (iface == NULL) 2271214501Srpaulo return; 2272214501Srpaulo 2273281806Srpaulo hostapd_set_state(iface, HAPD_IFACE_DISABLED); 2274281806Srpaulo 2275281806Srpaulo eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); 2276281806Srpaulo iface->wait_channel_update = 0; 2277281806Srpaulo 2278289549Srpaulo#ifdef CONFIG_FST 2279289549Srpaulo if (iface->fst) { 2280289549Srpaulo fst_detach(iface->fst); 2281289549Srpaulo iface->fst = NULL; 2282289549Srpaulo } 2283289549Srpaulo#endif /* CONFIG_FST */ 2284289549Srpaulo 2285346981Scy for (j = (int) iface->num_bss - 1; j >= 0; j--) { 2286337817Scy if (!iface->bss) 2287337817Scy break; 2288281806Srpaulo hostapd_bss_deinit(iface->bss[j]); 2289337817Scy } 2290346981Scy 2291346981Scy#ifdef CONFIG_IEEE80211N 2292346981Scy#ifdef NEED_AP_MLME 2293346981Scy hostapd_stop_setup_timers(iface); 2294346981Scy eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL); 2295346981Scy#endif /* NEED_AP_MLME */ 2296346981Scy#endif /* CONFIG_IEEE80211N */ 2297214501Srpaulo} 2298214501Srpaulo 2299214501Srpaulo 2300214501Srpaulovoid hostapd_interface_free(struct hostapd_iface *iface) 2301214501Srpaulo{ 2302214501Srpaulo size_t j; 2303281806Srpaulo wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); 2304281806Srpaulo for (j = 0; j < iface->num_bss; j++) { 2305337817Scy if (!iface->bss) 2306337817Scy break; 2307281806Srpaulo wpa_printf(MSG_DEBUG, "%s: free hapd %p", 2308281806Srpaulo __func__, iface->bss[j]); 2309214501Srpaulo os_free(iface->bss[j]); 2310281806Srpaulo } 2311214501Srpaulo hostapd_cleanup_iface(iface); 2312214501Srpaulo} 2313214501Srpaulo 2314214501Srpaulo 2315337817Scystruct hostapd_iface * hostapd_alloc_iface(void) 2316337817Scy{ 2317337817Scy struct hostapd_iface *hapd_iface; 2318337817Scy 2319337817Scy hapd_iface = os_zalloc(sizeof(*hapd_iface)); 2320337817Scy if (!hapd_iface) 2321337817Scy return NULL; 2322337817Scy 2323337817Scy dl_list_init(&hapd_iface->sta_seen); 2324337817Scy 2325337817Scy return hapd_iface; 2326337817Scy} 2327337817Scy 2328337817Scy 2329281806Srpaulo/** 2330281806Srpaulo * hostapd_init - Allocate and initialize per-interface data 2331281806Srpaulo * @config_file: Path to the configuration file 2332281806Srpaulo * Returns: Pointer to the allocated interface data or %NULL on failure 2333281806Srpaulo * 2334281806Srpaulo * This function is used to allocate main data structures for per-interface 2335281806Srpaulo * data. The allocated data buffer will be freed by calling 2336281806Srpaulo * hostapd_cleanup_iface(). 2337281806Srpaulo */ 2338281806Srpaulostruct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces, 2339281806Srpaulo const char *config_file) 2340281806Srpaulo{ 2341281806Srpaulo struct hostapd_iface *hapd_iface = NULL; 2342281806Srpaulo struct hostapd_config *conf = NULL; 2343281806Srpaulo struct hostapd_data *hapd; 2344281806Srpaulo size_t i; 2345252726Srpaulo 2346337817Scy hapd_iface = hostapd_alloc_iface(); 2347281806Srpaulo if (hapd_iface == NULL) 2348281806Srpaulo goto fail; 2349281806Srpaulo 2350281806Srpaulo hapd_iface->config_fname = os_strdup(config_file); 2351281806Srpaulo if (hapd_iface->config_fname == NULL) 2352281806Srpaulo goto fail; 2353281806Srpaulo 2354281806Srpaulo conf = interfaces->config_read_cb(hapd_iface->config_fname); 2355281806Srpaulo if (conf == NULL) 2356281806Srpaulo goto fail; 2357281806Srpaulo hapd_iface->conf = conf; 2358281806Srpaulo 2359281806Srpaulo hapd_iface->num_bss = conf->num_bss; 2360281806Srpaulo hapd_iface->bss = os_calloc(conf->num_bss, 2361281806Srpaulo sizeof(struct hostapd_data *)); 2362281806Srpaulo if (hapd_iface->bss == NULL) 2363281806Srpaulo goto fail; 2364281806Srpaulo 2365281806Srpaulo for (i = 0; i < conf->num_bss; i++) { 2366281806Srpaulo hapd = hapd_iface->bss[i] = 2367281806Srpaulo hostapd_alloc_bss_data(hapd_iface, conf, 2368281806Srpaulo conf->bss[i]); 2369281806Srpaulo if (hapd == NULL) 2370281806Srpaulo goto fail; 2371281806Srpaulo hapd->msg_ctx = hapd; 2372281806Srpaulo } 2373281806Srpaulo 2374281806Srpaulo return hapd_iface; 2375281806Srpaulo 2376281806Srpaulofail: 2377281806Srpaulo wpa_printf(MSG_ERROR, "Failed to set up interface with %s", 2378281806Srpaulo config_file); 2379281806Srpaulo if (conf) 2380281806Srpaulo hostapd_config_free(conf); 2381281806Srpaulo if (hapd_iface) { 2382281806Srpaulo os_free(hapd_iface->config_fname); 2383281806Srpaulo os_free(hapd_iface->bss); 2384281806Srpaulo wpa_printf(MSG_DEBUG, "%s: free iface %p", 2385281806Srpaulo __func__, hapd_iface); 2386281806Srpaulo os_free(hapd_iface); 2387281806Srpaulo } 2388281806Srpaulo return NULL; 2389281806Srpaulo} 2390281806Srpaulo 2391281806Srpaulo 2392281806Srpaulostatic int ifname_in_use(struct hapd_interfaces *interfaces, const char *ifname) 2393281806Srpaulo{ 2394281806Srpaulo size_t i, j; 2395281806Srpaulo 2396281806Srpaulo for (i = 0; i < interfaces->count; i++) { 2397281806Srpaulo struct hostapd_iface *iface = interfaces->iface[i]; 2398281806Srpaulo for (j = 0; j < iface->num_bss; j++) { 2399281806Srpaulo struct hostapd_data *hapd = iface->bss[j]; 2400281806Srpaulo if (os_strcmp(ifname, hapd->conf->iface) == 0) 2401281806Srpaulo return 1; 2402281806Srpaulo } 2403281806Srpaulo } 2404281806Srpaulo 2405281806Srpaulo return 0; 2406281806Srpaulo} 2407281806Srpaulo 2408281806Srpaulo 2409281806Srpaulo/** 2410281806Srpaulo * hostapd_interface_init_bss - Read configuration file and init BSS data 2411281806Srpaulo * 2412281806Srpaulo * This function is used to parse configuration file for a BSS. This BSS is 2413281806Srpaulo * added to an existing interface sharing the same radio (if any) or a new 2414281806Srpaulo * interface is created if this is the first interface on a radio. This 2415281806Srpaulo * allocate memory for the BSS. No actual driver operations are started. 2416281806Srpaulo * 2417281806Srpaulo * This is similar to hostapd_interface_init(), but for a case where the 2418281806Srpaulo * configuration is used to add a single BSS instead of all BSSes for a radio. 2419281806Srpaulo */ 2420281806Srpaulostruct hostapd_iface * 2421281806Srpaulohostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy, 2422281806Srpaulo const char *config_fname, int debug) 2423281806Srpaulo{ 2424281806Srpaulo struct hostapd_iface *new_iface = NULL, *iface = NULL; 2425281806Srpaulo struct hostapd_data *hapd; 2426281806Srpaulo int k; 2427281806Srpaulo size_t i, bss_idx; 2428281806Srpaulo 2429281806Srpaulo if (!phy || !*phy) 2430281806Srpaulo return NULL; 2431281806Srpaulo 2432281806Srpaulo for (i = 0; i < interfaces->count; i++) { 2433281806Srpaulo if (os_strcmp(interfaces->iface[i]->phy, phy) == 0) { 2434281806Srpaulo iface = interfaces->iface[i]; 2435281806Srpaulo break; 2436281806Srpaulo } 2437281806Srpaulo } 2438281806Srpaulo 2439281806Srpaulo wpa_printf(MSG_INFO, "Configuration file: %s (phy %s)%s", 2440281806Srpaulo config_fname, phy, iface ? "" : " --> new PHY"); 2441281806Srpaulo if (iface) { 2442281806Srpaulo struct hostapd_config *conf; 2443281806Srpaulo struct hostapd_bss_config **tmp_conf; 2444281806Srpaulo struct hostapd_data **tmp_bss; 2445281806Srpaulo struct hostapd_bss_config *bss; 2446281806Srpaulo const char *ifname; 2447281806Srpaulo 2448281806Srpaulo /* Add new BSS to existing iface */ 2449281806Srpaulo conf = interfaces->config_read_cb(config_fname); 2450281806Srpaulo if (conf == NULL) 2451281806Srpaulo return NULL; 2452281806Srpaulo if (conf->num_bss > 1) { 2453281806Srpaulo wpa_printf(MSG_ERROR, "Multiple BSSes specified in BSS-config"); 2454281806Srpaulo hostapd_config_free(conf); 2455281806Srpaulo return NULL; 2456281806Srpaulo } 2457281806Srpaulo 2458281806Srpaulo ifname = conf->bss[0]->iface; 2459281806Srpaulo if (ifname[0] != '\0' && ifname_in_use(interfaces, ifname)) { 2460281806Srpaulo wpa_printf(MSG_ERROR, 2461281806Srpaulo "Interface name %s already in use", ifname); 2462281806Srpaulo hostapd_config_free(conf); 2463281806Srpaulo return NULL; 2464281806Srpaulo } 2465281806Srpaulo 2466281806Srpaulo tmp_conf = os_realloc_array( 2467281806Srpaulo iface->conf->bss, iface->conf->num_bss + 1, 2468281806Srpaulo sizeof(struct hostapd_bss_config *)); 2469281806Srpaulo tmp_bss = os_realloc_array(iface->bss, iface->num_bss + 1, 2470281806Srpaulo sizeof(struct hostapd_data *)); 2471281806Srpaulo if (tmp_bss) 2472281806Srpaulo iface->bss = tmp_bss; 2473281806Srpaulo if (tmp_conf) { 2474281806Srpaulo iface->conf->bss = tmp_conf; 2475281806Srpaulo iface->conf->last_bss = tmp_conf[0]; 2476281806Srpaulo } 2477281806Srpaulo if (tmp_bss == NULL || tmp_conf == NULL) { 2478281806Srpaulo hostapd_config_free(conf); 2479281806Srpaulo return NULL; 2480281806Srpaulo } 2481281806Srpaulo bss = iface->conf->bss[iface->conf->num_bss] = conf->bss[0]; 2482281806Srpaulo iface->conf->num_bss++; 2483281806Srpaulo 2484281806Srpaulo hapd = hostapd_alloc_bss_data(iface, iface->conf, bss); 2485281806Srpaulo if (hapd == NULL) { 2486281806Srpaulo iface->conf->num_bss--; 2487281806Srpaulo hostapd_config_free(conf); 2488281806Srpaulo return NULL; 2489281806Srpaulo } 2490281806Srpaulo iface->conf->last_bss = bss; 2491281806Srpaulo iface->bss[iface->num_bss] = hapd; 2492281806Srpaulo hapd->msg_ctx = hapd; 2493281806Srpaulo 2494281806Srpaulo bss_idx = iface->num_bss++; 2495281806Srpaulo conf->num_bss--; 2496281806Srpaulo conf->bss[0] = NULL; 2497281806Srpaulo hostapd_config_free(conf); 2498281806Srpaulo } else { 2499281806Srpaulo /* Add a new iface with the first BSS */ 2500281806Srpaulo new_iface = iface = hostapd_init(interfaces, config_fname); 2501281806Srpaulo if (!iface) 2502281806Srpaulo return NULL; 2503281806Srpaulo os_strlcpy(iface->phy, phy, sizeof(iface->phy)); 2504281806Srpaulo iface->interfaces = interfaces; 2505281806Srpaulo bss_idx = 0; 2506281806Srpaulo } 2507281806Srpaulo 2508281806Srpaulo for (k = 0; k < debug; k++) { 2509281806Srpaulo if (iface->bss[bss_idx]->conf->logger_stdout_level > 0) 2510281806Srpaulo iface->bss[bss_idx]->conf->logger_stdout_level--; 2511281806Srpaulo } 2512281806Srpaulo 2513281806Srpaulo if (iface->conf->bss[bss_idx]->iface[0] == '\0' && 2514281806Srpaulo !hostapd_drv_none(iface->bss[bss_idx])) { 2515281806Srpaulo wpa_printf(MSG_ERROR, "Interface name not specified in %s", 2516281806Srpaulo config_fname); 2517281806Srpaulo if (new_iface) 2518281806Srpaulo hostapd_interface_deinit_free(new_iface); 2519281806Srpaulo return NULL; 2520281806Srpaulo } 2521281806Srpaulo 2522281806Srpaulo return iface; 2523281806Srpaulo} 2524281806Srpaulo 2525281806Srpaulo 2526252726Srpaulovoid hostapd_interface_deinit_free(struct hostapd_iface *iface) 2527252726Srpaulo{ 2528252726Srpaulo const struct wpa_driver_ops *driver; 2529252726Srpaulo void *drv_priv; 2530281806Srpaulo 2531281806Srpaulo wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); 2532252726Srpaulo if (iface == NULL) 2533252726Srpaulo return; 2534281806Srpaulo wpa_printf(MSG_DEBUG, "%s: num_bss=%u conf->num_bss=%u", 2535281806Srpaulo __func__, (unsigned int) iface->num_bss, 2536281806Srpaulo (unsigned int) iface->conf->num_bss); 2537252726Srpaulo driver = iface->bss[0]->driver; 2538252726Srpaulo drv_priv = iface->bss[0]->drv_priv; 2539252726Srpaulo hostapd_interface_deinit(iface); 2540281806Srpaulo wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit", 2541281806Srpaulo __func__, driver, drv_priv); 2542281806Srpaulo if (driver && driver->hapd_deinit && drv_priv) { 2543252726Srpaulo driver->hapd_deinit(drv_priv); 2544281806Srpaulo iface->bss[0]->drv_priv = NULL; 2545281806Srpaulo } 2546252726Srpaulo hostapd_interface_free(iface); 2547252726Srpaulo} 2548252726Srpaulo 2549252726Srpaulo 2550281806Srpaulostatic void hostapd_deinit_driver(const struct wpa_driver_ops *driver, 2551281806Srpaulo void *drv_priv, 2552281806Srpaulo struct hostapd_iface *hapd_iface) 2553281806Srpaulo{ 2554281806Srpaulo size_t j; 2555281806Srpaulo 2556281806Srpaulo wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit", 2557281806Srpaulo __func__, driver, drv_priv); 2558281806Srpaulo if (driver && driver->hapd_deinit && drv_priv) { 2559281806Srpaulo driver->hapd_deinit(drv_priv); 2560281806Srpaulo for (j = 0; j < hapd_iface->num_bss; j++) { 2561281806Srpaulo wpa_printf(MSG_DEBUG, "%s:bss[%d]->drv_priv=%p", 2562281806Srpaulo __func__, (int) j, 2563281806Srpaulo hapd_iface->bss[j]->drv_priv); 2564351611Scy if (hapd_iface->bss[j]->drv_priv == drv_priv) { 2565281806Srpaulo hapd_iface->bss[j]->drv_priv = NULL; 2566351611Scy hapd_iface->extended_capa = NULL; 2567351611Scy hapd_iface->extended_capa_mask = NULL; 2568351611Scy hapd_iface->extended_capa_len = 0; 2569351611Scy } 2570281806Srpaulo } 2571281806Srpaulo } 2572281806Srpaulo} 2573281806Srpaulo 2574281806Srpaulo 2575252726Srpauloint hostapd_enable_iface(struct hostapd_iface *hapd_iface) 2576252726Srpaulo{ 2577281806Srpaulo size_t j; 2578281806Srpaulo 2579252726Srpaulo if (hapd_iface->bss[0]->drv_priv != NULL) { 2580252726Srpaulo wpa_printf(MSG_ERROR, "Interface %s already enabled", 2581281806Srpaulo hapd_iface->conf->bss[0]->iface); 2582252726Srpaulo return -1; 2583252726Srpaulo } 2584252726Srpaulo 2585252726Srpaulo wpa_printf(MSG_DEBUG, "Enable interface %s", 2586281806Srpaulo hapd_iface->conf->bss[0]->iface); 2587252726Srpaulo 2588281806Srpaulo for (j = 0; j < hapd_iface->num_bss; j++) 2589281806Srpaulo hostapd_set_security_params(hapd_iface->conf->bss[j], 1); 2590281806Srpaulo if (hostapd_config_check(hapd_iface->conf, 1) < 0) { 2591281806Srpaulo wpa_printf(MSG_INFO, "Invalid configuration - cannot enable"); 2592281806Srpaulo return -1; 2593281806Srpaulo } 2594281806Srpaulo 2595252726Srpaulo if (hapd_iface->interfaces == NULL || 2596252726Srpaulo hapd_iface->interfaces->driver_init == NULL || 2597281806Srpaulo hapd_iface->interfaces->driver_init(hapd_iface)) 2598252726Srpaulo return -1; 2599281806Srpaulo 2600281806Srpaulo if (hostapd_setup_interface(hapd_iface)) { 2601281806Srpaulo hostapd_deinit_driver(hapd_iface->bss[0]->driver, 2602281806Srpaulo hapd_iface->bss[0]->drv_priv, 2603281806Srpaulo hapd_iface); 2604281806Srpaulo return -1; 2605252726Srpaulo } 2606281806Srpaulo 2607252726Srpaulo return 0; 2608252726Srpaulo} 2609252726Srpaulo 2610252726Srpaulo 2611252726Srpauloint hostapd_reload_iface(struct hostapd_iface *hapd_iface) 2612252726Srpaulo{ 2613252726Srpaulo size_t j; 2614252726Srpaulo 2615252726Srpaulo wpa_printf(MSG_DEBUG, "Reload interface %s", 2616281806Srpaulo hapd_iface->conf->bss[0]->iface); 2617281806Srpaulo for (j = 0; j < hapd_iface->num_bss; j++) 2618281806Srpaulo hostapd_set_security_params(hapd_iface->conf->bss[j], 1); 2619281806Srpaulo if (hostapd_config_check(hapd_iface->conf, 1) < 0) { 2620281806Srpaulo wpa_printf(MSG_ERROR, "Updated configuration is invalid"); 2621281806Srpaulo return -1; 2622281806Srpaulo } 2623281806Srpaulo hostapd_clear_old(hapd_iface); 2624281806Srpaulo for (j = 0; j < hapd_iface->num_bss; j++) 2625281806Srpaulo hostapd_reload_bss(hapd_iface->bss[j]); 2626252726Srpaulo 2627252726Srpaulo return 0; 2628252726Srpaulo} 2629252726Srpaulo 2630252726Srpaulo 2631252726Srpauloint hostapd_disable_iface(struct hostapd_iface *hapd_iface) 2632252726Srpaulo{ 2633252726Srpaulo size_t j; 2634252726Srpaulo const struct wpa_driver_ops *driver; 2635252726Srpaulo void *drv_priv; 2636252726Srpaulo 2637252726Srpaulo if (hapd_iface == NULL) 2638252726Srpaulo return -1; 2639281806Srpaulo 2640281806Srpaulo if (hapd_iface->bss[0]->drv_priv == NULL) { 2641281806Srpaulo wpa_printf(MSG_INFO, "Interface %s already disabled", 2642281806Srpaulo hapd_iface->conf->bss[0]->iface); 2643281806Srpaulo return -1; 2644281806Srpaulo } 2645281806Srpaulo 2646281806Srpaulo wpa_msg(hapd_iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); 2647252726Srpaulo driver = hapd_iface->bss[0]->driver; 2648252726Srpaulo drv_priv = hapd_iface->bss[0]->drv_priv; 2649252726Srpaulo 2650281806Srpaulo hapd_iface->driver_ap_teardown = 2651281806Srpaulo !!(hapd_iface->drv_flags & 2652281806Srpaulo WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT); 2653281806Srpaulo 2654346981Scy#ifdef NEED_AP_MLME 2655346981Scy for (j = 0; j < hapd_iface->num_bss; j++) 2656346981Scy hostapd_cleanup_cs_params(hapd_iface->bss[j]); 2657346981Scy#endif /* NEED_AP_MLME */ 2658346981Scy 2659281806Srpaulo /* same as hostapd_interface_deinit without deinitializing ctrl-iface */ 2660252726Srpaulo for (j = 0; j < hapd_iface->num_bss; j++) { 2661252726Srpaulo struct hostapd_data *hapd = hapd_iface->bss[j]; 2662281806Srpaulo hostapd_bss_deinit_no_free(hapd); 2663252726Srpaulo hostapd_free_hapd_data(hapd); 2664252726Srpaulo } 2665252726Srpaulo 2666281806Srpaulo hostapd_deinit_driver(driver, drv_priv, hapd_iface); 2667252726Srpaulo 2668252726Srpaulo /* From hostapd_cleanup_iface: These were initialized in 2669252726Srpaulo * hostapd_setup_interface and hostapd_setup_interface_complete 2670252726Srpaulo */ 2671252726Srpaulo hostapd_cleanup_iface_partial(hapd_iface); 2672252726Srpaulo 2673281806Srpaulo wpa_printf(MSG_DEBUG, "Interface %s disabled", 2674281806Srpaulo hapd_iface->bss[0]->conf->iface); 2675281806Srpaulo hostapd_set_state(hapd_iface, HAPD_IFACE_DISABLED); 2676252726Srpaulo return 0; 2677252726Srpaulo} 2678252726Srpaulo 2679252726Srpaulo 2680252726Srpaulostatic struct hostapd_iface * 2681252726Srpaulohostapd_iface_alloc(struct hapd_interfaces *interfaces) 2682252726Srpaulo{ 2683252726Srpaulo struct hostapd_iface **iface, *hapd_iface; 2684252726Srpaulo 2685252726Srpaulo iface = os_realloc_array(interfaces->iface, interfaces->count + 1, 2686252726Srpaulo sizeof(struct hostapd_iface *)); 2687252726Srpaulo if (iface == NULL) 2688252726Srpaulo return NULL; 2689252726Srpaulo interfaces->iface = iface; 2690252726Srpaulo hapd_iface = interfaces->iface[interfaces->count] = 2691337817Scy hostapd_alloc_iface(); 2692252726Srpaulo if (hapd_iface == NULL) { 2693252726Srpaulo wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for " 2694252726Srpaulo "the interface", __func__); 2695252726Srpaulo return NULL; 2696252726Srpaulo } 2697252726Srpaulo interfaces->count++; 2698252726Srpaulo hapd_iface->interfaces = interfaces; 2699252726Srpaulo 2700252726Srpaulo return hapd_iface; 2701252726Srpaulo} 2702252726Srpaulo 2703252726Srpaulo 2704252726Srpaulostatic struct hostapd_config * 2705252726Srpaulohostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname, 2706289549Srpaulo const char *ctrl_iface, const char *driver) 2707252726Srpaulo{ 2708252726Srpaulo struct hostapd_bss_config *bss; 2709252726Srpaulo struct hostapd_config *conf; 2710252726Srpaulo 2711252726Srpaulo /* Allocates memory for bss and conf */ 2712252726Srpaulo conf = hostapd_config_defaults(); 2713252726Srpaulo if (conf == NULL) { 2714252726Srpaulo wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for " 2715252726Srpaulo "configuration", __func__); 2716346981Scy return NULL; 2717252726Srpaulo } 2718252726Srpaulo 2719289549Srpaulo if (driver) { 2720289549Srpaulo int j; 2721289549Srpaulo 2722289549Srpaulo for (j = 0; wpa_drivers[j]; j++) { 2723289549Srpaulo if (os_strcmp(driver, wpa_drivers[j]->name) == 0) { 2724289549Srpaulo conf->driver = wpa_drivers[j]; 2725289549Srpaulo goto skip; 2726289549Srpaulo } 2727289549Srpaulo } 2728289549Srpaulo 2729289549Srpaulo wpa_printf(MSG_ERROR, 2730289549Srpaulo "Invalid/unknown driver '%s' - registering the default driver", 2731289549Srpaulo driver); 2732289549Srpaulo } 2733289549Srpaulo 2734252726Srpaulo conf->driver = wpa_drivers[0]; 2735252726Srpaulo if (conf->driver == NULL) { 2736252726Srpaulo wpa_printf(MSG_ERROR, "No driver wrappers registered!"); 2737252726Srpaulo hostapd_config_free(conf); 2738252726Srpaulo return NULL; 2739252726Srpaulo } 2740252726Srpaulo 2741289549Srpauloskip: 2742281806Srpaulo bss = conf->last_bss = conf->bss[0]; 2743252726Srpaulo 2744252726Srpaulo os_strlcpy(bss->iface, ifname, sizeof(bss->iface)); 2745252726Srpaulo bss->ctrl_interface = os_strdup(ctrl_iface); 2746252726Srpaulo if (bss->ctrl_interface == NULL) { 2747252726Srpaulo hostapd_config_free(conf); 2748252726Srpaulo return NULL; 2749252726Srpaulo } 2750252726Srpaulo 2751252726Srpaulo /* Reading configuration file skipped, will be done in SET! 2752252726Srpaulo * From reading the configuration till the end has to be done in 2753252726Srpaulo * SET 2754252726Srpaulo */ 2755252726Srpaulo return conf; 2756252726Srpaulo} 2757252726Srpaulo 2758252726Srpaulo 2759281806Srpaulostatic int hostapd_data_alloc(struct hostapd_iface *hapd_iface, 2760281806Srpaulo struct hostapd_config *conf) 2761252726Srpaulo{ 2762252726Srpaulo size_t i; 2763252726Srpaulo struct hostapd_data *hapd; 2764252726Srpaulo 2765281806Srpaulo hapd_iface->bss = os_calloc(conf->num_bss, 2766252726Srpaulo sizeof(struct hostapd_data *)); 2767252726Srpaulo if (hapd_iface->bss == NULL) 2768281806Srpaulo return -1; 2769252726Srpaulo 2770252726Srpaulo for (i = 0; i < conf->num_bss; i++) { 2771252726Srpaulo hapd = hapd_iface->bss[i] = 2772281806Srpaulo hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]); 2773281806Srpaulo if (hapd == NULL) { 2774281806Srpaulo while (i > 0) { 2775281806Srpaulo i--; 2776281806Srpaulo os_free(hapd_iface->bss[i]); 2777281806Srpaulo hapd_iface->bss[i] = NULL; 2778281806Srpaulo } 2779281806Srpaulo os_free(hapd_iface->bss); 2780281806Srpaulo hapd_iface->bss = NULL; 2781281806Srpaulo return -1; 2782281806Srpaulo } 2783252726Srpaulo hapd->msg_ctx = hapd; 2784252726Srpaulo } 2785252726Srpaulo 2786281806Srpaulo hapd_iface->conf = conf; 2787281806Srpaulo hapd_iface->num_bss = conf->num_bss; 2788252726Srpaulo 2789281806Srpaulo return 0; 2790252726Srpaulo} 2791252726Srpaulo 2792252726Srpaulo 2793252726Srpauloint hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf) 2794252726Srpaulo{ 2795252726Srpaulo struct hostapd_config *conf = NULL; 2796281806Srpaulo struct hostapd_iface *hapd_iface = NULL, *new_iface = NULL; 2797281806Srpaulo struct hostapd_data *hapd; 2798252726Srpaulo char *ptr; 2799281806Srpaulo size_t i, j; 2800281806Srpaulo const char *conf_file = NULL, *phy_name = NULL; 2801252726Srpaulo 2802281806Srpaulo if (os_strncmp(buf, "bss_config=", 11) == 0) { 2803281806Srpaulo char *pos; 2804281806Srpaulo phy_name = buf + 11; 2805281806Srpaulo pos = os_strchr(phy_name, ':'); 2806281806Srpaulo if (!pos) 2807281806Srpaulo return -1; 2808281806Srpaulo *pos++ = '\0'; 2809281806Srpaulo conf_file = pos; 2810281806Srpaulo if (!os_strlen(conf_file)) 2811281806Srpaulo return -1; 2812281806Srpaulo 2813281806Srpaulo hapd_iface = hostapd_interface_init_bss(interfaces, phy_name, 2814281806Srpaulo conf_file, 0); 2815281806Srpaulo if (!hapd_iface) 2816281806Srpaulo return -1; 2817281806Srpaulo for (j = 0; j < interfaces->count; j++) { 2818281806Srpaulo if (interfaces->iface[j] == hapd_iface) 2819281806Srpaulo break; 2820281806Srpaulo } 2821281806Srpaulo if (j == interfaces->count) { 2822281806Srpaulo struct hostapd_iface **tmp; 2823281806Srpaulo tmp = os_realloc_array(interfaces->iface, 2824281806Srpaulo interfaces->count + 1, 2825281806Srpaulo sizeof(struct hostapd_iface *)); 2826281806Srpaulo if (!tmp) { 2827281806Srpaulo hostapd_interface_deinit_free(hapd_iface); 2828281806Srpaulo return -1; 2829281806Srpaulo } 2830281806Srpaulo interfaces->iface = tmp; 2831281806Srpaulo interfaces->iface[interfaces->count++] = hapd_iface; 2832281806Srpaulo new_iface = hapd_iface; 2833281806Srpaulo } 2834281806Srpaulo 2835281806Srpaulo if (new_iface) { 2836281806Srpaulo if (interfaces->driver_init(hapd_iface)) 2837281806Srpaulo goto fail; 2838281806Srpaulo 2839281806Srpaulo if (hostapd_setup_interface(hapd_iface)) { 2840281806Srpaulo hostapd_deinit_driver( 2841281806Srpaulo hapd_iface->bss[0]->driver, 2842281806Srpaulo hapd_iface->bss[0]->drv_priv, 2843281806Srpaulo hapd_iface); 2844281806Srpaulo goto fail; 2845281806Srpaulo } 2846281806Srpaulo } else { 2847281806Srpaulo /* Assign new BSS with bss[0]'s driver info */ 2848281806Srpaulo hapd = hapd_iface->bss[hapd_iface->num_bss - 1]; 2849281806Srpaulo hapd->driver = hapd_iface->bss[0]->driver; 2850281806Srpaulo hapd->drv_priv = hapd_iface->bss[0]->drv_priv; 2851281806Srpaulo os_memcpy(hapd->own_addr, hapd_iface->bss[0]->own_addr, 2852281806Srpaulo ETH_ALEN); 2853281806Srpaulo 2854281806Srpaulo if (start_ctrl_iface_bss(hapd) < 0 || 2855281806Srpaulo (hapd_iface->state == HAPD_IFACE_ENABLED && 2856281806Srpaulo hostapd_setup_bss(hapd, -1))) { 2857281806Srpaulo hostapd_cleanup(hapd); 2858281806Srpaulo hapd_iface->bss[hapd_iface->num_bss - 1] = NULL; 2859281806Srpaulo hapd_iface->conf->num_bss--; 2860281806Srpaulo hapd_iface->num_bss--; 2861281806Srpaulo wpa_printf(MSG_DEBUG, "%s: free hapd %p %s", 2862281806Srpaulo __func__, hapd, hapd->conf->iface); 2863281806Srpaulo hostapd_config_free_bss(hapd->conf); 2864281806Srpaulo hapd->conf = NULL; 2865281806Srpaulo os_free(hapd); 2866281806Srpaulo return -1; 2867281806Srpaulo } 2868281806Srpaulo } 2869346981Scy hostapd_owe_update_trans(hapd_iface); 2870281806Srpaulo return 0; 2871281806Srpaulo } 2872281806Srpaulo 2873252726Srpaulo ptr = os_strchr(buf, ' '); 2874252726Srpaulo if (ptr == NULL) 2875252726Srpaulo return -1; 2876252726Srpaulo *ptr++ = '\0'; 2877252726Srpaulo 2878281806Srpaulo if (os_strncmp(ptr, "config=", 7) == 0) 2879281806Srpaulo conf_file = ptr + 7; 2880281806Srpaulo 2881252726Srpaulo for (i = 0; i < interfaces->count; i++) { 2882281806Srpaulo if (!os_strcmp(interfaces->iface[i]->conf->bss[0]->iface, 2883252726Srpaulo buf)) { 2884252726Srpaulo wpa_printf(MSG_INFO, "Cannot add interface - it " 2885252726Srpaulo "already exists"); 2886252726Srpaulo return -1; 2887252726Srpaulo } 2888252726Srpaulo } 2889252726Srpaulo 2890252726Srpaulo hapd_iface = hostapd_iface_alloc(interfaces); 2891252726Srpaulo if (hapd_iface == NULL) { 2892252726Srpaulo wpa_printf(MSG_ERROR, "%s: Failed to allocate memory " 2893252726Srpaulo "for interface", __func__); 2894252726Srpaulo goto fail; 2895252726Srpaulo } 2896281806Srpaulo new_iface = hapd_iface; 2897252726Srpaulo 2898281806Srpaulo if (conf_file && interfaces->config_read_cb) { 2899281806Srpaulo conf = interfaces->config_read_cb(conf_file); 2900281806Srpaulo if (conf && conf->bss) 2901281806Srpaulo os_strlcpy(conf->bss[0]->iface, buf, 2902281806Srpaulo sizeof(conf->bss[0]->iface)); 2903289549Srpaulo } else { 2904289549Srpaulo char *driver = os_strchr(ptr, ' '); 2905289549Srpaulo 2906289549Srpaulo if (driver) 2907289549Srpaulo *driver++ = '\0'; 2908289549Srpaulo conf = hostapd_config_alloc(interfaces, buf, ptr, driver); 2909289549Srpaulo } 2910289549Srpaulo 2911281806Srpaulo if (conf == NULL || conf->bss == NULL) { 2912252726Srpaulo wpa_printf(MSG_ERROR, "%s: Failed to allocate memory " 2913252726Srpaulo "for configuration", __func__); 2914252726Srpaulo goto fail; 2915252726Srpaulo } 2916252726Srpaulo 2917281806Srpaulo if (hostapd_data_alloc(hapd_iface, conf) < 0) { 2918252726Srpaulo wpa_printf(MSG_ERROR, "%s: Failed to allocate memory " 2919252726Srpaulo "for hostapd", __func__); 2920252726Srpaulo goto fail; 2921252726Srpaulo } 2922281806Srpaulo conf = NULL; 2923252726Srpaulo 2924281806Srpaulo if (start_ctrl_iface(hapd_iface) < 0) 2925252726Srpaulo goto fail; 2926252726Srpaulo 2927281806Srpaulo wpa_printf(MSG_INFO, "Add interface '%s'", 2928281806Srpaulo hapd_iface->conf->bss[0]->iface); 2929281806Srpaulo 2930252726Srpaulo return 0; 2931252726Srpaulo 2932252726Srpaulofail: 2933252726Srpaulo if (conf) 2934252726Srpaulo hostapd_config_free(conf); 2935252726Srpaulo if (hapd_iface) { 2936281806Srpaulo if (hapd_iface->bss) { 2937281806Srpaulo for (i = 0; i < hapd_iface->num_bss; i++) { 2938281806Srpaulo hapd = hapd_iface->bss[i]; 2939281806Srpaulo if (!hapd) 2940281806Srpaulo continue; 2941281806Srpaulo if (hapd_iface->interfaces && 2942281806Srpaulo hapd_iface->interfaces->ctrl_iface_deinit) 2943281806Srpaulo hapd_iface->interfaces-> 2944281806Srpaulo ctrl_iface_deinit(hapd); 2945281806Srpaulo wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)", 2946281806Srpaulo __func__, hapd_iface->bss[i], 2947281806Srpaulo hapd->conf->iface); 2948281806Srpaulo hostapd_cleanup(hapd); 2949281806Srpaulo os_free(hapd); 2950281806Srpaulo hapd_iface->bss[i] = NULL; 2951281806Srpaulo } 2952281806Srpaulo os_free(hapd_iface->bss); 2953281806Srpaulo hapd_iface->bss = NULL; 2954281806Srpaulo } 2955281806Srpaulo if (new_iface) { 2956281806Srpaulo interfaces->count--; 2957281806Srpaulo interfaces->iface[interfaces->count] = NULL; 2958281806Srpaulo } 2959281806Srpaulo hostapd_cleanup_iface(hapd_iface); 2960252726Srpaulo } 2961252726Srpaulo return -1; 2962252726Srpaulo} 2963252726Srpaulo 2964252726Srpaulo 2965281806Srpaulostatic int hostapd_remove_bss(struct hostapd_iface *iface, unsigned int idx) 2966281806Srpaulo{ 2967281806Srpaulo size_t i; 2968281806Srpaulo 2969281806Srpaulo wpa_printf(MSG_INFO, "Remove BSS '%s'", iface->conf->bss[idx]->iface); 2970281806Srpaulo 2971281806Srpaulo /* Remove hostapd_data only if it has already been initialized */ 2972281806Srpaulo if (idx < iface->num_bss) { 2973281806Srpaulo struct hostapd_data *hapd = iface->bss[idx]; 2974281806Srpaulo 2975281806Srpaulo hostapd_bss_deinit(hapd); 2976281806Srpaulo wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)", 2977281806Srpaulo __func__, hapd, hapd->conf->iface); 2978281806Srpaulo hostapd_config_free_bss(hapd->conf); 2979281806Srpaulo hapd->conf = NULL; 2980281806Srpaulo os_free(hapd); 2981281806Srpaulo 2982281806Srpaulo iface->num_bss--; 2983281806Srpaulo 2984281806Srpaulo for (i = idx; i < iface->num_bss; i++) 2985281806Srpaulo iface->bss[i] = iface->bss[i + 1]; 2986281806Srpaulo } else { 2987281806Srpaulo hostapd_config_free_bss(iface->conf->bss[idx]); 2988281806Srpaulo iface->conf->bss[idx] = NULL; 2989281806Srpaulo } 2990281806Srpaulo 2991281806Srpaulo iface->conf->num_bss--; 2992281806Srpaulo for (i = idx; i < iface->conf->num_bss; i++) 2993281806Srpaulo iface->conf->bss[i] = iface->conf->bss[i + 1]; 2994281806Srpaulo 2995281806Srpaulo return 0; 2996281806Srpaulo} 2997281806Srpaulo 2998281806Srpaulo 2999252726Srpauloint hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf) 3000252726Srpaulo{ 3001252726Srpaulo struct hostapd_iface *hapd_iface; 3002281806Srpaulo size_t i, j, k = 0; 3003252726Srpaulo 3004252726Srpaulo for (i = 0; i < interfaces->count; i++) { 3005252726Srpaulo hapd_iface = interfaces->iface[i]; 3006252726Srpaulo if (hapd_iface == NULL) 3007252726Srpaulo return -1; 3008281806Srpaulo if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) { 3009252726Srpaulo wpa_printf(MSG_INFO, "Remove interface '%s'", buf); 3010281806Srpaulo hapd_iface->driver_ap_teardown = 3011281806Srpaulo !!(hapd_iface->drv_flags & 3012281806Srpaulo WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT); 3013281806Srpaulo 3014252726Srpaulo hostapd_interface_deinit_free(hapd_iface); 3015252726Srpaulo k = i; 3016252726Srpaulo while (k < (interfaces->count - 1)) { 3017252726Srpaulo interfaces->iface[k] = 3018252726Srpaulo interfaces->iface[k + 1]; 3019252726Srpaulo k++; 3020252726Srpaulo } 3021252726Srpaulo interfaces->count--; 3022252726Srpaulo return 0; 3023252726Srpaulo } 3024281806Srpaulo 3025281806Srpaulo for (j = 0; j < hapd_iface->conf->num_bss; j++) { 3026281806Srpaulo if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf)) { 3027281806Srpaulo hapd_iface->driver_ap_teardown = 3028281806Srpaulo !(hapd_iface->drv_flags & 3029281806Srpaulo WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT); 3030281806Srpaulo return hostapd_remove_bss(hapd_iface, j); 3031281806Srpaulo } 3032281806Srpaulo } 3033252726Srpaulo } 3034252726Srpaulo return -1; 3035252726Srpaulo} 3036252726Srpaulo 3037252726Srpaulo 3038214501Srpaulo/** 3039214501Srpaulo * hostapd_new_assoc_sta - Notify that a new station associated with the AP 3040214501Srpaulo * @hapd: Pointer to BSS data 3041214501Srpaulo * @sta: Pointer to the associated STA data 3042214501Srpaulo * @reassoc: 1 to indicate this was a re-association; 0 = first association 3043214501Srpaulo * 3044214501Srpaulo * This function will be called whenever a station associates with the AP. It 3045214501Srpaulo * can be called from ieee802_11.c for drivers that export MLME to hostapd and 3046214501Srpaulo * from drv_callbacks.c based on driver events for drivers that take care of 3047214501Srpaulo * management frames (IEEE 802.11 authentication and association) internally. 3048214501Srpaulo */ 3049214501Srpaulovoid hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, 3050214501Srpaulo int reassoc) 3051214501Srpaulo{ 3052214501Srpaulo if (hapd->tkip_countermeasures) { 3053252726Srpaulo hostapd_drv_sta_deauth(hapd, sta->addr, 3054252726Srpaulo WLAN_REASON_MICHAEL_MIC_FAILURE); 3055214501Srpaulo return; 3056214501Srpaulo } 3057214501Srpaulo 3058214501Srpaulo hostapd_prune_associations(hapd, sta->addr); 3059337817Scy ap_sta_clear_disconnect_timeouts(hapd, sta); 3060214501Srpaulo 3061214501Srpaulo /* IEEE 802.11F (IAPP) */ 3062214501Srpaulo if (hapd->conf->ieee802_11f) 3063214501Srpaulo iapp_new_station(hapd->iapp, sta); 3064214501Srpaulo 3065252726Srpaulo#ifdef CONFIG_P2P 3066252726Srpaulo if (sta->p2p_ie == NULL && !sta->no_p2p_set) { 3067252726Srpaulo sta->no_p2p_set = 1; 3068252726Srpaulo hapd->num_sta_no_p2p++; 3069252726Srpaulo if (hapd->num_sta_no_p2p == 1) 3070252726Srpaulo hostapd_p2p_non_p2p_sta_connected(hapd); 3071252726Srpaulo } 3072252726Srpaulo#endif /* CONFIG_P2P */ 3073252726Srpaulo 3074351611Scy airtime_policy_new_sta(hapd, sta); 3075351611Scy 3076214501Srpaulo /* Start accounting here, if IEEE 802.1X and WPA are not used. 3077214501Srpaulo * IEEE 802.1X/WPA code will start accounting after the station has 3078214501Srpaulo * been authorized. */ 3079281806Srpaulo if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen) { 3080281806Srpaulo ap_sta_set_authorized(hapd, sta, 1); 3081281806Srpaulo os_get_reltime(&sta->connected_time); 3082214501Srpaulo accounting_sta_start(hapd, sta); 3083252726Srpaulo } 3084214501Srpaulo 3085214501Srpaulo /* Start IEEE 802.1X authentication process for new stations */ 3086214501Srpaulo ieee802_1x_new_station(hapd, sta); 3087214501Srpaulo if (reassoc) { 3088214501Srpaulo if (sta->auth_alg != WLAN_AUTH_FT && 3089346981Scy sta->auth_alg != WLAN_AUTH_FILS_SK && 3090346981Scy sta->auth_alg != WLAN_AUTH_FILS_SK_PFS && 3091346981Scy sta->auth_alg != WLAN_AUTH_FILS_PK && 3092214501Srpaulo !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) 3093214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH); 3094214501Srpaulo } else 3095214501Srpaulo wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm); 3096252726Srpaulo 3097346981Scy if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) { 3098346981Scy if (eloop_cancel_timeout(ap_handle_timer, hapd, sta) > 0) { 3099346981Scy wpa_printf(MSG_DEBUG, 3100346981Scy "%s: %s: canceled wired ap_handle_timer timeout for " 3101346981Scy MACSTR, 3102346981Scy hapd->conf->iface, __func__, 3103346981Scy MAC2STR(sta->addr)); 3104346981Scy } 3105346981Scy } else if (!(hapd->iface->drv_flags & 3106346981Scy WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) { 3107337817Scy wpa_printf(MSG_DEBUG, 3108337817Scy "%s: %s: reschedule ap_handle_timer timeout for " 3109337817Scy MACSTR " (%d seconds - ap_max_inactivity)", 3110337817Scy hapd->conf->iface, __func__, MAC2STR(sta->addr), 3111281806Srpaulo hapd->conf->ap_max_inactivity); 3112281806Srpaulo eloop_cancel_timeout(ap_handle_timer, hapd, sta); 3113281806Srpaulo eloop_register_timeout(hapd->conf->ap_max_inactivity, 0, 3114281806Srpaulo ap_handle_timer, hapd, sta); 3115281806Srpaulo } 3116351611Scy 3117351611Scy#ifdef CONFIG_MACSEC 3118351611Scy if (hapd->conf->wpa_key_mgmt == WPA_KEY_MGMT_NONE && 3119351611Scy hapd->conf->mka_psk_set) 3120351611Scy ieee802_1x_create_preshared_mka_hapd(hapd, sta); 3121351611Scy else 3122351611Scy ieee802_1x_alloc_kay_sm_hapd(hapd, sta); 3123351611Scy#endif /* CONFIG_MACSEC */ 3124214501Srpaulo} 3125281806Srpaulo 3126281806Srpaulo 3127281806Srpauloconst char * hostapd_state_text(enum hostapd_iface_state s) 3128281806Srpaulo{ 3129281806Srpaulo switch (s) { 3130281806Srpaulo case HAPD_IFACE_UNINITIALIZED: 3131281806Srpaulo return "UNINITIALIZED"; 3132281806Srpaulo case HAPD_IFACE_DISABLED: 3133281806Srpaulo return "DISABLED"; 3134281806Srpaulo case HAPD_IFACE_COUNTRY_UPDATE: 3135281806Srpaulo return "COUNTRY_UPDATE"; 3136281806Srpaulo case HAPD_IFACE_ACS: 3137281806Srpaulo return "ACS"; 3138281806Srpaulo case HAPD_IFACE_HT_SCAN: 3139281806Srpaulo return "HT_SCAN"; 3140281806Srpaulo case HAPD_IFACE_DFS: 3141281806Srpaulo return "DFS"; 3142281806Srpaulo case HAPD_IFACE_ENABLED: 3143281806Srpaulo return "ENABLED"; 3144281806Srpaulo } 3145281806Srpaulo 3146281806Srpaulo return "UNKNOWN"; 3147281806Srpaulo} 3148281806Srpaulo 3149281806Srpaulo 3150281806Srpaulovoid hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s) 3151281806Srpaulo{ 3152281806Srpaulo wpa_printf(MSG_INFO, "%s: interface state %s->%s", 3153337817Scy iface->conf ? iface->conf->bss[0]->iface : "N/A", 3154337817Scy hostapd_state_text(iface->state), hostapd_state_text(s)); 3155281806Srpaulo iface->state = s; 3156281806Srpaulo} 3157281806Srpaulo 3158281806Srpaulo 3159337817Scyint hostapd_csa_in_progress(struct hostapd_iface *iface) 3160337817Scy{ 3161337817Scy unsigned int i; 3162337817Scy 3163337817Scy for (i = 0; i < iface->num_bss; i++) 3164337817Scy if (iface->bss[i]->csa_in_progress) 3165337817Scy return 1; 3166337817Scy return 0; 3167337817Scy} 3168337817Scy 3169337817Scy 3170281806Srpaulo#ifdef NEED_AP_MLME 3171281806Srpaulo 3172281806Srpaulostatic void free_beacon_data(struct beacon_data *beacon) 3173281806Srpaulo{ 3174281806Srpaulo os_free(beacon->head); 3175281806Srpaulo beacon->head = NULL; 3176281806Srpaulo os_free(beacon->tail); 3177281806Srpaulo beacon->tail = NULL; 3178281806Srpaulo os_free(beacon->probe_resp); 3179281806Srpaulo beacon->probe_resp = NULL; 3180281806Srpaulo os_free(beacon->beacon_ies); 3181281806Srpaulo beacon->beacon_ies = NULL; 3182281806Srpaulo os_free(beacon->proberesp_ies); 3183281806Srpaulo beacon->proberesp_ies = NULL; 3184281806Srpaulo os_free(beacon->assocresp_ies); 3185281806Srpaulo beacon->assocresp_ies = NULL; 3186281806Srpaulo} 3187281806Srpaulo 3188281806Srpaulo 3189281806Srpaulostatic int hostapd_build_beacon_data(struct hostapd_data *hapd, 3190281806Srpaulo struct beacon_data *beacon) 3191281806Srpaulo{ 3192281806Srpaulo struct wpabuf *beacon_extra, *proberesp_extra, *assocresp_extra; 3193281806Srpaulo struct wpa_driver_ap_params params; 3194281806Srpaulo int ret; 3195281806Srpaulo 3196281806Srpaulo os_memset(beacon, 0, sizeof(*beacon)); 3197281806Srpaulo ret = ieee802_11_build_ap_params(hapd, ¶ms); 3198281806Srpaulo if (ret < 0) 3199281806Srpaulo return ret; 3200281806Srpaulo 3201281806Srpaulo ret = hostapd_build_ap_extra_ies(hapd, &beacon_extra, 3202281806Srpaulo &proberesp_extra, 3203281806Srpaulo &assocresp_extra); 3204281806Srpaulo if (ret) 3205281806Srpaulo goto free_ap_params; 3206281806Srpaulo 3207281806Srpaulo ret = -1; 3208346981Scy beacon->head = os_memdup(params.head, params.head_len); 3209281806Srpaulo if (!beacon->head) 3210281806Srpaulo goto free_ap_extra_ies; 3211281806Srpaulo 3212281806Srpaulo beacon->head_len = params.head_len; 3213281806Srpaulo 3214346981Scy beacon->tail = os_memdup(params.tail, params.tail_len); 3215281806Srpaulo if (!beacon->tail) 3216281806Srpaulo goto free_beacon; 3217281806Srpaulo 3218281806Srpaulo beacon->tail_len = params.tail_len; 3219281806Srpaulo 3220281806Srpaulo if (params.proberesp != NULL) { 3221346981Scy beacon->probe_resp = os_memdup(params.proberesp, 3222346981Scy params.proberesp_len); 3223281806Srpaulo if (!beacon->probe_resp) 3224281806Srpaulo goto free_beacon; 3225281806Srpaulo 3226281806Srpaulo beacon->probe_resp_len = params.proberesp_len; 3227281806Srpaulo } 3228281806Srpaulo 3229281806Srpaulo /* copy the extra ies */ 3230281806Srpaulo if (beacon_extra) { 3231346981Scy beacon->beacon_ies = os_memdup(beacon_extra->buf, 3232346981Scy wpabuf_len(beacon_extra)); 3233281806Srpaulo if (!beacon->beacon_ies) 3234281806Srpaulo goto free_beacon; 3235281806Srpaulo 3236281806Srpaulo beacon->beacon_ies_len = wpabuf_len(beacon_extra); 3237281806Srpaulo } 3238281806Srpaulo 3239281806Srpaulo if (proberesp_extra) { 3240346981Scy beacon->proberesp_ies = os_memdup(proberesp_extra->buf, 3241346981Scy wpabuf_len(proberesp_extra)); 3242281806Srpaulo if (!beacon->proberesp_ies) 3243281806Srpaulo goto free_beacon; 3244281806Srpaulo 3245281806Srpaulo beacon->proberesp_ies_len = wpabuf_len(proberesp_extra); 3246281806Srpaulo } 3247281806Srpaulo 3248281806Srpaulo if (assocresp_extra) { 3249346981Scy beacon->assocresp_ies = os_memdup(assocresp_extra->buf, 3250346981Scy wpabuf_len(assocresp_extra)); 3251281806Srpaulo if (!beacon->assocresp_ies) 3252281806Srpaulo goto free_beacon; 3253281806Srpaulo 3254281806Srpaulo beacon->assocresp_ies_len = wpabuf_len(assocresp_extra); 3255281806Srpaulo } 3256281806Srpaulo 3257281806Srpaulo ret = 0; 3258281806Srpaulofree_beacon: 3259281806Srpaulo /* if the function fails, the caller should not free beacon data */ 3260281806Srpaulo if (ret) 3261281806Srpaulo free_beacon_data(beacon); 3262281806Srpaulo 3263281806Srpaulofree_ap_extra_ies: 3264281806Srpaulo hostapd_free_ap_extra_ies(hapd, beacon_extra, proberesp_extra, 3265281806Srpaulo assocresp_extra); 3266281806Srpaulofree_ap_params: 3267281806Srpaulo ieee802_11_free_ap_params(¶ms); 3268281806Srpaulo return ret; 3269281806Srpaulo} 3270281806Srpaulo 3271281806Srpaulo 3272281806Srpaulo/* 3273337817Scy * TODO: This flow currently supports only changing channel and width within 3274337817Scy * the same hw_mode. Any other changes to MAC parameters or provided settings 3275337817Scy * are not supported. 3276281806Srpaulo */ 3277281806Srpaulostatic int hostapd_change_config_freq(struct hostapd_data *hapd, 3278281806Srpaulo struct hostapd_config *conf, 3279281806Srpaulo struct hostapd_freq_params *params, 3280281806Srpaulo struct hostapd_freq_params *old_params) 3281281806Srpaulo{ 3282281806Srpaulo int channel; 3283351611Scy u8 seg0, seg1; 3284351611Scy struct hostapd_hw_modes *mode; 3285281806Srpaulo 3286281806Srpaulo if (!params->channel) { 3287281806Srpaulo /* check if the new channel is supported by hw */ 3288281806Srpaulo params->channel = hostapd_hw_get_channel(hapd, params->freq); 3289281806Srpaulo } 3290281806Srpaulo 3291281806Srpaulo channel = params->channel; 3292281806Srpaulo if (!channel) 3293281806Srpaulo return -1; 3294281806Srpaulo 3295351611Scy mode = hapd->iface->current_mode; 3296351611Scy 3297281806Srpaulo /* if a pointer to old_params is provided we save previous state */ 3298337817Scy if (old_params && 3299337817Scy hostapd_set_freq_params(old_params, conf->hw_mode, 3300337817Scy hostapd_hw_get_freq(hapd, conf->channel), 3301337817Scy conf->channel, conf->ieee80211n, 3302351611Scy conf->ieee80211ac, conf->ieee80211ax, 3303337817Scy conf->secondary_channel, 3304351611Scy hostapd_get_oper_chwidth(conf), 3305351611Scy hostapd_get_oper_centr_freq_seg0_idx(conf), 3306351611Scy hostapd_get_oper_centr_freq_seg1_idx(conf), 3307351611Scy conf->vht_capab, 3308351611Scy mode ? &mode->he_capab[IEEE80211_MODE_AP] : 3309351611Scy NULL)) 3310337817Scy return -1; 3311337817Scy 3312337817Scy switch (params->bandwidth) { 3313337817Scy case 0: 3314337817Scy case 20: 3315337817Scy case 40: 3316351611Scy hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT); 3317337817Scy break; 3318337817Scy case 80: 3319337817Scy if (params->center_freq2) 3320351611Scy hostapd_set_oper_chwidth(conf, CHANWIDTH_80P80MHZ); 3321337817Scy else 3322351611Scy hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ); 3323337817Scy break; 3324337817Scy case 160: 3325351611Scy hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ); 3326337817Scy break; 3327337817Scy default: 3328337817Scy return -1; 3329281806Srpaulo } 3330281806Srpaulo 3331281806Srpaulo conf->channel = channel; 3332281806Srpaulo conf->ieee80211n = params->ht_enabled; 3333281806Srpaulo conf->secondary_channel = params->sec_channel_offset; 3334337817Scy ieee80211_freq_to_chan(params->center_freq1, 3335351611Scy &seg0); 3336337817Scy ieee80211_freq_to_chan(params->center_freq2, 3337351611Scy &seg1); 3338351611Scy hostapd_set_oper_centr_freq_seg0_idx(conf, seg0); 3339351611Scy hostapd_set_oper_centr_freq_seg1_idx(conf, seg1); 3340281806Srpaulo 3341281806Srpaulo /* TODO: maybe call here hostapd_config_check here? */ 3342281806Srpaulo 3343281806Srpaulo return 0; 3344281806Srpaulo} 3345281806Srpaulo 3346281806Srpaulo 3347281806Srpaulostatic int hostapd_fill_csa_settings(struct hostapd_data *hapd, 3348281806Srpaulo struct csa_settings *settings) 3349281806Srpaulo{ 3350281806Srpaulo struct hostapd_iface *iface = hapd->iface; 3351281806Srpaulo struct hostapd_freq_params old_freq; 3352281806Srpaulo int ret; 3353351611Scy u8 chan, bandwidth; 3354281806Srpaulo 3355281806Srpaulo os_memset(&old_freq, 0, sizeof(old_freq)); 3356281806Srpaulo if (!iface || !iface->freq || hapd->csa_in_progress) 3357281806Srpaulo return -1; 3358281806Srpaulo 3359337817Scy switch (settings->freq_params.bandwidth) { 3360337817Scy case 80: 3361337817Scy if (settings->freq_params.center_freq2) 3362351611Scy bandwidth = CHANWIDTH_80P80MHZ; 3363337817Scy else 3364351611Scy bandwidth = CHANWIDTH_80MHZ; 3365337817Scy break; 3366337817Scy case 160: 3367351611Scy bandwidth = CHANWIDTH_160MHZ; 3368337817Scy break; 3369337817Scy default: 3370351611Scy bandwidth = CHANWIDTH_USE_HT; 3371337817Scy break; 3372337817Scy } 3373337817Scy 3374337817Scy if (ieee80211_freq_to_channel_ext( 3375337817Scy settings->freq_params.freq, 3376337817Scy settings->freq_params.sec_channel_offset, 3377351611Scy bandwidth, 3378337817Scy &hapd->iface->cs_oper_class, 3379337817Scy &chan) == NUM_HOSTAPD_MODES) { 3380337817Scy wpa_printf(MSG_DEBUG, 3381351611Scy "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d)", 3382337817Scy settings->freq_params.freq, 3383337817Scy settings->freq_params.sec_channel_offset, 3384351611Scy settings->freq_params.vht_enabled, 3385351611Scy settings->freq_params.he_enabled); 3386337817Scy return -1; 3387337817Scy } 3388337817Scy 3389337817Scy settings->freq_params.channel = chan; 3390337817Scy 3391281806Srpaulo ret = hostapd_change_config_freq(iface->bss[0], iface->conf, 3392281806Srpaulo &settings->freq_params, 3393281806Srpaulo &old_freq); 3394281806Srpaulo if (ret) 3395281806Srpaulo return ret; 3396281806Srpaulo 3397281806Srpaulo ret = hostapd_build_beacon_data(hapd, &settings->beacon_after); 3398281806Srpaulo 3399281806Srpaulo /* change back the configuration */ 3400281806Srpaulo hostapd_change_config_freq(iface->bss[0], iface->conf, 3401281806Srpaulo &old_freq, NULL); 3402281806Srpaulo 3403281806Srpaulo if (ret) 3404281806Srpaulo return ret; 3405281806Srpaulo 3406281806Srpaulo /* set channel switch parameters for csa ie */ 3407281806Srpaulo hapd->cs_freq_params = settings->freq_params; 3408281806Srpaulo hapd->cs_count = settings->cs_count; 3409281806Srpaulo hapd->cs_block_tx = settings->block_tx; 3410281806Srpaulo 3411281806Srpaulo ret = hostapd_build_beacon_data(hapd, &settings->beacon_csa); 3412281806Srpaulo if (ret) { 3413281806Srpaulo free_beacon_data(&settings->beacon_after); 3414281806Srpaulo return ret; 3415281806Srpaulo } 3416281806Srpaulo 3417337817Scy settings->counter_offset_beacon[0] = hapd->cs_c_off_beacon; 3418337817Scy settings->counter_offset_presp[0] = hapd->cs_c_off_proberesp; 3419337817Scy settings->counter_offset_beacon[1] = hapd->cs_c_off_ecsa_beacon; 3420337817Scy settings->counter_offset_presp[1] = hapd->cs_c_off_ecsa_proberesp; 3421281806Srpaulo 3422281806Srpaulo return 0; 3423281806Srpaulo} 3424281806Srpaulo 3425281806Srpaulo 3426281806Srpaulovoid hostapd_cleanup_cs_params(struct hostapd_data *hapd) 3427281806Srpaulo{ 3428281806Srpaulo os_memset(&hapd->cs_freq_params, 0, sizeof(hapd->cs_freq_params)); 3429281806Srpaulo hapd->cs_count = 0; 3430281806Srpaulo hapd->cs_block_tx = 0; 3431281806Srpaulo hapd->cs_c_off_beacon = 0; 3432281806Srpaulo hapd->cs_c_off_proberesp = 0; 3433281806Srpaulo hapd->csa_in_progress = 0; 3434337817Scy hapd->cs_c_off_ecsa_beacon = 0; 3435337817Scy hapd->cs_c_off_ecsa_proberesp = 0; 3436281806Srpaulo} 3437281806Srpaulo 3438281806Srpaulo 3439346981Scyvoid hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled) 3440346981Scy{ 3441346981Scy if (vht_enabled) 3442346981Scy hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_ENABLED; 3443346981Scy else 3444346981Scy hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_DISABLED; 3445346981Scy 3446346981Scy hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 3447346981Scy HOSTAPD_LEVEL_INFO, "CHAN_SWITCH VHT CONFIG 0x%x", 3448346981Scy hapd->iconf->ch_switch_vht_config); 3449346981Scy} 3450346981Scy 3451346981Scy 3452281806Srpauloint hostapd_switch_channel(struct hostapd_data *hapd, 3453281806Srpaulo struct csa_settings *settings) 3454281806Srpaulo{ 3455281806Srpaulo int ret; 3456281806Srpaulo 3457281806Srpaulo if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)) { 3458281806Srpaulo wpa_printf(MSG_INFO, "CSA is not supported"); 3459281806Srpaulo return -1; 3460281806Srpaulo } 3461281806Srpaulo 3462281806Srpaulo ret = hostapd_fill_csa_settings(hapd, settings); 3463281806Srpaulo if (ret) 3464281806Srpaulo return ret; 3465281806Srpaulo 3466281806Srpaulo ret = hostapd_drv_switch_channel(hapd, settings); 3467281806Srpaulo free_beacon_data(&settings->beacon_csa); 3468281806Srpaulo free_beacon_data(&settings->beacon_after); 3469281806Srpaulo 3470281806Srpaulo if (ret) { 3471281806Srpaulo /* if we failed, clean cs parameters */ 3472281806Srpaulo hostapd_cleanup_cs_params(hapd); 3473281806Srpaulo return ret; 3474281806Srpaulo } 3475281806Srpaulo 3476281806Srpaulo hapd->csa_in_progress = 1; 3477281806Srpaulo return 0; 3478281806Srpaulo} 3479281806Srpaulo 3480281806Srpaulo 3481281806Srpaulovoid 3482281806Srpaulohostapd_switch_channel_fallback(struct hostapd_iface *iface, 3483281806Srpaulo const struct hostapd_freq_params *freq_params) 3484281806Srpaulo{ 3485351611Scy int seg0_idx = 0, seg1_idx = 0, bw = CHANWIDTH_USE_HT; 3486281806Srpaulo 3487281806Srpaulo wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes"); 3488281806Srpaulo 3489281806Srpaulo if (freq_params->center_freq1) 3490351611Scy seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5; 3491281806Srpaulo if (freq_params->center_freq2) 3492351611Scy seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5; 3493281806Srpaulo 3494281806Srpaulo switch (freq_params->bandwidth) { 3495281806Srpaulo case 0: 3496281806Srpaulo case 20: 3497281806Srpaulo case 40: 3498351611Scy bw = CHANWIDTH_USE_HT; 3499281806Srpaulo break; 3500281806Srpaulo case 80: 3501281806Srpaulo if (freq_params->center_freq2) 3502351611Scy bw = CHANWIDTH_80P80MHZ; 3503281806Srpaulo else 3504351611Scy bw = CHANWIDTH_80MHZ; 3505281806Srpaulo break; 3506281806Srpaulo case 160: 3507351611Scy bw = CHANWIDTH_160MHZ; 3508281806Srpaulo break; 3509281806Srpaulo default: 3510281806Srpaulo wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d", 3511281806Srpaulo freq_params->bandwidth); 3512281806Srpaulo break; 3513281806Srpaulo } 3514281806Srpaulo 3515281806Srpaulo iface->freq = freq_params->freq; 3516281806Srpaulo iface->conf->channel = freq_params->channel; 3517281806Srpaulo iface->conf->secondary_channel = freq_params->sec_channel_offset; 3518351611Scy hostapd_set_oper_centr_freq_seg0_idx(iface->conf, seg0_idx); 3519351611Scy hostapd_set_oper_centr_freq_seg1_idx(iface->conf, seg1_idx); 3520351611Scy hostapd_set_oper_chwidth(iface->conf, bw); 3521281806Srpaulo iface->conf->ieee80211n = freq_params->ht_enabled; 3522281806Srpaulo iface->conf->ieee80211ac = freq_params->vht_enabled; 3523351611Scy iface->conf->ieee80211ax = freq_params->he_enabled; 3524281806Srpaulo 3525281806Srpaulo /* 3526281806Srpaulo * cs_params must not be cleared earlier because the freq_params 3527281806Srpaulo * argument may actually point to one of these. 3528346981Scy * These params will be cleared during interface disable below. 3529281806Srpaulo */ 3530281806Srpaulo hostapd_disable_iface(iface); 3531281806Srpaulo hostapd_enable_iface(iface); 3532281806Srpaulo} 3533281806Srpaulo 3534337817Scy#endif /* NEED_AP_MLME */ 3535289549Srpaulo 3536337817Scy 3537289549Srpaulostruct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces, 3538289549Srpaulo const char *ifname) 3539289549Srpaulo{ 3540289549Srpaulo size_t i, j; 3541289549Srpaulo 3542289549Srpaulo for (i = 0; i < interfaces->count; i++) { 3543289549Srpaulo struct hostapd_iface *iface = interfaces->iface[i]; 3544289549Srpaulo 3545289549Srpaulo for (j = 0; j < iface->num_bss; j++) { 3546289549Srpaulo struct hostapd_data *hapd = iface->bss[j]; 3547289549Srpaulo 3548289549Srpaulo if (os_strcmp(ifname, hapd->conf->iface) == 0) 3549289549Srpaulo return hapd; 3550289549Srpaulo } 3551289549Srpaulo } 3552289549Srpaulo 3553289549Srpaulo return NULL; 3554289549Srpaulo} 3555289549Srpaulo 3556289549Srpaulo 3557289549Srpaulovoid hostapd_periodic_iface(struct hostapd_iface *iface) 3558289549Srpaulo{ 3559289549Srpaulo size_t i; 3560289549Srpaulo 3561289549Srpaulo ap_list_timer(iface); 3562289549Srpaulo 3563289549Srpaulo for (i = 0; i < iface->num_bss; i++) { 3564289549Srpaulo struct hostapd_data *hapd = iface->bss[i]; 3565289549Srpaulo 3566289549Srpaulo if (!hapd->started) 3567289549Srpaulo continue; 3568289549Srpaulo 3569289549Srpaulo#ifndef CONFIG_NO_RADIUS 3570289549Srpaulo hostapd_acl_expire(hapd); 3571289549Srpaulo#endif /* CONFIG_NO_RADIUS */ 3572289549Srpaulo } 3573289549Srpaulo} 3574