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 1422976643 Lines: 466 540 86.3 %
Date: 2015-02-03 Functions: 36 40 90.0 %

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

Generated by: LCOV version 1.10