]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa/src/ap/neighbor_db.c
THIS BRANCH IS OBSOLETE, PLEASE READ:
[FreeBSD/FreeBSD.git] / contrib / wpa / src / ap / neighbor_db.c
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                                        &center_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 }