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 1401264779 Lines: 419 520 80.6 %
Date: 2014-05-28 Functions: 33 39 84.6 %

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

Generated by: LCOV version 1.10