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

Generated by: LCOV version 1.10