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, int he) 143 { 144 u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf); 145 146 if (!ht && !vht && !he) 147 return NR_CHAN_WIDTH_20; 148 if (!hapd->iconf->secondary_channel) 149 return NR_CHAN_WIDTH_20; 150 if ((!vht && !he) || oper_chwidth == CHANWIDTH_USE_HT) 151 return NR_CHAN_WIDTH_40; 152 if (oper_chwidth == CHANWIDTH_80MHZ) 153 return NR_CHAN_WIDTH_80; 154 if (oper_chwidth == CHANWIDTH_160MHZ) 155 return NR_CHAN_WIDTH_160; 156 if (oper_chwidth == CHANWIDTH_80P80MHZ) 157 return NR_CHAN_WIDTH_80P80; 158 return NR_CHAN_WIDTH_20; 159 } 160 #endif /* NEED_AP_MLME */ 161 162 163 void hostapd_neighbor_set_own_report(struct hostapd_data *hapd) 164 { 165 #ifdef NEED_AP_MLME 166 u16 capab = hostapd_own_capab_info(hapd); 167 int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n; 168 int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac; 169 int he = hapd->iconf->ieee80211ax; 170 struct wpa_ssid_value ssid; 171 u8 channel, op_class; 172 u8 center_freq1_idx = 0, center_freq2_idx = 0; 173 enum nr_chan_width width; 174 u32 bssid_info; 175 struct wpabuf *nr; 176 177 if (!(hapd->conf->radio_measurements[0] & 178 WLAN_RRM_CAPS_NEIGHBOR_REPORT)) 179 return; 180 181 bssid_info = 3; /* AP is reachable */ 182 bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */ 183 bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */ 184 185 if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) 186 bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT; 187 188 bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */ 189 190 if (hapd->conf->wmm_enabled) { 191 bssid_info |= NEI_REP_BSSID_INFO_QOS; 192 193 if (hapd->conf->wmm_uapsd && 194 (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD)) 195 bssid_info |= NEI_REP_BSSID_INFO_APSD; 196 } 197 198 if (ht) { 199 bssid_info |= NEI_REP_BSSID_INFO_HT | 200 NEI_REP_BSSID_INFO_DELAYED_BA; 201 202 /* VHT bit added in IEEE P802.11-REVmc/D4.3 */ 203 if (vht) 204 bssid_info |= NEI_REP_BSSID_INFO_VHT; 205 } 206 207 /* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */ 208 209 if (ieee80211_freq_to_channel_ext(hapd->iface->freq, 210 hapd->iconf->secondary_channel, 211 hostapd_get_oper_chwidth(hapd->iconf), 212 &op_class, &channel) == 213 NUM_HOSTAPD_MODES) 214 return; 215 width = hostapd_get_nr_chan_width(hapd, ht, vht, he); 216 if (vht) { 217 center_freq1_idx = hostapd_get_oper_centr_freq_seg0_idx( 218 hapd->iconf); 219 if (width == NR_CHAN_WIDTH_80P80) 220 center_freq2_idx = 221 hostapd_get_oper_centr_freq_seg1_idx( 222 hapd->iconf); 223 } else if (ht) { 224 ieee80211_freq_to_chan(hapd->iface->freq + 225 10 * hapd->iconf->secondary_channel, 226 ¢er_freq1_idx); 227 } 228 229 ssid.ssid_len = hapd->conf->ssid.ssid_len; 230 os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len); 231 232 /* 233 * Neighbor Report element size = BSSID + BSSID info + op_class + chan + 234 * phy type + wide bandwidth channel subelement. 235 */ 236 nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5); 237 if (!nr) 238 return; 239 240 wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN); 241 wpabuf_put_le32(nr, bssid_info); 242 wpabuf_put_u8(nr, op_class); 243 wpabuf_put_u8(nr, channel); 244 wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht)); 245 246 /* 247 * Wide Bandwidth Channel subelement may be needed to allow the 248 * receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0 249 * Figure 9-301. 250 */ 251 wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN); 252 wpabuf_put_u8(nr, 3); 253 wpabuf_put_u8(nr, width); 254 wpabuf_put_u8(nr, center_freq1_idx); 255 wpabuf_put_u8(nr, center_freq2_idx); 256 257 hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci, 258 hapd->iconf->civic, hapd->iconf->stationary_ap); 259 260 wpabuf_free(nr); 261 #endif /* NEED_AP_MLME */ 262 } 263