OSDN Git Service

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