bss.c revision 1.1.1.4 1 1.1 christos /*
2 1.1 christos * BSS table
3 1.1.1.3 christos * Copyright (c) 2009-2012, Jouni Malinen <j (at) w1.fi>
4 1.1 christos *
5 1.1.1.3 christos * This software may be distributed under the terms of the BSD license.
6 1.1.1.3 christos * See README for more details.
7 1.1 christos */
8 1.1 christos
9 1.1 christos #include "utils/includes.h"
10 1.1 christos
11 1.1 christos #include "utils/common.h"
12 1.1 christos #include "utils/eloop.h"
13 1.1 christos #include "common/ieee802_11_defs.h"
14 1.1 christos #include "drivers/driver.h"
15 1.1 christos #include "wpa_supplicant_i.h"
16 1.1 christos #include "config.h"
17 1.1 christos #include "notify.h"
18 1.1 christos #include "scan.h"
19 1.1 christos #include "bss.h"
20 1.1 christos
21 1.1 christos
22 1.1 christos /**
23 1.1 christos * WPA_BSS_EXPIRATION_PERIOD - Period of expiration run in seconds
24 1.1 christos */
25 1.1 christos #define WPA_BSS_EXPIRATION_PERIOD 10
26 1.1 christos
27 1.1 christos #define WPA_BSS_FREQ_CHANGED_FLAG BIT(0)
28 1.1 christos #define WPA_BSS_SIGNAL_CHANGED_FLAG BIT(1)
29 1.1 christos #define WPA_BSS_PRIVACY_CHANGED_FLAG BIT(2)
30 1.1 christos #define WPA_BSS_MODE_CHANGED_FLAG BIT(3)
31 1.1 christos #define WPA_BSS_WPAIE_CHANGED_FLAG BIT(4)
32 1.1 christos #define WPA_BSS_RSNIE_CHANGED_FLAG BIT(5)
33 1.1 christos #define WPA_BSS_WPS_CHANGED_FLAG BIT(6)
34 1.1 christos #define WPA_BSS_RATES_CHANGED_FLAG BIT(7)
35 1.1 christos #define WPA_BSS_IES_CHANGED_FLAG BIT(8)
36 1.1 christos
37 1.1 christos
38 1.1.1.3 christos static void wpa_bss_set_hessid(struct wpa_bss *bss)
39 1.1.1.3 christos {
40 1.1.1.3 christos #ifdef CONFIG_INTERWORKING
41 1.1.1.3 christos const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
42 1.1.1.3 christos if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
43 1.1.1.3 christos os_memset(bss->hessid, 0, ETH_ALEN);
44 1.1.1.3 christos return;
45 1.1.1.3 christos }
46 1.1.1.3 christos if (ie[1] == 7)
47 1.1.1.3 christos os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
48 1.1.1.3 christos else
49 1.1.1.3 christos os_memcpy(bss->hessid, ie + 5, ETH_ALEN);
50 1.1.1.3 christos #endif /* CONFIG_INTERWORKING */
51 1.1.1.3 christos }
52 1.1.1.3 christos
53 1.1.1.3 christos
54 1.1.1.3 christos /**
55 1.1.1.3 christos * wpa_bss_anqp_alloc - Allocate ANQP data structure for a BSS entry
56 1.1.1.3 christos * Returns: Allocated ANQP data structure or %NULL on failure
57 1.1.1.3 christos *
58 1.1.1.3 christos * The allocated ANQP data structure has its users count set to 1. It may be
59 1.1.1.3 christos * shared by multiple BSS entries and each shared entry is freed with
60 1.1.1.3 christos * wpa_bss_anqp_free().
61 1.1.1.3 christos */
62 1.1.1.3 christos struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
63 1.1.1.3 christos {
64 1.1.1.3 christos struct wpa_bss_anqp *anqp;
65 1.1.1.3 christos anqp = os_zalloc(sizeof(*anqp));
66 1.1.1.3 christos if (anqp == NULL)
67 1.1.1.3 christos return NULL;
68 1.1.1.3 christos anqp->users = 1;
69 1.1.1.3 christos return anqp;
70 1.1.1.3 christos }
71 1.1.1.3 christos
72 1.1.1.3 christos
73 1.1.1.3 christos /**
74 1.1.1.3 christos * wpa_bss_anqp_clone - Clone an ANQP data structure
75 1.1.1.3 christos * @anqp: ANQP data structure from wpa_bss_anqp_alloc()
76 1.1.1.3 christos * Returns: Cloned ANQP data structure or %NULL on failure
77 1.1.1.3 christos */
78 1.1.1.3 christos static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
79 1.1.1.3 christos {
80 1.1.1.3 christos struct wpa_bss_anqp *n;
81 1.1.1.3 christos
82 1.1.1.3 christos n = os_zalloc(sizeof(*n));
83 1.1.1.3 christos if (n == NULL)
84 1.1.1.3 christos return NULL;
85 1.1.1.3 christos
86 1.1.1.3 christos #define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
87 1.1.1.3 christos #ifdef CONFIG_INTERWORKING
88 1.1.1.3 christos ANQP_DUP(venue_name);
89 1.1.1.3 christos ANQP_DUP(network_auth_type);
90 1.1.1.3 christos ANQP_DUP(roaming_consortium);
91 1.1.1.3 christos ANQP_DUP(ip_addr_type_availability);
92 1.1.1.3 christos ANQP_DUP(nai_realm);
93 1.1.1.3 christos ANQP_DUP(anqp_3gpp);
94 1.1.1.3 christos ANQP_DUP(domain_name);
95 1.1.1.3 christos #endif /* CONFIG_INTERWORKING */
96 1.1.1.3 christos #ifdef CONFIG_HS20
97 1.1.1.3 christos ANQP_DUP(hs20_operator_friendly_name);
98 1.1.1.3 christos ANQP_DUP(hs20_wan_metrics);
99 1.1.1.3 christos ANQP_DUP(hs20_connection_capability);
100 1.1.1.3 christos ANQP_DUP(hs20_operating_class);
101 1.1.1.4 christos ANQP_DUP(hs20_osu_providers_list);
102 1.1.1.3 christos #endif /* CONFIG_HS20 */
103 1.1.1.3 christos #undef ANQP_DUP
104 1.1.1.3 christos
105 1.1.1.3 christos return n;
106 1.1.1.3 christos }
107 1.1.1.3 christos
108 1.1.1.3 christos
109 1.1.1.3 christos /**
110 1.1.1.3 christos * wpa_bss_anqp_unshare_alloc - Unshare ANQP data (if shared) in a BSS entry
111 1.1.1.3 christos * @bss: BSS entry
112 1.1.1.3 christos * Returns: 0 on success, -1 on failure
113 1.1.1.3 christos *
114 1.1.1.3 christos * This function ensures the specific BSS entry has an ANQP data structure that
115 1.1.1.3 christos * is not shared with any other BSS entry.
116 1.1.1.3 christos */
117 1.1.1.3 christos int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
118 1.1.1.3 christos {
119 1.1.1.3 christos struct wpa_bss_anqp *anqp;
120 1.1.1.3 christos
121 1.1.1.3 christos if (bss->anqp && bss->anqp->users > 1) {
122 1.1.1.3 christos /* allocated, but shared - clone an unshared copy */
123 1.1.1.3 christos anqp = wpa_bss_anqp_clone(bss->anqp);
124 1.1.1.3 christos if (anqp == NULL)
125 1.1.1.3 christos return -1;
126 1.1.1.3 christos anqp->users = 1;
127 1.1.1.3 christos bss->anqp->users--;
128 1.1.1.3 christos bss->anqp = anqp;
129 1.1.1.3 christos return 0;
130 1.1.1.3 christos }
131 1.1.1.3 christos
132 1.1.1.3 christos if (bss->anqp)
133 1.1.1.3 christos return 0; /* already allocated and not shared */
134 1.1.1.3 christos
135 1.1.1.3 christos /* not allocated - allocate a new storage area */
136 1.1.1.3 christos bss->anqp = wpa_bss_anqp_alloc();
137 1.1.1.3 christos return bss->anqp ? 0 : -1;
138 1.1.1.3 christos }
139 1.1.1.3 christos
140 1.1.1.3 christos
141 1.1.1.3 christos /**
142 1.1.1.3 christos * wpa_bss_anqp_free - Free an ANQP data structure
143 1.1.1.3 christos * @anqp: ANQP data structure from wpa_bss_anqp_alloc() or wpa_bss_anqp_clone()
144 1.1.1.3 christos */
145 1.1.1.3 christos static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
146 1.1 christos {
147 1.1.1.3 christos if (anqp == NULL)
148 1.1.1.3 christos return;
149 1.1.1.3 christos
150 1.1.1.3 christos anqp->users--;
151 1.1.1.3 christos if (anqp->users > 0) {
152 1.1.1.3 christos /* Another BSS entry holds a pointer to this ANQP info */
153 1.1.1.3 christos return;
154 1.1.1.3 christos }
155 1.1.1.3 christos
156 1.1.1.3 christos #ifdef CONFIG_INTERWORKING
157 1.1.1.3 christos wpabuf_free(anqp->venue_name);
158 1.1.1.3 christos wpabuf_free(anqp->network_auth_type);
159 1.1.1.3 christos wpabuf_free(anqp->roaming_consortium);
160 1.1.1.3 christos wpabuf_free(anqp->ip_addr_type_availability);
161 1.1.1.3 christos wpabuf_free(anqp->nai_realm);
162 1.1.1.3 christos wpabuf_free(anqp->anqp_3gpp);
163 1.1.1.3 christos wpabuf_free(anqp->domain_name);
164 1.1.1.3 christos #endif /* CONFIG_INTERWORKING */
165 1.1.1.3 christos #ifdef CONFIG_HS20
166 1.1.1.3 christos wpabuf_free(anqp->hs20_operator_friendly_name);
167 1.1.1.3 christos wpabuf_free(anqp->hs20_wan_metrics);
168 1.1.1.3 christos wpabuf_free(anqp->hs20_connection_capability);
169 1.1.1.3 christos wpabuf_free(anqp->hs20_operating_class);
170 1.1.1.4 christos wpabuf_free(anqp->hs20_osu_providers_list);
171 1.1.1.3 christos #endif /* CONFIG_HS20 */
172 1.1.1.3 christos
173 1.1.1.3 christos os_free(anqp);
174 1.1.1.3 christos }
175 1.1.1.3 christos
176 1.1.1.3 christos
177 1.1.1.3 christos static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
178 1.1.1.3 christos const char *reason)
179 1.1.1.3 christos {
180 1.1.1.3 christos if (wpa_s->last_scan_res) {
181 1.1.1.3 christos unsigned int i;
182 1.1.1.3 christos for (i = 0; i < wpa_s->last_scan_res_used; i++) {
183 1.1.1.3 christos if (wpa_s->last_scan_res[i] == bss) {
184 1.1.1.3 christos os_memmove(&wpa_s->last_scan_res[i],
185 1.1.1.3 christos &wpa_s->last_scan_res[i + 1],
186 1.1.1.3 christos (wpa_s->last_scan_res_used - i - 1)
187 1.1.1.3 christos * sizeof(struct wpa_bss *));
188 1.1.1.3 christos wpa_s->last_scan_res_used--;
189 1.1.1.3 christos break;
190 1.1.1.3 christos }
191 1.1.1.3 christos }
192 1.1.1.3 christos }
193 1.1 christos dl_list_del(&bss->list);
194 1.1 christos dl_list_del(&bss->list_id);
195 1.1 christos wpa_s->num_bss--;
196 1.1.1.2 christos wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
197 1.1.1.3 christos " SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
198 1.1.1.3 christos wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
199 1.1 christos wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
200 1.1.1.3 christos wpa_bss_anqp_free(bss->anqp);
201 1.1 christos os_free(bss);
202 1.1 christos }
203 1.1 christos
204 1.1 christos
205 1.1.1.3 christos /**
206 1.1.1.3 christos * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID
207 1.1.1.3 christos * @wpa_s: Pointer to wpa_supplicant data
208 1.1.1.3 christos * @bssid: BSSID
209 1.1.1.3 christos * @ssid: SSID
210 1.1.1.3 christos * @ssid_len: Length of @ssid
211 1.1.1.3 christos * Returns: Pointer to the BSS entry or %NULL if not found
212 1.1.1.3 christos */
213 1.1 christos struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
214 1.1 christos const u8 *ssid, size_t ssid_len)
215 1.1 christos {
216 1.1 christos struct wpa_bss *bss;
217 1.1.1.3 christos if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
218 1.1.1.3 christos return NULL;
219 1.1 christos dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
220 1.1 christos if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
221 1.1 christos bss->ssid_len == ssid_len &&
222 1.1 christos os_memcmp(bss->ssid, ssid, ssid_len) == 0)
223 1.1 christos return bss;
224 1.1 christos }
225 1.1 christos return NULL;
226 1.1 christos }
227 1.1 christos
228 1.1 christos
229 1.1.1.4 christos static void calculate_update_time(const struct os_reltime *fetch_time,
230 1.1.1.4 christos unsigned int age_ms,
231 1.1.1.4 christos struct os_reltime *update_time)
232 1.1 christos {
233 1.1 christos os_time_t usec;
234 1.1 christos
235 1.1.1.4 christos update_time->sec = fetch_time->sec;
236 1.1.1.4 christos update_time->usec = fetch_time->usec;
237 1.1.1.4 christos update_time->sec -= age_ms / 1000;
238 1.1.1.4 christos usec = (age_ms % 1000) * 1000;
239 1.1.1.4 christos if (update_time->usec < usec) {
240 1.1.1.4 christos update_time->sec--;
241 1.1.1.4 christos update_time->usec += 1000000;
242 1.1.1.4 christos }
243 1.1.1.4 christos update_time->usec -= usec;
244 1.1.1.4 christos }
245 1.1.1.4 christos
246 1.1.1.4 christos
247 1.1.1.4 christos static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
248 1.1.1.4 christos struct os_reltime *fetch_time)
249 1.1.1.4 christos {
250 1.1 christos dst->flags = src->flags;
251 1.1 christos os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
252 1.1 christos dst->freq = src->freq;
253 1.1 christos dst->beacon_int = src->beacon_int;
254 1.1 christos dst->caps = src->caps;
255 1.1 christos dst->qual = src->qual;
256 1.1 christos dst->noise = src->noise;
257 1.1 christos dst->level = src->level;
258 1.1 christos dst->tsf = src->tsf;
259 1.1 christos
260 1.1.1.4 christos calculate_update_time(fetch_time, src->age, &dst->last_update);
261 1.1 christos }
262 1.1 christos
263 1.1 christos
264 1.1.1.2 christos static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
265 1.1.1.2 christos {
266 1.1.1.2 christos struct wpa_ssid *ssid;
267 1.1.1.2 christos
268 1.1.1.2 christos for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
269 1.1.1.2 christos if (ssid->ssid == NULL || ssid->ssid_len == 0)
270 1.1.1.2 christos continue;
271 1.1.1.2 christos if (ssid->ssid_len == bss->ssid_len &&
272 1.1.1.2 christos os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
273 1.1.1.2 christos return 1;
274 1.1.1.2 christos }
275 1.1.1.2 christos
276 1.1.1.2 christos return 0;
277 1.1.1.2 christos }
278 1.1.1.2 christos
279 1.1.1.2 christos
280 1.1.1.3 christos static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
281 1.1.1.3 christos {
282 1.1.1.3 christos return bss == wpa_s->current_bss ||
283 1.1.1.3 christos os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
284 1.1.1.3 christos os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
285 1.1.1.3 christos }
286 1.1.1.3 christos
287 1.1.1.3 christos
288 1.1.1.2 christos static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
289 1.1.1.2 christos {
290 1.1.1.2 christos struct wpa_bss *bss;
291 1.1.1.2 christos
292 1.1.1.2 christos dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
293 1.1.1.2 christos if (!wpa_bss_known(wpa_s, bss)) {
294 1.1.1.3 christos wpa_bss_remove(wpa_s, bss, __func__);
295 1.1.1.2 christos return 0;
296 1.1.1.2 christos }
297 1.1.1.2 christos }
298 1.1.1.2 christos
299 1.1.1.2 christos return -1;
300 1.1.1.2 christos }
301 1.1.1.2 christos
302 1.1.1.2 christos
303 1.1.1.3 christos static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
304 1.1.1.2 christos {
305 1.1.1.3 christos struct wpa_bss *bss;
306 1.1.1.3 christos
307 1.1.1.2 christos /*
308 1.1.1.2 christos * Remove the oldest entry that does not match with any configured
309 1.1.1.2 christos * network.
310 1.1.1.2 christos */
311 1.1.1.2 christos if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
312 1.1.1.3 christos return 0;
313 1.1.1.2 christos
314 1.1.1.2 christos /*
315 1.1.1.3 christos * Remove the oldest entry that isn't currently in use.
316 1.1.1.2 christos */
317 1.1.1.3 christos dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
318 1.1.1.3 christos if (!wpa_bss_in_use(wpa_s, bss)) {
319 1.1.1.3 christos wpa_bss_remove(wpa_s, bss, __func__);
320 1.1.1.3 christos return 0;
321 1.1.1.3 christos }
322 1.1.1.3 christos }
323 1.1.1.3 christos
324 1.1.1.3 christos return -1;
325 1.1.1.2 christos }
326 1.1.1.2 christos
327 1.1.1.2 christos
328 1.1.1.3 christos static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
329 1.1.1.3 christos const u8 *ssid, size_t ssid_len,
330 1.1.1.4 christos struct wpa_scan_res *res,
331 1.1.1.4 christos struct os_reltime *fetch_time)
332 1.1 christos {
333 1.1 christos struct wpa_bss *bss;
334 1.1 christos
335 1.1 christos bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
336 1.1 christos if (bss == NULL)
337 1.1.1.3 christos return NULL;
338 1.1 christos bss->id = wpa_s->bss_next_id++;
339 1.1 christos bss->last_update_idx = wpa_s->bss_update_idx;
340 1.1.1.4 christos wpa_bss_copy_res(bss, res, fetch_time);
341 1.1 christos os_memcpy(bss->ssid, ssid, ssid_len);
342 1.1 christos bss->ssid_len = ssid_len;
343 1.1 christos bss->ie_len = res->ie_len;
344 1.1 christos bss->beacon_ie_len = res->beacon_ie_len;
345 1.1 christos os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
346 1.1.1.3 christos wpa_bss_set_hessid(bss);
347 1.1 christos
348 1.1.1.4 christos if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count &&
349 1.1.1.4 christos wpa_bss_remove_oldest(wpa_s) != 0) {
350 1.1.1.4 christos wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
351 1.1.1.4 christos "because all BSSes are in use. We should normally "
352 1.1.1.4 christos "not get here!", (int) wpa_s->num_bss + 1);
353 1.1.1.4 christos wpa_s->conf->bss_max_count = wpa_s->num_bss + 1;
354 1.1.1.4 christos }
355 1.1.1.4 christos
356 1.1 christos dl_list_add_tail(&wpa_s->bss, &bss->list);
357 1.1 christos dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
358 1.1 christos wpa_s->num_bss++;
359 1.1.1.2 christos wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
360 1.1.1.2 christos " SSID '%s'",
361 1.1.1.2 christos bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
362 1.1 christos wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
363 1.1.1.3 christos return bss;
364 1.1 christos }
365 1.1 christos
366 1.1 christos
367 1.1 christos static int are_ies_equal(const struct wpa_bss *old,
368 1.1 christos const struct wpa_scan_res *new, u32 ie)
369 1.1 christos {
370 1.1 christos const u8 *old_ie, *new_ie;
371 1.1 christos struct wpabuf *old_ie_buff = NULL;
372 1.1 christos struct wpabuf *new_ie_buff = NULL;
373 1.1 christos int new_ie_len, old_ie_len, ret, is_multi;
374 1.1 christos
375 1.1 christos switch (ie) {
376 1.1 christos case WPA_IE_VENDOR_TYPE:
377 1.1 christos old_ie = wpa_bss_get_vendor_ie(old, ie);
378 1.1 christos new_ie = wpa_scan_get_vendor_ie(new, ie);
379 1.1 christos is_multi = 0;
380 1.1 christos break;
381 1.1 christos case WPS_IE_VENDOR_TYPE:
382 1.1 christos old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
383 1.1 christos new_ie_buff = wpa_scan_get_vendor_ie_multi(new, ie);
384 1.1 christos is_multi = 1;
385 1.1 christos break;
386 1.1 christos case WLAN_EID_RSN:
387 1.1 christos case WLAN_EID_SUPP_RATES:
388 1.1 christos case WLAN_EID_EXT_SUPP_RATES:
389 1.1 christos old_ie = wpa_bss_get_ie(old, ie);
390 1.1 christos new_ie = wpa_scan_get_ie(new, ie);
391 1.1 christos is_multi = 0;
392 1.1 christos break;
393 1.1 christos default:
394 1.1 christos wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
395 1.1 christos return 0;
396 1.1 christos }
397 1.1 christos
398 1.1 christos if (is_multi) {
399 1.1 christos /* in case of multiple IEs stored in buffer */
400 1.1 christos old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
401 1.1 christos new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
402 1.1 christos old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
403 1.1 christos new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
404 1.1 christos } else {
405 1.1 christos /* in case of single IE */
406 1.1 christos old_ie_len = old_ie ? old_ie[1] + 2 : 0;
407 1.1 christos new_ie_len = new_ie ? new_ie[1] + 2 : 0;
408 1.1 christos }
409 1.1 christos
410 1.1.1.2 christos if (!old_ie || !new_ie)
411 1.1.1.2 christos ret = !old_ie && !new_ie;
412 1.1.1.2 christos else
413 1.1.1.2 christos ret = (old_ie_len == new_ie_len &&
414 1.1.1.2 christos os_memcmp(old_ie, new_ie, old_ie_len) == 0);
415 1.1 christos
416 1.1 christos wpabuf_free(old_ie_buff);
417 1.1 christos wpabuf_free(new_ie_buff);
418 1.1 christos
419 1.1 christos return ret;
420 1.1 christos }
421 1.1 christos
422 1.1 christos
423 1.1 christos static u32 wpa_bss_compare_res(const struct wpa_bss *old,
424 1.1 christos const struct wpa_scan_res *new)
425 1.1 christos {
426 1.1 christos u32 changes = 0;
427 1.1 christos int caps_diff = old->caps ^ new->caps;
428 1.1 christos
429 1.1 christos if (old->freq != new->freq)
430 1.1 christos changes |= WPA_BSS_FREQ_CHANGED_FLAG;
431 1.1 christos
432 1.1 christos if (old->level != new->level)
433 1.1 christos changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
434 1.1 christos
435 1.1 christos if (caps_diff & IEEE80211_CAP_PRIVACY)
436 1.1 christos changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
437 1.1 christos
438 1.1 christos if (caps_diff & IEEE80211_CAP_IBSS)
439 1.1 christos changes |= WPA_BSS_MODE_CHANGED_FLAG;
440 1.1 christos
441 1.1 christos if (old->ie_len == new->ie_len &&
442 1.1 christos os_memcmp(old + 1, new + 1, old->ie_len) == 0)
443 1.1 christos return changes;
444 1.1 christos changes |= WPA_BSS_IES_CHANGED_FLAG;
445 1.1 christos
446 1.1 christos if (!are_ies_equal(old, new, WPA_IE_VENDOR_TYPE))
447 1.1 christos changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
448 1.1 christos
449 1.1 christos if (!are_ies_equal(old, new, WLAN_EID_RSN))
450 1.1 christos changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
451 1.1 christos
452 1.1 christos if (!are_ies_equal(old, new, WPS_IE_VENDOR_TYPE))
453 1.1 christos changes |= WPA_BSS_WPS_CHANGED_FLAG;
454 1.1 christos
455 1.1 christos if (!are_ies_equal(old, new, WLAN_EID_SUPP_RATES) ||
456 1.1 christos !are_ies_equal(old, new, WLAN_EID_EXT_SUPP_RATES))
457 1.1 christos changes |= WPA_BSS_RATES_CHANGED_FLAG;
458 1.1 christos
459 1.1 christos return changes;
460 1.1 christos }
461 1.1 christos
462 1.1 christos
463 1.1 christos static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
464 1.1 christos const struct wpa_bss *bss)
465 1.1 christos {
466 1.1 christos if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
467 1.1 christos wpas_notify_bss_freq_changed(wpa_s, bss->id);
468 1.1 christos
469 1.1 christos if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
470 1.1 christos wpas_notify_bss_signal_changed(wpa_s, bss->id);
471 1.1 christos
472 1.1 christos if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
473 1.1 christos wpas_notify_bss_privacy_changed(wpa_s, bss->id);
474 1.1 christos
475 1.1 christos if (changes & WPA_BSS_MODE_CHANGED_FLAG)
476 1.1 christos wpas_notify_bss_mode_changed(wpa_s, bss->id);
477 1.1 christos
478 1.1 christos if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
479 1.1 christos wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
480 1.1 christos
481 1.1 christos if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
482 1.1 christos wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
483 1.1 christos
484 1.1 christos if (changes & WPA_BSS_WPS_CHANGED_FLAG)
485 1.1 christos wpas_notify_bss_wps_changed(wpa_s, bss->id);
486 1.1 christos
487 1.1 christos if (changes & WPA_BSS_IES_CHANGED_FLAG)
488 1.1 christos wpas_notify_bss_ies_changed(wpa_s, bss->id);
489 1.1 christos
490 1.1 christos if (changes & WPA_BSS_RATES_CHANGED_FLAG)
491 1.1 christos wpas_notify_bss_rates_changed(wpa_s, bss->id);
492 1.1.1.4 christos
493 1.1.1.4 christos wpas_notify_bss_seen(wpa_s, bss->id);
494 1.1 christos }
495 1.1 christos
496 1.1 christos
497 1.1.1.3 christos static struct wpa_bss *
498 1.1.1.3 christos wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
499 1.1.1.4 christos struct wpa_scan_res *res, struct os_reltime *fetch_time)
500 1.1 christos {
501 1.1 christos u32 changes;
502 1.1 christos
503 1.1 christos changes = wpa_bss_compare_res(bss, res);
504 1.1 christos bss->scan_miss_count = 0;
505 1.1 christos bss->last_update_idx = wpa_s->bss_update_idx;
506 1.1.1.4 christos wpa_bss_copy_res(bss, res, fetch_time);
507 1.1 christos /* Move the entry to the end of the list */
508 1.1 christos dl_list_del(&bss->list);
509 1.1.1.4 christos #ifdef CONFIG_P2P
510 1.1.1.4 christos if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
511 1.1.1.4 christos !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE)) {
512 1.1.1.4 christos /*
513 1.1.1.4 christos * This can happen when non-P2P station interface runs a scan
514 1.1.1.4 christos * without P2P IE in the Probe Request frame. P2P GO would reply
515 1.1.1.4 christos * to that with a Probe Response that does not include P2P IE.
516 1.1.1.4 christos * Do not update the IEs in this BSS entry to avoid such loss of
517 1.1.1.4 christos * information that may be needed for P2P operations to
518 1.1.1.4 christos * determine group information.
519 1.1.1.4 christos */
520 1.1.1.4 christos wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Do not update scan IEs for "
521 1.1.1.4 christos MACSTR " since that would remove P2P IE information",
522 1.1.1.4 christos MAC2STR(bss->bssid));
523 1.1.1.4 christos } else
524 1.1.1.4 christos #endif /* CONFIG_P2P */
525 1.1 christos if (bss->ie_len + bss->beacon_ie_len >=
526 1.1 christos res->ie_len + res->beacon_ie_len) {
527 1.1 christos os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
528 1.1 christos bss->ie_len = res->ie_len;
529 1.1 christos bss->beacon_ie_len = res->beacon_ie_len;
530 1.1 christos } else {
531 1.1 christos struct wpa_bss *nbss;
532 1.1 christos struct dl_list *prev = bss->list_id.prev;
533 1.1 christos dl_list_del(&bss->list_id);
534 1.1 christos nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
535 1.1 christos res->beacon_ie_len);
536 1.1 christos if (nbss) {
537 1.1.1.3 christos unsigned int i;
538 1.1.1.3 christos for (i = 0; i < wpa_s->last_scan_res_used; i++) {
539 1.1.1.3 christos if (wpa_s->last_scan_res[i] == bss) {
540 1.1.1.3 christos wpa_s->last_scan_res[i] = nbss;
541 1.1.1.3 christos break;
542 1.1.1.3 christos }
543 1.1.1.3 christos }
544 1.1.1.2 christos if (wpa_s->current_bss == bss)
545 1.1.1.2 christos wpa_s->current_bss = nbss;
546 1.1 christos bss = nbss;
547 1.1 christos os_memcpy(bss + 1, res + 1,
548 1.1 christos res->ie_len + res->beacon_ie_len);
549 1.1 christos bss->ie_len = res->ie_len;
550 1.1 christos bss->beacon_ie_len = res->beacon_ie_len;
551 1.1 christos }
552 1.1 christos dl_list_add(prev, &bss->list_id);
553 1.1 christos }
554 1.1.1.3 christos if (changes & WPA_BSS_IES_CHANGED_FLAG)
555 1.1.1.3 christos wpa_bss_set_hessid(bss);
556 1.1 christos dl_list_add_tail(&wpa_s->bss, &bss->list);
557 1.1 christos
558 1.1 christos notify_bss_changes(wpa_s, changes, bss);
559 1.1 christos
560 1.1.1.3 christos return bss;
561 1.1 christos }
562 1.1 christos
563 1.1 christos
564 1.1.1.3 christos /**
565 1.1.1.3 christos * wpa_bss_update_start - Start a BSS table update from scan results
566 1.1.1.3 christos * @wpa_s: Pointer to wpa_supplicant data
567 1.1.1.3 christos *
568 1.1.1.3 christos * This function is called at the start of each BSS table update round for new
569 1.1.1.3 christos * scan results. The actual scan result entries are indicated with calls to
570 1.1.1.3 christos * wpa_bss_update_scan_res() and the update round is finished with a call to
571 1.1.1.3 christos * wpa_bss_update_end().
572 1.1.1.3 christos */
573 1.1 christos void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
574 1.1 christos {
575 1.1 christos wpa_s->bss_update_idx++;
576 1.1.1.2 christos wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
577 1.1.1.2 christos wpa_s->bss_update_idx);
578 1.1.1.3 christos wpa_s->last_scan_res_used = 0;
579 1.1 christos }
580 1.1 christos
581 1.1 christos
582 1.1.1.3 christos /**
583 1.1.1.3 christos * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
584 1.1.1.3 christos * @wpa_s: Pointer to wpa_supplicant data
585 1.1.1.3 christos * @res: Scan result
586 1.1.1.4 christos * @fetch_time: Time when the result was fetched from the driver
587 1.1.1.3 christos *
588 1.1.1.3 christos * This function updates a BSS table entry (or adds one) based on a scan result.
589 1.1.1.3 christos * This is called separately for each scan result between the calls to
590 1.1.1.3 christos * wpa_bss_update_start() and wpa_bss_update_end().
591 1.1.1.3 christos */
592 1.1 christos void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
593 1.1.1.4 christos struct wpa_scan_res *res,
594 1.1.1.4 christos struct os_reltime *fetch_time)
595 1.1 christos {
596 1.1.1.2 christos const u8 *ssid, *p2p;
597 1.1 christos struct wpa_bss *bss;
598 1.1 christos
599 1.1.1.4 christos if (wpa_s->conf->ignore_old_scan_res) {
600 1.1.1.4 christos struct os_reltime update;
601 1.1.1.4 christos calculate_update_time(fetch_time, res->age, &update);
602 1.1.1.4 christos if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) {
603 1.1.1.4 christos struct os_reltime age;
604 1.1.1.4 christos os_reltime_sub(&wpa_s->scan_trigger_time, &update,
605 1.1.1.4 christos &age);
606 1.1.1.4 christos wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS "
607 1.1.1.4 christos "table entry that is %u.%06u seconds older "
608 1.1.1.4 christos "than our scan trigger",
609 1.1.1.4 christos (unsigned int) age.sec,
610 1.1.1.4 christos (unsigned int) age.usec);
611 1.1.1.4 christos return;
612 1.1.1.4 christos }
613 1.1.1.4 christos }
614 1.1.1.4 christos
615 1.1 christos ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
616 1.1 christos if (ssid == NULL) {
617 1.1.1.2 christos wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
618 1.1.1.2 christos MACSTR, MAC2STR(res->bssid));
619 1.1 christos return;
620 1.1 christos }
621 1.1 christos if (ssid[1] > 32) {
622 1.1.1.2 christos wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
623 1.1.1.2 christos MACSTR, MAC2STR(res->bssid));
624 1.1 christos return;
625 1.1 christos }
626 1.1 christos
627 1.1.1.2 christos p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
628 1.1.1.3 christos #ifdef CONFIG_P2P
629 1.1.1.3 christos if (p2p == NULL &&
630 1.1.1.3 christos wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
631 1.1.1.3 christos /*
632 1.1.1.3 christos * If it's a P2P specific interface, then don't update
633 1.1.1.3 christos * the scan result without a P2P IE.
634 1.1.1.3 christos */
635 1.1.1.3 christos wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
636 1.1.1.3 christos " update for P2P interface", MAC2STR(res->bssid));
637 1.1.1.3 christos return;
638 1.1.1.3 christos }
639 1.1.1.3 christos #endif /* CONFIG_P2P */
640 1.1.1.2 christos if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
641 1.1.1.2 christos os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
642 1.1.1.2 christos return; /* Skip P2P listen discovery results here */
643 1.1.1.2 christos
644 1.1 christos /* TODO: add option for ignoring BSSes we are not interested in
645 1.1 christos * (to save memory) */
646 1.1 christos bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
647 1.1 christos if (bss == NULL)
648 1.1.1.4 christos bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
649 1.1.1.4 christos else {
650 1.1.1.4 christos bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
651 1.1.1.4 christos if (wpa_s->last_scan_res) {
652 1.1.1.4 christos unsigned int i;
653 1.1.1.4 christos for (i = 0; i < wpa_s->last_scan_res_used; i++) {
654 1.1.1.4 christos if (bss == wpa_s->last_scan_res[i]) {
655 1.1.1.4 christos /* Already in the list */
656 1.1.1.4 christos return;
657 1.1.1.4 christos }
658 1.1.1.4 christos }
659 1.1.1.4 christos }
660 1.1.1.4 christos }
661 1.1.1.3 christos
662 1.1.1.3 christos if (bss == NULL)
663 1.1.1.3 christos return;
664 1.1.1.3 christos if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
665 1.1.1.3 christos struct wpa_bss **n;
666 1.1.1.3 christos unsigned int siz;
667 1.1.1.3 christos if (wpa_s->last_scan_res_size == 0)
668 1.1.1.3 christos siz = 32;
669 1.1.1.3 christos else
670 1.1.1.3 christos siz = wpa_s->last_scan_res_size * 2;
671 1.1.1.3 christos n = os_realloc_array(wpa_s->last_scan_res, siz,
672 1.1.1.3 christos sizeof(struct wpa_bss *));
673 1.1.1.3 christos if (n == NULL)
674 1.1.1.3 christos return;
675 1.1.1.3 christos wpa_s->last_scan_res = n;
676 1.1.1.3 christos wpa_s->last_scan_res_size = siz;
677 1.1.1.3 christos }
678 1.1.1.3 christos
679 1.1.1.4 christos if (wpa_s->last_scan_res)
680 1.1.1.4 christos wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
681 1.1 christos }
682 1.1 christos
683 1.1 christos
684 1.1 christos static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
685 1.1 christos const struct scan_info *info)
686 1.1 christos {
687 1.1 christos int found;
688 1.1 christos size_t i;
689 1.1 christos
690 1.1 christos if (info == NULL)
691 1.1 christos return 1;
692 1.1 christos
693 1.1 christos if (info->num_freqs) {
694 1.1 christos found = 0;
695 1.1 christos for (i = 0; i < info->num_freqs; i++) {
696 1.1 christos if (bss->freq == info->freqs[i]) {
697 1.1 christos found = 1;
698 1.1 christos break;
699 1.1 christos }
700 1.1 christos }
701 1.1 christos if (!found)
702 1.1 christos return 0;
703 1.1 christos }
704 1.1 christos
705 1.1 christos if (info->num_ssids) {
706 1.1 christos found = 0;
707 1.1 christos for (i = 0; i < info->num_ssids; i++) {
708 1.1 christos const struct wpa_driver_scan_ssid *s = &info->ssids[i];
709 1.1 christos if ((s->ssid == NULL || s->ssid_len == 0) ||
710 1.1 christos (s->ssid_len == bss->ssid_len &&
711 1.1 christos os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
712 1.1 christos 0)) {
713 1.1 christos found = 1;
714 1.1 christos break;
715 1.1 christos }
716 1.1 christos }
717 1.1 christos if (!found)
718 1.1 christos return 0;
719 1.1 christos }
720 1.1 christos
721 1.1 christos return 1;
722 1.1 christos }
723 1.1 christos
724 1.1 christos
725 1.1.1.3 christos /**
726 1.1.1.3 christos * wpa_bss_update_end - End a BSS table update from scan results
727 1.1.1.3 christos * @wpa_s: Pointer to wpa_supplicant data
728 1.1.1.3 christos * @info: Information about scan parameters
729 1.1.1.3 christos * @new_scan: Whether this update round was based on a new scan
730 1.1.1.3 christos *
731 1.1.1.3 christos * This function is called at the end of each BSS table update round for new
732 1.1.1.3 christos * scan results. The start of the update was indicated with a call to
733 1.1.1.3 christos * wpa_bss_update_start().
734 1.1.1.3 christos */
735 1.1 christos void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
736 1.1 christos int new_scan)
737 1.1 christos {
738 1.1 christos struct wpa_bss *bss, *n;
739 1.1 christos
740 1.1.1.4 christos os_get_reltime(&wpa_s->last_scan);
741 1.1 christos if (!new_scan)
742 1.1 christos return; /* do not expire entries without new scan */
743 1.1 christos
744 1.1 christos dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
745 1.1 christos if (wpa_bss_in_use(wpa_s, bss))
746 1.1 christos continue;
747 1.1 christos if (!wpa_bss_included_in_scan(bss, info))
748 1.1 christos continue; /* expire only BSSes that were scanned */
749 1.1 christos if (bss->last_update_idx < wpa_s->bss_update_idx)
750 1.1 christos bss->scan_miss_count++;
751 1.1.1.2 christos if (bss->scan_miss_count >=
752 1.1.1.2 christos wpa_s->conf->bss_expiration_scan_count) {
753 1.1.1.3 christos wpa_bss_remove(wpa_s, bss, "no match in scan");
754 1.1 christos }
755 1.1 christos }
756 1.1.1.3 christos
757 1.1.1.4 christos wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u",
758 1.1.1.4 christos wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
759 1.1 christos }
760 1.1 christos
761 1.1 christos
762 1.1.1.3 christos /**
763 1.1.1.3 christos * wpa_bss_flush_by_age - Flush old BSS entries
764 1.1.1.3 christos * @wpa_s: Pointer to wpa_supplicant data
765 1.1.1.3 christos * @age: Maximum entry age in seconds
766 1.1.1.3 christos *
767 1.1.1.3 christos * Remove BSS entries that have not been updated during the last @age seconds.
768 1.1.1.3 christos */
769 1.1.1.2 christos void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
770 1.1 christos {
771 1.1 christos struct wpa_bss *bss, *n;
772 1.1.1.4 christos struct os_reltime t;
773 1.1 christos
774 1.1 christos if (dl_list_empty(&wpa_s->bss))
775 1.1 christos return;
776 1.1 christos
777 1.1.1.4 christos os_get_reltime(&t);
778 1.1.1.2 christos t.sec -= age;
779 1.1 christos
780 1.1 christos dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
781 1.1 christos if (wpa_bss_in_use(wpa_s, bss))
782 1.1 christos continue;
783 1.1 christos
784 1.1.1.4 christos if (os_reltime_before(&bss->last_update, &t)) {
785 1.1.1.3 christos wpa_bss_remove(wpa_s, bss, __func__);
786 1.1 christos } else
787 1.1 christos break;
788 1.1 christos }
789 1.1.1.2 christos }
790 1.1.1.2 christos
791 1.1.1.2 christos
792 1.1.1.2 christos static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
793 1.1.1.2 christos {
794 1.1.1.2 christos struct wpa_supplicant *wpa_s = eloop_ctx;
795 1.1.1.2 christos
796 1.1.1.2 christos wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
797 1.1 christos eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
798 1.1 christos wpa_bss_timeout, wpa_s, NULL);
799 1.1 christos }
800 1.1 christos
801 1.1 christos
802 1.1.1.3 christos /**
803 1.1.1.3 christos * wpa_bss_init - Initialize BSS table
804 1.1.1.3 christos * @wpa_s: Pointer to wpa_supplicant data
805 1.1.1.3 christos * Returns: 0 on success, -1 on failure
806 1.1.1.3 christos *
807 1.1.1.3 christos * This prepares BSS table lists and timer for periodic updates. The BSS table
808 1.1.1.3 christos * is deinitialized with wpa_bss_deinit() once not needed anymore.
809 1.1.1.3 christos */
810 1.1 christos int wpa_bss_init(struct wpa_supplicant *wpa_s)
811 1.1 christos {
812 1.1 christos dl_list_init(&wpa_s->bss);
813 1.1 christos dl_list_init(&wpa_s->bss_id);
814 1.1 christos eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
815 1.1 christos wpa_bss_timeout, wpa_s, NULL);
816 1.1 christos return 0;
817 1.1 christos }
818 1.1 christos
819 1.1 christos
820 1.1.1.3 christos /**
821 1.1.1.3 christos * wpa_bss_flush - Flush all unused BSS entries
822 1.1.1.3 christos * @wpa_s: Pointer to wpa_supplicant data
823 1.1.1.3 christos */
824 1.1.1.2 christos void wpa_bss_flush(struct wpa_supplicant *wpa_s)
825 1.1 christos {
826 1.1 christos struct wpa_bss *bss, *n;
827 1.1.1.2 christos
828 1.1.1.4 christos wpa_s->clear_driver_scan_cache = 1;
829 1.1.1.4 christos
830 1.1 christos if (wpa_s->bss.next == NULL)
831 1.1 christos return; /* BSS table not yet initialized */
832 1.1.1.2 christos
833 1.1.1.2 christos dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
834 1.1.1.2 christos if (wpa_bss_in_use(wpa_s, bss))
835 1.1.1.2 christos continue;
836 1.1.1.3 christos wpa_bss_remove(wpa_s, bss, __func__);
837 1.1.1.2 christos }
838 1.1.1.2 christos }
839 1.1.1.2 christos
840 1.1.1.2 christos
841 1.1.1.3 christos /**
842 1.1.1.3 christos * wpa_bss_deinit - Deinitialize BSS table
843 1.1.1.3 christos * @wpa_s: Pointer to wpa_supplicant data
844 1.1.1.3 christos */
845 1.1.1.2 christos void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
846 1.1.1.2 christos {
847 1.1.1.2 christos eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
848 1.1.1.2 christos wpa_bss_flush(wpa_s);
849 1.1 christos }
850 1.1 christos
851 1.1 christos
852 1.1.1.3 christos /**
853 1.1.1.3 christos * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
854 1.1.1.3 christos * @wpa_s: Pointer to wpa_supplicant data
855 1.1.1.3 christos * @bssid: BSSID
856 1.1.1.3 christos * Returns: Pointer to the BSS entry or %NULL if not found
857 1.1.1.3 christos */
858 1.1 christos struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
859 1.1 christos const u8 *bssid)
860 1.1 christos {
861 1.1 christos struct wpa_bss *bss;
862 1.1.1.3 christos if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
863 1.1.1.3 christos return NULL;
864 1.1.1.2 christos dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
865 1.1 christos if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
866 1.1 christos return bss;
867 1.1 christos }
868 1.1 christos return NULL;
869 1.1 christos }
870 1.1 christos
871 1.1 christos
872 1.1.1.4 christos /**
873 1.1.1.4 christos * wpa_bss_get_bssid_latest - Fetch the latest BSS table entry based on BSSID
874 1.1.1.4 christos * @wpa_s: Pointer to wpa_supplicant data
875 1.1.1.4 christos * @bssid: BSSID
876 1.1.1.4 christos * Returns: Pointer to the BSS entry or %NULL if not found
877 1.1.1.4 christos *
878 1.1.1.4 christos * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to
879 1.1.1.4 christos * find the entry that has the most recent update. This can help in finding the
880 1.1.1.4 christos * correct entry in cases where the SSID of the AP may have changed recently
881 1.1.1.4 christos * (e.g., in WPS reconfiguration cases).
882 1.1.1.4 christos */
883 1.1.1.4 christos struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
884 1.1.1.4 christos const u8 *bssid)
885 1.1.1.4 christos {
886 1.1.1.4 christos struct wpa_bss *bss, *found = NULL;
887 1.1.1.4 christos if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
888 1.1.1.4 christos return NULL;
889 1.1.1.4 christos dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
890 1.1.1.4 christos if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
891 1.1.1.4 christos continue;
892 1.1.1.4 christos if (found == NULL ||
893 1.1.1.4 christos os_reltime_before(&found->last_update, &bss->last_update))
894 1.1.1.4 christos found = bss;
895 1.1.1.4 christos }
896 1.1.1.4 christos return found;
897 1.1.1.4 christos }
898 1.1.1.4 christos
899 1.1.1.4 christos
900 1.1.1.2 christos #ifdef CONFIG_P2P
901 1.1.1.3 christos /**
902 1.1.1.3 christos * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
903 1.1.1.3 christos * @wpa_s: Pointer to wpa_supplicant data
904 1.1.1.3 christos * @dev_addr: P2P Device Address of the GO
905 1.1.1.3 christos * Returns: Pointer to the BSS entry or %NULL if not found
906 1.1.1.3 christos */
907 1.1.1.2 christos struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
908 1.1.1.2 christos const u8 *dev_addr)
909 1.1.1.2 christos {
910 1.1.1.2 christos struct wpa_bss *bss;
911 1.1.1.2 christos dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
912 1.1.1.2 christos u8 addr[ETH_ALEN];
913 1.1.1.2 christos if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
914 1.1.1.2 christos addr) == 0 &&
915 1.1.1.2 christos os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
916 1.1.1.2 christos return bss;
917 1.1.1.2 christos }
918 1.1.1.2 christos return NULL;
919 1.1.1.2 christos }
920 1.1.1.2 christos #endif /* CONFIG_P2P */
921 1.1.1.2 christos
922 1.1.1.2 christos
923 1.1.1.3 christos /**
924 1.1.1.3 christos * wpa_bss_get_id - Fetch a BSS table entry based on identifier
925 1.1.1.3 christos * @wpa_s: Pointer to wpa_supplicant data
926 1.1.1.3 christos * @id: Unique identifier (struct wpa_bss::id) assigned for the entry
927 1.1.1.3 christos * Returns: Pointer to the BSS entry or %NULL if not found
928 1.1.1.3 christos */
929 1.1 christos struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
930 1.1 christos {
931 1.1 christos struct wpa_bss *bss;
932 1.1 christos dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
933 1.1 christos if (bss->id == id)
934 1.1 christos return bss;
935 1.1 christos }
936 1.1 christos return NULL;
937 1.1 christos }
938 1.1 christos
939 1.1 christos
940 1.1.1.3 christos /**
941 1.1.1.4 christos * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range
942 1.1.1.4 christos * @wpa_s: Pointer to wpa_supplicant data
943 1.1.1.4 christos * @idf: Smallest allowed identifier assigned for the entry
944 1.1.1.4 christos * @idf: Largest allowed identifier assigned for the entry
945 1.1.1.4 christos * Returns: Pointer to the BSS entry or %NULL if not found
946 1.1.1.4 christos *
947 1.1.1.4 christos * This function is similar to wpa_bss_get_id() but allows a BSS entry with the
948 1.1.1.4 christos * smallest id value to be fetched within the specified range without the
949 1.1.1.4 christos * caller having to know the exact id.
950 1.1.1.4 christos */
951 1.1.1.4 christos struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
952 1.1.1.4 christos unsigned int idf, unsigned int idl)
953 1.1.1.4 christos {
954 1.1.1.4 christos struct wpa_bss *bss;
955 1.1.1.4 christos dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
956 1.1.1.4 christos if (bss->id >= idf && bss->id <= idl)
957 1.1.1.4 christos return bss;
958 1.1.1.4 christos }
959 1.1.1.4 christos return NULL;
960 1.1.1.4 christos }
961 1.1.1.4 christos
962 1.1.1.4 christos
963 1.1.1.4 christos /**
964 1.1.1.3 christos * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
965 1.1.1.3 christos * @bss: BSS table entry
966 1.1.1.3 christos * @ie: Information element identitifier (WLAN_EID_*)
967 1.1.1.3 christos * Returns: Pointer to the information element (id field) or %NULL if not found
968 1.1.1.3 christos *
969 1.1.1.3 christos * This function returns the first matching information element in the BSS
970 1.1.1.3 christos * entry.
971 1.1.1.3 christos */
972 1.1 christos const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
973 1.1 christos {
974 1.1 christos const u8 *end, *pos;
975 1.1 christos
976 1.1 christos pos = (const u8 *) (bss + 1);
977 1.1 christos end = pos + bss->ie_len;
978 1.1 christos
979 1.1 christos while (pos + 1 < end) {
980 1.1 christos if (pos + 2 + pos[1] > end)
981 1.1 christos break;
982 1.1 christos if (pos[0] == ie)
983 1.1 christos return pos;
984 1.1 christos pos += 2 + pos[1];
985 1.1 christos }
986 1.1 christos
987 1.1 christos return NULL;
988 1.1 christos }
989 1.1 christos
990 1.1 christos
991 1.1.1.3 christos /**
992 1.1.1.3 christos * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
993 1.1.1.3 christos * @bss: BSS table entry
994 1.1.1.3 christos * @vendor_type: Vendor type (four octets starting the IE payload)
995 1.1.1.3 christos * Returns: Pointer to the information element (id field) or %NULL if not found
996 1.1.1.3 christos *
997 1.1.1.3 christos * This function returns the first matching information element in the BSS
998 1.1.1.3 christos * entry.
999 1.1.1.3 christos */
1000 1.1 christos const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
1001 1.1 christos {
1002 1.1 christos const u8 *end, *pos;
1003 1.1 christos
1004 1.1 christos pos = (const u8 *) (bss + 1);
1005 1.1 christos end = pos + bss->ie_len;
1006 1.1 christos
1007 1.1 christos while (pos + 1 < end) {
1008 1.1 christos if (pos + 2 + pos[1] > end)
1009 1.1 christos break;
1010 1.1 christos if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1011 1.1 christos vendor_type == WPA_GET_BE32(&pos[2]))
1012 1.1 christos return pos;
1013 1.1 christos pos += 2 + pos[1];
1014 1.1 christos }
1015 1.1 christos
1016 1.1 christos return NULL;
1017 1.1 christos }
1018 1.1 christos
1019 1.1 christos
1020 1.1.1.3 christos /**
1021 1.1.1.4 christos * wpa_bss_get_vendor_ie_beacon - Fetch a vendor information from a BSS entry
1022 1.1.1.4 christos * @bss: BSS table entry
1023 1.1.1.4 christos * @vendor_type: Vendor type (four octets starting the IE payload)
1024 1.1.1.4 christos * Returns: Pointer to the information element (id field) or %NULL if not found
1025 1.1.1.4 christos *
1026 1.1.1.4 christos * This function returns the first matching information element in the BSS
1027 1.1.1.4 christos * entry.
1028 1.1.1.4 christos *
1029 1.1.1.4 christos * This function is like wpa_bss_get_vendor_ie(), but uses IE buffer only
1030 1.1.1.4 christos * from Beacon frames instead of either Beacon or Probe Response frames.
1031 1.1.1.4 christos */
1032 1.1.1.4 christos const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
1033 1.1.1.4 christos u32 vendor_type)
1034 1.1.1.4 christos {
1035 1.1.1.4 christos const u8 *end, *pos;
1036 1.1.1.4 christos
1037 1.1.1.4 christos if (bss->beacon_ie_len == 0)
1038 1.1.1.4 christos return NULL;
1039 1.1.1.4 christos
1040 1.1.1.4 christos pos = (const u8 *) (bss + 1);
1041 1.1.1.4 christos pos += bss->ie_len;
1042 1.1.1.4 christos end = pos + bss->beacon_ie_len;
1043 1.1.1.4 christos
1044 1.1.1.4 christos while (pos + 1 < end) {
1045 1.1.1.4 christos if (pos + 2 + pos[1] > end)
1046 1.1.1.4 christos break;
1047 1.1.1.4 christos if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1048 1.1.1.4 christos vendor_type == WPA_GET_BE32(&pos[2]))
1049 1.1.1.4 christos return pos;
1050 1.1.1.4 christos pos += 2 + pos[1];
1051 1.1.1.4 christos }
1052 1.1.1.4 christos
1053 1.1.1.4 christos return NULL;
1054 1.1.1.4 christos }
1055 1.1.1.4 christos
1056 1.1.1.4 christos
1057 1.1.1.4 christos /**
1058 1.1.1.3 christos * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
1059 1.1.1.3 christos * @bss: BSS table entry
1060 1.1.1.3 christos * @vendor_type: Vendor type (four octets starting the IE payload)
1061 1.1.1.3 christos * Returns: Pointer to the information element payload or %NULL if not found
1062 1.1.1.3 christos *
1063 1.1.1.3 christos * This function returns concatenated payload of possibly fragmented vendor
1064 1.1.1.3 christos * specific information elements in the BSS entry. The caller is responsible for
1065 1.1.1.3 christos * freeing the returned buffer.
1066 1.1.1.3 christos */
1067 1.1 christos struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
1068 1.1 christos u32 vendor_type)
1069 1.1 christos {
1070 1.1 christos struct wpabuf *buf;
1071 1.1 christos const u8 *end, *pos;
1072 1.1 christos
1073 1.1 christos buf = wpabuf_alloc(bss->ie_len);
1074 1.1 christos if (buf == NULL)
1075 1.1 christos return NULL;
1076 1.1 christos
1077 1.1 christos pos = (const u8 *) (bss + 1);
1078 1.1 christos end = pos + bss->ie_len;
1079 1.1 christos
1080 1.1 christos while (pos + 1 < end) {
1081 1.1 christos if (pos + 2 + pos[1] > end)
1082 1.1 christos break;
1083 1.1 christos if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1084 1.1 christos vendor_type == WPA_GET_BE32(&pos[2]))
1085 1.1 christos wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
1086 1.1 christos pos += 2 + pos[1];
1087 1.1 christos }
1088 1.1 christos
1089 1.1 christos if (wpabuf_len(buf) == 0) {
1090 1.1 christos wpabuf_free(buf);
1091 1.1 christos buf = NULL;
1092 1.1 christos }
1093 1.1 christos
1094 1.1 christos return buf;
1095 1.1 christos }
1096 1.1 christos
1097 1.1 christos
1098 1.1.1.3 christos /**
1099 1.1.1.3 christos * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry
1100 1.1.1.3 christos * @bss: BSS table entry
1101 1.1.1.3 christos * @vendor_type: Vendor type (four octets starting the IE payload)
1102 1.1.1.3 christos * Returns: Pointer to the information element payload or %NULL if not found
1103 1.1.1.3 christos *
1104 1.1.1.3 christos * This function returns concatenated payload of possibly fragmented vendor
1105 1.1.1.3 christos * specific information elements in the BSS entry. The caller is responsible for
1106 1.1.1.3 christos * freeing the returned buffer.
1107 1.1.1.3 christos *
1108 1.1.1.3 christos * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only
1109 1.1.1.3 christos * from Beacon frames instead of either Beacon or Probe Response frames.
1110 1.1.1.3 christos */
1111 1.1.1.3 christos struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
1112 1.1.1.3 christos u32 vendor_type)
1113 1.1.1.3 christos {
1114 1.1.1.3 christos struct wpabuf *buf;
1115 1.1.1.3 christos const u8 *end, *pos;
1116 1.1.1.3 christos
1117 1.1.1.3 christos buf = wpabuf_alloc(bss->beacon_ie_len);
1118 1.1.1.3 christos if (buf == NULL)
1119 1.1.1.3 christos return NULL;
1120 1.1.1.3 christos
1121 1.1.1.3 christos pos = (const u8 *) (bss + 1);
1122 1.1.1.3 christos pos += bss->ie_len;
1123 1.1.1.3 christos end = pos + bss->beacon_ie_len;
1124 1.1.1.3 christos
1125 1.1.1.3 christos while (pos + 1 < end) {
1126 1.1.1.3 christos if (pos + 2 + pos[1] > end)
1127 1.1.1.3 christos break;
1128 1.1.1.3 christos if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1129 1.1.1.3 christos vendor_type == WPA_GET_BE32(&pos[2]))
1130 1.1.1.3 christos wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
1131 1.1.1.3 christos pos += 2 + pos[1];
1132 1.1.1.3 christos }
1133 1.1.1.3 christos
1134 1.1.1.3 christos if (wpabuf_len(buf) == 0) {
1135 1.1.1.3 christos wpabuf_free(buf);
1136 1.1.1.3 christos buf = NULL;
1137 1.1.1.3 christos }
1138 1.1.1.3 christos
1139 1.1.1.3 christos return buf;
1140 1.1.1.3 christos }
1141 1.1.1.3 christos
1142 1.1.1.3 christos
1143 1.1.1.3 christos /**
1144 1.1.1.3 christos * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS
1145 1.1.1.3 christos * @bss: BSS table entry
1146 1.1.1.3 christos * Returns: Maximum legacy rate in units of 500 kbps
1147 1.1.1.3 christos */
1148 1.1 christos int wpa_bss_get_max_rate(const struct wpa_bss *bss)
1149 1.1 christos {
1150 1.1 christos int rate = 0;
1151 1.1 christos const u8 *ie;
1152 1.1 christos int i;
1153 1.1 christos
1154 1.1 christos ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
1155 1.1 christos for (i = 0; ie && i < ie[1]; i++) {
1156 1.1 christos if ((ie[i + 2] & 0x7f) > rate)
1157 1.1 christos rate = ie[i + 2] & 0x7f;
1158 1.1 christos }
1159 1.1 christos
1160 1.1 christos ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
1161 1.1 christos for (i = 0; ie && i < ie[1]; i++) {
1162 1.1 christos if ((ie[i + 2] & 0x7f) > rate)
1163 1.1 christos rate = ie[i + 2] & 0x7f;
1164 1.1 christos }
1165 1.1 christos
1166 1.1 christos return rate;
1167 1.1 christos }
1168 1.1 christos
1169 1.1 christos
1170 1.1.1.3 christos /**
1171 1.1.1.3 christos * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS
1172 1.1.1.3 christos * @bss: BSS table entry
1173 1.1.1.3 christos * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps)
1174 1.1.1.3 christos * Returns: number of legacy TX rates or -1 on failure
1175 1.1.1.3 christos *
1176 1.1.1.3 christos * The caller is responsible for freeing the returned buffer with os_free() in
1177 1.1.1.3 christos * case of success.
1178 1.1.1.3 christos */
1179 1.1 christos int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
1180 1.1 christos {
1181 1.1 christos const u8 *ie, *ie2;
1182 1.1 christos int i, j;
1183 1.1 christos unsigned int len;
1184 1.1 christos u8 *r;
1185 1.1 christos
1186 1.1 christos ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
1187 1.1 christos ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
1188 1.1 christos
1189 1.1 christos len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
1190 1.1 christos
1191 1.1 christos r = os_malloc(len);
1192 1.1 christos if (!r)
1193 1.1 christos return -1;
1194 1.1 christos
1195 1.1 christos for (i = 0; ie && i < ie[1]; i++)
1196 1.1 christos r[i] = ie[i + 2] & 0x7f;
1197 1.1 christos
1198 1.1 christos for (j = 0; ie2 && j < ie2[1]; j++)
1199 1.1 christos r[i + j] = ie2[j + 2] & 0x7f;
1200 1.1 christos
1201 1.1 christos *rates = r;
1202 1.1 christos return len;
1203 1.1 christos }
1204