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