hostapd.c revision 337817
1214501Srpaulo/* 2214501Srpaulo * hostapd / Initialization and configuration 3281806Srpaulo * Copyright (c) 2002-2014, 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" 10214501Srpaulo 11214501Srpaulo#include "utils/common.h" 12214501Srpaulo#include "utils/eloop.h" 13214501Srpaulo#include "common/ieee802_11_defs.h" 14281806Srpaulo#include "common/wpa_ctrl.h" 15337817Scy#include "common/hw_features_common.h" 16214501Srpaulo#include "radius/radius_client.h" 17252726Srpaulo#include "radius/radius_das.h" 18281806Srpaulo#include "eap_server/tncs.h" 19281806Srpaulo#include "eapol_auth/eapol_auth_sm.h" 20281806Srpaulo#include "eapol_auth/eapol_auth_sm_i.h" 21289549Srpaulo#include "fst/fst.h" 22214501Srpaulo#include "hostapd.h" 23214501Srpaulo#include "authsrv.h" 24214501Srpaulo#include "sta_info.h" 25214501Srpaulo#include "accounting.h" 26214501Srpaulo#include "ap_list.h" 27214501Srpaulo#include "beacon.h" 28214501Srpaulo#include "iapp.h" 29214501Srpaulo#include "ieee802_1x.h" 30214501Srpaulo#include "ieee802_11_auth.h" 31214501Srpaulo#include "vlan_init.h" 32214501Srpaulo#include "wpa_auth.h" 33214501Srpaulo#include "wps_hostapd.h" 34214501Srpaulo#include "hw_features.h" 35214501Srpaulo#include "wpa_auth_glue.h" 36214501Srpaulo#include "ap_drv_ops.h" 37214501Srpaulo#include "ap_config.h" 38252726Srpaulo#include "p2p_hostapd.h" 39252726Srpaulo#include "gas_serv.h" 40281806Srpaulo#include "dfs.h" 41281806Srpaulo#include "ieee802_11.h" 42281806Srpaulo#include "bss_load.h" 43281806Srpaulo#include "x_snoop.h" 44281806Srpaulo#include "dhcp_snoop.h" 45281806Srpaulo#include "ndisc_snoop.h" 46337817Scy#include "neighbor_db.h" 47337817Scy#include "rrm.h" 48214501Srpaulo 49214501Srpaulo 50252726Srpaulostatic int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason); 51214501Srpaulostatic int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd); 52252726Srpaulostatic int hostapd_broadcast_wep_clear(struct hostapd_data *hapd); 53281806Srpaulostatic int setup_interface2(struct hostapd_iface *iface); 54281806Srpaulostatic void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx); 55214501Srpaulo 56214501Srpaulo 57252726Srpauloint hostapd_for_each_interface(struct hapd_interfaces *interfaces, 58252726Srpaulo int (*cb)(struct hostapd_iface *iface, 59252726Srpaulo void *ctx), void *ctx) 60214501Srpaulo{ 61252726Srpaulo size_t i; 62252726Srpaulo int ret; 63214501Srpaulo 64252726Srpaulo for (i = 0; i < interfaces->count; i++) { 65252726Srpaulo ret = cb(interfaces->iface[i], ctx); 66252726Srpaulo if (ret) 67252726Srpaulo return ret; 68252726Srpaulo } 69214501Srpaulo 70252726Srpaulo return 0; 71252726Srpaulo} 72214501Srpaulo 73252726Srpaulo 74252726Srpaulostatic void hostapd_reload_bss(struct hostapd_data *hapd) 75252726Srpaulo{ 76281806Srpaulo struct hostapd_ssid *ssid; 77281806Srpaulo 78214501Srpaulo#ifndef CONFIG_NO_RADIUS 79252726Srpaulo radius_client_reconfig(hapd->radius, hapd->conf->radius); 80214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 81214501Srpaulo 82281806Srpaulo ssid = &hapd->conf->ssid; 83281806Srpaulo if (!ssid->wpa_psk_set && ssid->wpa_psk && !ssid->wpa_psk->next && 84281806Srpaulo ssid->wpa_passphrase_set && ssid->wpa_passphrase) { 85281806Srpaulo /* 86281806Srpaulo * Force PSK to be derived again since SSID or passphrase may 87281806Srpaulo * have changed. 88281806Srpaulo */ 89281806Srpaulo hostapd_config_clear_wpa_psk(&hapd->conf->ssid.wpa_psk); 90281806Srpaulo } 91214501Srpaulo if (hostapd_setup_wpa_psk(hapd->conf)) { 92214501Srpaulo wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK " 93214501Srpaulo "after reloading configuration"); 94214501Srpaulo } 95214501Srpaulo 96214501Srpaulo if (hapd->conf->ieee802_1x || hapd->conf->wpa) 97252726Srpaulo hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1); 98214501Srpaulo else 99252726Srpaulo hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); 100214501Srpaulo 101281806Srpaulo if ((hapd->conf->wpa || hapd->conf->osen) && hapd->wpa_auth == NULL) { 102214501Srpaulo hostapd_setup_wpa(hapd); 103252726Srpaulo if (hapd->wpa_auth) 104252726Srpaulo wpa_init_keys(hapd->wpa_auth); 105252726Srpaulo } else if (hapd->conf->wpa) { 106214501Srpaulo const u8 *wpa_ie; 107214501Srpaulo size_t wpa_ie_len; 108214501Srpaulo hostapd_reconfig_wpa(hapd); 109214501Srpaulo wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len); 110214501Srpaulo if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) 111214501Srpaulo wpa_printf(MSG_ERROR, "Failed to configure WPA IE for " 112214501Srpaulo "the kernel driver."); 113214501Srpaulo } else if (hapd->wpa_auth) { 114214501Srpaulo wpa_deinit(hapd->wpa_auth); 115214501Srpaulo hapd->wpa_auth = NULL; 116214501Srpaulo hostapd_set_privacy(hapd, 0); 117214501Srpaulo hostapd_setup_encryption(hapd->conf->iface, hapd); 118214501Srpaulo hostapd_set_generic_elem(hapd, (u8 *) "", 0); 119214501Srpaulo } 120214501Srpaulo 121214501Srpaulo ieee802_11_set_beacon(hapd); 122214501Srpaulo hostapd_update_wps(hapd); 123214501Srpaulo 124214501Srpaulo if (hapd->conf->ssid.ssid_set && 125252726Srpaulo hostapd_set_ssid(hapd, hapd->conf->ssid.ssid, 126214501Srpaulo hapd->conf->ssid.ssid_len)) { 127214501Srpaulo wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); 128214501Srpaulo /* try to continue */ 129214501Srpaulo } 130252726Srpaulo wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface); 131252726Srpaulo} 132214501Srpaulo 133252726Srpaulo 134281806Srpaulostatic void hostapd_clear_old(struct hostapd_iface *iface) 135252726Srpaulo{ 136252726Srpaulo size_t j; 137252726Srpaulo 138252726Srpaulo /* 139252726Srpaulo * Deauthenticate all stations since the new configuration may not 140252726Srpaulo * allow them to use the BSS anymore. 141252726Srpaulo */ 142252726Srpaulo for (j = 0; j < iface->num_bss; j++) { 143252726Srpaulo hostapd_flush_old_stations(iface->bss[j], 144252726Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 145252726Srpaulo hostapd_broadcast_wep_clear(iface->bss[j]); 146252726Srpaulo 147252726Srpaulo#ifndef CONFIG_NO_RADIUS 148252726Srpaulo /* TODO: update dynamic data based on changed configuration 149252726Srpaulo * items (e.g., open/close sockets, etc.) */ 150252726Srpaulo radius_client_flush(iface->bss[j]->radius, 0); 151252726Srpaulo#endif /* CONFIG_NO_RADIUS */ 152252726Srpaulo } 153281806Srpaulo} 154252726Srpaulo 155281806Srpaulo 156281806Srpauloint hostapd_reload_config(struct hostapd_iface *iface) 157281806Srpaulo{ 158281806Srpaulo struct hostapd_data *hapd = iface->bss[0]; 159281806Srpaulo struct hostapd_config *newconf, *oldconf; 160281806Srpaulo size_t j; 161281806Srpaulo 162281806Srpaulo if (iface->config_fname == NULL) { 163281806Srpaulo /* Only in-memory config in use - assume it has been updated */ 164281806Srpaulo hostapd_clear_old(iface); 165281806Srpaulo for (j = 0; j < iface->num_bss; j++) 166281806Srpaulo hostapd_reload_bss(iface->bss[j]); 167281806Srpaulo return 0; 168281806Srpaulo } 169281806Srpaulo 170281806Srpaulo if (iface->interfaces == NULL || 171281806Srpaulo iface->interfaces->config_read_cb == NULL) 172281806Srpaulo return -1; 173281806Srpaulo newconf = iface->interfaces->config_read_cb(iface->config_fname); 174281806Srpaulo if (newconf == NULL) 175281806Srpaulo return -1; 176281806Srpaulo 177281806Srpaulo hostapd_clear_old(iface); 178281806Srpaulo 179252726Srpaulo oldconf = hapd->iconf; 180252726Srpaulo iface->conf = newconf; 181252726Srpaulo 182252726Srpaulo for (j = 0; j < iface->num_bss; j++) { 183252726Srpaulo hapd = iface->bss[j]; 184252726Srpaulo hapd->iconf = newconf; 185281806Srpaulo hapd->iconf->channel = oldconf->channel; 186289549Srpaulo hapd->iconf->acs = oldconf->acs; 187281806Srpaulo hapd->iconf->secondary_channel = oldconf->secondary_channel; 188281806Srpaulo hapd->iconf->ieee80211n = oldconf->ieee80211n; 189281806Srpaulo hapd->iconf->ieee80211ac = oldconf->ieee80211ac; 190281806Srpaulo hapd->iconf->ht_capab = oldconf->ht_capab; 191281806Srpaulo hapd->iconf->vht_capab = oldconf->vht_capab; 192281806Srpaulo hapd->iconf->vht_oper_chwidth = oldconf->vht_oper_chwidth; 193281806Srpaulo hapd->iconf->vht_oper_centr_freq_seg0_idx = 194281806Srpaulo oldconf->vht_oper_centr_freq_seg0_idx; 195281806Srpaulo hapd->iconf->vht_oper_centr_freq_seg1_idx = 196281806Srpaulo oldconf->vht_oper_centr_freq_seg1_idx; 197281806Srpaulo hapd->conf = newconf->bss[j]; 198252726Srpaulo hostapd_reload_bss(hapd); 199252726Srpaulo } 200252726Srpaulo 201214501Srpaulo hostapd_config_free(oldconf); 202214501Srpaulo 203214501Srpaulo 204214501Srpaulo return 0; 205214501Srpaulo} 206214501Srpaulo 207214501Srpaulo 208214501Srpaulostatic void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd, 209337817Scy const char *ifname) 210214501Srpaulo{ 211214501Srpaulo int i; 212214501Srpaulo 213337817Scy if (!ifname) 214337817Scy return; 215214501Srpaulo for (i = 0; i < NUM_WEP_KEYS; i++) { 216252726Srpaulo if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, 217252726Srpaulo 0, NULL, 0, NULL, 0)) { 218214501Srpaulo wpa_printf(MSG_DEBUG, "Failed to clear default " 219214501Srpaulo "encryption keys (ifname=%s keyidx=%d)", 220214501Srpaulo ifname, i); 221214501Srpaulo } 222214501Srpaulo } 223214501Srpaulo#ifdef CONFIG_IEEE80211W 224214501Srpaulo if (hapd->conf->ieee80211w) { 225214501Srpaulo for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) { 226252726Srpaulo if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, 227252726Srpaulo NULL, i, 0, NULL, 228252726Srpaulo 0, NULL, 0)) { 229214501Srpaulo wpa_printf(MSG_DEBUG, "Failed to clear " 230214501Srpaulo "default mgmt encryption keys " 231214501Srpaulo "(ifname=%s keyidx=%d)", ifname, i); 232214501Srpaulo } 233214501Srpaulo } 234214501Srpaulo } 235214501Srpaulo#endif /* CONFIG_IEEE80211W */ 236214501Srpaulo} 237214501Srpaulo 238214501Srpaulo 239214501Srpaulostatic int hostapd_broadcast_wep_clear(struct hostapd_data *hapd) 240214501Srpaulo{ 241214501Srpaulo hostapd_broadcast_key_clear_iface(hapd, hapd->conf->iface); 242214501Srpaulo return 0; 243214501Srpaulo} 244214501Srpaulo 245214501Srpaulo 246214501Srpaulostatic int hostapd_broadcast_wep_set(struct hostapd_data *hapd) 247214501Srpaulo{ 248214501Srpaulo int errors = 0, idx; 249214501Srpaulo struct hostapd_ssid *ssid = &hapd->conf->ssid; 250214501Srpaulo 251214501Srpaulo idx = ssid->wep.idx; 252214501Srpaulo if (ssid->wep.default_len && 253252726Srpaulo hostapd_drv_set_key(hapd->conf->iface, 254252726Srpaulo hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, 255252726Srpaulo 1, NULL, 0, ssid->wep.key[idx], 256252726Srpaulo ssid->wep.len[idx])) { 257214501Srpaulo wpa_printf(MSG_WARNING, "Could not set WEP encryption."); 258214501Srpaulo errors++; 259214501Srpaulo } 260214501Srpaulo 261214501Srpaulo return errors; 262214501Srpaulo} 263214501Srpaulo 264252726Srpaulo 265252726Srpaulostatic void hostapd_free_hapd_data(struct hostapd_data *hapd) 266214501Srpaulo{ 267281806Srpaulo os_free(hapd->probereq_cb); 268281806Srpaulo hapd->probereq_cb = NULL; 269289549Srpaulo hapd->num_probereq_cb = 0; 270281806Srpaulo 271281806Srpaulo#ifdef CONFIG_P2P 272281806Srpaulo wpabuf_free(hapd->p2p_beacon_ie); 273281806Srpaulo hapd->p2p_beacon_ie = NULL; 274281806Srpaulo wpabuf_free(hapd->p2p_probe_resp_ie); 275281806Srpaulo hapd->p2p_probe_resp_ie = NULL; 276281806Srpaulo#endif /* CONFIG_P2P */ 277281806Srpaulo 278281806Srpaulo if (!hapd->started) { 279281806Srpaulo wpa_printf(MSG_ERROR, "%s: Interface %s wasn't started", 280281806Srpaulo __func__, hapd->conf->iface); 281281806Srpaulo return; 282281806Srpaulo } 283281806Srpaulo hapd->started = 0; 284281806Srpaulo 285281806Srpaulo wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface); 286214501Srpaulo iapp_deinit(hapd->iapp); 287214501Srpaulo hapd->iapp = NULL; 288214501Srpaulo accounting_deinit(hapd); 289214501Srpaulo hostapd_deinit_wpa(hapd); 290214501Srpaulo vlan_deinit(hapd); 291214501Srpaulo hostapd_acl_deinit(hapd); 292214501Srpaulo#ifndef CONFIG_NO_RADIUS 293214501Srpaulo radius_client_deinit(hapd->radius); 294214501Srpaulo hapd->radius = NULL; 295252726Srpaulo radius_das_deinit(hapd->radius_das); 296252726Srpaulo hapd->radius_das = NULL; 297214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 298214501Srpaulo 299214501Srpaulo hostapd_deinit_wps(hapd); 300214501Srpaulo 301214501Srpaulo authsrv_deinit(hapd); 302214501Srpaulo 303281806Srpaulo if (hapd->interface_added) { 304281806Srpaulo hapd->interface_added = 0; 305281806Srpaulo if (hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) { 306281806Srpaulo wpa_printf(MSG_WARNING, 307281806Srpaulo "Failed to remove BSS interface %s", 308281806Srpaulo hapd->conf->iface); 309281806Srpaulo hapd->interface_added = 1; 310281806Srpaulo } else { 311281806Srpaulo /* 312281806Srpaulo * Since this was a dynamically added interface, the 313281806Srpaulo * driver wrapper may have removed its internal instance 314281806Srpaulo * and hapd->drv_priv is not valid anymore. 315281806Srpaulo */ 316281806Srpaulo hapd->drv_priv = NULL; 317281806Srpaulo } 318214501Srpaulo } 319214501Srpaulo 320252726Srpaulo wpabuf_free(hapd->time_adv); 321252726Srpaulo 322252726Srpaulo#ifdef CONFIG_INTERWORKING 323252726Srpaulo gas_serv_deinit(hapd); 324252726Srpaulo#endif /* CONFIG_INTERWORKING */ 325252726Srpaulo 326281806Srpaulo bss_load_update_deinit(hapd); 327281806Srpaulo ndisc_snoop_deinit(hapd); 328281806Srpaulo dhcp_snoop_deinit(hapd); 329281806Srpaulo x_snoop_deinit(hapd); 330281806Srpaulo 331252726Srpaulo#ifdef CONFIG_SQLITE 332281806Srpaulo bin_clear_free(hapd->tmp_eap_user.identity, 333281806Srpaulo hapd->tmp_eap_user.identity_len); 334281806Srpaulo bin_clear_free(hapd->tmp_eap_user.password, 335281806Srpaulo hapd->tmp_eap_user.password_len); 336252726Srpaulo#endif /* CONFIG_SQLITE */ 337281806Srpaulo 338281806Srpaulo#ifdef CONFIG_MESH 339281806Srpaulo wpabuf_free(hapd->mesh_pending_auth); 340281806Srpaulo hapd->mesh_pending_auth = NULL; 341281806Srpaulo#endif /* CONFIG_MESH */ 342337817Scy 343337817Scy hostapd_clean_rrm(hapd); 344214501Srpaulo} 345214501Srpaulo 346214501Srpaulo 347214501Srpaulo/** 348252726Srpaulo * hostapd_cleanup - Per-BSS cleanup (deinitialization) 349252726Srpaulo * @hapd: Pointer to BSS data 350252726Srpaulo * 351252726Srpaulo * This function is used to free all per-BSS data structures and resources. 352281806Srpaulo * Most of the modules that are initialized in hostapd_setup_bss() are 353281806Srpaulo * deinitialized here. 354252726Srpaulo */ 355252726Srpaulostatic void hostapd_cleanup(struct hostapd_data *hapd) 356252726Srpaulo{ 357281806Srpaulo wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd, 358281806Srpaulo hapd->conf->iface); 359252726Srpaulo if (hapd->iface->interfaces && 360252726Srpaulo hapd->iface->interfaces->ctrl_iface_deinit) 361252726Srpaulo hapd->iface->interfaces->ctrl_iface_deinit(hapd); 362252726Srpaulo hostapd_free_hapd_data(hapd); 363252726Srpaulo} 364252726Srpaulo 365252726Srpaulo 366289549Srpaulostatic void sta_track_deinit(struct hostapd_iface *iface) 367289549Srpaulo{ 368289549Srpaulo struct hostapd_sta_info *info; 369289549Srpaulo 370289549Srpaulo if (!iface->num_sta_seen) 371289549Srpaulo return; 372289549Srpaulo 373289549Srpaulo while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info, 374289549Srpaulo list))) { 375289549Srpaulo dl_list_del(&info->list); 376289549Srpaulo iface->num_sta_seen--; 377337817Scy sta_track_del(info); 378289549Srpaulo } 379289549Srpaulo} 380289549Srpaulo 381289549Srpaulo 382252726Srpaulostatic void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) 383252726Srpaulo{ 384281806Srpaulo wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); 385281806Srpaulo#ifdef CONFIG_IEEE80211N 386281806Srpaulo#ifdef NEED_AP_MLME 387281806Srpaulo hostapd_stop_setup_timers(iface); 388281806Srpaulo#endif /* NEED_AP_MLME */ 389281806Srpaulo#endif /* CONFIG_IEEE80211N */ 390252726Srpaulo hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); 391252726Srpaulo iface->hw_features = NULL; 392252726Srpaulo os_free(iface->current_rates); 393252726Srpaulo iface->current_rates = NULL; 394252726Srpaulo os_free(iface->basic_rates); 395252726Srpaulo iface->basic_rates = NULL; 396252726Srpaulo ap_list_deinit(iface); 397289549Srpaulo sta_track_deinit(iface); 398252726Srpaulo} 399252726Srpaulo 400252726Srpaulo 401214501Srpaulo/** 402214501Srpaulo * hostapd_cleanup_iface - Complete per-interface cleanup 403214501Srpaulo * @iface: Pointer to interface data 404214501Srpaulo * 405214501Srpaulo * This function is called after per-BSS data structures are deinitialized 406214501Srpaulo * with hostapd_cleanup(). 407214501Srpaulo */ 408214501Srpaulostatic void hostapd_cleanup_iface(struct hostapd_iface *iface) 409214501Srpaulo{ 410281806Srpaulo wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); 411281806Srpaulo eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); 412281806Srpaulo 413252726Srpaulo hostapd_cleanup_iface_partial(iface); 414214501Srpaulo hostapd_config_free(iface->conf); 415214501Srpaulo iface->conf = NULL; 416214501Srpaulo 417214501Srpaulo os_free(iface->config_fname); 418214501Srpaulo os_free(iface->bss); 419281806Srpaulo wpa_printf(MSG_DEBUG, "%s: free iface=%p", __func__, iface); 420214501Srpaulo os_free(iface); 421214501Srpaulo} 422214501Srpaulo 423214501Srpaulo 424252726Srpaulostatic void hostapd_clear_wep(struct hostapd_data *hapd) 425252726Srpaulo{ 426281806Srpaulo if (hapd->drv_priv && !hapd->iface->driver_ap_teardown) { 427252726Srpaulo hostapd_set_privacy(hapd, 0); 428252726Srpaulo hostapd_broadcast_wep_clear(hapd); 429252726Srpaulo } 430252726Srpaulo} 431252726Srpaulo 432252726Srpaulo 433214501Srpaulostatic int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd) 434214501Srpaulo{ 435214501Srpaulo int i; 436214501Srpaulo 437214501Srpaulo hostapd_broadcast_wep_set(hapd); 438214501Srpaulo 439214501Srpaulo if (hapd->conf->ssid.wep.default_len) { 440214501Srpaulo hostapd_set_privacy(hapd, 1); 441214501Srpaulo return 0; 442214501Srpaulo } 443214501Srpaulo 444252726Srpaulo /* 445252726Srpaulo * When IEEE 802.1X is not enabled, the driver may need to know how to 446252726Srpaulo * set authentication algorithms for static WEP. 447252726Srpaulo */ 448252726Srpaulo hostapd_drv_set_authmode(hapd, hapd->conf->auth_algs); 449252726Srpaulo 450214501Srpaulo for (i = 0; i < 4; i++) { 451214501Srpaulo if (hapd->conf->ssid.wep.key[i] && 452252726Srpaulo hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i, 453252726Srpaulo i == hapd->conf->ssid.wep.idx, NULL, 0, 454252726Srpaulo hapd->conf->ssid.wep.key[i], 455252726Srpaulo hapd->conf->ssid.wep.len[i])) { 456214501Srpaulo wpa_printf(MSG_WARNING, "Could not set WEP " 457214501Srpaulo "encryption."); 458214501Srpaulo return -1; 459214501Srpaulo } 460214501Srpaulo if (hapd->conf->ssid.wep.key[i] && 461214501Srpaulo i == hapd->conf->ssid.wep.idx) 462214501Srpaulo hostapd_set_privacy(hapd, 1); 463214501Srpaulo } 464214501Srpaulo 465214501Srpaulo return 0; 466214501Srpaulo} 467214501Srpaulo 468214501Srpaulo 469252726Srpaulostatic int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason) 470214501Srpaulo{ 471214501Srpaulo int ret = 0; 472252726Srpaulo u8 addr[ETH_ALEN]; 473214501Srpaulo 474214501Srpaulo if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL) 475214501Srpaulo return 0; 476214501Srpaulo 477281806Srpaulo if (!hapd->iface->driver_ap_teardown) { 478281806Srpaulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, 479281806Srpaulo "Flushing old station entries"); 480281806Srpaulo 481281806Srpaulo if (hostapd_flush(hapd)) { 482281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_WARNING, 483281806Srpaulo "Could not connect to kernel driver"); 484281806Srpaulo ret = -1; 485281806Srpaulo } 486214501Srpaulo } 487252726Srpaulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations"); 488252726Srpaulo os_memset(addr, 0xff, ETH_ALEN); 489252726Srpaulo hostapd_drv_sta_deauth(hapd, addr, reason); 490252726Srpaulo hostapd_free_stas(hapd); 491214501Srpaulo 492214501Srpaulo return ret; 493214501Srpaulo} 494214501Srpaulo 495214501Srpaulo 496281806Srpaulostatic void hostapd_bss_deinit_no_free(struct hostapd_data *hapd) 497281806Srpaulo{ 498281806Srpaulo hostapd_free_stas(hapd); 499281806Srpaulo hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING); 500281806Srpaulo hostapd_clear_wep(hapd); 501281806Srpaulo} 502281806Srpaulo 503281806Srpaulo 504214501Srpaulo/** 505214501Srpaulo * hostapd_validate_bssid_configuration - Validate BSSID configuration 506214501Srpaulo * @iface: Pointer to interface data 507214501Srpaulo * Returns: 0 on success, -1 on failure 508214501Srpaulo * 509214501Srpaulo * This function is used to validate that the configured BSSIDs are valid. 510214501Srpaulo */ 511214501Srpaulostatic int hostapd_validate_bssid_configuration(struct hostapd_iface *iface) 512214501Srpaulo{ 513214501Srpaulo u8 mask[ETH_ALEN] = { 0 }; 514214501Srpaulo struct hostapd_data *hapd = iface->bss[0]; 515214501Srpaulo unsigned int i = iface->conf->num_bss, bits = 0, j; 516214501Srpaulo int auto_addr = 0; 517214501Srpaulo 518214501Srpaulo if (hostapd_drv_none(hapd)) 519214501Srpaulo return 0; 520214501Srpaulo 521337817Scy if (iface->conf->use_driver_iface_addr) 522337817Scy return 0; 523337817Scy 524214501Srpaulo /* Generate BSSID mask that is large enough to cover the BSSIDs. */ 525214501Srpaulo 526214501Srpaulo /* Determine the bits necessary to cover the number of BSSIDs. */ 527214501Srpaulo for (i--; i; i >>= 1) 528214501Srpaulo bits++; 529214501Srpaulo 530214501Srpaulo /* Determine the bits necessary to any configured BSSIDs, 531214501Srpaulo if they are higher than the number of BSSIDs. */ 532214501Srpaulo for (j = 0; j < iface->conf->num_bss; j++) { 533337817Scy if (is_zero_ether_addr(iface->conf->bss[j]->bssid)) { 534214501Srpaulo if (j) 535214501Srpaulo auto_addr++; 536214501Srpaulo continue; 537214501Srpaulo } 538214501Srpaulo 539214501Srpaulo for (i = 0; i < ETH_ALEN; i++) { 540214501Srpaulo mask[i] |= 541281806Srpaulo iface->conf->bss[j]->bssid[i] ^ 542214501Srpaulo hapd->own_addr[i]; 543214501Srpaulo } 544214501Srpaulo } 545214501Srpaulo 546214501Srpaulo if (!auto_addr) 547214501Srpaulo goto skip_mask_ext; 548214501Srpaulo 549214501Srpaulo for (i = 0; i < ETH_ALEN && mask[i] == 0; i++) 550214501Srpaulo ; 551214501Srpaulo j = 0; 552214501Srpaulo if (i < ETH_ALEN) { 553214501Srpaulo j = (5 - i) * 8; 554214501Srpaulo 555214501Srpaulo while (mask[i] != 0) { 556214501Srpaulo mask[i] >>= 1; 557214501Srpaulo j++; 558214501Srpaulo } 559214501Srpaulo } 560214501Srpaulo 561214501Srpaulo if (bits < j) 562214501Srpaulo bits = j; 563214501Srpaulo 564214501Srpaulo if (bits > 40) { 565214501Srpaulo wpa_printf(MSG_ERROR, "Too many bits in the BSSID mask (%u)", 566214501Srpaulo bits); 567214501Srpaulo return -1; 568214501Srpaulo } 569214501Srpaulo 570214501Srpaulo os_memset(mask, 0xff, ETH_ALEN); 571214501Srpaulo j = bits / 8; 572214501Srpaulo for (i = 5; i > 5 - j; i--) 573214501Srpaulo mask[i] = 0; 574214501Srpaulo j = bits % 8; 575214501Srpaulo while (j--) 576214501Srpaulo mask[i] <<= 1; 577214501Srpaulo 578214501Srpauloskip_mask_ext: 579214501Srpaulo wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)", 580214501Srpaulo (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits); 581214501Srpaulo 582214501Srpaulo if (!auto_addr) 583214501Srpaulo return 0; 584214501Srpaulo 585214501Srpaulo for (i = 0; i < ETH_ALEN; i++) { 586214501Srpaulo if ((hapd->own_addr[i] & mask[i]) != hapd->own_addr[i]) { 587214501Srpaulo wpa_printf(MSG_ERROR, "Invalid BSSID mask " MACSTR 588214501Srpaulo " for start address " MACSTR ".", 589214501Srpaulo MAC2STR(mask), MAC2STR(hapd->own_addr)); 590214501Srpaulo wpa_printf(MSG_ERROR, "Start address must be the " 591214501Srpaulo "first address in the block (i.e., addr " 592214501Srpaulo "AND mask == addr)."); 593214501Srpaulo return -1; 594214501Srpaulo } 595214501Srpaulo } 596214501Srpaulo 597214501Srpaulo return 0; 598214501Srpaulo} 599214501Srpaulo 600214501Srpaulo 601214501Srpaulostatic int mac_in_conf(struct hostapd_config *conf, const void *a) 602214501Srpaulo{ 603214501Srpaulo size_t i; 604214501Srpaulo 605214501Srpaulo for (i = 0; i < conf->num_bss; i++) { 606281806Srpaulo if (hostapd_mac_comp(conf->bss[i]->bssid, a) == 0) { 607214501Srpaulo return 1; 608214501Srpaulo } 609214501Srpaulo } 610214501Srpaulo 611214501Srpaulo return 0; 612214501Srpaulo} 613214501Srpaulo 614214501Srpaulo 615252726Srpaulo#ifndef CONFIG_NO_RADIUS 616214501Srpaulo 617252726Srpaulostatic int hostapd_das_nas_mismatch(struct hostapd_data *hapd, 618252726Srpaulo struct radius_das_attrs *attr) 619252726Srpaulo{ 620281806Srpaulo if (attr->nas_identifier && 621281806Srpaulo (!hapd->conf->nas_identifier || 622281806Srpaulo os_strlen(hapd->conf->nas_identifier) != 623281806Srpaulo attr->nas_identifier_len || 624281806Srpaulo os_memcmp(hapd->conf->nas_identifier, attr->nas_identifier, 625281806Srpaulo attr->nas_identifier_len) != 0)) { 626281806Srpaulo wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-Identifier mismatch"); 627281806Srpaulo return 1; 628281806Srpaulo } 629281806Srpaulo 630281806Srpaulo if (attr->nas_ip_addr && 631281806Srpaulo (hapd->conf->own_ip_addr.af != AF_INET || 632281806Srpaulo os_memcmp(&hapd->conf->own_ip_addr.u.v4, attr->nas_ip_addr, 4) != 633281806Srpaulo 0)) { 634281806Srpaulo wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-IP-Address mismatch"); 635281806Srpaulo return 1; 636281806Srpaulo } 637281806Srpaulo 638281806Srpaulo#ifdef CONFIG_IPV6 639281806Srpaulo if (attr->nas_ipv6_addr && 640281806Srpaulo (hapd->conf->own_ip_addr.af != AF_INET6 || 641281806Srpaulo os_memcmp(&hapd->conf->own_ip_addr.u.v6, attr->nas_ipv6_addr, 16) 642281806Srpaulo != 0)) { 643281806Srpaulo wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-IPv6-Address mismatch"); 644281806Srpaulo return 1; 645281806Srpaulo } 646281806Srpaulo#endif /* CONFIG_IPV6 */ 647281806Srpaulo 648252726Srpaulo return 0; 649252726Srpaulo} 650214501Srpaulo 651252726Srpaulo 652252726Srpaulostatic struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd, 653281806Srpaulo struct radius_das_attrs *attr, 654281806Srpaulo int *multi) 655252726Srpaulo{ 656281806Srpaulo struct sta_info *selected, *sta; 657252726Srpaulo char buf[128]; 658281806Srpaulo int num_attr = 0; 659281806Srpaulo int count; 660252726Srpaulo 661281806Srpaulo *multi = 0; 662281806Srpaulo 663281806Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) 664281806Srpaulo sta->radius_das_match = 1; 665281806Srpaulo 666281806Srpaulo if (attr->sta_addr) { 667281806Srpaulo num_attr++; 668252726Srpaulo sta = ap_get_sta(hapd, attr->sta_addr); 669281806Srpaulo if (!sta) { 670281806Srpaulo wpa_printf(MSG_DEBUG, 671281806Srpaulo "RADIUS DAS: No Calling-Station-Id match"); 672281806Srpaulo return NULL; 673281806Srpaulo } 674252726Srpaulo 675281806Srpaulo selected = sta; 676252726Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 677281806Srpaulo if (sta != selected) 678281806Srpaulo sta->radius_das_match = 0; 679281806Srpaulo } 680281806Srpaulo wpa_printf(MSG_DEBUG, "RADIUS DAS: Calling-Station-Id match"); 681281806Srpaulo } 682281806Srpaulo 683281806Srpaulo if (attr->acct_session_id) { 684281806Srpaulo num_attr++; 685337817Scy if (attr->acct_session_id_len != 16) { 686281806Srpaulo wpa_printf(MSG_DEBUG, 687281806Srpaulo "RADIUS DAS: Acct-Session-Id cannot match"); 688281806Srpaulo return NULL; 689281806Srpaulo } 690281806Srpaulo count = 0; 691281806Srpaulo 692281806Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 693281806Srpaulo if (!sta->radius_das_match) 694281806Srpaulo continue; 695337817Scy os_snprintf(buf, sizeof(buf), "%016llX", 696337817Scy (unsigned long long) sta->acct_session_id); 697337817Scy if (os_memcmp(attr->acct_session_id, buf, 16) != 0) 698281806Srpaulo sta->radius_das_match = 0; 699281806Srpaulo else 700281806Srpaulo count++; 701252726Srpaulo } 702281806Srpaulo 703281806Srpaulo if (count == 0) { 704281806Srpaulo wpa_printf(MSG_DEBUG, 705281806Srpaulo "RADIUS DAS: No matches remaining after Acct-Session-Id check"); 706281806Srpaulo return NULL; 707281806Srpaulo } 708281806Srpaulo wpa_printf(MSG_DEBUG, "RADIUS DAS: Acct-Session-Id match"); 709252726Srpaulo } 710252726Srpaulo 711281806Srpaulo if (attr->acct_multi_session_id) { 712281806Srpaulo num_attr++; 713337817Scy if (attr->acct_multi_session_id_len != 16) { 714281806Srpaulo wpa_printf(MSG_DEBUG, 715281806Srpaulo "RADIUS DAS: Acct-Multi-Session-Id cannot match"); 716281806Srpaulo return NULL; 717281806Srpaulo } 718281806Srpaulo count = 0; 719281806Srpaulo 720252726Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 721281806Srpaulo if (!sta->radius_das_match) 722281806Srpaulo continue; 723281806Srpaulo if (!sta->eapol_sm || 724337817Scy !sta->eapol_sm->acct_multi_session_id) { 725281806Srpaulo sta->radius_das_match = 0; 726281806Srpaulo continue; 727281806Srpaulo } 728337817Scy os_snprintf(buf, sizeof(buf), "%016llX", 729337817Scy (unsigned long long) 730337817Scy sta->eapol_sm->acct_multi_session_id); 731337817Scy if (os_memcmp(attr->acct_multi_session_id, buf, 16) != 732281806Srpaulo 0) 733281806Srpaulo sta->radius_das_match = 0; 734281806Srpaulo else 735281806Srpaulo count++; 736281806Srpaulo } 737281806Srpaulo 738281806Srpaulo if (count == 0) { 739281806Srpaulo wpa_printf(MSG_DEBUG, 740281806Srpaulo "RADIUS DAS: No matches remaining after Acct-Multi-Session-Id check"); 741281806Srpaulo return NULL; 742281806Srpaulo } 743281806Srpaulo wpa_printf(MSG_DEBUG, 744281806Srpaulo "RADIUS DAS: Acct-Multi-Session-Id match"); 745281806Srpaulo } 746281806Srpaulo 747281806Srpaulo if (attr->cui) { 748281806Srpaulo num_attr++; 749281806Srpaulo count = 0; 750281806Srpaulo 751281806Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 752252726Srpaulo struct wpabuf *cui; 753281806Srpaulo 754281806Srpaulo if (!sta->radius_das_match) 755281806Srpaulo continue; 756252726Srpaulo cui = ieee802_1x_get_radius_cui(sta->eapol_sm); 757281806Srpaulo if (!cui || wpabuf_len(cui) != attr->cui_len || 758252726Srpaulo os_memcmp(wpabuf_head(cui), attr->cui, 759281806Srpaulo attr->cui_len) != 0) 760281806Srpaulo sta->radius_das_match = 0; 761281806Srpaulo else 762281806Srpaulo count++; 763252726Srpaulo } 764281806Srpaulo 765281806Srpaulo if (count == 0) { 766281806Srpaulo wpa_printf(MSG_DEBUG, 767281806Srpaulo "RADIUS DAS: No matches remaining after Chargeable-User-Identity check"); 768281806Srpaulo return NULL; 769281806Srpaulo } 770281806Srpaulo wpa_printf(MSG_DEBUG, 771281806Srpaulo "RADIUS DAS: Chargeable-User-Identity match"); 772252726Srpaulo } 773252726Srpaulo 774281806Srpaulo if (attr->user_name) { 775281806Srpaulo num_attr++; 776281806Srpaulo count = 0; 777281806Srpaulo 778252726Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 779252726Srpaulo u8 *identity; 780252726Srpaulo size_t identity_len; 781281806Srpaulo 782281806Srpaulo if (!sta->radius_das_match) 783281806Srpaulo continue; 784252726Srpaulo identity = ieee802_1x_get_identity(sta->eapol_sm, 785252726Srpaulo &identity_len); 786281806Srpaulo if (!identity || 787281806Srpaulo identity_len != attr->user_name_len || 788252726Srpaulo os_memcmp(identity, attr->user_name, identity_len) 789281806Srpaulo != 0) 790281806Srpaulo sta->radius_das_match = 0; 791281806Srpaulo else 792281806Srpaulo count++; 793252726Srpaulo } 794281806Srpaulo 795281806Srpaulo if (count == 0) { 796281806Srpaulo wpa_printf(MSG_DEBUG, 797281806Srpaulo "RADIUS DAS: No matches remaining after User-Name check"); 798281806Srpaulo return NULL; 799281806Srpaulo } 800281806Srpaulo wpa_printf(MSG_DEBUG, 801281806Srpaulo "RADIUS DAS: User-Name match"); 802252726Srpaulo } 803252726Srpaulo 804281806Srpaulo if (num_attr == 0) { 805281806Srpaulo /* 806281806Srpaulo * In theory, we could match all current associations, but it 807281806Srpaulo * seems safer to just reject requests that do not include any 808281806Srpaulo * session identification attributes. 809281806Srpaulo */ 810281806Srpaulo wpa_printf(MSG_DEBUG, 811281806Srpaulo "RADIUS DAS: No session identification attributes included"); 812281806Srpaulo return NULL; 813281806Srpaulo } 814281806Srpaulo 815281806Srpaulo selected = NULL; 816281806Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 817281806Srpaulo if (sta->radius_das_match) { 818281806Srpaulo if (selected) { 819281806Srpaulo *multi = 1; 820281806Srpaulo return NULL; 821281806Srpaulo } 822281806Srpaulo selected = sta; 823281806Srpaulo } 824281806Srpaulo } 825281806Srpaulo 826281806Srpaulo return selected; 827252726Srpaulo} 828252726Srpaulo 829252726Srpaulo 830281806Srpaulostatic int hostapd_das_disconnect_pmksa(struct hostapd_data *hapd, 831281806Srpaulo struct radius_das_attrs *attr) 832281806Srpaulo{ 833281806Srpaulo if (!hapd->wpa_auth) 834281806Srpaulo return -1; 835281806Srpaulo return wpa_auth_radius_das_disconnect_pmksa(hapd->wpa_auth, attr); 836281806Srpaulo} 837281806Srpaulo 838281806Srpaulo 839252726Srpaulostatic enum radius_das_res 840252726Srpaulohostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr) 841252726Srpaulo{ 842252726Srpaulo struct hostapd_data *hapd = ctx; 843252726Srpaulo struct sta_info *sta; 844281806Srpaulo int multi; 845252726Srpaulo 846252726Srpaulo if (hostapd_das_nas_mismatch(hapd, attr)) 847252726Srpaulo return RADIUS_DAS_NAS_MISMATCH; 848252726Srpaulo 849281806Srpaulo sta = hostapd_das_find_sta(hapd, attr, &multi); 850281806Srpaulo if (sta == NULL) { 851281806Srpaulo if (multi) { 852281806Srpaulo wpa_printf(MSG_DEBUG, 853281806Srpaulo "RADIUS DAS: Multiple sessions match - not supported"); 854281806Srpaulo return RADIUS_DAS_MULTI_SESSION_MATCH; 855281806Srpaulo } 856281806Srpaulo if (hostapd_das_disconnect_pmksa(hapd, attr) == 0) { 857281806Srpaulo wpa_printf(MSG_DEBUG, 858281806Srpaulo "RADIUS DAS: PMKSA cache entry matched"); 859281806Srpaulo return RADIUS_DAS_SUCCESS; 860281806Srpaulo } 861281806Srpaulo wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found"); 862252726Srpaulo return RADIUS_DAS_SESSION_NOT_FOUND; 863281806Srpaulo } 864252726Srpaulo 865281806Srpaulo wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR 866281806Srpaulo " - disconnecting", MAC2STR(sta->addr)); 867281806Srpaulo wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr); 868281806Srpaulo 869252726Srpaulo hostapd_drv_sta_deauth(hapd, sta->addr, 870252726Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 871252726Srpaulo ap_sta_deauthenticate(hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID); 872252726Srpaulo 873252726Srpaulo return RADIUS_DAS_SUCCESS; 874252726Srpaulo} 875252726Srpaulo 876252726Srpaulo#endif /* CONFIG_NO_RADIUS */ 877252726Srpaulo 878252726Srpaulo 879214501Srpaulo/** 880214501Srpaulo * hostapd_setup_bss - Per-BSS setup (initialization) 881214501Srpaulo * @hapd: Pointer to BSS data 882281806Srpaulo * @first: Whether this BSS is the first BSS of an interface; -1 = not first, 883281806Srpaulo * but interface may exist 884214501Srpaulo * 885214501Srpaulo * This function is used to initialize all per-BSS data structures and 886214501Srpaulo * resources. This gets called in a loop for each BSS when an interface is 887214501Srpaulo * initialized. Most of the modules that are initialized here will be 888214501Srpaulo * deinitialized in hostapd_cleanup(). 889214501Srpaulo */ 890214501Srpaulostatic int hostapd_setup_bss(struct hostapd_data *hapd, int first) 891214501Srpaulo{ 892214501Srpaulo struct hostapd_bss_config *conf = hapd->conf; 893289549Srpaulo u8 ssid[SSID_MAX_LEN + 1]; 894214501Srpaulo int ssid_len, set_ssid; 895214501Srpaulo char force_ifname[IFNAMSIZ]; 896214501Srpaulo u8 if_addr[ETH_ALEN]; 897281806Srpaulo int flush_old_stations = 1; 898214501Srpaulo 899281806Srpaulo wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s), first=%d)", 900281806Srpaulo __func__, hapd, conf->iface, first); 901281806Srpaulo 902281806Srpaulo#ifdef EAP_SERVER_TNC 903281806Srpaulo if (conf->tnc && tncs_global_init() < 0) { 904281806Srpaulo wpa_printf(MSG_ERROR, "Failed to initialize TNCS"); 905281806Srpaulo return -1; 906281806Srpaulo } 907281806Srpaulo#endif /* EAP_SERVER_TNC */ 908281806Srpaulo 909281806Srpaulo if (hapd->started) { 910281806Srpaulo wpa_printf(MSG_ERROR, "%s: Interface %s was already started", 911281806Srpaulo __func__, conf->iface); 912281806Srpaulo return -1; 913281806Srpaulo } 914281806Srpaulo hapd->started = 1; 915281806Srpaulo 916281806Srpaulo if (!first || first == -1) { 917337817Scy u8 *addr = hapd->own_addr; 918337817Scy 919337817Scy if (!is_zero_ether_addr(conf->bssid)) { 920214501Srpaulo /* Allocate the configured BSSID. */ 921281806Srpaulo os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN); 922214501Srpaulo 923214501Srpaulo if (hostapd_mac_comp(hapd->own_addr, 924214501Srpaulo hapd->iface->bss[0]->own_addr) == 925214501Srpaulo 0) { 926214501Srpaulo wpa_printf(MSG_ERROR, "BSS '%s' may not have " 927214501Srpaulo "BSSID set to the MAC address of " 928281806Srpaulo "the radio", conf->iface); 929214501Srpaulo return -1; 930214501Srpaulo } 931337817Scy } else if (hapd->iconf->use_driver_iface_addr) { 932337817Scy addr = NULL; 933337817Scy } else { 934337817Scy /* Allocate the next available BSSID. */ 935337817Scy do { 936337817Scy inc_byte_array(hapd->own_addr, ETH_ALEN); 937337817Scy } while (mac_in_conf(hapd->iconf, hapd->own_addr)); 938214501Srpaulo } 939214501Srpaulo 940214501Srpaulo hapd->interface_added = 1; 941214501Srpaulo if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS, 942337817Scy conf->iface, addr, hapd, 943252726Srpaulo &hapd->drv_priv, force_ifname, if_addr, 944281806Srpaulo conf->bridge[0] ? conf->bridge : NULL, 945281806Srpaulo first == -1)) { 946214501Srpaulo wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID=" 947214501Srpaulo MACSTR ")", MAC2STR(hapd->own_addr)); 948281806Srpaulo hapd->interface_added = 0; 949214501Srpaulo return -1; 950214501Srpaulo } 951337817Scy 952337817Scy if (!addr) 953337817Scy os_memcpy(hapd->own_addr, if_addr, ETH_ALEN); 954214501Srpaulo } 955214501Srpaulo 956252726Srpaulo if (conf->wmm_enabled < 0) 957252726Srpaulo conf->wmm_enabled = hapd->iconf->ieee80211n; 958252726Srpaulo 959337817Scy#ifdef CONFIG_IEEE80211R 960337817Scy if (is_zero_ether_addr(conf->r1_key_holder)) 961337817Scy os_memcpy(conf->r1_key_holder, hapd->own_addr, ETH_ALEN); 962337817Scy#endif /* CONFIG_IEEE80211R */ 963337817Scy 964281806Srpaulo#ifdef CONFIG_MESH 965281806Srpaulo if (hapd->iface->mconf == NULL) 966281806Srpaulo flush_old_stations = 0; 967281806Srpaulo#endif /* CONFIG_MESH */ 968281806Srpaulo 969281806Srpaulo if (flush_old_stations) 970281806Srpaulo hostapd_flush_old_stations(hapd, 971281806Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 972214501Srpaulo hostapd_set_privacy(hapd, 0); 973214501Srpaulo 974214501Srpaulo hostapd_broadcast_wep_clear(hapd); 975281806Srpaulo if (hostapd_setup_encryption(conf->iface, hapd)) 976214501Srpaulo return -1; 977214501Srpaulo 978214501Srpaulo /* 979214501Srpaulo * Fetch the SSID from the system and use it or, 980214501Srpaulo * if one was specified in the config file, verify they 981214501Srpaulo * match. 982214501Srpaulo */ 983214501Srpaulo ssid_len = hostapd_get_ssid(hapd, ssid, sizeof(ssid)); 984214501Srpaulo if (ssid_len < 0) { 985214501Srpaulo wpa_printf(MSG_ERROR, "Could not read SSID from system"); 986214501Srpaulo return -1; 987214501Srpaulo } 988214501Srpaulo if (conf->ssid.ssid_set) { 989214501Srpaulo /* 990214501Srpaulo * If SSID is specified in the config file and it differs 991214501Srpaulo * from what is being used then force installation of the 992214501Srpaulo * new SSID. 993214501Srpaulo */ 994214501Srpaulo set_ssid = (conf->ssid.ssid_len != (size_t) ssid_len || 995214501Srpaulo os_memcmp(conf->ssid.ssid, ssid, ssid_len) != 0); 996214501Srpaulo } else { 997214501Srpaulo /* 998214501Srpaulo * No SSID in the config file; just use the one we got 999214501Srpaulo * from the system. 1000214501Srpaulo */ 1001214501Srpaulo set_ssid = 0; 1002214501Srpaulo conf->ssid.ssid_len = ssid_len; 1003214501Srpaulo os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len); 1004214501Srpaulo } 1005214501Srpaulo 1006214501Srpaulo if (!hostapd_drv_none(hapd)) { 1007214501Srpaulo wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR 1008252726Srpaulo " and ssid \"%s\"", 1009281806Srpaulo conf->iface, MAC2STR(hapd->own_addr), 1010281806Srpaulo wpa_ssid_txt(conf->ssid.ssid, conf->ssid.ssid_len)); 1011214501Srpaulo } 1012214501Srpaulo 1013214501Srpaulo if (hostapd_setup_wpa_psk(conf)) { 1014214501Srpaulo wpa_printf(MSG_ERROR, "WPA-PSK setup failed."); 1015214501Srpaulo return -1; 1016214501Srpaulo } 1017214501Srpaulo 1018214501Srpaulo /* Set SSID for the kernel driver (to be used in beacon and probe 1019214501Srpaulo * response frames) */ 1020252726Srpaulo if (set_ssid && hostapd_set_ssid(hapd, conf->ssid.ssid, 1021214501Srpaulo conf->ssid.ssid_len)) { 1022214501Srpaulo wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); 1023214501Srpaulo return -1; 1024214501Srpaulo } 1025214501Srpaulo 1026281806Srpaulo if (wpa_debug_level <= MSG_MSGDUMP) 1027214501Srpaulo conf->radius->msg_dumps = 1; 1028214501Srpaulo#ifndef CONFIG_NO_RADIUS 1029214501Srpaulo hapd->radius = radius_client_init(hapd, conf->radius); 1030214501Srpaulo if (hapd->radius == NULL) { 1031214501Srpaulo wpa_printf(MSG_ERROR, "RADIUS client initialization failed."); 1032214501Srpaulo return -1; 1033214501Srpaulo } 1034252726Srpaulo 1035281806Srpaulo if (conf->radius_das_port) { 1036252726Srpaulo struct radius_das_conf das_conf; 1037252726Srpaulo os_memset(&das_conf, 0, sizeof(das_conf)); 1038281806Srpaulo das_conf.port = conf->radius_das_port; 1039281806Srpaulo das_conf.shared_secret = conf->radius_das_shared_secret; 1040252726Srpaulo das_conf.shared_secret_len = 1041281806Srpaulo conf->radius_das_shared_secret_len; 1042281806Srpaulo das_conf.client_addr = &conf->radius_das_client_addr; 1043281806Srpaulo das_conf.time_window = conf->radius_das_time_window; 1044252726Srpaulo das_conf.require_event_timestamp = 1045281806Srpaulo conf->radius_das_require_event_timestamp; 1046337817Scy das_conf.require_message_authenticator = 1047337817Scy conf->radius_das_require_message_authenticator; 1048252726Srpaulo das_conf.ctx = hapd; 1049252726Srpaulo das_conf.disconnect = hostapd_das_disconnect; 1050252726Srpaulo hapd->radius_das = radius_das_init(&das_conf); 1051252726Srpaulo if (hapd->radius_das == NULL) { 1052252726Srpaulo wpa_printf(MSG_ERROR, "RADIUS DAS initialization " 1053252726Srpaulo "failed."); 1054252726Srpaulo return -1; 1055252726Srpaulo } 1056252726Srpaulo } 1057214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 1058214501Srpaulo 1059214501Srpaulo if (hostapd_acl_init(hapd)) { 1060214501Srpaulo wpa_printf(MSG_ERROR, "ACL initialization failed."); 1061214501Srpaulo return -1; 1062214501Srpaulo } 1063214501Srpaulo if (hostapd_init_wps(hapd, conf)) 1064214501Srpaulo return -1; 1065214501Srpaulo 1066214501Srpaulo if (authsrv_init(hapd) < 0) 1067214501Srpaulo return -1; 1068214501Srpaulo 1069214501Srpaulo if (ieee802_1x_init(hapd)) { 1070214501Srpaulo wpa_printf(MSG_ERROR, "IEEE 802.1X initialization failed."); 1071214501Srpaulo return -1; 1072214501Srpaulo } 1073214501Srpaulo 1074281806Srpaulo if ((conf->wpa || conf->osen) && hostapd_setup_wpa(hapd)) 1075214501Srpaulo return -1; 1076214501Srpaulo 1077214501Srpaulo if (accounting_init(hapd)) { 1078214501Srpaulo wpa_printf(MSG_ERROR, "Accounting initialization failed."); 1079214501Srpaulo return -1; 1080214501Srpaulo } 1081214501Srpaulo 1082281806Srpaulo if (conf->ieee802_11f && 1083281806Srpaulo (hapd->iapp = iapp_init(hapd, conf->iapp_iface)) == NULL) { 1084214501Srpaulo wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization " 1085214501Srpaulo "failed."); 1086214501Srpaulo return -1; 1087214501Srpaulo } 1088214501Srpaulo 1089252726Srpaulo#ifdef CONFIG_INTERWORKING 1090252726Srpaulo if (gas_serv_init(hapd)) { 1091252726Srpaulo wpa_printf(MSG_ERROR, "GAS server initialization failed"); 1092252726Srpaulo return -1; 1093252726Srpaulo } 1094281806Srpaulo 1095281806Srpaulo if (conf->qos_map_set_len && 1096281806Srpaulo hostapd_drv_set_qos_map(hapd, conf->qos_map_set, 1097281806Srpaulo conf->qos_map_set_len)) { 1098281806Srpaulo wpa_printf(MSG_ERROR, "Failed to initialize QoS Map"); 1099281806Srpaulo return -1; 1100281806Srpaulo } 1101252726Srpaulo#endif /* CONFIG_INTERWORKING */ 1102252726Srpaulo 1103281806Srpaulo if (conf->bss_load_update_period && bss_load_update_init(hapd)) { 1104281806Srpaulo wpa_printf(MSG_ERROR, "BSS Load initialization failed"); 1105214501Srpaulo return -1; 1106214501Srpaulo } 1107214501Srpaulo 1108281806Srpaulo if (conf->proxy_arp) { 1109281806Srpaulo if (x_snoop_init(hapd)) { 1110281806Srpaulo wpa_printf(MSG_ERROR, 1111281806Srpaulo "Generic snooping infrastructure initialization failed"); 1112281806Srpaulo return -1; 1113281806Srpaulo } 1114281806Srpaulo 1115281806Srpaulo if (dhcp_snoop_init(hapd)) { 1116281806Srpaulo wpa_printf(MSG_ERROR, 1117281806Srpaulo "DHCP snooping initialization failed"); 1118281806Srpaulo return -1; 1119281806Srpaulo } 1120281806Srpaulo 1121281806Srpaulo if (ndisc_snoop_init(hapd)) { 1122281806Srpaulo wpa_printf(MSG_ERROR, 1123281806Srpaulo "Neighbor Discovery snooping initialization failed"); 1124281806Srpaulo return -1; 1125281806Srpaulo } 1126281806Srpaulo } 1127281806Srpaulo 1128214501Srpaulo if (!hostapd_drv_none(hapd) && vlan_init(hapd)) { 1129214501Srpaulo wpa_printf(MSG_ERROR, "VLAN initialization failed."); 1130214501Srpaulo return -1; 1131214501Srpaulo } 1132214501Srpaulo 1133281806Srpaulo if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0) 1134281806Srpaulo return -1; 1135214501Srpaulo 1136252726Srpaulo if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0) 1137252726Srpaulo return -1; 1138252726Srpaulo 1139252726Srpaulo if (hapd->driver && hapd->driver->set_operstate) 1140252726Srpaulo hapd->driver->set_operstate(hapd->drv_priv, 1); 1141252726Srpaulo 1142214501Srpaulo return 0; 1143214501Srpaulo} 1144214501Srpaulo 1145214501Srpaulo 1146214501Srpaulostatic void hostapd_tx_queue_params(struct hostapd_iface *iface) 1147214501Srpaulo{ 1148214501Srpaulo struct hostapd_data *hapd = iface->bss[0]; 1149214501Srpaulo int i; 1150214501Srpaulo struct hostapd_tx_queue_params *p; 1151214501Srpaulo 1152281806Srpaulo#ifdef CONFIG_MESH 1153281806Srpaulo if (iface->mconf == NULL) 1154281806Srpaulo return; 1155281806Srpaulo#endif /* CONFIG_MESH */ 1156281806Srpaulo 1157214501Srpaulo for (i = 0; i < NUM_TX_QUEUES; i++) { 1158214501Srpaulo p = &iface->conf->tx_queue[i]; 1159214501Srpaulo 1160214501Srpaulo if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin, 1161214501Srpaulo p->cwmax, p->burst)) { 1162214501Srpaulo wpa_printf(MSG_DEBUG, "Failed to set TX queue " 1163214501Srpaulo "parameters for queue %d.", i); 1164214501Srpaulo /* Continue anyway */ 1165214501Srpaulo } 1166214501Srpaulo } 1167214501Srpaulo} 1168214501Srpaulo 1169214501Srpaulo 1170281806Srpaulostatic int hostapd_set_acl_list(struct hostapd_data *hapd, 1171281806Srpaulo struct mac_acl_entry *mac_acl, 1172281806Srpaulo int n_entries, u8 accept_acl) 1173281806Srpaulo{ 1174281806Srpaulo struct hostapd_acl_params *acl_params; 1175281806Srpaulo int i, err; 1176281806Srpaulo 1177281806Srpaulo acl_params = os_zalloc(sizeof(*acl_params) + 1178281806Srpaulo (n_entries * sizeof(acl_params->mac_acl[0]))); 1179281806Srpaulo if (!acl_params) 1180281806Srpaulo return -ENOMEM; 1181281806Srpaulo 1182281806Srpaulo for (i = 0; i < n_entries; i++) 1183281806Srpaulo os_memcpy(acl_params->mac_acl[i].addr, mac_acl[i].addr, 1184281806Srpaulo ETH_ALEN); 1185281806Srpaulo 1186281806Srpaulo acl_params->acl_policy = accept_acl; 1187281806Srpaulo acl_params->num_mac_acl = n_entries; 1188281806Srpaulo 1189281806Srpaulo err = hostapd_drv_set_acl(hapd, acl_params); 1190281806Srpaulo 1191281806Srpaulo os_free(acl_params); 1192281806Srpaulo 1193281806Srpaulo return err; 1194281806Srpaulo} 1195281806Srpaulo 1196281806Srpaulo 1197281806Srpaulostatic void hostapd_set_acl(struct hostapd_data *hapd) 1198281806Srpaulo{ 1199281806Srpaulo struct hostapd_config *conf = hapd->iconf; 1200281806Srpaulo int err; 1201281806Srpaulo u8 accept_acl; 1202281806Srpaulo 1203281806Srpaulo if (hapd->iface->drv_max_acl_mac_addrs == 0) 1204281806Srpaulo return; 1205281806Srpaulo 1206281806Srpaulo if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) { 1207281806Srpaulo accept_acl = 1; 1208281806Srpaulo err = hostapd_set_acl_list(hapd, conf->bss[0]->accept_mac, 1209281806Srpaulo conf->bss[0]->num_accept_mac, 1210281806Srpaulo accept_acl); 1211281806Srpaulo if (err) { 1212281806Srpaulo wpa_printf(MSG_DEBUG, "Failed to set accept acl"); 1213281806Srpaulo return; 1214281806Srpaulo } 1215281806Srpaulo } else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) { 1216281806Srpaulo accept_acl = 0; 1217281806Srpaulo err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac, 1218281806Srpaulo conf->bss[0]->num_deny_mac, 1219281806Srpaulo accept_acl); 1220281806Srpaulo if (err) { 1221281806Srpaulo wpa_printf(MSG_DEBUG, "Failed to set deny acl"); 1222281806Srpaulo return; 1223281806Srpaulo } 1224281806Srpaulo } 1225281806Srpaulo} 1226281806Srpaulo 1227281806Srpaulo 1228281806Srpaulostatic int start_ctrl_iface_bss(struct hostapd_data *hapd) 1229281806Srpaulo{ 1230281806Srpaulo if (!hapd->iface->interfaces || 1231281806Srpaulo !hapd->iface->interfaces->ctrl_iface_init) 1232281806Srpaulo return 0; 1233281806Srpaulo 1234281806Srpaulo if (hapd->iface->interfaces->ctrl_iface_init(hapd)) { 1235281806Srpaulo wpa_printf(MSG_ERROR, 1236281806Srpaulo "Failed to setup control interface for %s", 1237281806Srpaulo hapd->conf->iface); 1238281806Srpaulo return -1; 1239281806Srpaulo } 1240281806Srpaulo 1241281806Srpaulo return 0; 1242281806Srpaulo} 1243281806Srpaulo 1244281806Srpaulo 1245281806Srpaulostatic int start_ctrl_iface(struct hostapd_iface *iface) 1246281806Srpaulo{ 1247281806Srpaulo size_t i; 1248281806Srpaulo 1249281806Srpaulo if (!iface->interfaces || !iface->interfaces->ctrl_iface_init) 1250281806Srpaulo return 0; 1251281806Srpaulo 1252281806Srpaulo for (i = 0; i < iface->num_bss; i++) { 1253281806Srpaulo struct hostapd_data *hapd = iface->bss[i]; 1254281806Srpaulo if (iface->interfaces->ctrl_iface_init(hapd)) { 1255281806Srpaulo wpa_printf(MSG_ERROR, 1256281806Srpaulo "Failed to setup control interface for %s", 1257281806Srpaulo hapd->conf->iface); 1258281806Srpaulo return -1; 1259281806Srpaulo } 1260281806Srpaulo } 1261281806Srpaulo 1262281806Srpaulo return 0; 1263281806Srpaulo} 1264281806Srpaulo 1265281806Srpaulo 1266281806Srpaulostatic void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx) 1267281806Srpaulo{ 1268281806Srpaulo struct hostapd_iface *iface = eloop_ctx; 1269281806Srpaulo 1270281806Srpaulo if (!iface->wait_channel_update) { 1271281806Srpaulo wpa_printf(MSG_INFO, "Channel list update timeout, but interface was not waiting for it"); 1272281806Srpaulo return; 1273281806Srpaulo } 1274281806Srpaulo 1275281806Srpaulo /* 1276281806Srpaulo * It is possible that the existing channel list is acceptable, so try 1277281806Srpaulo * to proceed. 1278281806Srpaulo */ 1279281806Srpaulo wpa_printf(MSG_DEBUG, "Channel list update timeout - try to continue anyway"); 1280281806Srpaulo setup_interface2(iface); 1281281806Srpaulo} 1282281806Srpaulo 1283281806Srpaulo 1284281806Srpaulovoid hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator) 1285281806Srpaulo{ 1286281806Srpaulo if (!iface->wait_channel_update || initiator != REGDOM_SET_BY_USER) 1287281806Srpaulo return; 1288281806Srpaulo 1289281806Srpaulo wpa_printf(MSG_DEBUG, "Channel list updated - continue setup"); 1290281806Srpaulo eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); 1291281806Srpaulo setup_interface2(iface); 1292281806Srpaulo} 1293281806Srpaulo 1294281806Srpaulo 1295214501Srpaulostatic int setup_interface(struct hostapd_iface *iface) 1296214501Srpaulo{ 1297214501Srpaulo struct hostapd_data *hapd = iface->bss[0]; 1298214501Srpaulo size_t i; 1299214501Srpaulo 1300214501Srpaulo /* 1301281806Srpaulo * It is possible that setup_interface() is called after the interface 1302281806Srpaulo * was disabled etc., in which case driver_ap_teardown is possibly set 1303281806Srpaulo * to 1. Clear it here so any other key/station deletion, which is not 1304281806Srpaulo * part of a teardown flow, would also call the relevant driver 1305281806Srpaulo * callbacks. 1306281806Srpaulo */ 1307281806Srpaulo iface->driver_ap_teardown = 0; 1308281806Srpaulo 1309281806Srpaulo if (!iface->phy[0]) { 1310281806Srpaulo const char *phy = hostapd_drv_get_radio_name(hapd); 1311281806Srpaulo if (phy) { 1312281806Srpaulo wpa_printf(MSG_DEBUG, "phy: %s", phy); 1313281806Srpaulo os_strlcpy(iface->phy, phy, sizeof(iface->phy)); 1314281806Srpaulo } 1315281806Srpaulo } 1316281806Srpaulo 1317281806Srpaulo /* 1318214501Srpaulo * Make sure that all BSSes get configured with a pointer to the same 1319214501Srpaulo * driver interface. 1320214501Srpaulo */ 1321214501Srpaulo for (i = 1; i < iface->num_bss; i++) { 1322214501Srpaulo iface->bss[i]->driver = hapd->driver; 1323214501Srpaulo iface->bss[i]->drv_priv = hapd->drv_priv; 1324214501Srpaulo } 1325214501Srpaulo 1326214501Srpaulo if (hostapd_validate_bssid_configuration(iface)) 1327214501Srpaulo return -1; 1328214501Srpaulo 1329281806Srpaulo /* 1330281806Srpaulo * Initialize control interfaces early to allow external monitoring of 1331281806Srpaulo * channel setup operations that may take considerable amount of time 1332281806Srpaulo * especially for DFS cases. 1333281806Srpaulo */ 1334281806Srpaulo if (start_ctrl_iface(iface)) 1335281806Srpaulo return -1; 1336281806Srpaulo 1337214501Srpaulo if (hapd->iconf->country[0] && hapd->iconf->country[1]) { 1338281806Srpaulo char country[4], previous_country[4]; 1339281806Srpaulo 1340281806Srpaulo hostapd_set_state(iface, HAPD_IFACE_COUNTRY_UPDATE); 1341281806Srpaulo if (hostapd_get_country(hapd, previous_country) < 0) 1342281806Srpaulo previous_country[0] = '\0'; 1343281806Srpaulo 1344214501Srpaulo os_memcpy(country, hapd->iconf->country, 3); 1345214501Srpaulo country[3] = '\0'; 1346214501Srpaulo if (hostapd_set_country(hapd, country) < 0) { 1347214501Srpaulo wpa_printf(MSG_ERROR, "Failed to set country code"); 1348214501Srpaulo return -1; 1349214501Srpaulo } 1350281806Srpaulo 1351281806Srpaulo wpa_printf(MSG_DEBUG, "Previous country code %s, new country code %s", 1352281806Srpaulo previous_country, country); 1353281806Srpaulo 1354281806Srpaulo if (os_strncmp(previous_country, country, 2) != 0) { 1355281806Srpaulo wpa_printf(MSG_DEBUG, "Continue interface setup after channel list update"); 1356281806Srpaulo iface->wait_channel_update = 1; 1357281806Srpaulo eloop_register_timeout(5, 0, 1358281806Srpaulo channel_list_update_timeout, 1359281806Srpaulo iface, NULL); 1360281806Srpaulo return 0; 1361281806Srpaulo } 1362214501Srpaulo } 1363214501Srpaulo 1364281806Srpaulo return setup_interface2(iface); 1365281806Srpaulo} 1366281806Srpaulo 1367281806Srpaulo 1368281806Srpaulostatic int setup_interface2(struct hostapd_iface *iface) 1369281806Srpaulo{ 1370281806Srpaulo iface->wait_channel_update = 0; 1371281806Srpaulo 1372214501Srpaulo if (hostapd_get_hw_features(iface)) { 1373214501Srpaulo /* Not all drivers support this yet, so continue without hw 1374214501Srpaulo * feature data. */ 1375214501Srpaulo } else { 1376214501Srpaulo int ret = hostapd_select_hw_mode(iface); 1377214501Srpaulo if (ret < 0) { 1378214501Srpaulo wpa_printf(MSG_ERROR, "Could not select hw_mode and " 1379214501Srpaulo "channel. (%d)", ret); 1380281806Srpaulo goto fail; 1381214501Srpaulo } 1382281806Srpaulo if (ret == 1) { 1383281806Srpaulo wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback (ACS)"); 1384281806Srpaulo return 0; 1385281806Srpaulo } 1386214501Srpaulo ret = hostapd_check_ht_capab(iface); 1387214501Srpaulo if (ret < 0) 1388281806Srpaulo goto fail; 1389214501Srpaulo if (ret == 1) { 1390214501Srpaulo wpa_printf(MSG_DEBUG, "Interface initialization will " 1391214501Srpaulo "be completed in a callback"); 1392214501Srpaulo return 0; 1393214501Srpaulo } 1394281806Srpaulo 1395281806Srpaulo if (iface->conf->ieee80211h) 1396281806Srpaulo wpa_printf(MSG_DEBUG, "DFS support is enabled"); 1397214501Srpaulo } 1398214501Srpaulo return hostapd_setup_interface_complete(iface, 0); 1399281806Srpaulo 1400281806Srpaulofail: 1401281806Srpaulo hostapd_set_state(iface, HAPD_IFACE_DISABLED); 1402281806Srpaulo wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); 1403281806Srpaulo if (iface->interfaces && iface->interfaces->terminate_on_error) 1404281806Srpaulo eloop_terminate(); 1405281806Srpaulo return -1; 1406214501Srpaulo} 1407214501Srpaulo 1408214501Srpaulo 1409289549Srpaulo#ifdef CONFIG_FST 1410289549Srpaulo 1411289549Srpaulostatic const u8 * fst_hostapd_get_bssid_cb(void *ctx) 1412289549Srpaulo{ 1413289549Srpaulo struct hostapd_data *hapd = ctx; 1414289549Srpaulo 1415289549Srpaulo return hapd->own_addr; 1416289549Srpaulo} 1417289549Srpaulo 1418289549Srpaulo 1419289549Srpaulostatic void fst_hostapd_get_channel_info_cb(void *ctx, 1420289549Srpaulo enum hostapd_hw_mode *hw_mode, 1421289549Srpaulo u8 *channel) 1422289549Srpaulo{ 1423289549Srpaulo struct hostapd_data *hapd = ctx; 1424289549Srpaulo 1425289549Srpaulo *hw_mode = ieee80211_freq_to_chan(hapd->iface->freq, channel); 1426289549Srpaulo} 1427289549Srpaulo 1428289549Srpaulo 1429289549Srpaulostatic void fst_hostapd_set_ies_cb(void *ctx, const struct wpabuf *fst_ies) 1430289549Srpaulo{ 1431289549Srpaulo struct hostapd_data *hapd = ctx; 1432289549Srpaulo 1433289549Srpaulo if (hapd->iface->fst_ies != fst_ies) { 1434289549Srpaulo hapd->iface->fst_ies = fst_ies; 1435289549Srpaulo if (ieee802_11_set_beacon(hapd)) 1436289549Srpaulo wpa_printf(MSG_WARNING, "FST: Cannot set beacon"); 1437289549Srpaulo } 1438289549Srpaulo} 1439289549Srpaulo 1440289549Srpaulo 1441289549Srpaulostatic int fst_hostapd_send_action_cb(void *ctx, const u8 *da, 1442289549Srpaulo struct wpabuf *buf) 1443289549Srpaulo{ 1444289549Srpaulo struct hostapd_data *hapd = ctx; 1445289549Srpaulo 1446289549Srpaulo return hostapd_drv_send_action(hapd, hapd->iface->freq, 0, da, 1447289549Srpaulo wpabuf_head(buf), wpabuf_len(buf)); 1448289549Srpaulo} 1449289549Srpaulo 1450289549Srpaulo 1451289549Srpaulostatic const struct wpabuf * fst_hostapd_get_mb_ie_cb(void *ctx, const u8 *addr) 1452289549Srpaulo{ 1453289549Srpaulo struct hostapd_data *hapd = ctx; 1454289549Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 1455289549Srpaulo 1456289549Srpaulo return sta ? sta->mb_ies : NULL; 1457289549Srpaulo} 1458289549Srpaulo 1459289549Srpaulo 1460289549Srpaulostatic void fst_hostapd_update_mb_ie_cb(void *ctx, const u8 *addr, 1461289549Srpaulo const u8 *buf, size_t size) 1462289549Srpaulo{ 1463289549Srpaulo struct hostapd_data *hapd = ctx; 1464289549Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 1465289549Srpaulo 1466289549Srpaulo if (sta) { 1467289549Srpaulo struct mb_ies_info info; 1468289549Srpaulo 1469289549Srpaulo if (!mb_ies_info_by_ies(&info, buf, size)) { 1470289549Srpaulo wpabuf_free(sta->mb_ies); 1471289549Srpaulo sta->mb_ies = mb_ies_by_info(&info); 1472289549Srpaulo } 1473289549Srpaulo } 1474289549Srpaulo} 1475289549Srpaulo 1476289549Srpaulo 1477289549Srpaulostatic const u8 * fst_hostapd_get_sta(struct fst_get_peer_ctx **get_ctx, 1478289549Srpaulo Boolean mb_only) 1479289549Srpaulo{ 1480289549Srpaulo struct sta_info *s = (struct sta_info *) *get_ctx; 1481289549Srpaulo 1482289549Srpaulo if (mb_only) { 1483289549Srpaulo for (; s && !s->mb_ies; s = s->next) 1484289549Srpaulo ; 1485289549Srpaulo } 1486289549Srpaulo 1487289549Srpaulo if (s) { 1488289549Srpaulo *get_ctx = (struct fst_get_peer_ctx *) s->next; 1489289549Srpaulo 1490289549Srpaulo return s->addr; 1491289549Srpaulo } 1492289549Srpaulo 1493289549Srpaulo *get_ctx = NULL; 1494289549Srpaulo return NULL; 1495289549Srpaulo} 1496289549Srpaulo 1497289549Srpaulo 1498289549Srpaulostatic const u8 * fst_hostapd_get_peer_first(void *ctx, 1499289549Srpaulo struct fst_get_peer_ctx **get_ctx, 1500289549Srpaulo Boolean mb_only) 1501289549Srpaulo{ 1502289549Srpaulo struct hostapd_data *hapd = ctx; 1503289549Srpaulo 1504289549Srpaulo *get_ctx = (struct fst_get_peer_ctx *) hapd->sta_list; 1505289549Srpaulo 1506289549Srpaulo return fst_hostapd_get_sta(get_ctx, mb_only); 1507289549Srpaulo} 1508289549Srpaulo 1509289549Srpaulo 1510289549Srpaulostatic const u8 * fst_hostapd_get_peer_next(void *ctx, 1511289549Srpaulo struct fst_get_peer_ctx **get_ctx, 1512289549Srpaulo Boolean mb_only) 1513289549Srpaulo{ 1514289549Srpaulo return fst_hostapd_get_sta(get_ctx, mb_only); 1515289549Srpaulo} 1516289549Srpaulo 1517289549Srpaulo 1518289549Srpaulovoid fst_hostapd_fill_iface_obj(struct hostapd_data *hapd, 1519289549Srpaulo struct fst_wpa_obj *iface_obj) 1520289549Srpaulo{ 1521289549Srpaulo iface_obj->ctx = hapd; 1522289549Srpaulo iface_obj->get_bssid = fst_hostapd_get_bssid_cb; 1523289549Srpaulo iface_obj->get_channel_info = fst_hostapd_get_channel_info_cb; 1524289549Srpaulo iface_obj->set_ies = fst_hostapd_set_ies_cb; 1525289549Srpaulo iface_obj->send_action = fst_hostapd_send_action_cb; 1526289549Srpaulo iface_obj->get_mb_ie = fst_hostapd_get_mb_ie_cb; 1527289549Srpaulo iface_obj->update_mb_ie = fst_hostapd_update_mb_ie_cb; 1528289549Srpaulo iface_obj->get_peer_first = fst_hostapd_get_peer_first; 1529289549Srpaulo iface_obj->get_peer_next = fst_hostapd_get_peer_next; 1530289549Srpaulo} 1531289549Srpaulo 1532289549Srpaulo#endif /* CONFIG_FST */ 1533289549Srpaulo 1534289549Srpaulo 1535337817Scy#ifdef NEED_AP_MLME 1536337817Scystatic enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd, 1537337817Scy int ht, int vht) 1538214501Srpaulo{ 1539337817Scy if (!ht && !vht) 1540337817Scy return NR_CHAN_WIDTH_20; 1541337817Scy if (!hapd->iconf->secondary_channel) 1542337817Scy return NR_CHAN_WIDTH_20; 1543337817Scy if (!vht || hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT) 1544337817Scy return NR_CHAN_WIDTH_40; 1545337817Scy if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ) 1546337817Scy return NR_CHAN_WIDTH_80; 1547337817Scy if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ) 1548337817Scy return NR_CHAN_WIDTH_160; 1549337817Scy if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ) 1550337817Scy return NR_CHAN_WIDTH_80P80; 1551337817Scy return NR_CHAN_WIDTH_20; 1552337817Scy} 1553337817Scy#endif /* NEED_AP_MLME */ 1554337817Scy 1555337817Scy 1556337817Scystatic void hostapd_set_own_neighbor_report(struct hostapd_data *hapd) 1557337817Scy{ 1558337817Scy#ifdef NEED_AP_MLME 1559337817Scy u16 capab = hostapd_own_capab_info(hapd); 1560337817Scy int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n; 1561337817Scy int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac; 1562337817Scy struct wpa_ssid_value ssid; 1563337817Scy u8 channel, op_class; 1564337817Scy int center_freq1 = 0, center_freq2 = 0; 1565337817Scy enum nr_chan_width width; 1566337817Scy u32 bssid_info; 1567337817Scy struct wpabuf *nr; 1568337817Scy 1569337817Scy if (!(hapd->conf->radio_measurements[0] & 1570337817Scy WLAN_RRM_CAPS_NEIGHBOR_REPORT)) 1571337817Scy return; 1572337817Scy 1573337817Scy bssid_info = 3; /* AP is reachable */ 1574337817Scy bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */ 1575337817Scy bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */ 1576337817Scy 1577337817Scy if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) 1578337817Scy bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT; 1579337817Scy 1580337817Scy bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */ 1581337817Scy 1582337817Scy if (hapd->conf->wmm_enabled) { 1583337817Scy bssid_info |= NEI_REP_BSSID_INFO_QOS; 1584337817Scy 1585337817Scy if (hapd->conf->wmm_uapsd && 1586337817Scy (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD)) 1587337817Scy bssid_info |= NEI_REP_BSSID_INFO_APSD; 1588337817Scy } 1589337817Scy 1590337817Scy if (ht) { 1591337817Scy bssid_info |= NEI_REP_BSSID_INFO_HT | 1592337817Scy NEI_REP_BSSID_INFO_DELAYED_BA; 1593337817Scy 1594337817Scy /* VHT bit added in IEEE P802.11-REVmc/D4.3 */ 1595337817Scy if (vht) 1596337817Scy bssid_info |= NEI_REP_BSSID_INFO_VHT; 1597337817Scy } 1598337817Scy 1599337817Scy /* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */ 1600337817Scy 1601337817Scy ieee80211_freq_to_channel_ext(hapd->iface->freq, 1602337817Scy hapd->iconf->secondary_channel, 1603337817Scy hapd->iconf->vht_oper_chwidth, 1604337817Scy &op_class, &channel); 1605337817Scy width = hostapd_get_nr_chan_width(hapd, ht, vht); 1606337817Scy if (vht) { 1607337817Scy center_freq1 = ieee80211_chan_to_freq( 1608337817Scy NULL, op_class, 1609337817Scy hapd->iconf->vht_oper_centr_freq_seg0_idx); 1610337817Scy if (width == NR_CHAN_WIDTH_80P80) 1611337817Scy center_freq2 = ieee80211_chan_to_freq( 1612337817Scy NULL, op_class, 1613337817Scy hapd->iconf->vht_oper_centr_freq_seg1_idx); 1614337817Scy } else if (ht) { 1615337817Scy center_freq1 = hapd->iface->freq + 1616337817Scy 10 * hapd->iconf->secondary_channel; 1617337817Scy } 1618337817Scy 1619337817Scy ssid.ssid_len = hapd->conf->ssid.ssid_len; 1620337817Scy os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len); 1621337817Scy 1622337817Scy /* 1623337817Scy * Neighbor Report element size = BSSID + BSSID info + op_class + chan + 1624337817Scy * phy type + wide bandwidth channel subelement. 1625337817Scy */ 1626337817Scy nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5); 1627337817Scy if (!nr) 1628337817Scy return; 1629337817Scy 1630337817Scy wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN); 1631337817Scy wpabuf_put_le32(nr, bssid_info); 1632337817Scy wpabuf_put_u8(nr, op_class); 1633337817Scy wpabuf_put_u8(nr, channel); 1634337817Scy wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht)); 1635337817Scy 1636337817Scy /* 1637337817Scy * Wide Bandwidth Channel subelement may be needed to allow the 1638337817Scy * receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0 1639337817Scy * Figure 9-301. 1640337817Scy */ 1641337817Scy wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN); 1642337817Scy wpabuf_put_u8(nr, 3); 1643337817Scy wpabuf_put_u8(nr, width); 1644337817Scy wpabuf_put_u8(nr, center_freq1); 1645337817Scy wpabuf_put_u8(nr, center_freq2); 1646337817Scy 1647337817Scy hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci, 1648337817Scy hapd->iconf->civic); 1649337817Scy 1650337817Scy wpabuf_free(nr); 1651337817Scy#endif /* NEED_AP_MLME */ 1652337817Scy} 1653337817Scy 1654337817Scy 1655337817Scystatic int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface, 1656337817Scy int err) 1657337817Scy{ 1658214501Srpaulo struct hostapd_data *hapd = iface->bss[0]; 1659214501Srpaulo size_t j; 1660214501Srpaulo u8 *prev_addr; 1661281806Srpaulo int delay_apply_cfg = 0; 1662281806Srpaulo int res_dfs_offload = 0; 1663214501Srpaulo 1664281806Srpaulo if (err) 1665281806Srpaulo goto fail; 1666214501Srpaulo 1667214501Srpaulo wpa_printf(MSG_DEBUG, "Completing interface initialization"); 1668281806Srpaulo if (iface->conf->channel) { 1669281806Srpaulo#ifdef NEED_AP_MLME 1670281806Srpaulo int res; 1671281806Srpaulo#endif /* NEED_AP_MLME */ 1672281806Srpaulo 1673281806Srpaulo iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel); 1674214501Srpaulo wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d " 1675214501Srpaulo "Frequency: %d MHz", 1676281806Srpaulo hostapd_hw_mode_txt(iface->conf->hw_mode), 1677281806Srpaulo iface->conf->channel, iface->freq); 1678214501Srpaulo 1679281806Srpaulo#ifdef NEED_AP_MLME 1680281806Srpaulo /* Handle DFS only if it is not offloaded to the driver */ 1681281806Srpaulo if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) { 1682281806Srpaulo /* Check DFS */ 1683281806Srpaulo res = hostapd_handle_dfs(iface); 1684281806Srpaulo if (res <= 0) { 1685281806Srpaulo if (res < 0) 1686281806Srpaulo goto fail; 1687281806Srpaulo return res; 1688281806Srpaulo } 1689281806Srpaulo } else { 1690281806Srpaulo /* If DFS is offloaded to the driver */ 1691281806Srpaulo res_dfs_offload = hostapd_handle_dfs_offload(iface); 1692281806Srpaulo if (res_dfs_offload <= 0) { 1693281806Srpaulo if (res_dfs_offload < 0) 1694281806Srpaulo goto fail; 1695281806Srpaulo } else { 1696281806Srpaulo wpa_printf(MSG_DEBUG, 1697281806Srpaulo "Proceed with AP/channel setup"); 1698281806Srpaulo /* 1699281806Srpaulo * If this is a DFS channel, move to completing 1700281806Srpaulo * AP setup. 1701281806Srpaulo */ 1702281806Srpaulo if (res_dfs_offload == 1) 1703281806Srpaulo goto dfs_offload; 1704281806Srpaulo /* Otherwise fall through. */ 1705281806Srpaulo } 1706281806Srpaulo } 1707281806Srpaulo#endif /* NEED_AP_MLME */ 1708281806Srpaulo 1709281806Srpaulo#ifdef CONFIG_MESH 1710281806Srpaulo if (iface->mconf != NULL) { 1711281806Srpaulo wpa_printf(MSG_DEBUG, 1712281806Srpaulo "%s: Mesh configuration will be applied while joining the mesh network", 1713281806Srpaulo iface->bss[0]->conf->iface); 1714281806Srpaulo delay_apply_cfg = 1; 1715281806Srpaulo } 1716281806Srpaulo#endif /* CONFIG_MESH */ 1717281806Srpaulo 1718281806Srpaulo if (!delay_apply_cfg && 1719281806Srpaulo hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq, 1720214501Srpaulo hapd->iconf->channel, 1721214501Srpaulo hapd->iconf->ieee80211n, 1722281806Srpaulo hapd->iconf->ieee80211ac, 1723281806Srpaulo hapd->iconf->secondary_channel, 1724281806Srpaulo hapd->iconf->vht_oper_chwidth, 1725281806Srpaulo hapd->iconf->vht_oper_centr_freq_seg0_idx, 1726281806Srpaulo hapd->iconf->vht_oper_centr_freq_seg1_idx)) { 1727214501Srpaulo wpa_printf(MSG_ERROR, "Could not set channel for " 1728214501Srpaulo "kernel driver"); 1729281806Srpaulo goto fail; 1730214501Srpaulo } 1731214501Srpaulo } 1732214501Srpaulo 1733252726Srpaulo if (iface->current_mode) { 1734252726Srpaulo if (hostapd_prepare_rates(iface, iface->current_mode)) { 1735252726Srpaulo wpa_printf(MSG_ERROR, "Failed to prepare rates " 1736252726Srpaulo "table."); 1737252726Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 1738252726Srpaulo HOSTAPD_LEVEL_WARNING, 1739252726Srpaulo "Failed to prepare rates table."); 1740281806Srpaulo goto fail; 1741252726Srpaulo } 1742252726Srpaulo } 1743252726Srpaulo 1744214501Srpaulo if (hapd->iconf->rts_threshold > -1 && 1745214501Srpaulo hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) { 1746214501Srpaulo wpa_printf(MSG_ERROR, "Could not set RTS threshold for " 1747214501Srpaulo "kernel driver"); 1748281806Srpaulo goto fail; 1749214501Srpaulo } 1750214501Srpaulo 1751214501Srpaulo if (hapd->iconf->fragm_threshold > -1 && 1752214501Srpaulo hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) { 1753214501Srpaulo wpa_printf(MSG_ERROR, "Could not set fragmentation threshold " 1754214501Srpaulo "for kernel driver"); 1755281806Srpaulo goto fail; 1756214501Srpaulo } 1757214501Srpaulo 1758214501Srpaulo prev_addr = hapd->own_addr; 1759214501Srpaulo 1760214501Srpaulo for (j = 0; j < iface->num_bss; j++) { 1761214501Srpaulo hapd = iface->bss[j]; 1762214501Srpaulo if (j) 1763214501Srpaulo os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN); 1764281806Srpaulo if (hostapd_setup_bss(hapd, j == 0)) { 1765281806Srpaulo do { 1766281806Srpaulo hapd = iface->bss[j]; 1767281806Srpaulo hostapd_bss_deinit_no_free(hapd); 1768281806Srpaulo hostapd_free_hapd_data(hapd); 1769281806Srpaulo } while (j-- > 0); 1770281806Srpaulo goto fail; 1771281806Srpaulo } 1772337817Scy if (is_zero_ether_addr(hapd->conf->bssid)) 1773214501Srpaulo prev_addr = hapd->own_addr; 1774214501Srpaulo } 1775281806Srpaulo hapd = iface->bss[0]; 1776214501Srpaulo 1777214501Srpaulo hostapd_tx_queue_params(iface); 1778214501Srpaulo 1779214501Srpaulo ap_list_init(iface); 1780214501Srpaulo 1781281806Srpaulo hostapd_set_acl(hapd); 1782281806Srpaulo 1783214501Srpaulo if (hostapd_driver_commit(hapd) < 0) { 1784214501Srpaulo wpa_printf(MSG_ERROR, "%s: Failed to commit driver " 1785214501Srpaulo "configuration", __func__); 1786281806Srpaulo goto fail; 1787214501Srpaulo } 1788214501Srpaulo 1789252726Srpaulo /* 1790252726Srpaulo * WPS UPnP module can be initialized only when the "upnp_iface" is up. 1791252726Srpaulo * If "interface" and "upnp_iface" are the same (e.g., non-bridge 1792252726Srpaulo * mode), the interface is up only after driver_commit, so initialize 1793252726Srpaulo * WPS after driver_commit. 1794252726Srpaulo */ 1795252726Srpaulo for (j = 0; j < iface->num_bss; j++) { 1796252726Srpaulo if (hostapd_init_wps_complete(iface->bss[j])) 1797281806Srpaulo goto fail; 1798252726Srpaulo } 1799252726Srpaulo 1800281806Srpaulo if ((iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) && 1801281806Srpaulo !res_dfs_offload) { 1802281806Srpaulo /* 1803281806Srpaulo * If freq is DFS, and DFS is offloaded to the driver, then wait 1804281806Srpaulo * for CAC to complete. 1805281806Srpaulo */ 1806281806Srpaulo wpa_printf(MSG_DEBUG, "%s: Wait for CAC to complete", __func__); 1807281806Srpaulo return res_dfs_offload; 1808281806Srpaulo } 1809281806Srpaulo 1810281806Srpaulo#ifdef NEED_AP_MLME 1811281806Srpaulodfs_offload: 1812281806Srpaulo#endif /* NEED_AP_MLME */ 1813289549Srpaulo 1814289549Srpaulo#ifdef CONFIG_FST 1815289549Srpaulo if (hapd->iconf->fst_cfg.group_id[0]) { 1816289549Srpaulo struct fst_wpa_obj iface_obj; 1817289549Srpaulo 1818289549Srpaulo fst_hostapd_fill_iface_obj(hapd, &iface_obj); 1819289549Srpaulo iface->fst = fst_attach(hapd->conf->iface, hapd->own_addr, 1820289549Srpaulo &iface_obj, &hapd->iconf->fst_cfg); 1821289549Srpaulo if (!iface->fst) { 1822289549Srpaulo wpa_printf(MSG_ERROR, "Could not attach to FST %s", 1823289549Srpaulo hapd->iconf->fst_cfg.group_id); 1824289549Srpaulo goto fail; 1825289549Srpaulo } 1826289549Srpaulo } 1827289549Srpaulo#endif /* CONFIG_FST */ 1828289549Srpaulo 1829281806Srpaulo hostapd_set_state(iface, HAPD_IFACE_ENABLED); 1830281806Srpaulo wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED); 1831252726Srpaulo if (hapd->setup_complete_cb) 1832252726Srpaulo hapd->setup_complete_cb(hapd->setup_complete_cb_ctx); 1833252726Srpaulo 1834214501Srpaulo wpa_printf(MSG_DEBUG, "%s: Setup of interface done.", 1835214501Srpaulo iface->bss[0]->conf->iface); 1836281806Srpaulo if (iface->interfaces && iface->interfaces->terminate_on_error > 0) 1837281806Srpaulo iface->interfaces->terminate_on_error--; 1838214501Srpaulo 1839337817Scy for (j = 0; j < iface->num_bss; j++) 1840337817Scy hostapd_set_own_neighbor_report(iface->bss[j]); 1841337817Scy 1842214501Srpaulo return 0; 1843281806Srpaulo 1844281806Srpaulofail: 1845281806Srpaulo wpa_printf(MSG_ERROR, "Interface initialization failed"); 1846281806Srpaulo hostapd_set_state(iface, HAPD_IFACE_DISABLED); 1847281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); 1848289549Srpaulo#ifdef CONFIG_FST 1849289549Srpaulo if (iface->fst) { 1850289549Srpaulo fst_detach(iface->fst); 1851289549Srpaulo iface->fst = NULL; 1852289549Srpaulo } 1853289549Srpaulo#endif /* CONFIG_FST */ 1854281806Srpaulo if (iface->interfaces && iface->interfaces->terminate_on_error) 1855281806Srpaulo eloop_terminate(); 1856281806Srpaulo return -1; 1857214501Srpaulo} 1858214501Srpaulo 1859214501Srpaulo 1860214501Srpaulo/** 1861337817Scy * hostapd_setup_interface_complete - Complete interface setup 1862337817Scy * 1863337817Scy * This function is called when previous steps in the interface setup has been 1864337817Scy * completed. This can also start operations, e.g., DFS, that will require 1865337817Scy * additional processing before interface is ready to be enabled. Such 1866337817Scy * operations will call this function from eloop callbacks when finished. 1867337817Scy */ 1868337817Scyint hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) 1869337817Scy{ 1870337817Scy struct hapd_interfaces *interfaces = iface->interfaces; 1871337817Scy struct hostapd_data *hapd = iface->bss[0]; 1872337817Scy unsigned int i; 1873337817Scy int not_ready_in_sync_ifaces = 0; 1874337817Scy 1875337817Scy if (!iface->need_to_start_in_sync) 1876337817Scy return hostapd_setup_interface_complete_sync(iface, err); 1877337817Scy 1878337817Scy if (err) { 1879337817Scy wpa_printf(MSG_ERROR, "Interface initialization failed"); 1880337817Scy hostapd_set_state(iface, HAPD_IFACE_DISABLED); 1881337817Scy iface->need_to_start_in_sync = 0; 1882337817Scy wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); 1883337817Scy if (interfaces && interfaces->terminate_on_error) 1884337817Scy eloop_terminate(); 1885337817Scy return -1; 1886337817Scy } 1887337817Scy 1888337817Scy if (iface->ready_to_start_in_sync) { 1889337817Scy /* Already in ready and waiting. should never happpen */ 1890337817Scy return 0; 1891337817Scy } 1892337817Scy 1893337817Scy for (i = 0; i < interfaces->count; i++) { 1894337817Scy if (interfaces->iface[i]->need_to_start_in_sync && 1895337817Scy !interfaces->iface[i]->ready_to_start_in_sync) 1896337817Scy not_ready_in_sync_ifaces++; 1897337817Scy } 1898337817Scy 1899337817Scy /* 1900337817Scy * Check if this is the last interface, if yes then start all the other 1901337817Scy * waiting interfaces. If not, add this interface to the waiting list. 1902337817Scy */ 1903337817Scy if (not_ready_in_sync_ifaces > 1 && iface->state == HAPD_IFACE_DFS) { 1904337817Scy /* 1905337817Scy * If this interface went through CAC, do not synchronize, just 1906337817Scy * start immediately. 1907337817Scy */ 1908337817Scy iface->need_to_start_in_sync = 0; 1909337817Scy wpa_printf(MSG_INFO, 1910337817Scy "%s: Finished CAC - bypass sync and start interface", 1911337817Scy iface->bss[0]->conf->iface); 1912337817Scy return hostapd_setup_interface_complete_sync(iface, err); 1913337817Scy } 1914337817Scy 1915337817Scy if (not_ready_in_sync_ifaces > 1) { 1916337817Scy /* need to wait as there are other interfaces still coming up */ 1917337817Scy iface->ready_to_start_in_sync = 1; 1918337817Scy wpa_printf(MSG_INFO, 1919337817Scy "%s: Interface waiting to sync with other interfaces", 1920337817Scy iface->bss[0]->conf->iface); 1921337817Scy return 0; 1922337817Scy } 1923337817Scy 1924337817Scy wpa_printf(MSG_INFO, 1925337817Scy "%s: Last interface to sync - starting all interfaces", 1926337817Scy iface->bss[0]->conf->iface); 1927337817Scy iface->need_to_start_in_sync = 0; 1928337817Scy hostapd_setup_interface_complete_sync(iface, err); 1929337817Scy for (i = 0; i < interfaces->count; i++) { 1930337817Scy if (interfaces->iface[i]->need_to_start_in_sync && 1931337817Scy interfaces->iface[i]->ready_to_start_in_sync) { 1932337817Scy hostapd_setup_interface_complete_sync( 1933337817Scy interfaces->iface[i], 0); 1934337817Scy /* Only once the interfaces are sync started */ 1935337817Scy interfaces->iface[i]->need_to_start_in_sync = 0; 1936337817Scy } 1937337817Scy } 1938337817Scy 1939337817Scy return 0; 1940337817Scy} 1941337817Scy 1942337817Scy 1943337817Scy/** 1944214501Srpaulo * hostapd_setup_interface - Setup of an interface 1945214501Srpaulo * @iface: Pointer to interface data. 1946214501Srpaulo * Returns: 0 on success, -1 on failure 1947214501Srpaulo * 1948214501Srpaulo * Initializes the driver interface, validates the configuration, 1949214501Srpaulo * and sets driver parameters based on the configuration. 1950214501Srpaulo * Flushes old stations, sets the channel, encryption, 1951214501Srpaulo * beacons, and WDS links based on the configuration. 1952281806Srpaulo * 1953281806Srpaulo * If interface setup requires more time, e.g., to perform HT co-ex scans, ACS, 1954281806Srpaulo * or DFS operations, this function returns 0 before such operations have been 1955281806Srpaulo * completed. The pending operations are registered into eloop and will be 1956281806Srpaulo * completed from eloop callbacks. Those callbacks end up calling 1957281806Srpaulo * hostapd_setup_interface_complete() once setup has been completed. 1958214501Srpaulo */ 1959214501Srpauloint hostapd_setup_interface(struct hostapd_iface *iface) 1960214501Srpaulo{ 1961214501Srpaulo int ret; 1962214501Srpaulo 1963214501Srpaulo ret = setup_interface(iface); 1964214501Srpaulo if (ret) { 1965214501Srpaulo wpa_printf(MSG_ERROR, "%s: Unable to setup interface.", 1966214501Srpaulo iface->bss[0]->conf->iface); 1967214501Srpaulo return -1; 1968214501Srpaulo } 1969214501Srpaulo 1970214501Srpaulo return 0; 1971214501Srpaulo} 1972214501Srpaulo 1973214501Srpaulo 1974214501Srpaulo/** 1975214501Srpaulo * hostapd_alloc_bss_data - Allocate and initialize per-BSS data 1976214501Srpaulo * @hapd_iface: Pointer to interface data 1977214501Srpaulo * @conf: Pointer to per-interface configuration 1978214501Srpaulo * @bss: Pointer to per-BSS configuration for this BSS 1979214501Srpaulo * Returns: Pointer to allocated BSS data 1980214501Srpaulo * 1981214501Srpaulo * This function is used to allocate per-BSS data structure. This data will be 1982214501Srpaulo * freed after hostapd_cleanup() is called for it during interface 1983214501Srpaulo * deinitialization. 1984214501Srpaulo */ 1985214501Srpaulostruct hostapd_data * 1986214501Srpaulohostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, 1987214501Srpaulo struct hostapd_config *conf, 1988214501Srpaulo struct hostapd_bss_config *bss) 1989214501Srpaulo{ 1990214501Srpaulo struct hostapd_data *hapd; 1991214501Srpaulo 1992214501Srpaulo hapd = os_zalloc(sizeof(*hapd)); 1993214501Srpaulo if (hapd == NULL) 1994214501Srpaulo return NULL; 1995214501Srpaulo 1996214501Srpaulo hapd->new_assoc_sta_cb = hostapd_new_assoc_sta; 1997214501Srpaulo hapd->iconf = conf; 1998214501Srpaulo hapd->conf = bss; 1999214501Srpaulo hapd->iface = hapd_iface; 2000214501Srpaulo hapd->driver = hapd->iconf->driver; 2001252726Srpaulo hapd->ctrl_sock = -1; 2002337817Scy dl_list_init(&hapd->ctrl_dst); 2003337817Scy dl_list_init(&hapd->nr_db); 2004214501Srpaulo 2005214501Srpaulo return hapd; 2006214501Srpaulo} 2007214501Srpaulo 2008214501Srpaulo 2009281806Srpaulostatic void hostapd_bss_deinit(struct hostapd_data *hapd) 2010281806Srpaulo{ 2011337817Scy if (!hapd) 2012337817Scy return; 2013281806Srpaulo wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__, 2014281806Srpaulo hapd->conf->iface); 2015281806Srpaulo hostapd_bss_deinit_no_free(hapd); 2016281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); 2017281806Srpaulo hostapd_cleanup(hapd); 2018281806Srpaulo} 2019281806Srpaulo 2020281806Srpaulo 2021214501Srpaulovoid hostapd_interface_deinit(struct hostapd_iface *iface) 2022214501Srpaulo{ 2023281806Srpaulo int j; 2024214501Srpaulo 2025281806Srpaulo wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); 2026214501Srpaulo if (iface == NULL) 2027214501Srpaulo return; 2028214501Srpaulo 2029281806Srpaulo hostapd_set_state(iface, HAPD_IFACE_DISABLED); 2030281806Srpaulo 2031281806Srpaulo#ifdef CONFIG_IEEE80211N 2032281806Srpaulo#ifdef NEED_AP_MLME 2033281806Srpaulo hostapd_stop_setup_timers(iface); 2034281806Srpaulo eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL); 2035281806Srpaulo#endif /* NEED_AP_MLME */ 2036281806Srpaulo#endif /* CONFIG_IEEE80211N */ 2037281806Srpaulo eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); 2038281806Srpaulo iface->wait_channel_update = 0; 2039281806Srpaulo 2040289549Srpaulo#ifdef CONFIG_FST 2041289549Srpaulo if (iface->fst) { 2042289549Srpaulo fst_detach(iface->fst); 2043289549Srpaulo iface->fst = NULL; 2044289549Srpaulo } 2045289549Srpaulo#endif /* CONFIG_FST */ 2046289549Srpaulo 2047337817Scy for (j = iface->num_bss - 1; j >= 0; j--) { 2048337817Scy if (!iface->bss) 2049337817Scy break; 2050281806Srpaulo hostapd_bss_deinit(iface->bss[j]); 2051337817Scy } 2052214501Srpaulo} 2053214501Srpaulo 2054214501Srpaulo 2055214501Srpaulovoid hostapd_interface_free(struct hostapd_iface *iface) 2056214501Srpaulo{ 2057214501Srpaulo size_t j; 2058281806Srpaulo wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); 2059281806Srpaulo for (j = 0; j < iface->num_bss; j++) { 2060337817Scy if (!iface->bss) 2061337817Scy break; 2062281806Srpaulo wpa_printf(MSG_DEBUG, "%s: free hapd %p", 2063281806Srpaulo __func__, iface->bss[j]); 2064214501Srpaulo os_free(iface->bss[j]); 2065281806Srpaulo } 2066214501Srpaulo hostapd_cleanup_iface(iface); 2067214501Srpaulo} 2068214501Srpaulo 2069214501Srpaulo 2070337817Scystruct hostapd_iface * hostapd_alloc_iface(void) 2071337817Scy{ 2072337817Scy struct hostapd_iface *hapd_iface; 2073337817Scy 2074337817Scy hapd_iface = os_zalloc(sizeof(*hapd_iface)); 2075337817Scy if (!hapd_iface) 2076337817Scy return NULL; 2077337817Scy 2078337817Scy dl_list_init(&hapd_iface->sta_seen); 2079337817Scy 2080337817Scy return hapd_iface; 2081337817Scy} 2082337817Scy 2083337817Scy 2084281806Srpaulo/** 2085281806Srpaulo * hostapd_init - Allocate and initialize per-interface data 2086281806Srpaulo * @config_file: Path to the configuration file 2087281806Srpaulo * Returns: Pointer to the allocated interface data or %NULL on failure 2088281806Srpaulo * 2089281806Srpaulo * This function is used to allocate main data structures for per-interface 2090281806Srpaulo * data. The allocated data buffer will be freed by calling 2091281806Srpaulo * hostapd_cleanup_iface(). 2092281806Srpaulo */ 2093281806Srpaulostruct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces, 2094281806Srpaulo const char *config_file) 2095281806Srpaulo{ 2096281806Srpaulo struct hostapd_iface *hapd_iface = NULL; 2097281806Srpaulo struct hostapd_config *conf = NULL; 2098281806Srpaulo struct hostapd_data *hapd; 2099281806Srpaulo size_t i; 2100252726Srpaulo 2101337817Scy hapd_iface = hostapd_alloc_iface(); 2102281806Srpaulo if (hapd_iface == NULL) 2103281806Srpaulo goto fail; 2104281806Srpaulo 2105281806Srpaulo hapd_iface->config_fname = os_strdup(config_file); 2106281806Srpaulo if (hapd_iface->config_fname == NULL) 2107281806Srpaulo goto fail; 2108281806Srpaulo 2109281806Srpaulo conf = interfaces->config_read_cb(hapd_iface->config_fname); 2110281806Srpaulo if (conf == NULL) 2111281806Srpaulo goto fail; 2112281806Srpaulo hapd_iface->conf = conf; 2113281806Srpaulo 2114281806Srpaulo hapd_iface->num_bss = conf->num_bss; 2115281806Srpaulo hapd_iface->bss = os_calloc(conf->num_bss, 2116281806Srpaulo sizeof(struct hostapd_data *)); 2117281806Srpaulo if (hapd_iface->bss == NULL) 2118281806Srpaulo goto fail; 2119281806Srpaulo 2120281806Srpaulo for (i = 0; i < conf->num_bss; i++) { 2121281806Srpaulo hapd = hapd_iface->bss[i] = 2122281806Srpaulo hostapd_alloc_bss_data(hapd_iface, conf, 2123281806Srpaulo conf->bss[i]); 2124281806Srpaulo if (hapd == NULL) 2125281806Srpaulo goto fail; 2126281806Srpaulo hapd->msg_ctx = hapd; 2127281806Srpaulo } 2128281806Srpaulo 2129281806Srpaulo return hapd_iface; 2130281806Srpaulo 2131281806Srpaulofail: 2132281806Srpaulo wpa_printf(MSG_ERROR, "Failed to set up interface with %s", 2133281806Srpaulo config_file); 2134281806Srpaulo if (conf) 2135281806Srpaulo hostapd_config_free(conf); 2136281806Srpaulo if (hapd_iface) { 2137281806Srpaulo os_free(hapd_iface->config_fname); 2138281806Srpaulo os_free(hapd_iface->bss); 2139281806Srpaulo wpa_printf(MSG_DEBUG, "%s: free iface %p", 2140281806Srpaulo __func__, hapd_iface); 2141281806Srpaulo os_free(hapd_iface); 2142281806Srpaulo } 2143281806Srpaulo return NULL; 2144281806Srpaulo} 2145281806Srpaulo 2146281806Srpaulo 2147281806Srpaulostatic int ifname_in_use(struct hapd_interfaces *interfaces, const char *ifname) 2148281806Srpaulo{ 2149281806Srpaulo size_t i, j; 2150281806Srpaulo 2151281806Srpaulo for (i = 0; i < interfaces->count; i++) { 2152281806Srpaulo struct hostapd_iface *iface = interfaces->iface[i]; 2153281806Srpaulo for (j = 0; j < iface->num_bss; j++) { 2154281806Srpaulo struct hostapd_data *hapd = iface->bss[j]; 2155281806Srpaulo if (os_strcmp(ifname, hapd->conf->iface) == 0) 2156281806Srpaulo return 1; 2157281806Srpaulo } 2158281806Srpaulo } 2159281806Srpaulo 2160281806Srpaulo return 0; 2161281806Srpaulo} 2162281806Srpaulo 2163281806Srpaulo 2164281806Srpaulo/** 2165281806Srpaulo * hostapd_interface_init_bss - Read configuration file and init BSS data 2166281806Srpaulo * 2167281806Srpaulo * This function is used to parse configuration file for a BSS. This BSS is 2168281806Srpaulo * added to an existing interface sharing the same radio (if any) or a new 2169281806Srpaulo * interface is created if this is the first interface on a radio. This 2170281806Srpaulo * allocate memory for the BSS. No actual driver operations are started. 2171281806Srpaulo * 2172281806Srpaulo * This is similar to hostapd_interface_init(), but for a case where the 2173281806Srpaulo * configuration is used to add a single BSS instead of all BSSes for a radio. 2174281806Srpaulo */ 2175281806Srpaulostruct hostapd_iface * 2176281806Srpaulohostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy, 2177281806Srpaulo const char *config_fname, int debug) 2178281806Srpaulo{ 2179281806Srpaulo struct hostapd_iface *new_iface = NULL, *iface = NULL; 2180281806Srpaulo struct hostapd_data *hapd; 2181281806Srpaulo int k; 2182281806Srpaulo size_t i, bss_idx; 2183281806Srpaulo 2184281806Srpaulo if (!phy || !*phy) 2185281806Srpaulo return NULL; 2186281806Srpaulo 2187281806Srpaulo for (i = 0; i < interfaces->count; i++) { 2188281806Srpaulo if (os_strcmp(interfaces->iface[i]->phy, phy) == 0) { 2189281806Srpaulo iface = interfaces->iface[i]; 2190281806Srpaulo break; 2191281806Srpaulo } 2192281806Srpaulo } 2193281806Srpaulo 2194281806Srpaulo wpa_printf(MSG_INFO, "Configuration file: %s (phy %s)%s", 2195281806Srpaulo config_fname, phy, iface ? "" : " --> new PHY"); 2196281806Srpaulo if (iface) { 2197281806Srpaulo struct hostapd_config *conf; 2198281806Srpaulo struct hostapd_bss_config **tmp_conf; 2199281806Srpaulo struct hostapd_data **tmp_bss; 2200281806Srpaulo struct hostapd_bss_config *bss; 2201281806Srpaulo const char *ifname; 2202281806Srpaulo 2203281806Srpaulo /* Add new BSS to existing iface */ 2204281806Srpaulo conf = interfaces->config_read_cb(config_fname); 2205281806Srpaulo if (conf == NULL) 2206281806Srpaulo return NULL; 2207281806Srpaulo if (conf->num_bss > 1) { 2208281806Srpaulo wpa_printf(MSG_ERROR, "Multiple BSSes specified in BSS-config"); 2209281806Srpaulo hostapd_config_free(conf); 2210281806Srpaulo return NULL; 2211281806Srpaulo } 2212281806Srpaulo 2213281806Srpaulo ifname = conf->bss[0]->iface; 2214281806Srpaulo if (ifname[0] != '\0' && ifname_in_use(interfaces, ifname)) { 2215281806Srpaulo wpa_printf(MSG_ERROR, 2216281806Srpaulo "Interface name %s already in use", ifname); 2217281806Srpaulo hostapd_config_free(conf); 2218281806Srpaulo return NULL; 2219281806Srpaulo } 2220281806Srpaulo 2221281806Srpaulo tmp_conf = os_realloc_array( 2222281806Srpaulo iface->conf->bss, iface->conf->num_bss + 1, 2223281806Srpaulo sizeof(struct hostapd_bss_config *)); 2224281806Srpaulo tmp_bss = os_realloc_array(iface->bss, iface->num_bss + 1, 2225281806Srpaulo sizeof(struct hostapd_data *)); 2226281806Srpaulo if (tmp_bss) 2227281806Srpaulo iface->bss = tmp_bss; 2228281806Srpaulo if (tmp_conf) { 2229281806Srpaulo iface->conf->bss = tmp_conf; 2230281806Srpaulo iface->conf->last_bss = tmp_conf[0]; 2231281806Srpaulo } 2232281806Srpaulo if (tmp_bss == NULL || tmp_conf == NULL) { 2233281806Srpaulo hostapd_config_free(conf); 2234281806Srpaulo return NULL; 2235281806Srpaulo } 2236281806Srpaulo bss = iface->conf->bss[iface->conf->num_bss] = conf->bss[0]; 2237281806Srpaulo iface->conf->num_bss++; 2238281806Srpaulo 2239281806Srpaulo hapd = hostapd_alloc_bss_data(iface, iface->conf, bss); 2240281806Srpaulo if (hapd == NULL) { 2241281806Srpaulo iface->conf->num_bss--; 2242281806Srpaulo hostapd_config_free(conf); 2243281806Srpaulo return NULL; 2244281806Srpaulo } 2245281806Srpaulo iface->conf->last_bss = bss; 2246281806Srpaulo iface->bss[iface->num_bss] = hapd; 2247281806Srpaulo hapd->msg_ctx = hapd; 2248281806Srpaulo 2249281806Srpaulo bss_idx = iface->num_bss++; 2250281806Srpaulo conf->num_bss--; 2251281806Srpaulo conf->bss[0] = NULL; 2252281806Srpaulo hostapd_config_free(conf); 2253281806Srpaulo } else { 2254281806Srpaulo /* Add a new iface with the first BSS */ 2255281806Srpaulo new_iface = iface = hostapd_init(interfaces, config_fname); 2256281806Srpaulo if (!iface) 2257281806Srpaulo return NULL; 2258281806Srpaulo os_strlcpy(iface->phy, phy, sizeof(iface->phy)); 2259281806Srpaulo iface->interfaces = interfaces; 2260281806Srpaulo bss_idx = 0; 2261281806Srpaulo } 2262281806Srpaulo 2263281806Srpaulo for (k = 0; k < debug; k++) { 2264281806Srpaulo if (iface->bss[bss_idx]->conf->logger_stdout_level > 0) 2265281806Srpaulo iface->bss[bss_idx]->conf->logger_stdout_level--; 2266281806Srpaulo } 2267281806Srpaulo 2268281806Srpaulo if (iface->conf->bss[bss_idx]->iface[0] == '\0' && 2269281806Srpaulo !hostapd_drv_none(iface->bss[bss_idx])) { 2270281806Srpaulo wpa_printf(MSG_ERROR, "Interface name not specified in %s", 2271281806Srpaulo config_fname); 2272281806Srpaulo if (new_iface) 2273281806Srpaulo hostapd_interface_deinit_free(new_iface); 2274281806Srpaulo return NULL; 2275281806Srpaulo } 2276281806Srpaulo 2277281806Srpaulo return iface; 2278281806Srpaulo} 2279281806Srpaulo 2280281806Srpaulo 2281252726Srpaulovoid hostapd_interface_deinit_free(struct hostapd_iface *iface) 2282252726Srpaulo{ 2283252726Srpaulo const struct wpa_driver_ops *driver; 2284252726Srpaulo void *drv_priv; 2285281806Srpaulo 2286281806Srpaulo wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); 2287252726Srpaulo if (iface == NULL) 2288252726Srpaulo return; 2289281806Srpaulo wpa_printf(MSG_DEBUG, "%s: num_bss=%u conf->num_bss=%u", 2290281806Srpaulo __func__, (unsigned int) iface->num_bss, 2291281806Srpaulo (unsigned int) iface->conf->num_bss); 2292252726Srpaulo driver = iface->bss[0]->driver; 2293252726Srpaulo drv_priv = iface->bss[0]->drv_priv; 2294252726Srpaulo hostapd_interface_deinit(iface); 2295281806Srpaulo wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit", 2296281806Srpaulo __func__, driver, drv_priv); 2297281806Srpaulo if (driver && driver->hapd_deinit && drv_priv) { 2298252726Srpaulo driver->hapd_deinit(drv_priv); 2299281806Srpaulo iface->bss[0]->drv_priv = NULL; 2300281806Srpaulo } 2301252726Srpaulo hostapd_interface_free(iface); 2302252726Srpaulo} 2303252726Srpaulo 2304252726Srpaulo 2305281806Srpaulostatic void hostapd_deinit_driver(const struct wpa_driver_ops *driver, 2306281806Srpaulo void *drv_priv, 2307281806Srpaulo struct hostapd_iface *hapd_iface) 2308281806Srpaulo{ 2309281806Srpaulo size_t j; 2310281806Srpaulo 2311281806Srpaulo wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit", 2312281806Srpaulo __func__, driver, drv_priv); 2313281806Srpaulo if (driver && driver->hapd_deinit && drv_priv) { 2314281806Srpaulo driver->hapd_deinit(drv_priv); 2315281806Srpaulo for (j = 0; j < hapd_iface->num_bss; j++) { 2316281806Srpaulo wpa_printf(MSG_DEBUG, "%s:bss[%d]->drv_priv=%p", 2317281806Srpaulo __func__, (int) j, 2318281806Srpaulo hapd_iface->bss[j]->drv_priv); 2319281806Srpaulo if (hapd_iface->bss[j]->drv_priv == drv_priv) 2320281806Srpaulo hapd_iface->bss[j]->drv_priv = NULL; 2321281806Srpaulo } 2322281806Srpaulo } 2323281806Srpaulo} 2324281806Srpaulo 2325281806Srpaulo 2326252726Srpauloint hostapd_enable_iface(struct hostapd_iface *hapd_iface) 2327252726Srpaulo{ 2328281806Srpaulo size_t j; 2329281806Srpaulo 2330252726Srpaulo if (hapd_iface->bss[0]->drv_priv != NULL) { 2331252726Srpaulo wpa_printf(MSG_ERROR, "Interface %s already enabled", 2332281806Srpaulo hapd_iface->conf->bss[0]->iface); 2333252726Srpaulo return -1; 2334252726Srpaulo } 2335252726Srpaulo 2336252726Srpaulo wpa_printf(MSG_DEBUG, "Enable interface %s", 2337281806Srpaulo hapd_iface->conf->bss[0]->iface); 2338252726Srpaulo 2339281806Srpaulo for (j = 0; j < hapd_iface->num_bss; j++) 2340281806Srpaulo hostapd_set_security_params(hapd_iface->conf->bss[j], 1); 2341281806Srpaulo if (hostapd_config_check(hapd_iface->conf, 1) < 0) { 2342281806Srpaulo wpa_printf(MSG_INFO, "Invalid configuration - cannot enable"); 2343281806Srpaulo return -1; 2344281806Srpaulo } 2345281806Srpaulo 2346252726Srpaulo if (hapd_iface->interfaces == NULL || 2347252726Srpaulo hapd_iface->interfaces->driver_init == NULL || 2348281806Srpaulo hapd_iface->interfaces->driver_init(hapd_iface)) 2349252726Srpaulo return -1; 2350281806Srpaulo 2351281806Srpaulo if (hostapd_setup_interface(hapd_iface)) { 2352281806Srpaulo hostapd_deinit_driver(hapd_iface->bss[0]->driver, 2353281806Srpaulo hapd_iface->bss[0]->drv_priv, 2354281806Srpaulo hapd_iface); 2355281806Srpaulo return -1; 2356252726Srpaulo } 2357281806Srpaulo 2358252726Srpaulo return 0; 2359252726Srpaulo} 2360252726Srpaulo 2361252726Srpaulo 2362252726Srpauloint hostapd_reload_iface(struct hostapd_iface *hapd_iface) 2363252726Srpaulo{ 2364252726Srpaulo size_t j; 2365252726Srpaulo 2366252726Srpaulo wpa_printf(MSG_DEBUG, "Reload interface %s", 2367281806Srpaulo hapd_iface->conf->bss[0]->iface); 2368281806Srpaulo for (j = 0; j < hapd_iface->num_bss; j++) 2369281806Srpaulo hostapd_set_security_params(hapd_iface->conf->bss[j], 1); 2370281806Srpaulo if (hostapd_config_check(hapd_iface->conf, 1) < 0) { 2371281806Srpaulo wpa_printf(MSG_ERROR, "Updated configuration is invalid"); 2372281806Srpaulo return -1; 2373281806Srpaulo } 2374281806Srpaulo hostapd_clear_old(hapd_iface); 2375281806Srpaulo for (j = 0; j < hapd_iface->num_bss; j++) 2376281806Srpaulo hostapd_reload_bss(hapd_iface->bss[j]); 2377252726Srpaulo 2378252726Srpaulo return 0; 2379252726Srpaulo} 2380252726Srpaulo 2381252726Srpaulo 2382252726Srpauloint hostapd_disable_iface(struct hostapd_iface *hapd_iface) 2383252726Srpaulo{ 2384252726Srpaulo size_t j; 2385252726Srpaulo const struct wpa_driver_ops *driver; 2386252726Srpaulo void *drv_priv; 2387252726Srpaulo 2388252726Srpaulo if (hapd_iface == NULL) 2389252726Srpaulo return -1; 2390281806Srpaulo 2391281806Srpaulo if (hapd_iface->bss[0]->drv_priv == NULL) { 2392281806Srpaulo wpa_printf(MSG_INFO, "Interface %s already disabled", 2393281806Srpaulo hapd_iface->conf->bss[0]->iface); 2394281806Srpaulo return -1; 2395281806Srpaulo } 2396281806Srpaulo 2397281806Srpaulo wpa_msg(hapd_iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); 2398252726Srpaulo driver = hapd_iface->bss[0]->driver; 2399252726Srpaulo drv_priv = hapd_iface->bss[0]->drv_priv; 2400252726Srpaulo 2401281806Srpaulo hapd_iface->driver_ap_teardown = 2402281806Srpaulo !!(hapd_iface->drv_flags & 2403281806Srpaulo WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT); 2404281806Srpaulo 2405281806Srpaulo /* same as hostapd_interface_deinit without deinitializing ctrl-iface */ 2406252726Srpaulo for (j = 0; j < hapd_iface->num_bss; j++) { 2407252726Srpaulo struct hostapd_data *hapd = hapd_iface->bss[j]; 2408281806Srpaulo hostapd_bss_deinit_no_free(hapd); 2409252726Srpaulo hostapd_free_hapd_data(hapd); 2410252726Srpaulo } 2411252726Srpaulo 2412281806Srpaulo hostapd_deinit_driver(driver, drv_priv, hapd_iface); 2413252726Srpaulo 2414252726Srpaulo /* From hostapd_cleanup_iface: These were initialized in 2415252726Srpaulo * hostapd_setup_interface and hostapd_setup_interface_complete 2416252726Srpaulo */ 2417252726Srpaulo hostapd_cleanup_iface_partial(hapd_iface); 2418252726Srpaulo 2419281806Srpaulo wpa_printf(MSG_DEBUG, "Interface %s disabled", 2420281806Srpaulo hapd_iface->bss[0]->conf->iface); 2421281806Srpaulo hostapd_set_state(hapd_iface, HAPD_IFACE_DISABLED); 2422252726Srpaulo return 0; 2423252726Srpaulo} 2424252726Srpaulo 2425252726Srpaulo 2426252726Srpaulostatic struct hostapd_iface * 2427252726Srpaulohostapd_iface_alloc(struct hapd_interfaces *interfaces) 2428252726Srpaulo{ 2429252726Srpaulo struct hostapd_iface **iface, *hapd_iface; 2430252726Srpaulo 2431252726Srpaulo iface = os_realloc_array(interfaces->iface, interfaces->count + 1, 2432252726Srpaulo sizeof(struct hostapd_iface *)); 2433252726Srpaulo if (iface == NULL) 2434252726Srpaulo return NULL; 2435252726Srpaulo interfaces->iface = iface; 2436252726Srpaulo hapd_iface = interfaces->iface[interfaces->count] = 2437337817Scy hostapd_alloc_iface(); 2438252726Srpaulo if (hapd_iface == NULL) { 2439252726Srpaulo wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for " 2440252726Srpaulo "the interface", __func__); 2441252726Srpaulo return NULL; 2442252726Srpaulo } 2443252726Srpaulo interfaces->count++; 2444252726Srpaulo hapd_iface->interfaces = interfaces; 2445252726Srpaulo 2446252726Srpaulo return hapd_iface; 2447252726Srpaulo} 2448252726Srpaulo 2449252726Srpaulo 2450252726Srpaulostatic struct hostapd_config * 2451252726Srpaulohostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname, 2452289549Srpaulo const char *ctrl_iface, const char *driver) 2453252726Srpaulo{ 2454252726Srpaulo struct hostapd_bss_config *bss; 2455252726Srpaulo struct hostapd_config *conf; 2456252726Srpaulo 2457252726Srpaulo /* Allocates memory for bss and conf */ 2458252726Srpaulo conf = hostapd_config_defaults(); 2459252726Srpaulo if (conf == NULL) { 2460252726Srpaulo wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for " 2461252726Srpaulo "configuration", __func__); 2462252726Srpaulo return NULL; 2463252726Srpaulo } 2464252726Srpaulo 2465289549Srpaulo if (driver) { 2466289549Srpaulo int j; 2467289549Srpaulo 2468289549Srpaulo for (j = 0; wpa_drivers[j]; j++) { 2469289549Srpaulo if (os_strcmp(driver, wpa_drivers[j]->name) == 0) { 2470289549Srpaulo conf->driver = wpa_drivers[j]; 2471289549Srpaulo goto skip; 2472289549Srpaulo } 2473289549Srpaulo } 2474289549Srpaulo 2475289549Srpaulo wpa_printf(MSG_ERROR, 2476289549Srpaulo "Invalid/unknown driver '%s' - registering the default driver", 2477289549Srpaulo driver); 2478289549Srpaulo } 2479289549Srpaulo 2480252726Srpaulo conf->driver = wpa_drivers[0]; 2481252726Srpaulo if (conf->driver == NULL) { 2482252726Srpaulo wpa_printf(MSG_ERROR, "No driver wrappers registered!"); 2483252726Srpaulo hostapd_config_free(conf); 2484252726Srpaulo return NULL; 2485252726Srpaulo } 2486252726Srpaulo 2487289549Srpauloskip: 2488281806Srpaulo bss = conf->last_bss = conf->bss[0]; 2489252726Srpaulo 2490252726Srpaulo os_strlcpy(bss->iface, ifname, sizeof(bss->iface)); 2491252726Srpaulo bss->ctrl_interface = os_strdup(ctrl_iface); 2492252726Srpaulo if (bss->ctrl_interface == NULL) { 2493252726Srpaulo hostapd_config_free(conf); 2494252726Srpaulo return NULL; 2495252726Srpaulo } 2496252726Srpaulo 2497252726Srpaulo /* Reading configuration file skipped, will be done in SET! 2498252726Srpaulo * From reading the configuration till the end has to be done in 2499252726Srpaulo * SET 2500252726Srpaulo */ 2501252726Srpaulo return conf; 2502252726Srpaulo} 2503252726Srpaulo 2504252726Srpaulo 2505281806Srpaulostatic int hostapd_data_alloc(struct hostapd_iface *hapd_iface, 2506281806Srpaulo struct hostapd_config *conf) 2507252726Srpaulo{ 2508252726Srpaulo size_t i; 2509252726Srpaulo struct hostapd_data *hapd; 2510252726Srpaulo 2511281806Srpaulo hapd_iface->bss = os_calloc(conf->num_bss, 2512252726Srpaulo sizeof(struct hostapd_data *)); 2513252726Srpaulo if (hapd_iface->bss == NULL) 2514281806Srpaulo return -1; 2515252726Srpaulo 2516252726Srpaulo for (i = 0; i < conf->num_bss; i++) { 2517252726Srpaulo hapd = hapd_iface->bss[i] = 2518281806Srpaulo hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]); 2519281806Srpaulo if (hapd == NULL) { 2520281806Srpaulo while (i > 0) { 2521281806Srpaulo i--; 2522281806Srpaulo os_free(hapd_iface->bss[i]); 2523281806Srpaulo hapd_iface->bss[i] = NULL; 2524281806Srpaulo } 2525281806Srpaulo os_free(hapd_iface->bss); 2526281806Srpaulo hapd_iface->bss = NULL; 2527281806Srpaulo return -1; 2528281806Srpaulo } 2529252726Srpaulo hapd->msg_ctx = hapd; 2530252726Srpaulo } 2531252726Srpaulo 2532281806Srpaulo hapd_iface->conf = conf; 2533281806Srpaulo hapd_iface->num_bss = conf->num_bss; 2534252726Srpaulo 2535281806Srpaulo return 0; 2536252726Srpaulo} 2537252726Srpaulo 2538252726Srpaulo 2539252726Srpauloint hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf) 2540252726Srpaulo{ 2541252726Srpaulo struct hostapd_config *conf = NULL; 2542281806Srpaulo struct hostapd_iface *hapd_iface = NULL, *new_iface = NULL; 2543281806Srpaulo struct hostapd_data *hapd; 2544252726Srpaulo char *ptr; 2545281806Srpaulo size_t i, j; 2546281806Srpaulo const char *conf_file = NULL, *phy_name = NULL; 2547252726Srpaulo 2548281806Srpaulo if (os_strncmp(buf, "bss_config=", 11) == 0) { 2549281806Srpaulo char *pos; 2550281806Srpaulo phy_name = buf + 11; 2551281806Srpaulo pos = os_strchr(phy_name, ':'); 2552281806Srpaulo if (!pos) 2553281806Srpaulo return -1; 2554281806Srpaulo *pos++ = '\0'; 2555281806Srpaulo conf_file = pos; 2556281806Srpaulo if (!os_strlen(conf_file)) 2557281806Srpaulo return -1; 2558281806Srpaulo 2559281806Srpaulo hapd_iface = hostapd_interface_init_bss(interfaces, phy_name, 2560281806Srpaulo conf_file, 0); 2561281806Srpaulo if (!hapd_iface) 2562281806Srpaulo return -1; 2563281806Srpaulo for (j = 0; j < interfaces->count; j++) { 2564281806Srpaulo if (interfaces->iface[j] == hapd_iface) 2565281806Srpaulo break; 2566281806Srpaulo } 2567281806Srpaulo if (j == interfaces->count) { 2568281806Srpaulo struct hostapd_iface **tmp; 2569281806Srpaulo tmp = os_realloc_array(interfaces->iface, 2570281806Srpaulo interfaces->count + 1, 2571281806Srpaulo sizeof(struct hostapd_iface *)); 2572281806Srpaulo if (!tmp) { 2573281806Srpaulo hostapd_interface_deinit_free(hapd_iface); 2574281806Srpaulo return -1; 2575281806Srpaulo } 2576281806Srpaulo interfaces->iface = tmp; 2577281806Srpaulo interfaces->iface[interfaces->count++] = hapd_iface; 2578281806Srpaulo new_iface = hapd_iface; 2579281806Srpaulo } 2580281806Srpaulo 2581281806Srpaulo if (new_iface) { 2582281806Srpaulo if (interfaces->driver_init(hapd_iface)) 2583281806Srpaulo goto fail; 2584281806Srpaulo 2585281806Srpaulo if (hostapd_setup_interface(hapd_iface)) { 2586281806Srpaulo hostapd_deinit_driver( 2587281806Srpaulo hapd_iface->bss[0]->driver, 2588281806Srpaulo hapd_iface->bss[0]->drv_priv, 2589281806Srpaulo hapd_iface); 2590281806Srpaulo goto fail; 2591281806Srpaulo } 2592281806Srpaulo } else { 2593281806Srpaulo /* Assign new BSS with bss[0]'s driver info */ 2594281806Srpaulo hapd = hapd_iface->bss[hapd_iface->num_bss - 1]; 2595281806Srpaulo hapd->driver = hapd_iface->bss[0]->driver; 2596281806Srpaulo hapd->drv_priv = hapd_iface->bss[0]->drv_priv; 2597281806Srpaulo os_memcpy(hapd->own_addr, hapd_iface->bss[0]->own_addr, 2598281806Srpaulo ETH_ALEN); 2599281806Srpaulo 2600281806Srpaulo if (start_ctrl_iface_bss(hapd) < 0 || 2601281806Srpaulo (hapd_iface->state == HAPD_IFACE_ENABLED && 2602281806Srpaulo hostapd_setup_bss(hapd, -1))) { 2603281806Srpaulo hostapd_cleanup(hapd); 2604281806Srpaulo hapd_iface->bss[hapd_iface->num_bss - 1] = NULL; 2605281806Srpaulo hapd_iface->conf->num_bss--; 2606281806Srpaulo hapd_iface->num_bss--; 2607281806Srpaulo wpa_printf(MSG_DEBUG, "%s: free hapd %p %s", 2608281806Srpaulo __func__, hapd, hapd->conf->iface); 2609281806Srpaulo hostapd_config_free_bss(hapd->conf); 2610281806Srpaulo hapd->conf = NULL; 2611281806Srpaulo os_free(hapd); 2612281806Srpaulo return -1; 2613281806Srpaulo } 2614281806Srpaulo } 2615281806Srpaulo return 0; 2616281806Srpaulo } 2617281806Srpaulo 2618252726Srpaulo ptr = os_strchr(buf, ' '); 2619252726Srpaulo if (ptr == NULL) 2620252726Srpaulo return -1; 2621252726Srpaulo *ptr++ = '\0'; 2622252726Srpaulo 2623281806Srpaulo if (os_strncmp(ptr, "config=", 7) == 0) 2624281806Srpaulo conf_file = ptr + 7; 2625281806Srpaulo 2626252726Srpaulo for (i = 0; i < interfaces->count; i++) { 2627281806Srpaulo if (!os_strcmp(interfaces->iface[i]->conf->bss[0]->iface, 2628252726Srpaulo buf)) { 2629252726Srpaulo wpa_printf(MSG_INFO, "Cannot add interface - it " 2630252726Srpaulo "already exists"); 2631252726Srpaulo return -1; 2632252726Srpaulo } 2633252726Srpaulo } 2634252726Srpaulo 2635252726Srpaulo hapd_iface = hostapd_iface_alloc(interfaces); 2636252726Srpaulo if (hapd_iface == NULL) { 2637252726Srpaulo wpa_printf(MSG_ERROR, "%s: Failed to allocate memory " 2638252726Srpaulo "for interface", __func__); 2639252726Srpaulo goto fail; 2640252726Srpaulo } 2641281806Srpaulo new_iface = hapd_iface; 2642252726Srpaulo 2643281806Srpaulo if (conf_file && interfaces->config_read_cb) { 2644281806Srpaulo conf = interfaces->config_read_cb(conf_file); 2645281806Srpaulo if (conf && conf->bss) 2646281806Srpaulo os_strlcpy(conf->bss[0]->iface, buf, 2647281806Srpaulo sizeof(conf->bss[0]->iface)); 2648289549Srpaulo } else { 2649289549Srpaulo char *driver = os_strchr(ptr, ' '); 2650289549Srpaulo 2651289549Srpaulo if (driver) 2652289549Srpaulo *driver++ = '\0'; 2653289549Srpaulo conf = hostapd_config_alloc(interfaces, buf, ptr, driver); 2654289549Srpaulo } 2655289549Srpaulo 2656281806Srpaulo if (conf == NULL || conf->bss == NULL) { 2657252726Srpaulo wpa_printf(MSG_ERROR, "%s: Failed to allocate memory " 2658252726Srpaulo "for configuration", __func__); 2659252726Srpaulo goto fail; 2660252726Srpaulo } 2661252726Srpaulo 2662281806Srpaulo if (hostapd_data_alloc(hapd_iface, conf) < 0) { 2663252726Srpaulo wpa_printf(MSG_ERROR, "%s: Failed to allocate memory " 2664252726Srpaulo "for hostapd", __func__); 2665252726Srpaulo goto fail; 2666252726Srpaulo } 2667281806Srpaulo conf = NULL; 2668252726Srpaulo 2669281806Srpaulo if (start_ctrl_iface(hapd_iface) < 0) 2670252726Srpaulo goto fail; 2671252726Srpaulo 2672281806Srpaulo wpa_printf(MSG_INFO, "Add interface '%s'", 2673281806Srpaulo hapd_iface->conf->bss[0]->iface); 2674281806Srpaulo 2675252726Srpaulo return 0; 2676252726Srpaulo 2677252726Srpaulofail: 2678252726Srpaulo if (conf) 2679252726Srpaulo hostapd_config_free(conf); 2680252726Srpaulo if (hapd_iface) { 2681281806Srpaulo if (hapd_iface->bss) { 2682281806Srpaulo for (i = 0; i < hapd_iface->num_bss; i++) { 2683281806Srpaulo hapd = hapd_iface->bss[i]; 2684281806Srpaulo if (!hapd) 2685281806Srpaulo continue; 2686281806Srpaulo if (hapd_iface->interfaces && 2687281806Srpaulo hapd_iface->interfaces->ctrl_iface_deinit) 2688281806Srpaulo hapd_iface->interfaces-> 2689281806Srpaulo ctrl_iface_deinit(hapd); 2690281806Srpaulo wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)", 2691281806Srpaulo __func__, hapd_iface->bss[i], 2692281806Srpaulo hapd->conf->iface); 2693281806Srpaulo hostapd_cleanup(hapd); 2694281806Srpaulo os_free(hapd); 2695281806Srpaulo hapd_iface->bss[i] = NULL; 2696281806Srpaulo } 2697281806Srpaulo os_free(hapd_iface->bss); 2698281806Srpaulo hapd_iface->bss = NULL; 2699281806Srpaulo } 2700281806Srpaulo if (new_iface) { 2701281806Srpaulo interfaces->count--; 2702281806Srpaulo interfaces->iface[interfaces->count] = NULL; 2703281806Srpaulo } 2704281806Srpaulo hostapd_cleanup_iface(hapd_iface); 2705252726Srpaulo } 2706252726Srpaulo return -1; 2707252726Srpaulo} 2708252726Srpaulo 2709252726Srpaulo 2710281806Srpaulostatic int hostapd_remove_bss(struct hostapd_iface *iface, unsigned int idx) 2711281806Srpaulo{ 2712281806Srpaulo size_t i; 2713281806Srpaulo 2714281806Srpaulo wpa_printf(MSG_INFO, "Remove BSS '%s'", iface->conf->bss[idx]->iface); 2715281806Srpaulo 2716281806Srpaulo /* Remove hostapd_data only if it has already been initialized */ 2717281806Srpaulo if (idx < iface->num_bss) { 2718281806Srpaulo struct hostapd_data *hapd = iface->bss[idx]; 2719281806Srpaulo 2720281806Srpaulo hostapd_bss_deinit(hapd); 2721281806Srpaulo wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)", 2722281806Srpaulo __func__, hapd, hapd->conf->iface); 2723281806Srpaulo hostapd_config_free_bss(hapd->conf); 2724281806Srpaulo hapd->conf = NULL; 2725281806Srpaulo os_free(hapd); 2726281806Srpaulo 2727281806Srpaulo iface->num_bss--; 2728281806Srpaulo 2729281806Srpaulo for (i = idx; i < iface->num_bss; i++) 2730281806Srpaulo iface->bss[i] = iface->bss[i + 1]; 2731281806Srpaulo } else { 2732281806Srpaulo hostapd_config_free_bss(iface->conf->bss[idx]); 2733281806Srpaulo iface->conf->bss[idx] = NULL; 2734281806Srpaulo } 2735281806Srpaulo 2736281806Srpaulo iface->conf->num_bss--; 2737281806Srpaulo for (i = idx; i < iface->conf->num_bss; i++) 2738281806Srpaulo iface->conf->bss[i] = iface->conf->bss[i + 1]; 2739281806Srpaulo 2740281806Srpaulo return 0; 2741281806Srpaulo} 2742281806Srpaulo 2743281806Srpaulo 2744252726Srpauloint hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf) 2745252726Srpaulo{ 2746252726Srpaulo struct hostapd_iface *hapd_iface; 2747281806Srpaulo size_t i, j, k = 0; 2748252726Srpaulo 2749252726Srpaulo for (i = 0; i < interfaces->count; i++) { 2750252726Srpaulo hapd_iface = interfaces->iface[i]; 2751252726Srpaulo if (hapd_iface == NULL) 2752252726Srpaulo return -1; 2753281806Srpaulo if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) { 2754252726Srpaulo wpa_printf(MSG_INFO, "Remove interface '%s'", buf); 2755281806Srpaulo hapd_iface->driver_ap_teardown = 2756281806Srpaulo !!(hapd_iface->drv_flags & 2757281806Srpaulo WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT); 2758281806Srpaulo 2759252726Srpaulo hostapd_interface_deinit_free(hapd_iface); 2760252726Srpaulo k = i; 2761252726Srpaulo while (k < (interfaces->count - 1)) { 2762252726Srpaulo interfaces->iface[k] = 2763252726Srpaulo interfaces->iface[k + 1]; 2764252726Srpaulo k++; 2765252726Srpaulo } 2766252726Srpaulo interfaces->count--; 2767252726Srpaulo return 0; 2768252726Srpaulo } 2769281806Srpaulo 2770281806Srpaulo for (j = 0; j < hapd_iface->conf->num_bss; j++) { 2771281806Srpaulo if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf)) { 2772281806Srpaulo hapd_iface->driver_ap_teardown = 2773281806Srpaulo !(hapd_iface->drv_flags & 2774281806Srpaulo WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT); 2775281806Srpaulo return hostapd_remove_bss(hapd_iface, j); 2776281806Srpaulo } 2777281806Srpaulo } 2778252726Srpaulo } 2779252726Srpaulo return -1; 2780252726Srpaulo} 2781252726Srpaulo 2782252726Srpaulo 2783214501Srpaulo/** 2784214501Srpaulo * hostapd_new_assoc_sta - Notify that a new station associated with the AP 2785214501Srpaulo * @hapd: Pointer to BSS data 2786214501Srpaulo * @sta: Pointer to the associated STA data 2787214501Srpaulo * @reassoc: 1 to indicate this was a re-association; 0 = first association 2788214501Srpaulo * 2789214501Srpaulo * This function will be called whenever a station associates with the AP. It 2790214501Srpaulo * can be called from ieee802_11.c for drivers that export MLME to hostapd and 2791214501Srpaulo * from drv_callbacks.c based on driver events for drivers that take care of 2792214501Srpaulo * management frames (IEEE 802.11 authentication and association) internally. 2793214501Srpaulo */ 2794214501Srpaulovoid hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, 2795214501Srpaulo int reassoc) 2796214501Srpaulo{ 2797214501Srpaulo if (hapd->tkip_countermeasures) { 2798252726Srpaulo hostapd_drv_sta_deauth(hapd, sta->addr, 2799252726Srpaulo WLAN_REASON_MICHAEL_MIC_FAILURE); 2800214501Srpaulo return; 2801214501Srpaulo } 2802214501Srpaulo 2803214501Srpaulo hostapd_prune_associations(hapd, sta->addr); 2804337817Scy ap_sta_clear_disconnect_timeouts(hapd, sta); 2805214501Srpaulo 2806214501Srpaulo /* IEEE 802.11F (IAPP) */ 2807214501Srpaulo if (hapd->conf->ieee802_11f) 2808214501Srpaulo iapp_new_station(hapd->iapp, sta); 2809214501Srpaulo 2810252726Srpaulo#ifdef CONFIG_P2P 2811252726Srpaulo if (sta->p2p_ie == NULL && !sta->no_p2p_set) { 2812252726Srpaulo sta->no_p2p_set = 1; 2813252726Srpaulo hapd->num_sta_no_p2p++; 2814252726Srpaulo if (hapd->num_sta_no_p2p == 1) 2815252726Srpaulo hostapd_p2p_non_p2p_sta_connected(hapd); 2816252726Srpaulo } 2817252726Srpaulo#endif /* CONFIG_P2P */ 2818252726Srpaulo 2819214501Srpaulo /* Start accounting here, if IEEE 802.1X and WPA are not used. 2820214501Srpaulo * IEEE 802.1X/WPA code will start accounting after the station has 2821214501Srpaulo * been authorized. */ 2822281806Srpaulo if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen) { 2823281806Srpaulo ap_sta_set_authorized(hapd, sta, 1); 2824281806Srpaulo os_get_reltime(&sta->connected_time); 2825214501Srpaulo accounting_sta_start(hapd, sta); 2826252726Srpaulo } 2827214501Srpaulo 2828214501Srpaulo /* Start IEEE 802.1X authentication process for new stations */ 2829214501Srpaulo ieee802_1x_new_station(hapd, sta); 2830214501Srpaulo if (reassoc) { 2831214501Srpaulo if (sta->auth_alg != WLAN_AUTH_FT && 2832214501Srpaulo !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) 2833214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH); 2834214501Srpaulo } else 2835214501Srpaulo wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm); 2836252726Srpaulo 2837281806Srpaulo if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) { 2838337817Scy wpa_printf(MSG_DEBUG, 2839337817Scy "%s: %s: reschedule ap_handle_timer timeout for " 2840337817Scy MACSTR " (%d seconds - ap_max_inactivity)", 2841337817Scy hapd->conf->iface, __func__, MAC2STR(sta->addr), 2842281806Srpaulo hapd->conf->ap_max_inactivity); 2843281806Srpaulo eloop_cancel_timeout(ap_handle_timer, hapd, sta); 2844281806Srpaulo eloop_register_timeout(hapd->conf->ap_max_inactivity, 0, 2845281806Srpaulo ap_handle_timer, hapd, sta); 2846281806Srpaulo } 2847214501Srpaulo} 2848281806Srpaulo 2849281806Srpaulo 2850281806Srpauloconst char * hostapd_state_text(enum hostapd_iface_state s) 2851281806Srpaulo{ 2852281806Srpaulo switch (s) { 2853281806Srpaulo case HAPD_IFACE_UNINITIALIZED: 2854281806Srpaulo return "UNINITIALIZED"; 2855281806Srpaulo case HAPD_IFACE_DISABLED: 2856281806Srpaulo return "DISABLED"; 2857281806Srpaulo case HAPD_IFACE_COUNTRY_UPDATE: 2858281806Srpaulo return "COUNTRY_UPDATE"; 2859281806Srpaulo case HAPD_IFACE_ACS: 2860281806Srpaulo return "ACS"; 2861281806Srpaulo case HAPD_IFACE_HT_SCAN: 2862281806Srpaulo return "HT_SCAN"; 2863281806Srpaulo case HAPD_IFACE_DFS: 2864281806Srpaulo return "DFS"; 2865281806Srpaulo case HAPD_IFACE_ENABLED: 2866281806Srpaulo return "ENABLED"; 2867281806Srpaulo } 2868281806Srpaulo 2869281806Srpaulo return "UNKNOWN"; 2870281806Srpaulo} 2871281806Srpaulo 2872281806Srpaulo 2873281806Srpaulovoid hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s) 2874281806Srpaulo{ 2875281806Srpaulo wpa_printf(MSG_INFO, "%s: interface state %s->%s", 2876337817Scy iface->conf ? iface->conf->bss[0]->iface : "N/A", 2877337817Scy hostapd_state_text(iface->state), hostapd_state_text(s)); 2878281806Srpaulo iface->state = s; 2879281806Srpaulo} 2880281806Srpaulo 2881281806Srpaulo 2882337817Scyint hostapd_csa_in_progress(struct hostapd_iface *iface) 2883337817Scy{ 2884337817Scy unsigned int i; 2885337817Scy 2886337817Scy for (i = 0; i < iface->num_bss; i++) 2887337817Scy if (iface->bss[i]->csa_in_progress) 2888337817Scy return 1; 2889337817Scy return 0; 2890337817Scy} 2891337817Scy 2892337817Scy 2893281806Srpaulo#ifdef NEED_AP_MLME 2894281806Srpaulo 2895281806Srpaulostatic void free_beacon_data(struct beacon_data *beacon) 2896281806Srpaulo{ 2897281806Srpaulo os_free(beacon->head); 2898281806Srpaulo beacon->head = NULL; 2899281806Srpaulo os_free(beacon->tail); 2900281806Srpaulo beacon->tail = NULL; 2901281806Srpaulo os_free(beacon->probe_resp); 2902281806Srpaulo beacon->probe_resp = NULL; 2903281806Srpaulo os_free(beacon->beacon_ies); 2904281806Srpaulo beacon->beacon_ies = NULL; 2905281806Srpaulo os_free(beacon->proberesp_ies); 2906281806Srpaulo beacon->proberesp_ies = NULL; 2907281806Srpaulo os_free(beacon->assocresp_ies); 2908281806Srpaulo beacon->assocresp_ies = NULL; 2909281806Srpaulo} 2910281806Srpaulo 2911281806Srpaulo 2912281806Srpaulostatic int hostapd_build_beacon_data(struct hostapd_data *hapd, 2913281806Srpaulo struct beacon_data *beacon) 2914281806Srpaulo{ 2915281806Srpaulo struct wpabuf *beacon_extra, *proberesp_extra, *assocresp_extra; 2916281806Srpaulo struct wpa_driver_ap_params params; 2917281806Srpaulo int ret; 2918281806Srpaulo 2919281806Srpaulo os_memset(beacon, 0, sizeof(*beacon)); 2920281806Srpaulo ret = ieee802_11_build_ap_params(hapd, ¶ms); 2921281806Srpaulo if (ret < 0) 2922281806Srpaulo return ret; 2923281806Srpaulo 2924281806Srpaulo ret = hostapd_build_ap_extra_ies(hapd, &beacon_extra, 2925281806Srpaulo &proberesp_extra, 2926281806Srpaulo &assocresp_extra); 2927281806Srpaulo if (ret) 2928281806Srpaulo goto free_ap_params; 2929281806Srpaulo 2930281806Srpaulo ret = -1; 2931281806Srpaulo beacon->head = os_malloc(params.head_len); 2932281806Srpaulo if (!beacon->head) 2933281806Srpaulo goto free_ap_extra_ies; 2934281806Srpaulo 2935281806Srpaulo os_memcpy(beacon->head, params.head, params.head_len); 2936281806Srpaulo beacon->head_len = params.head_len; 2937281806Srpaulo 2938281806Srpaulo beacon->tail = os_malloc(params.tail_len); 2939281806Srpaulo if (!beacon->tail) 2940281806Srpaulo goto free_beacon; 2941281806Srpaulo 2942281806Srpaulo os_memcpy(beacon->tail, params.tail, params.tail_len); 2943281806Srpaulo beacon->tail_len = params.tail_len; 2944281806Srpaulo 2945281806Srpaulo if (params.proberesp != NULL) { 2946281806Srpaulo beacon->probe_resp = os_malloc(params.proberesp_len); 2947281806Srpaulo if (!beacon->probe_resp) 2948281806Srpaulo goto free_beacon; 2949281806Srpaulo 2950281806Srpaulo os_memcpy(beacon->probe_resp, params.proberesp, 2951281806Srpaulo params.proberesp_len); 2952281806Srpaulo beacon->probe_resp_len = params.proberesp_len; 2953281806Srpaulo } 2954281806Srpaulo 2955281806Srpaulo /* copy the extra ies */ 2956281806Srpaulo if (beacon_extra) { 2957281806Srpaulo beacon->beacon_ies = os_malloc(wpabuf_len(beacon_extra)); 2958281806Srpaulo if (!beacon->beacon_ies) 2959281806Srpaulo goto free_beacon; 2960281806Srpaulo 2961281806Srpaulo os_memcpy(beacon->beacon_ies, 2962281806Srpaulo beacon_extra->buf, wpabuf_len(beacon_extra)); 2963281806Srpaulo beacon->beacon_ies_len = wpabuf_len(beacon_extra); 2964281806Srpaulo } 2965281806Srpaulo 2966281806Srpaulo if (proberesp_extra) { 2967281806Srpaulo beacon->proberesp_ies = 2968281806Srpaulo os_malloc(wpabuf_len(proberesp_extra)); 2969281806Srpaulo if (!beacon->proberesp_ies) 2970281806Srpaulo goto free_beacon; 2971281806Srpaulo 2972281806Srpaulo os_memcpy(beacon->proberesp_ies, proberesp_extra->buf, 2973281806Srpaulo wpabuf_len(proberesp_extra)); 2974281806Srpaulo beacon->proberesp_ies_len = wpabuf_len(proberesp_extra); 2975281806Srpaulo } 2976281806Srpaulo 2977281806Srpaulo if (assocresp_extra) { 2978281806Srpaulo beacon->assocresp_ies = 2979281806Srpaulo os_malloc(wpabuf_len(assocresp_extra)); 2980281806Srpaulo if (!beacon->assocresp_ies) 2981281806Srpaulo goto free_beacon; 2982281806Srpaulo 2983281806Srpaulo os_memcpy(beacon->assocresp_ies, assocresp_extra->buf, 2984281806Srpaulo wpabuf_len(assocresp_extra)); 2985281806Srpaulo beacon->assocresp_ies_len = wpabuf_len(assocresp_extra); 2986281806Srpaulo } 2987281806Srpaulo 2988281806Srpaulo ret = 0; 2989281806Srpaulofree_beacon: 2990281806Srpaulo /* if the function fails, the caller should not free beacon data */ 2991281806Srpaulo if (ret) 2992281806Srpaulo free_beacon_data(beacon); 2993281806Srpaulo 2994281806Srpaulofree_ap_extra_ies: 2995281806Srpaulo hostapd_free_ap_extra_ies(hapd, beacon_extra, proberesp_extra, 2996281806Srpaulo assocresp_extra); 2997281806Srpaulofree_ap_params: 2998281806Srpaulo ieee802_11_free_ap_params(¶ms); 2999281806Srpaulo return ret; 3000281806Srpaulo} 3001281806Srpaulo 3002281806Srpaulo 3003281806Srpaulo/* 3004337817Scy * TODO: This flow currently supports only changing channel and width within 3005337817Scy * the same hw_mode. Any other changes to MAC parameters or provided settings 3006337817Scy * are not supported. 3007281806Srpaulo */ 3008281806Srpaulostatic int hostapd_change_config_freq(struct hostapd_data *hapd, 3009281806Srpaulo struct hostapd_config *conf, 3010281806Srpaulo struct hostapd_freq_params *params, 3011281806Srpaulo struct hostapd_freq_params *old_params) 3012281806Srpaulo{ 3013281806Srpaulo int channel; 3014281806Srpaulo 3015281806Srpaulo if (!params->channel) { 3016281806Srpaulo /* check if the new channel is supported by hw */ 3017281806Srpaulo params->channel = hostapd_hw_get_channel(hapd, params->freq); 3018281806Srpaulo } 3019281806Srpaulo 3020281806Srpaulo channel = params->channel; 3021281806Srpaulo if (!channel) 3022281806Srpaulo return -1; 3023281806Srpaulo 3024281806Srpaulo /* if a pointer to old_params is provided we save previous state */ 3025337817Scy if (old_params && 3026337817Scy hostapd_set_freq_params(old_params, conf->hw_mode, 3027337817Scy hostapd_hw_get_freq(hapd, conf->channel), 3028337817Scy conf->channel, conf->ieee80211n, 3029337817Scy conf->ieee80211ac, 3030337817Scy conf->secondary_channel, 3031337817Scy conf->vht_oper_chwidth, 3032337817Scy conf->vht_oper_centr_freq_seg0_idx, 3033337817Scy conf->vht_oper_centr_freq_seg1_idx, 3034337817Scy conf->vht_capab)) 3035337817Scy return -1; 3036337817Scy 3037337817Scy switch (params->bandwidth) { 3038337817Scy case 0: 3039337817Scy case 20: 3040337817Scy case 40: 3041337817Scy conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT; 3042337817Scy break; 3043337817Scy case 80: 3044337817Scy if (params->center_freq2) 3045337817Scy conf->vht_oper_chwidth = VHT_CHANWIDTH_80P80MHZ; 3046337817Scy else 3047337817Scy conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ; 3048337817Scy break; 3049337817Scy case 160: 3050337817Scy conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ; 3051337817Scy break; 3052337817Scy default: 3053337817Scy return -1; 3054281806Srpaulo } 3055281806Srpaulo 3056281806Srpaulo conf->channel = channel; 3057281806Srpaulo conf->ieee80211n = params->ht_enabled; 3058281806Srpaulo conf->secondary_channel = params->sec_channel_offset; 3059337817Scy ieee80211_freq_to_chan(params->center_freq1, 3060337817Scy &conf->vht_oper_centr_freq_seg0_idx); 3061337817Scy ieee80211_freq_to_chan(params->center_freq2, 3062337817Scy &conf->vht_oper_centr_freq_seg1_idx); 3063281806Srpaulo 3064281806Srpaulo /* TODO: maybe call here hostapd_config_check here? */ 3065281806Srpaulo 3066281806Srpaulo return 0; 3067281806Srpaulo} 3068281806Srpaulo 3069281806Srpaulo 3070281806Srpaulostatic int hostapd_fill_csa_settings(struct hostapd_data *hapd, 3071281806Srpaulo struct csa_settings *settings) 3072281806Srpaulo{ 3073281806Srpaulo struct hostapd_iface *iface = hapd->iface; 3074281806Srpaulo struct hostapd_freq_params old_freq; 3075281806Srpaulo int ret; 3076337817Scy u8 chan, vht_bandwidth; 3077281806Srpaulo 3078281806Srpaulo os_memset(&old_freq, 0, sizeof(old_freq)); 3079281806Srpaulo if (!iface || !iface->freq || hapd->csa_in_progress) 3080281806Srpaulo return -1; 3081281806Srpaulo 3082337817Scy switch (settings->freq_params.bandwidth) { 3083337817Scy case 80: 3084337817Scy if (settings->freq_params.center_freq2) 3085337817Scy vht_bandwidth = VHT_CHANWIDTH_80P80MHZ; 3086337817Scy else 3087337817Scy vht_bandwidth = VHT_CHANWIDTH_80MHZ; 3088337817Scy break; 3089337817Scy case 160: 3090337817Scy vht_bandwidth = VHT_CHANWIDTH_160MHZ; 3091337817Scy break; 3092337817Scy default: 3093337817Scy vht_bandwidth = VHT_CHANWIDTH_USE_HT; 3094337817Scy break; 3095337817Scy } 3096337817Scy 3097337817Scy if (ieee80211_freq_to_channel_ext( 3098337817Scy settings->freq_params.freq, 3099337817Scy settings->freq_params.sec_channel_offset, 3100337817Scy vht_bandwidth, 3101337817Scy &hapd->iface->cs_oper_class, 3102337817Scy &chan) == NUM_HOSTAPD_MODES) { 3103337817Scy wpa_printf(MSG_DEBUG, 3104337817Scy "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d)", 3105337817Scy settings->freq_params.freq, 3106337817Scy settings->freq_params.sec_channel_offset, 3107337817Scy settings->freq_params.vht_enabled); 3108337817Scy return -1; 3109337817Scy } 3110337817Scy 3111337817Scy settings->freq_params.channel = chan; 3112337817Scy 3113281806Srpaulo ret = hostapd_change_config_freq(iface->bss[0], iface->conf, 3114281806Srpaulo &settings->freq_params, 3115281806Srpaulo &old_freq); 3116281806Srpaulo if (ret) 3117281806Srpaulo return ret; 3118281806Srpaulo 3119281806Srpaulo ret = hostapd_build_beacon_data(hapd, &settings->beacon_after); 3120281806Srpaulo 3121281806Srpaulo /* change back the configuration */ 3122281806Srpaulo hostapd_change_config_freq(iface->bss[0], iface->conf, 3123281806Srpaulo &old_freq, NULL); 3124281806Srpaulo 3125281806Srpaulo if (ret) 3126281806Srpaulo return ret; 3127281806Srpaulo 3128281806Srpaulo /* set channel switch parameters for csa ie */ 3129281806Srpaulo hapd->cs_freq_params = settings->freq_params; 3130281806Srpaulo hapd->cs_count = settings->cs_count; 3131281806Srpaulo hapd->cs_block_tx = settings->block_tx; 3132281806Srpaulo 3133281806Srpaulo ret = hostapd_build_beacon_data(hapd, &settings->beacon_csa); 3134281806Srpaulo if (ret) { 3135281806Srpaulo free_beacon_data(&settings->beacon_after); 3136281806Srpaulo return ret; 3137281806Srpaulo } 3138281806Srpaulo 3139337817Scy settings->counter_offset_beacon[0] = hapd->cs_c_off_beacon; 3140337817Scy settings->counter_offset_presp[0] = hapd->cs_c_off_proberesp; 3141337817Scy settings->counter_offset_beacon[1] = hapd->cs_c_off_ecsa_beacon; 3142337817Scy settings->counter_offset_presp[1] = hapd->cs_c_off_ecsa_proberesp; 3143281806Srpaulo 3144281806Srpaulo return 0; 3145281806Srpaulo} 3146281806Srpaulo 3147281806Srpaulo 3148281806Srpaulovoid hostapd_cleanup_cs_params(struct hostapd_data *hapd) 3149281806Srpaulo{ 3150281806Srpaulo os_memset(&hapd->cs_freq_params, 0, sizeof(hapd->cs_freq_params)); 3151281806Srpaulo hapd->cs_count = 0; 3152281806Srpaulo hapd->cs_block_tx = 0; 3153281806Srpaulo hapd->cs_c_off_beacon = 0; 3154281806Srpaulo hapd->cs_c_off_proberesp = 0; 3155281806Srpaulo hapd->csa_in_progress = 0; 3156337817Scy hapd->cs_c_off_ecsa_beacon = 0; 3157337817Scy hapd->cs_c_off_ecsa_proberesp = 0; 3158281806Srpaulo} 3159281806Srpaulo 3160281806Srpaulo 3161281806Srpauloint hostapd_switch_channel(struct hostapd_data *hapd, 3162281806Srpaulo struct csa_settings *settings) 3163281806Srpaulo{ 3164281806Srpaulo int ret; 3165281806Srpaulo 3166281806Srpaulo if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)) { 3167281806Srpaulo wpa_printf(MSG_INFO, "CSA is not supported"); 3168281806Srpaulo return -1; 3169281806Srpaulo } 3170281806Srpaulo 3171281806Srpaulo ret = hostapd_fill_csa_settings(hapd, settings); 3172281806Srpaulo if (ret) 3173281806Srpaulo return ret; 3174281806Srpaulo 3175281806Srpaulo ret = hostapd_drv_switch_channel(hapd, settings); 3176281806Srpaulo free_beacon_data(&settings->beacon_csa); 3177281806Srpaulo free_beacon_data(&settings->beacon_after); 3178281806Srpaulo 3179281806Srpaulo if (ret) { 3180281806Srpaulo /* if we failed, clean cs parameters */ 3181281806Srpaulo hostapd_cleanup_cs_params(hapd); 3182281806Srpaulo return ret; 3183281806Srpaulo } 3184281806Srpaulo 3185281806Srpaulo hapd->csa_in_progress = 1; 3186281806Srpaulo return 0; 3187281806Srpaulo} 3188281806Srpaulo 3189281806Srpaulo 3190281806Srpaulovoid 3191281806Srpaulohostapd_switch_channel_fallback(struct hostapd_iface *iface, 3192281806Srpaulo const struct hostapd_freq_params *freq_params) 3193281806Srpaulo{ 3194281806Srpaulo int vht_seg0_idx = 0, vht_seg1_idx = 0, vht_bw = VHT_CHANWIDTH_USE_HT; 3195281806Srpaulo unsigned int i; 3196281806Srpaulo 3197281806Srpaulo wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes"); 3198281806Srpaulo 3199281806Srpaulo if (freq_params->center_freq1) 3200281806Srpaulo vht_seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5; 3201281806Srpaulo if (freq_params->center_freq2) 3202281806Srpaulo vht_seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5; 3203281806Srpaulo 3204281806Srpaulo switch (freq_params->bandwidth) { 3205281806Srpaulo case 0: 3206281806Srpaulo case 20: 3207281806Srpaulo case 40: 3208281806Srpaulo vht_bw = VHT_CHANWIDTH_USE_HT; 3209281806Srpaulo break; 3210281806Srpaulo case 80: 3211281806Srpaulo if (freq_params->center_freq2) 3212281806Srpaulo vht_bw = VHT_CHANWIDTH_80P80MHZ; 3213281806Srpaulo else 3214281806Srpaulo vht_bw = VHT_CHANWIDTH_80MHZ; 3215281806Srpaulo break; 3216281806Srpaulo case 160: 3217281806Srpaulo vht_bw = VHT_CHANWIDTH_160MHZ; 3218281806Srpaulo break; 3219281806Srpaulo default: 3220281806Srpaulo wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d", 3221281806Srpaulo freq_params->bandwidth); 3222281806Srpaulo break; 3223281806Srpaulo } 3224281806Srpaulo 3225281806Srpaulo iface->freq = freq_params->freq; 3226281806Srpaulo iface->conf->channel = freq_params->channel; 3227281806Srpaulo iface->conf->secondary_channel = freq_params->sec_channel_offset; 3228281806Srpaulo iface->conf->vht_oper_centr_freq_seg0_idx = vht_seg0_idx; 3229281806Srpaulo iface->conf->vht_oper_centr_freq_seg1_idx = vht_seg1_idx; 3230281806Srpaulo iface->conf->vht_oper_chwidth = vht_bw; 3231281806Srpaulo iface->conf->ieee80211n = freq_params->ht_enabled; 3232281806Srpaulo iface->conf->ieee80211ac = freq_params->vht_enabled; 3233281806Srpaulo 3234281806Srpaulo /* 3235281806Srpaulo * cs_params must not be cleared earlier because the freq_params 3236281806Srpaulo * argument may actually point to one of these. 3237281806Srpaulo */ 3238281806Srpaulo for (i = 0; i < iface->num_bss; i++) 3239281806Srpaulo hostapd_cleanup_cs_params(iface->bss[i]); 3240281806Srpaulo 3241281806Srpaulo hostapd_disable_iface(iface); 3242281806Srpaulo hostapd_enable_iface(iface); 3243281806Srpaulo} 3244281806Srpaulo 3245337817Scy#endif /* NEED_AP_MLME */ 3246289549Srpaulo 3247337817Scy 3248289549Srpaulostruct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces, 3249289549Srpaulo const char *ifname) 3250289549Srpaulo{ 3251289549Srpaulo size_t i, j; 3252289549Srpaulo 3253289549Srpaulo for (i = 0; i < interfaces->count; i++) { 3254289549Srpaulo struct hostapd_iface *iface = interfaces->iface[i]; 3255289549Srpaulo 3256289549Srpaulo for (j = 0; j < iface->num_bss; j++) { 3257289549Srpaulo struct hostapd_data *hapd = iface->bss[j]; 3258289549Srpaulo 3259289549Srpaulo if (os_strcmp(ifname, hapd->conf->iface) == 0) 3260289549Srpaulo return hapd; 3261289549Srpaulo } 3262289549Srpaulo } 3263289549Srpaulo 3264289549Srpaulo return NULL; 3265289549Srpaulo} 3266289549Srpaulo 3267289549Srpaulo 3268289549Srpaulovoid hostapd_periodic_iface(struct hostapd_iface *iface) 3269289549Srpaulo{ 3270289549Srpaulo size_t i; 3271289549Srpaulo 3272289549Srpaulo ap_list_timer(iface); 3273289549Srpaulo 3274289549Srpaulo for (i = 0; i < iface->num_bss; i++) { 3275289549Srpaulo struct hostapd_data *hapd = iface->bss[i]; 3276289549Srpaulo 3277289549Srpaulo if (!hapd->started) 3278289549Srpaulo continue; 3279289549Srpaulo 3280289549Srpaulo#ifndef CONFIG_NO_RADIUS 3281289549Srpaulo hostapd_acl_expire(hapd); 3282289549Srpaulo#endif /* CONFIG_NO_RADIUS */ 3283289549Srpaulo } 3284289549Srpaulo} 3285