hostapd: Add own neighbor report data to neighbor database

Add own neighbor report data to neighbor database based on local LCI and
location civic data.

Signed-off-by: David Spinadel <david.spinadel@intel.com>
This commit is contained in:
David Spinadel 2016-04-06 19:42:08 +03:00 committed by Jouni Malinen
parent 9b4b226426
commit 061269b316

View file

@ -1528,6 +1528,126 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
#endif /* CONFIG_FST */
#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)
{
@ -1713,6 +1833,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: