Home | History | Annotate | Download | only in ap
      1 /*
      2  * hostapd / Neighboring APs DB
      3  * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
      4  * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
      5  *
      6  * This software may be distributed under the terms of the BSD license.
      7  * See README for more details.
      8  */
      9 
     10 #include "utils/includes.h"
     11 
     12 #include "utils/common.h"
     13 #include "hostapd.h"
     14 #include "ieee802_11.h"
     15 #include "neighbor_db.h"
     16 
     17 
     18 struct hostapd_neighbor_entry *
     19 hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
     20 		     const struct wpa_ssid_value *ssid)
     21 {
     22 	struct hostapd_neighbor_entry *nr;
     23 
     24 	dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
     25 			 list) {
     26 		if (os_memcmp(bssid, nr->bssid, ETH_ALEN) == 0 &&
     27 		    (!ssid ||
     28 		     (ssid->ssid_len == nr->ssid.ssid_len &&
     29 		      os_memcmp(ssid->ssid, nr->ssid.ssid,
     30 				ssid->ssid_len) == 0)))
     31 			return nr;
     32 	}
     33 	return NULL;
     34 }
     35 
     36 
     37 static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
     38 {
     39 	wpabuf_free(nr->nr);
     40 	nr->nr = NULL;
     41 	wpabuf_free(nr->lci);
     42 	nr->lci = NULL;
     43 	wpabuf_free(nr->civic);
     44 	nr->civic = NULL;
     45 	os_memset(nr->bssid, 0, sizeof(nr->bssid));
     46 	os_memset(&nr->ssid, 0, sizeof(nr->ssid));
     47 	nr->stationary = 0;
     48 }
     49 
     50 
     51 static struct hostapd_neighbor_entry *
     52 hostapd_neighbor_add(struct hostapd_data *hapd)
     53 {
     54 	struct hostapd_neighbor_entry *nr;
     55 
     56 	nr = os_zalloc(sizeof(struct hostapd_neighbor_entry));
     57 	if (!nr)
     58 		return NULL;
     59 
     60 	dl_list_add(&hapd->nr_db, &nr->list);
     61 
     62 	return nr;
     63 }
     64 
     65 
     66 int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
     67 			 const struct wpa_ssid_value *ssid,
     68 			 const struct wpabuf *nr, const struct wpabuf *lci,
     69 			 const struct wpabuf *civic, int stationary)
     70 {
     71 	struct hostapd_neighbor_entry *entry;
     72 
     73 	entry = hostapd_neighbor_get(hapd, bssid, ssid);
     74 	if (!entry)
     75 		entry = hostapd_neighbor_add(hapd);
     76 	if (!entry)
     77 		return -1;
     78 
     79 	hostapd_neighbor_clear_entry(entry);
     80 
     81 	os_memcpy(entry->bssid, bssid, ETH_ALEN);
     82 	os_memcpy(&entry->ssid, ssid, sizeof(entry->ssid));
     83 
     84 	entry->nr = wpabuf_dup(nr);
     85 	if (!entry->nr)
     86 		goto fail;
     87 
     88 	if (lci && wpabuf_len(lci)) {
     89 		entry->lci = wpabuf_dup(lci);
     90 		if (!entry->lci || os_get_time(&entry->lci_date))
     91 			goto fail;
     92 	}
     93 
     94 	if (civic && wpabuf_len(civic)) {
     95 		entry->civic = wpabuf_dup(civic);
     96 		if (!entry->civic)
     97 			goto fail;
     98 	}
     99 
    100 	entry->stationary = stationary;
    101 
    102 	return 0;
    103 
    104 fail:
    105 	hostapd_neighbor_remove(hapd, bssid, ssid);
    106 	return -1;
    107 }
    108 
    109 
    110 int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
    111 			    const struct wpa_ssid_value *ssid)
    112 {
    113 	struct hostapd_neighbor_entry *nr;
    114 
    115 	nr = hostapd_neighbor_get(hapd, bssid, ssid);
    116 	if (!nr)
    117 		return -1;
    118 
    119 	hostapd_neighbor_clear_entry(nr);
    120 	dl_list_del(&nr->list);
    121 	os_free(nr);
    122 
    123 	return 0;
    124 }
    125 
    126 
    127 void hostapd_free_neighbor_db(struct hostapd_data *hapd)
    128 {
    129 	struct hostapd_neighbor_entry *nr, *prev;
    130 
    131 	dl_list_for_each_safe(nr, prev, &hapd->nr_db,
    132 			      struct hostapd_neighbor_entry, list) {
    133 		hostapd_neighbor_clear_entry(nr);
    134 		dl_list_del(&nr->list);
    135 		os_free(nr);
    136 	}
    137 }
    138 
    139 
    140 #ifdef NEED_AP_MLME
    141 static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
    142 						    int ht, int vht)
    143 {
    144 	if (!ht && !vht)
    145 		return NR_CHAN_WIDTH_20;
    146 	if (!hapd->iconf->secondary_channel)
    147 		return NR_CHAN_WIDTH_20;
    148 	if (!vht || hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT)
    149 		return NR_CHAN_WIDTH_40;
    150 	if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
    151 		return NR_CHAN_WIDTH_80;
    152 	if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ)
    153 		return NR_CHAN_WIDTH_160;
    154 	if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ)
    155 		return NR_CHAN_WIDTH_80P80;
    156 	return NR_CHAN_WIDTH_20;
    157 }
    158 #endif /* NEED_AP_MLME */
    159 
    160 
    161 void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
    162 {
    163 #ifdef NEED_AP_MLME
    164 	u16 capab = hostapd_own_capab_info(hapd);
    165 	int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
    166 	int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
    167 	struct wpa_ssid_value ssid;
    168 	u8 channel, op_class;
    169 	u8 center_freq1_idx = 0, center_freq2_idx = 0;
    170 	enum nr_chan_width width;
    171 	u32 bssid_info;
    172 	struct wpabuf *nr;
    173 
    174 	if (!(hapd->conf->radio_measurements[0] &
    175 	      WLAN_RRM_CAPS_NEIGHBOR_REPORT))
    176 		return;
    177 
    178 	bssid_info = 3; /* AP is reachable */
    179 	bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */
    180 	bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */
    181 
    182 	if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT)
    183 		bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
    184 
    185 	bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */
    186 
    187 	if (hapd->conf->wmm_enabled) {
    188 		bssid_info |= NEI_REP_BSSID_INFO_QOS;
    189 
    190 		if (hapd->conf->wmm_uapsd &&
    191 		    (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
    192 			bssid_info |= NEI_REP_BSSID_INFO_APSD;
    193 	}
    194 
    195 	if (ht) {
    196 		bssid_info |= NEI_REP_BSSID_INFO_HT |
    197 			NEI_REP_BSSID_INFO_DELAYED_BA;
    198 
    199 		/* VHT bit added in IEEE P802.11-REVmc/D4.3 */
    200 		if (vht)
    201 			bssid_info |= NEI_REP_BSSID_INFO_VHT;
    202 	}
    203 
    204 	/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
    205 
    206 	if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
    207 					  hapd->iconf->secondary_channel,
    208 					  hapd->iconf->vht_oper_chwidth,
    209 					  &op_class, &channel) ==
    210 	    NUM_HOSTAPD_MODES)
    211 		return;
    212 	width = hostapd_get_nr_chan_width(hapd, ht, vht);
    213 	if (vht) {
    214 		center_freq1_idx = hapd->iconf->vht_oper_centr_freq_seg0_idx;
    215 		if (width == NR_CHAN_WIDTH_80P80)
    216 			center_freq2_idx =
    217 				hapd->iconf->vht_oper_centr_freq_seg1_idx;
    218 	} else if (ht) {
    219 		ieee80211_freq_to_chan(hapd->iface->freq +
    220 				       10 * hapd->iconf->secondary_channel,
    221 				       &center_freq1_idx);
    222 	}
    223 
    224 	ssid.ssid_len = hapd->conf->ssid.ssid_len;
    225 	os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
    226 
    227 	/*
    228 	 * Neighbor Report element size = BSSID + BSSID info + op_class + chan +
    229 	 * phy type + wide bandwidth channel subelement.
    230 	 */
    231 	nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5);
    232 	if (!nr)
    233 		return;
    234 
    235 	wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN);
    236 	wpabuf_put_le32(nr, bssid_info);
    237 	wpabuf_put_u8(nr, op_class);
    238 	wpabuf_put_u8(nr, channel);
    239 	wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht));
    240 
    241 	/*
    242 	 * Wide Bandwidth Channel subelement may be needed to allow the
    243 	 * receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0
    244 	 * Figure 9-301.
    245 	 */
    246 	wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN);
    247 	wpabuf_put_u8(nr, 3);
    248 	wpabuf_put_u8(nr, width);
    249 	wpabuf_put_u8(nr, center_freq1_idx);
    250 	wpabuf_put_u8(nr, center_freq2_idx);
    251 
    252 	hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci,
    253 			     hapd->iconf->civic, hapd->iconf->stationary_ap);
    254 
    255 	wpabuf_free(nr);
    256 #endif /* NEED_AP_MLME */
    257 }
    258