X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fap%2Fhostapd.c;h=9fafc7f457bb0c8d2a0b4fea8666da6195fbebb1;hb=442819406c9ebf9a10a771053af83e855a6efa3d;hp=36adf3eb8e6bcc4e4e0d0705c39383c2081517e3;hpb=d308a44fccc0b191956649b2264182621986af27;p=mech_eap.git diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 36adf3e..9fafc7f 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -43,6 +43,8 @@ #include "x_snoop.h" #include "dhcp_snoop.h" #include "ndisc_snoop.h" +#include "neighbor_db.h" +#include "rrm.h" static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason); @@ -204,10 +206,12 @@ int hostapd_reload_config(struct hostapd_iface *iface) static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd, - char *ifname) + const char *ifname) { int i; + if (!ifname) + return; for (i = 0; i < NUM_WEP_KEYS; i++) { if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, 0, NULL, 0, NULL, 0)) { @@ -335,6 +339,8 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd) wpabuf_free(hapd->mesh_pending_auth); hapd->mesh_pending_auth = NULL; #endif /* CONFIG_MESH */ + + hostapd_clean_rrm(hapd); } @@ -368,7 +374,7 @@ static void sta_track_deinit(struct hostapd_iface *iface) list))) { dl_list_del(&info->list); iface->num_sta_seen--; - os_free(info); + sta_track_del(info); } } @@ -512,6 +518,9 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface) if (hostapd_drv_none(hapd)) return 0; + if (iface->conf->use_driver_iface_addr) + return 0; + /* Generate BSSID mask that is large enough to cover the BSSIDs. */ /* Determine the bits necessary to cover the number of BSSIDs. */ @@ -521,7 +530,7 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface) /* Determine the bits necessary to any configured BSSIDs, if they are higher than the number of BSSIDs. */ for (j = 0; j < iface->conf->num_bss; j++) { - if (hostapd_mac_comp_empty(iface->conf->bss[j]->bssid) == 0) { + if (is_zero_ether_addr(iface->conf->bss[j]->bssid)) { if (j) auto_addr++; continue; @@ -673,7 +682,7 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd, if (attr->acct_session_id) { num_attr++; - if (attr->acct_session_id_len != 17) { + if (attr->acct_session_id_len != 16) { wpa_printf(MSG_DEBUG, "RADIUS DAS: Acct-Session-Id cannot match"); return NULL; @@ -683,10 +692,9 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd, for (sta = hapd->sta_list; sta; sta = sta->next) { if (!sta->radius_das_match) continue; - os_snprintf(buf, sizeof(buf), "%08X-%08X", - sta->acct_session_id_hi, - sta->acct_session_id_lo); - if (os_memcmp(attr->acct_session_id, buf, 17) != 0) + os_snprintf(buf, sizeof(buf), "%016llX", + (unsigned long long) sta->acct_session_id); + if (os_memcmp(attr->acct_session_id, buf, 16) != 0) sta->radius_das_match = 0; else count++; @@ -702,7 +710,7 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd, if (attr->acct_multi_session_id) { num_attr++; - if (attr->acct_multi_session_id_len != 17) { + if (attr->acct_multi_session_id_len != 16) { wpa_printf(MSG_DEBUG, "RADIUS DAS: Acct-Multi-Session-Id cannot match"); return NULL; @@ -713,14 +721,14 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd, if (!sta->radius_das_match) continue; if (!sta->eapol_sm || - !sta->eapol_sm->acct_multi_session_id_hi) { + !sta->eapol_sm->acct_multi_session_id) { sta->radius_das_match = 0; continue; } - os_snprintf(buf, sizeof(buf), "%08X+%08X", - sta->eapol_sm->acct_multi_session_id_hi, - sta->eapol_sm->acct_multi_session_id_lo); - if (os_memcmp(attr->acct_multi_session_id, buf, 17) != + os_snprintf(buf, sizeof(buf), "%016llX", + (unsigned long long) + sta->eapol_sm->acct_multi_session_id); + if (os_memcmp(attr->acct_multi_session_id, buf, 16) != 0) sta->radius_das_match = 0; else @@ -906,12 +914,9 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) hapd->started = 1; if (!first || first == -1) { - if (hostapd_mac_comp_empty(conf->bssid) == 0) { - /* Allocate the next available BSSID. */ - do { - inc_byte_array(hapd->own_addr, ETH_ALEN); - } while (mac_in_conf(hapd->iconf, hapd->own_addr)); - } else { + u8 *addr = hapd->own_addr; + + if (!is_zero_ether_addr(conf->bssid)) { /* Allocate the configured BSSID. */ os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN); @@ -923,11 +928,18 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) "the radio", conf->iface); return -1; } + } else if (hapd->iconf->use_driver_iface_addr) { + addr = NULL; + } else { + /* Allocate the next available BSSID. */ + do { + inc_byte_array(hapd->own_addr, ETH_ALEN); + } while (mac_in_conf(hapd->iconf, hapd->own_addr)); } hapd->interface_added = 1; if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS, - conf->iface, hapd->own_addr, hapd, + conf->iface, addr, hapd, &hapd->drv_priv, force_ifname, if_addr, conf->bridge[0] ? conf->bridge : NULL, first == -1)) { @@ -936,11 +948,19 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) hapd->interface_added = 0; return -1; } + + if (!addr) + os_memcpy(hapd->own_addr, if_addr, ETH_ALEN); } if (conf->wmm_enabled < 0) conf->wmm_enabled = hapd->iconf->ieee80211n; +#ifdef CONFIG_IEEE80211R + if (is_zero_ether_addr(conf->r1_key_holder)) + os_memcpy(conf->r1_key_holder, hapd->own_addr, ETH_ALEN); +#endif /* CONFIG_IEEE80211R */ + #ifdef CONFIG_MESH if (hapd->iface->mconf == NULL) flush_old_stations = 0; @@ -1023,6 +1043,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) das_conf.time_window = conf->radius_das_time_window; das_conf.require_event_timestamp = conf->radius_das_require_event_timestamp; + das_conf.require_message_authenticator = + conf->radius_das_require_message_authenticator; das_conf.ctx = hapd; das_conf.disconnect = hostapd_das_disconnect; hapd->radius_das = radius_das_init(&das_conf); @@ -1510,15 +1532,128 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd, #endif /* CONFIG_FST */ -/** - * hostapd_setup_interface_complete - Complete interface setup - * - * This function is called when previous steps in the interface setup has been - * completed. This can also start operations, e.g., DFS, that will require - * additional processing before interface is ready to be enabled. Such - * operations will call this function from eloop callbacks when finished. - */ -int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) +#ifdef NEED_AP_MLME +static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd, + int ht, int vht) +{ + if (!ht && !vht) + return NR_CHAN_WIDTH_20; + if (!hapd->iconf->secondary_channel) + return NR_CHAN_WIDTH_20; + if (!vht || hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT) + return NR_CHAN_WIDTH_40; + if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ) + return NR_CHAN_WIDTH_80; + if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ) + return NR_CHAN_WIDTH_160; + if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ) + return NR_CHAN_WIDTH_80P80; + return NR_CHAN_WIDTH_20; +} +#endif /* NEED_AP_MLME */ + + +static void hostapd_set_own_neighbor_report(struct hostapd_data *hapd) +{ +#ifdef NEED_AP_MLME + u16 capab = hostapd_own_capab_info(hapd); + int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n; + int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac; + struct wpa_ssid_value ssid; + u8 channel, op_class; + int center_freq1 = 0, center_freq2 = 0; + enum nr_chan_width width; + u32 bssid_info; + struct wpabuf *nr; + + if (!(hapd->conf->radio_measurements[0] & + WLAN_RRM_CAPS_NEIGHBOR_REPORT)) + return; + + bssid_info = 3; /* AP is reachable */ + bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */ + bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */ + + if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) + bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT; + + bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */ + + if (hapd->conf->wmm_enabled) { + bssid_info |= NEI_REP_BSSID_INFO_QOS; + + if (hapd->conf->wmm_uapsd && + (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD)) + bssid_info |= NEI_REP_BSSID_INFO_APSD; + } + + if (ht) { + bssid_info |= NEI_REP_BSSID_INFO_HT | + NEI_REP_BSSID_INFO_DELAYED_BA; + + /* VHT bit added in IEEE P802.11-REVmc/D4.3 */ + if (vht) + bssid_info |= NEI_REP_BSSID_INFO_VHT; + } + + /* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */ + + ieee80211_freq_to_channel_ext(hapd->iface->freq, + hapd->iconf->secondary_channel, + hapd->iconf->vht_oper_chwidth, + &op_class, &channel); + width = hostapd_get_nr_chan_width(hapd, ht, vht); + if (vht) { + center_freq1 = ieee80211_chan_to_freq( + NULL, op_class, + hapd->iconf->vht_oper_centr_freq_seg0_idx); + if (width == NR_CHAN_WIDTH_80P80) + center_freq2 = ieee80211_chan_to_freq( + NULL, op_class, + hapd->iconf->vht_oper_centr_freq_seg1_idx); + } else if (ht) { + center_freq1 = hapd->iface->freq + + 10 * hapd->iconf->secondary_channel; + } + + ssid.ssid_len = hapd->conf->ssid.ssid_len; + os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len); + + /* + * Neighbor Report element size = BSSID + BSSID info + op_class + chan + + * phy type + wide bandwidth channel subelement. + */ + nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5); + if (!nr) + return; + + wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN); + wpabuf_put_le32(nr, bssid_info); + wpabuf_put_u8(nr, op_class); + wpabuf_put_u8(nr, channel); + wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht)); + + /* + * Wide Bandwidth Channel subelement may be needed to allow the + * receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0 + * Figure 9-301. + */ + wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN); + wpabuf_put_u8(nr, 3); + wpabuf_put_u8(nr, width); + wpabuf_put_u8(nr, center_freq1); + wpabuf_put_u8(nr, center_freq2); + + hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci, + hapd->iconf->civic); + + wpabuf_free(nr); +#endif /* NEED_AP_MLME */ +} + + +static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface, + int err) { struct hostapd_data *hapd = iface->bss[0]; size_t j; @@ -1634,7 +1769,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) } while (j-- > 0); goto fail; } - if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) + if (is_zero_ether_addr(hapd->conf->bssid)) prev_addr = hapd->own_addr; } hapd = iface->bss[0]; @@ -1642,7 +1777,6 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) hostapd_tx_queue_params(iface); ap_list_init(iface); - dl_list_init(&iface->sta_seen); hostapd_set_acl(hapd); @@ -1702,6 +1836,9 @@ dfs_offload: if (iface->interfaces && iface->interfaces->terminate_on_error > 0) iface->interfaces->terminate_on_error--; + for (j = 0; j < iface->num_bss; j++) + hostapd_set_own_neighbor_report(iface->bss[j]); + return 0; fail: @@ -1721,6 +1858,89 @@ fail: /** + * hostapd_setup_interface_complete - Complete interface setup + * + * This function is called when previous steps in the interface setup has been + * completed. This can also start operations, e.g., DFS, that will require + * additional processing before interface is ready to be enabled. Such + * operations will call this function from eloop callbacks when finished. + */ +int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) +{ + struct hapd_interfaces *interfaces = iface->interfaces; + struct hostapd_data *hapd = iface->bss[0]; + unsigned int i; + int not_ready_in_sync_ifaces = 0; + + if (!iface->need_to_start_in_sync) + return hostapd_setup_interface_complete_sync(iface, err); + + if (err) { + wpa_printf(MSG_ERROR, "Interface initialization failed"); + hostapd_set_state(iface, HAPD_IFACE_DISABLED); + iface->need_to_start_in_sync = 0; + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); + if (interfaces && interfaces->terminate_on_error) + eloop_terminate(); + return -1; + } + + if (iface->ready_to_start_in_sync) { + /* Already in ready and waiting. should never happpen */ + return 0; + } + + for (i = 0; i < interfaces->count; i++) { + if (interfaces->iface[i]->need_to_start_in_sync && + !interfaces->iface[i]->ready_to_start_in_sync) + not_ready_in_sync_ifaces++; + } + + /* + * Check if this is the last interface, if yes then start all the other + * waiting interfaces. If not, add this interface to the waiting list. + */ + if (not_ready_in_sync_ifaces > 1 && iface->state == HAPD_IFACE_DFS) { + /* + * If this interface went through CAC, do not synchronize, just + * start immediately. + */ + iface->need_to_start_in_sync = 0; + wpa_printf(MSG_INFO, + "%s: Finished CAC - bypass sync and start interface", + iface->bss[0]->conf->iface); + return hostapd_setup_interface_complete_sync(iface, err); + } + + if (not_ready_in_sync_ifaces > 1) { + /* need to wait as there are other interfaces still coming up */ + iface->ready_to_start_in_sync = 1; + wpa_printf(MSG_INFO, + "%s: Interface waiting to sync with other interfaces", + iface->bss[0]->conf->iface); + return 0; + } + + wpa_printf(MSG_INFO, + "%s: Last interface to sync - starting all interfaces", + iface->bss[0]->conf->iface); + iface->need_to_start_in_sync = 0; + hostapd_setup_interface_complete_sync(iface, err); + for (i = 0; i < interfaces->count; i++) { + if (interfaces->iface[i]->need_to_start_in_sync && + interfaces->iface[i]->ready_to_start_in_sync) { + hostapd_setup_interface_complete_sync( + interfaces->iface[i], 0); + /* Only once the interfaces are sync started */ + interfaces->iface[i]->need_to_start_in_sync = 0; + } + } + + return 0; +} + + +/** * hostapd_setup_interface - Setup of an interface * @iface: Pointer to interface data. * Returns: 0 on success, -1 on failure @@ -1779,6 +1999,8 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, hapd->iface = hapd_iface; hapd->driver = hapd->iconf->driver; hapd->ctrl_sock = -1; + dl_list_init(&hapd->ctrl_dst); + dl_list_init(&hapd->nr_db); return hapd; } @@ -1786,6 +2008,8 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, static void hostapd_bss_deinit(struct hostapd_data *hapd) { + if (!hapd) + return; wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__, hapd->conf->iface); hostapd_bss_deinit_no_free(hapd); @@ -1820,8 +2044,11 @@ void hostapd_interface_deinit(struct hostapd_iface *iface) } #endif /* CONFIG_FST */ - for (j = iface->num_bss - 1; j >= 0; j--) + for (j = iface->num_bss - 1; j >= 0; j--) { + if (!iface->bss) + break; hostapd_bss_deinit(iface->bss[j]); + } } @@ -1830,6 +2057,8 @@ void hostapd_interface_free(struct hostapd_iface *iface) size_t j; wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); for (j = 0; j < iface->num_bss; j++) { + if (!iface->bss) + break; wpa_printf(MSG_DEBUG, "%s: free hapd %p", __func__, iface->bss[j]); os_free(iface->bss[j]); @@ -1838,6 +2067,20 @@ void hostapd_interface_free(struct hostapd_iface *iface) } +struct hostapd_iface * hostapd_alloc_iface(void) +{ + struct hostapd_iface *hapd_iface; + + hapd_iface = os_zalloc(sizeof(*hapd_iface)); + if (!hapd_iface) + return NULL; + + dl_list_init(&hapd_iface->sta_seen); + + return hapd_iface; +} + + /** * hostapd_init - Allocate and initialize per-interface data * @config_file: Path to the configuration file @@ -1855,7 +2098,7 @@ struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces, struct hostapd_data *hapd; size_t i; - hapd_iface = os_zalloc(sizeof(*hapd_iface)); + hapd_iface = hostapd_alloc_iface(); if (hapd_iface == NULL) goto fail; @@ -2191,7 +2434,7 @@ hostapd_iface_alloc(struct hapd_interfaces *interfaces) return NULL; interfaces->iface = iface; hapd_iface = interfaces->iface[interfaces->count] = - os_zalloc(sizeof(*hapd_iface)); + hostapd_alloc_iface(); if (hapd_iface == NULL) { wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for " "the interface", __func__); @@ -2558,6 +2801,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, } hostapd_prune_associations(hapd, sta->addr); + ap_sta_clear_disconnect_timeouts(hapd, sta); /* IEEE 802.11F (IAPP) */ if (hapd->conf->ieee802_11f) @@ -2591,9 +2835,10 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm); if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) { - wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " - "for " MACSTR " (%d seconds - ap_max_inactivity)", - __func__, MAC2STR(sta->addr), + wpa_printf(MSG_DEBUG, + "%s: %s: reschedule ap_handle_timer timeout for " + MACSTR " (%d seconds - ap_max_inactivity)", + hapd->conf->iface, __func__, MAC2STR(sta->addr), hapd->conf->ap_max_inactivity); eloop_cancel_timeout(ap_handle_timer, hapd, sta); eloop_register_timeout(hapd->conf->ap_max_inactivity, 0, @@ -2628,8 +2873,8 @@ const char * hostapd_state_text(enum hostapd_iface_state s) void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s) { wpa_printf(MSG_INFO, "%s: interface state %s->%s", - iface->conf->bss[0]->iface, hostapd_state_text(iface->state), - hostapd_state_text(s)); + iface->conf ? iface->conf->bss[0]->iface : "N/A", + hostapd_state_text(iface->state), hostapd_state_text(s)); iface->state = s; } @@ -2828,11 +3073,43 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd, struct hostapd_iface *iface = hapd->iface; struct hostapd_freq_params old_freq; int ret; + u8 chan, vht_bandwidth; os_memset(&old_freq, 0, sizeof(old_freq)); if (!iface || !iface->freq || hapd->csa_in_progress) return -1; + switch (settings->freq_params.bandwidth) { + case 80: + if (settings->freq_params.center_freq2) + vht_bandwidth = VHT_CHANWIDTH_80P80MHZ; + else + vht_bandwidth = VHT_CHANWIDTH_80MHZ; + break; + case 160: + vht_bandwidth = VHT_CHANWIDTH_160MHZ; + break; + default: + vht_bandwidth = VHT_CHANWIDTH_USE_HT; + break; + } + + if (ieee80211_freq_to_channel_ext( + settings->freq_params.freq, + settings->freq_params.sec_channel_offset, + vht_bandwidth, + &hapd->iface->cs_oper_class, + &chan) == NUM_HOSTAPD_MODES) { + wpa_printf(MSG_DEBUG, + "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d)", + settings->freq_params.freq, + settings->freq_params.sec_channel_offset, + settings->freq_params.vht_enabled); + return -1; + } + + settings->freq_params.channel = chan; + ret = hostapd_change_config_freq(iface->bss[0], iface->conf, &settings->freq_params, &old_freq); @@ -2965,6 +3242,8 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface, hostapd_enable_iface(iface); } +#endif /* NEED_AP_MLME */ + struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces, const char *ifname) @@ -2985,8 +3264,6 @@ struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces, return NULL; } -#endif /* NEED_AP_MLME */ - void hostapd_periodic_iface(struct hostapd_iface *iface) {