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