LCOV - code coverage report
Current view: top level - wpa_supplicant - bss.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1426431149 Lines: 472 546 86.4 %
Date: 2015-03-15 Functions: 36 40 90.0 %

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

Generated by: LCOV version 1.10