source: rtems-libbsd/freebsd/contrib/wpa/wpa_supplicant/bss.c @ 9c9d11b

55-freebsd-126-freebsd-12
Last change on this file since 9c9d11b was 9c9d11b, checked in by Sichen Zhao <1473996754@…>, on 08/01/17 at 12:43:41

Import wpa from FreeBSD

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