Maintain list of BSS entries in last scan result order
[mech_eap.git] / wpa_supplicant / bss.c
1 /*
2  * BSS table
3  * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8
9 #include "utils/includes.h"
10
11 #include "utils/common.h"
12 #include "utils/eloop.h"
13 #include "common/ieee802_11_defs.h"
14 #include "drivers/driver.h"
15 #include "wpa_supplicant_i.h"
16 #include "config.h"
17 #include "notify.h"
18 #include "scan.h"
19 #include "bss.h"
20
21
22 /**
23  * WPA_BSS_EXPIRATION_PERIOD - Period of expiration run in seconds
24  */
25 #define WPA_BSS_EXPIRATION_PERIOD 10
26
27 #define WPA_BSS_FREQ_CHANGED_FLAG       BIT(0)
28 #define WPA_BSS_SIGNAL_CHANGED_FLAG     BIT(1)
29 #define WPA_BSS_PRIVACY_CHANGED_FLAG    BIT(2)
30 #define WPA_BSS_MODE_CHANGED_FLAG       BIT(3)
31 #define WPA_BSS_WPAIE_CHANGED_FLAG      BIT(4)
32 #define WPA_BSS_RSNIE_CHANGED_FLAG      BIT(5)
33 #define WPA_BSS_WPS_CHANGED_FLAG        BIT(6)
34 #define WPA_BSS_RATES_CHANGED_FLAG      BIT(7)
35 #define WPA_BSS_IES_CHANGED_FLAG        BIT(8)
36
37
38 static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
39                            const char *reason)
40 {
41         if (wpa_s->last_scan_res) {
42                 unsigned int i;
43                 for (i = 0; i < wpa_s->last_scan_res_used; i++) {
44                         if (wpa_s->last_scan_res[i] == bss) {
45                                 os_memmove(&wpa_s->last_scan_res[i],
46                                            &wpa_s->last_scan_res[i + 1],
47                                            (wpa_s->last_scan_res_used - i - 1)
48                                            * sizeof(struct wpa_bss *));
49                                 wpa_s->last_scan_res_used--;
50                                 break;
51                         }
52                 }
53         }
54         dl_list_del(&bss->list);
55         dl_list_del(&bss->list_id);
56         wpa_s->num_bss--;
57         wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
58                 " SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
59                 wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
60         wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
61 #ifdef CONFIG_INTERWORKING
62         wpabuf_free(bss->anqp_venue_name);
63         wpabuf_free(bss->anqp_network_auth_type);
64         wpabuf_free(bss->anqp_roaming_consortium);
65         wpabuf_free(bss->anqp_ip_addr_type_availability);
66         wpabuf_free(bss->anqp_nai_realm);
67         wpabuf_free(bss->anqp_3gpp);
68         wpabuf_free(bss->anqp_domain_name);
69 #endif /* CONFIG_INTERWORKING */
70 #ifdef CONFIG_HS20
71         wpabuf_free(bss->hs20_operator_friendly_name);
72         wpabuf_free(bss->hs20_wan_metrics);
73         wpabuf_free(bss->hs20_connection_capability);
74         wpabuf_free(bss->hs20_operating_class);
75 #endif /* CONFIG_HS20 */
76         os_free(bss);
77 }
78
79
80 struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
81                              const u8 *ssid, size_t ssid_len)
82 {
83         struct wpa_bss *bss;
84         if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
85                 return NULL;
86         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
87                 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
88                     bss->ssid_len == ssid_len &&
89                     os_memcmp(bss->ssid, ssid, ssid_len) == 0)
90                         return bss;
91         }
92         return NULL;
93 }
94
95
96 static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
97 {
98         os_time_t usec;
99
100         dst->flags = src->flags;
101         os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
102         dst->freq = src->freq;
103         dst->beacon_int = src->beacon_int;
104         dst->caps = src->caps;
105         dst->qual = src->qual;
106         dst->noise = src->noise;
107         dst->level = src->level;
108         dst->tsf = src->tsf;
109
110         os_get_time(&dst->last_update);
111         dst->last_update.sec -= src->age / 1000;
112         usec = (src->age % 1000) * 1000;
113         if (dst->last_update.usec < usec) {
114                 dst->last_update.sec--;
115                 dst->last_update.usec += 1000000;
116         }
117         dst->last_update.usec -= usec;
118 }
119
120
121 static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
122 {
123         struct wpa_ssid *ssid;
124
125         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
126                 if (ssid->ssid == NULL || ssid->ssid_len == 0)
127                         continue;
128                 if (ssid->ssid_len == bss->ssid_len &&
129                     os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
130                         return 1;
131         }
132
133         return 0;
134 }
135
136
137 static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
138 {
139         return bss == wpa_s->current_bss ||
140                 os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
141                 os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
142 }
143
144
145 static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
146 {
147         struct wpa_bss *bss;
148
149         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
150                 if (!wpa_bss_known(wpa_s, bss)) {
151                         wpa_bss_remove(wpa_s, bss, __func__);
152                         return 0;
153                 }
154         }
155
156         return -1;
157 }
158
159
160 static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
161 {
162         struct wpa_bss *bss;
163
164         /*
165          * Remove the oldest entry that does not match with any configured
166          * network.
167          */
168         if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
169                 return 0;
170
171         /*
172          * Remove the oldest entry that isn't currently in use.
173          */
174         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
175                 if (!wpa_bss_in_use(wpa_s, bss)) {
176                         wpa_bss_remove(wpa_s, bss, __func__);
177                         return 0;
178                 }
179         }
180
181         return -1;
182 }
183
184
185 static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
186                                     const u8 *ssid, size_t ssid_len,
187                                     struct wpa_scan_res *res)
188 {
189         struct wpa_bss *bss;
190
191         bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
192         if (bss == NULL)
193                 return NULL;
194         bss->id = wpa_s->bss_next_id++;
195         bss->last_update_idx = wpa_s->bss_update_idx;
196         wpa_bss_copy_res(bss, res);
197         os_memcpy(bss->ssid, ssid, ssid_len);
198         bss->ssid_len = ssid_len;
199         bss->ie_len = res->ie_len;
200         bss->beacon_ie_len = res->beacon_ie_len;
201         os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
202
203         dl_list_add_tail(&wpa_s->bss, &bss->list);
204         dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
205         wpa_s->num_bss++;
206         wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
207                 " SSID '%s'",
208                 bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
209         wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
210         if (wpa_s->num_bss > wpa_s->conf->bss_max_count &&
211             wpa_bss_remove_oldest(wpa_s) != 0) {
212                 wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
213                            "because all BSSes are in use. We should normally "
214                            "not get here!", (int) wpa_s->num_bss);
215                 wpa_s->conf->bss_max_count = wpa_s->num_bss;
216         }
217         return bss;
218 }
219
220
221 static int are_ies_equal(const struct wpa_bss *old,
222                          const struct wpa_scan_res *new, u32 ie)
223 {
224         const u8 *old_ie, *new_ie;
225         struct wpabuf *old_ie_buff = NULL;
226         struct wpabuf *new_ie_buff = NULL;
227         int new_ie_len, old_ie_len, ret, is_multi;
228
229         switch (ie) {
230         case WPA_IE_VENDOR_TYPE:
231                 old_ie = wpa_bss_get_vendor_ie(old, ie);
232                 new_ie = wpa_scan_get_vendor_ie(new, ie);
233                 is_multi = 0;
234                 break;
235         case WPS_IE_VENDOR_TYPE:
236                 old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
237                 new_ie_buff = wpa_scan_get_vendor_ie_multi(new, ie);
238                 is_multi = 1;
239                 break;
240         case WLAN_EID_RSN:
241         case WLAN_EID_SUPP_RATES:
242         case WLAN_EID_EXT_SUPP_RATES:
243                 old_ie = wpa_bss_get_ie(old, ie);
244                 new_ie = wpa_scan_get_ie(new, ie);
245                 is_multi = 0;
246                 break;
247         default:
248                 wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
249                 return 0;
250         }
251
252         if (is_multi) {
253                 /* in case of multiple IEs stored in buffer */
254                 old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
255                 new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
256                 old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
257                 new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
258         } else {
259                 /* in case of single IE */
260                 old_ie_len = old_ie ? old_ie[1] + 2 : 0;
261                 new_ie_len = new_ie ? new_ie[1] + 2 : 0;
262         }
263
264         if (!old_ie || !new_ie)
265                 ret = !old_ie && !new_ie;
266         else
267                 ret = (old_ie_len == new_ie_len &&
268                        os_memcmp(old_ie, new_ie, old_ie_len) == 0);
269
270         wpabuf_free(old_ie_buff);
271         wpabuf_free(new_ie_buff);
272
273         return ret;
274 }
275
276
277 static u32 wpa_bss_compare_res(const struct wpa_bss *old,
278                                const struct wpa_scan_res *new)
279 {
280         u32 changes = 0;
281         int caps_diff = old->caps ^ new->caps;
282
283         if (old->freq != new->freq)
284                 changes |= WPA_BSS_FREQ_CHANGED_FLAG;
285
286         if (old->level != new->level)
287                 changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
288
289         if (caps_diff & IEEE80211_CAP_PRIVACY)
290                 changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
291
292         if (caps_diff & IEEE80211_CAP_IBSS)
293                 changes |= WPA_BSS_MODE_CHANGED_FLAG;
294
295         if (old->ie_len == new->ie_len &&
296             os_memcmp(old + 1, new + 1, old->ie_len) == 0)
297                 return changes;
298         changes |= WPA_BSS_IES_CHANGED_FLAG;
299
300         if (!are_ies_equal(old, new, WPA_IE_VENDOR_TYPE))
301                 changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
302
303         if (!are_ies_equal(old, new, WLAN_EID_RSN))
304                 changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
305
306         if (!are_ies_equal(old, new, WPS_IE_VENDOR_TYPE))
307                 changes |= WPA_BSS_WPS_CHANGED_FLAG;
308
309         if (!are_ies_equal(old, new, WLAN_EID_SUPP_RATES) ||
310             !are_ies_equal(old, new, WLAN_EID_EXT_SUPP_RATES))
311                 changes |= WPA_BSS_RATES_CHANGED_FLAG;
312
313         return changes;
314 }
315
316
317 static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
318                                const struct wpa_bss *bss)
319 {
320         if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
321                 wpas_notify_bss_freq_changed(wpa_s, bss->id);
322
323         if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
324                 wpas_notify_bss_signal_changed(wpa_s, bss->id);
325
326         if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
327                 wpas_notify_bss_privacy_changed(wpa_s, bss->id);
328
329         if (changes & WPA_BSS_MODE_CHANGED_FLAG)
330                 wpas_notify_bss_mode_changed(wpa_s, bss->id);
331
332         if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
333                 wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
334
335         if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
336                 wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
337
338         if (changes & WPA_BSS_WPS_CHANGED_FLAG)
339                 wpas_notify_bss_wps_changed(wpa_s, bss->id);
340
341         if (changes & WPA_BSS_IES_CHANGED_FLAG)
342                 wpas_notify_bss_ies_changed(wpa_s, bss->id);
343
344         if (changes & WPA_BSS_RATES_CHANGED_FLAG)
345                 wpas_notify_bss_rates_changed(wpa_s, bss->id);
346 }
347
348
349 static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
350                            struct wpa_scan_res *res)
351 {
352         u32 changes;
353
354         changes = wpa_bss_compare_res(bss, res);
355         bss->scan_miss_count = 0;
356         bss->last_update_idx = wpa_s->bss_update_idx;
357         wpa_bss_copy_res(bss, res);
358         /* Move the entry to the end of the list */
359         dl_list_del(&bss->list);
360         if (bss->ie_len + bss->beacon_ie_len >=
361             res->ie_len + res->beacon_ie_len) {
362                 os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
363                 bss->ie_len = res->ie_len;
364                 bss->beacon_ie_len = res->beacon_ie_len;
365         } else {
366                 struct wpa_bss *nbss;
367                 struct dl_list *prev = bss->list_id.prev;
368                 dl_list_del(&bss->list_id);
369                 nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
370                                   res->beacon_ie_len);
371                 if (nbss) {
372                         if (wpa_s->current_bss == bss)
373                                 wpa_s->current_bss = nbss;
374                         bss = nbss;
375                         os_memcpy(bss + 1, res + 1,
376                                   res->ie_len + res->beacon_ie_len);
377                         bss->ie_len = res->ie_len;
378                         bss->beacon_ie_len = res->beacon_ie_len;
379                 }
380                 dl_list_add(prev, &bss->list_id);
381         }
382         dl_list_add_tail(&wpa_s->bss, &bss->list);
383
384         notify_bss_changes(wpa_s, changes, bss);
385 }
386
387
388 void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
389 {
390         wpa_s->bss_update_idx++;
391         wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
392                 wpa_s->bss_update_idx);
393         wpa_s->last_scan_res_used = 0;
394 }
395
396
397 void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
398                              struct wpa_scan_res *res)
399 {
400         const u8 *ssid, *p2p;
401         struct wpa_bss *bss;
402
403         ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
404         if (ssid == NULL) {
405                 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
406                         MACSTR, MAC2STR(res->bssid));
407                 return;
408         }
409         if (ssid[1] > 32) {
410                 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
411                         MACSTR, MAC2STR(res->bssid));
412                 return;
413         }
414
415         p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
416 #ifdef CONFIG_P2P
417         if (p2p == NULL &&
418             wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
419                 /*
420                  * If it's a P2P specific interface, then don't update
421                  * the scan result without a P2P IE.
422                  */
423                 wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
424                            " update for P2P interface", MAC2STR(res->bssid));
425                 return;
426         }
427 #endif /* CONFIG_P2P */
428         if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
429             os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
430                 return; /* Skip P2P listen discovery results here */
431
432         /* TODO: add option for ignoring BSSes we are not interested in
433          * (to save memory) */
434         bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
435         if (bss == NULL)
436                 bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res);
437         else
438                 wpa_bss_update(wpa_s, bss, res);
439
440         if (bss == NULL)
441                 return;
442         if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
443                 struct wpa_bss **n;
444                 unsigned int siz;
445                 if (wpa_s->last_scan_res_size == 0)
446                         siz = 32;
447                 else
448                         siz = wpa_s->last_scan_res_size * 2;
449                 n = os_realloc_array(wpa_s->last_scan_res, siz,
450                                      sizeof(struct wpa_bss *));
451                 if (n == NULL)
452                         return;
453                 wpa_s->last_scan_res = n;
454                 wpa_s->last_scan_res_size = siz;
455         }
456
457         wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
458 }
459
460
461 static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
462                                     const struct scan_info *info)
463 {
464         int found;
465         size_t i;
466
467         if (info == NULL)
468                 return 1;
469
470         if (info->num_freqs) {
471                 found = 0;
472                 for (i = 0; i < info->num_freqs; i++) {
473                         if (bss->freq == info->freqs[i]) {
474                                 found = 1;
475                                 break;
476                         }
477                 }
478                 if (!found)
479                         return 0;
480         }
481
482         if (info->num_ssids) {
483                 found = 0;
484                 for (i = 0; i < info->num_ssids; i++) {
485                         const struct wpa_driver_scan_ssid *s = &info->ssids[i];
486                         if ((s->ssid == NULL || s->ssid_len == 0) ||
487                             (s->ssid_len == bss->ssid_len &&
488                              os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
489                              0)) {
490                                 found = 1;
491                                 break;
492                         }
493                 }
494                 if (!found)
495                         return 0;
496         }
497
498         return 1;
499 }
500
501
502 void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
503                         int new_scan)
504 {
505         struct wpa_bss *bss, *n;
506
507         wpa_s->last_scan_full = 0;
508         os_get_time(&wpa_s->last_scan);
509         if (!new_scan)
510                 return; /* do not expire entries without new scan */
511
512         if (info && !info->aborted && !info->freqs) {
513                 size_t i;
514                 if (info->num_ssids == 0) {
515                         wpa_s->last_scan_full = 1;
516                 } else {
517                         for (i = 0; i < info->num_ssids; i++) {
518                                 if (info->ssids[i].ssid == NULL ||
519                                     info->ssids[i].ssid_len == 0) {
520                                         wpa_s->last_scan_full = 1;
521                                         break;
522                                 }
523                         }
524                 }
525         }
526
527         dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
528                 if (wpa_bss_in_use(wpa_s, bss))
529                         continue;
530                 if (!wpa_bss_included_in_scan(bss, info))
531                         continue; /* expire only BSSes that were scanned */
532                 if (bss->last_update_idx < wpa_s->bss_update_idx)
533                         bss->scan_miss_count++;
534                 if (bss->scan_miss_count >=
535                     wpa_s->conf->bss_expiration_scan_count) {
536                         wpa_bss_remove(wpa_s, bss, "no match in scan");
537                 }
538         }
539
540         wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u "
541                    "last_scan_full=%d",
542                    wpa_s->last_scan_res_used, wpa_s->last_scan_res_size,
543                    wpa_s->last_scan_full);
544 }
545
546
547 void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
548 {
549         struct wpa_bss *bss, *n;
550         struct os_time t;
551
552         if (dl_list_empty(&wpa_s->bss))
553                 return;
554
555         os_get_time(&t);
556         t.sec -= age;
557
558         dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
559                 if (wpa_bss_in_use(wpa_s, bss))
560                         continue;
561
562                 if (os_time_before(&bss->last_update, &t)) {
563                         wpa_bss_remove(wpa_s, bss, __func__);
564                 } else
565                         break;
566         }
567 }
568
569
570 static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
571 {
572         struct wpa_supplicant *wpa_s = eloop_ctx;
573
574         wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
575         eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
576                                wpa_bss_timeout, wpa_s, NULL);
577 }
578
579
580 int wpa_bss_init(struct wpa_supplicant *wpa_s)
581 {
582         dl_list_init(&wpa_s->bss);
583         dl_list_init(&wpa_s->bss_id);
584         eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
585                                wpa_bss_timeout, wpa_s, NULL);
586         return 0;
587 }
588
589
590 void wpa_bss_flush(struct wpa_supplicant *wpa_s)
591 {
592         struct wpa_bss *bss, *n;
593
594         if (wpa_s->bss.next == NULL)
595                 return; /* BSS table not yet initialized */
596
597         dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
598                 if (wpa_bss_in_use(wpa_s, bss))
599                         continue;
600                 wpa_bss_remove(wpa_s, bss, __func__);
601         }
602 }
603
604
605 void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
606 {
607         eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
608         wpa_bss_flush(wpa_s);
609 }
610
611
612 struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
613                                    const u8 *bssid)
614 {
615         struct wpa_bss *bss;
616         if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
617                 return NULL;
618         dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
619                 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
620                         return bss;
621         }
622         return NULL;
623 }
624
625
626 #ifdef CONFIG_P2P
627 struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
628                                           const u8 *dev_addr)
629 {
630         struct wpa_bss *bss;
631         dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
632                 u8 addr[ETH_ALEN];
633                 if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
634                                        addr) == 0 &&
635                     os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
636                         return bss;
637         }
638         return NULL;
639 }
640 #endif /* CONFIG_P2P */
641
642
643 struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
644 {
645         struct wpa_bss *bss;
646         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
647                 if (bss->id == id)
648                         return bss;
649         }
650         return NULL;
651 }
652
653
654 const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
655 {
656         const u8 *end, *pos;
657
658         pos = (const u8 *) (bss + 1);
659         end = pos + bss->ie_len;
660
661         while (pos + 1 < end) {
662                 if (pos + 2 + pos[1] > end)
663                         break;
664                 if (pos[0] == ie)
665                         return pos;
666                 pos += 2 + pos[1];
667         }
668
669         return NULL;
670 }
671
672
673 const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
674 {
675         const u8 *end, *pos;
676
677         pos = (const u8 *) (bss + 1);
678         end = pos + bss->ie_len;
679
680         while (pos + 1 < end) {
681                 if (pos + 2 + pos[1] > end)
682                         break;
683                 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
684                     vendor_type == WPA_GET_BE32(&pos[2]))
685                         return pos;
686                 pos += 2 + pos[1];
687         }
688
689         return NULL;
690 }
691
692
693 struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
694                                             u32 vendor_type)
695 {
696         struct wpabuf *buf;
697         const u8 *end, *pos;
698
699         buf = wpabuf_alloc(bss->ie_len);
700         if (buf == NULL)
701                 return NULL;
702
703         pos = (const u8 *) (bss + 1);
704         end = pos + bss->ie_len;
705
706         while (pos + 1 < end) {
707                 if (pos + 2 + pos[1] > end)
708                         break;
709                 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
710                     vendor_type == WPA_GET_BE32(&pos[2]))
711                         wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
712                 pos += 2 + pos[1];
713         }
714
715         if (wpabuf_len(buf) == 0) {
716                 wpabuf_free(buf);
717                 buf = NULL;
718         }
719
720         return buf;
721 }
722
723
724 int wpa_bss_get_max_rate(const struct wpa_bss *bss)
725 {
726         int rate = 0;
727         const u8 *ie;
728         int i;
729
730         ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
731         for (i = 0; ie && i < ie[1]; i++) {
732                 if ((ie[i + 2] & 0x7f) > rate)
733                         rate = ie[i + 2] & 0x7f;
734         }
735
736         ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
737         for (i = 0; ie && i < ie[1]; i++) {
738                 if ((ie[i + 2] & 0x7f) > rate)
739                         rate = ie[i + 2] & 0x7f;
740         }
741
742         return rate;
743 }
744
745
746 int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
747 {
748         const u8 *ie, *ie2;
749         int i, j;
750         unsigned int len;
751         u8 *r;
752
753         ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
754         ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
755
756         len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
757
758         r = os_malloc(len);
759         if (!r)
760                 return -1;
761
762         for (i = 0; ie && i < ie[1]; i++)
763                 r[i] = ie[i + 2] & 0x7f;
764
765         for (j = 0; ie2 && j < ie2[1]; j++)
766                 r[i + j] = ie2[j + 2] & 0x7f;
767
768         *rates = r;
769         return len;
770 }