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 1443382998 Lines: 473 547 86.5 %
Date: 2015-09-27 Functions: 35 39 89.7 %

          Line data    Source code
       1             : /*
       2             :  * BSS table
       3             :  * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "utils/includes.h"
      10             : 
      11             : #include "utils/common.h"
      12             : #include "utils/eloop.h"
      13             : #include "common/ieee802_11_defs.h"
      14             : #include "drivers/driver.h"
      15             : #include "wpa_supplicant_i.h"
      16             : #include "config.h"
      17             : #include "notify.h"
      18             : #include "scan.h"
      19             : #include "bss.h"
      20             : 
      21             : 
      22             : #define WPA_BSS_FREQ_CHANGED_FLAG       BIT(0)
      23             : #define WPA_BSS_SIGNAL_CHANGED_FLAG     BIT(1)
      24             : #define WPA_BSS_PRIVACY_CHANGED_FLAG    BIT(2)
      25             : #define WPA_BSS_MODE_CHANGED_FLAG       BIT(3)
      26             : #define WPA_BSS_WPAIE_CHANGED_FLAG      BIT(4)
      27             : #define WPA_BSS_RSNIE_CHANGED_FLAG      BIT(5)
      28             : #define WPA_BSS_WPS_CHANGED_FLAG        BIT(6)
      29             : #define WPA_BSS_RATES_CHANGED_FLAG      BIT(7)
      30             : #define WPA_BSS_IES_CHANGED_FLAG        BIT(8)
      31             : 
      32             : 
      33        3315 : static void wpa_bss_set_hessid(struct wpa_bss *bss)
      34             : {
      35             : #ifdef CONFIG_INTERWORKING
      36        3315 :         const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
      37        3315 :         if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
      38        3246 :                 os_memset(bss->hessid, 0, ETH_ALEN);
      39        6561 :                 return;
      40             :         }
      41          69 :         if (ie[1] == 7)
      42           1 :                 os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
      43             :         else
      44          68 :                 os_memcpy(bss->hessid, ie + 5, ETH_ALEN);
      45             : #endif /* CONFIG_INTERWORKING */
      46             : }
      47             : 
      48             : 
      49             : /**
      50             :  * wpa_bss_anqp_alloc - Allocate ANQP data structure for a BSS entry
      51             :  * Returns: Allocated ANQP data structure or %NULL on failure
      52             :  *
      53             :  * The allocated ANQP data structure has its users count set to 1. It may be
      54             :  * shared by multiple BSS entries and each shared entry is freed with
      55             :  * wpa_bss_anqp_free().
      56             :  */
      57         116 : struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
      58             : {
      59             :         struct wpa_bss_anqp *anqp;
      60         116 :         anqp = os_zalloc(sizeof(*anqp));
      61         116 :         if (anqp == NULL)
      62           0 :                 return NULL;
      63         116 :         anqp->users = 1;
      64         116 :         return anqp;
      65             : }
      66             : 
      67             : 
      68             : /**
      69             :  * wpa_bss_anqp_clone - Clone an ANQP data structure
      70             :  * @anqp: ANQP data structure from wpa_bss_anqp_alloc()
      71             :  * Returns: Cloned ANQP data structure or %NULL on failure
      72             :  */
      73           1 : static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
      74             : {
      75             :         struct wpa_bss_anqp *n;
      76             : 
      77           1 :         n = os_zalloc(sizeof(*n));
      78           1 :         if (n == NULL)
      79           0 :                 return NULL;
      80             : 
      81             : #define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
      82             : #ifdef CONFIG_INTERWORKING
      83           1 :         ANQP_DUP(capability_list);
      84           1 :         ANQP_DUP(venue_name);
      85           1 :         ANQP_DUP(network_auth_type);
      86           1 :         ANQP_DUP(roaming_consortium);
      87           1 :         ANQP_DUP(ip_addr_type_availability);
      88           1 :         ANQP_DUP(nai_realm);
      89           1 :         ANQP_DUP(anqp_3gpp);
      90           1 :         ANQP_DUP(domain_name);
      91             : #endif /* CONFIG_INTERWORKING */
      92             : #ifdef CONFIG_HS20
      93           1 :         ANQP_DUP(hs20_capability_list);
      94           1 :         ANQP_DUP(hs20_operator_friendly_name);
      95           1 :         ANQP_DUP(hs20_wan_metrics);
      96           1 :         ANQP_DUP(hs20_connection_capability);
      97           1 :         ANQP_DUP(hs20_operating_class);
      98           1 :         ANQP_DUP(hs20_osu_providers_list);
      99             : #endif /* CONFIG_HS20 */
     100             : #undef ANQP_DUP
     101             : 
     102           1 :         return n;
     103             : }
     104             : 
     105             : 
     106             : /**
     107             :  * wpa_bss_anqp_unshare_alloc - Unshare ANQP data (if shared) in a BSS entry
     108             :  * @bss: BSS entry
     109             :  * Returns: 0 on success, -1 on failure
     110             :  *
     111             :  * This function ensures the specific BSS entry has an ANQP data structure that
     112             :  * is not shared with any other BSS entry.
     113             :  */
     114          31 : int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
     115             : {
     116             :         struct wpa_bss_anqp *anqp;
     117             : 
     118          31 :         if (bss->anqp && bss->anqp->users > 1) {
     119             :                 /* allocated, but shared - clone an unshared copy */
     120           1 :                 anqp = wpa_bss_anqp_clone(bss->anqp);
     121           1 :                 if (anqp == NULL)
     122           0 :                         return -1;
     123           1 :                 anqp->users = 1;
     124           1 :                 bss->anqp->users--;
     125           1 :                 bss->anqp = anqp;
     126           1 :                 return 0;
     127             :         }
     128             : 
     129          30 :         if (bss->anqp)
     130          16 :                 return 0; /* already allocated and not shared */
     131             : 
     132             :         /* not allocated - allocate a new storage area */
     133          14 :         bss->anqp = wpa_bss_anqp_alloc();
     134          14 :         return bss->anqp ? 0 : -1;
     135             : }
     136             : 
     137             : 
     138             : /**
     139             :  * wpa_bss_anqp_free - Free an ANQP data structure
     140             :  * @anqp: ANQP data structure from wpa_bss_anqp_alloc() or wpa_bss_anqp_clone()
     141             :  */
     142        3202 : static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
     143             : {
     144        3202 :         if (anqp == NULL)
     145        3085 :                 return;
     146             : 
     147         117 :         anqp->users--;
     148         117 :         if (anqp->users > 0) {
     149             :                 /* Another BSS entry holds a pointer to this ANQP info */
     150           0 :                 return;
     151             :         }
     152             : 
     153             : #ifdef CONFIG_INTERWORKING
     154         117 :         wpabuf_free(anqp->capability_list);
     155         117 :         wpabuf_free(anqp->venue_name);
     156         117 :         wpabuf_free(anqp->network_auth_type);
     157         117 :         wpabuf_free(anqp->roaming_consortium);
     158         117 :         wpabuf_free(anqp->ip_addr_type_availability);
     159         117 :         wpabuf_free(anqp->nai_realm);
     160         117 :         wpabuf_free(anqp->anqp_3gpp);
     161         117 :         wpabuf_free(anqp->domain_name);
     162             : #endif /* CONFIG_INTERWORKING */
     163             : #ifdef CONFIG_HS20
     164         117 :         wpabuf_free(anqp->hs20_capability_list);
     165         117 :         wpabuf_free(anqp->hs20_operator_friendly_name);
     166         117 :         wpabuf_free(anqp->hs20_wan_metrics);
     167         117 :         wpabuf_free(anqp->hs20_connection_capability);
     168         117 :         wpabuf_free(anqp->hs20_operating_class);
     169         117 :         wpabuf_free(anqp->hs20_osu_providers_list);
     170             : #endif /* CONFIG_HS20 */
     171             : 
     172         117 :         os_free(anqp);
     173             : }
     174             : 
     175             : 
     176        3455 : static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s,
     177             :                                            struct wpa_bss *old_bss,
     178             :                                            struct wpa_bss *new_bss)
     179             : {
     180             :         struct wpa_radio_work *work;
     181             :         struct wpa_connect_work *cwork;
     182             : 
     183        3455 :         work = radio_work_pending(wpa_s, "sme-connect");
     184        3455 :         if (!work)
     185        3452 :                 work = radio_work_pending(wpa_s, "connect");
     186        3455 :         if (!work)
     187        3446 :                 return;
     188             : 
     189           9 :         cwork = work->ctx;
     190           9 :         if (cwork->bss != old_bss)
     191           4 :                 return;
     192             : 
     193           5 :         wpa_printf(MSG_DEBUG,
     194             :                    "Update BSS pointer for the pending connect radio work");
     195           5 :         cwork->bss = new_bss;
     196           5 :         if (!new_bss)
     197           3 :                 cwork->bss_removed = 1;
     198             : }
     199             : 
     200             : 
     201        3202 : static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
     202             :                            const char *reason)
     203             : {
     204        3202 :         if (wpa_s->last_scan_res) {
     205             :                 unsigned int i;
     206        3309 :                 for (i = 0; i < wpa_s->last_scan_res_used; i++) {
     207        3196 :                         if (wpa_s->last_scan_res[i] == bss) {
     208        3089 :                                 os_memmove(&wpa_s->last_scan_res[i],
     209             :                                            &wpa_s->last_scan_res[i + 1],
     210             :                                            (wpa_s->last_scan_res_used - i - 1)
     211             :                                            * sizeof(struct wpa_bss *));
     212        3089 :                                 wpa_s->last_scan_res_used--;
     213        3089 :                                 break;
     214             :                         }
     215             :                 }
     216             :         }
     217        3202 :         wpa_bss_update_pending_connect(wpa_s, bss, NULL);
     218        3202 :         dl_list_del(&bss->list);
     219        3202 :         dl_list_del(&bss->list_id);
     220        3202 :         wpa_s->num_bss--;
     221        3202 :         wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
     222             :                 " SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
     223             :                 wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
     224        3202 :         wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
     225        3202 :         wpa_bss_anqp_free(bss->anqp);
     226        3202 :         os_free(bss);
     227        3202 : }
     228             : 
     229             : 
     230             : /**
     231             :  * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID
     232             :  * @wpa_s: Pointer to wpa_supplicant data
     233             :  * @bssid: BSSID
     234             :  * @ssid: SSID
     235             :  * @ssid_len: Length of @ssid
     236             :  * Returns: Pointer to the BSS entry or %NULL if not found
     237             :  */
     238        8943 : struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
     239             :                              const u8 *ssid, size_t ssid_len)
     240             : {
     241             :         struct wpa_bss *bss;
     242        8943 :         if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
     243           0 :                 return NULL;
     244       11387 :         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
     245       13966 :                 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
     246       12014 :                     bss->ssid_len == ssid_len &&
     247        5940 :                     os_memcmp(bss->ssid, ssid, ssid_len) == 0)
     248        5448 :                         return bss;
     249             :         }
     250        3495 :         return NULL;
     251             : }
     252             : 
     253             : 
     254        4809 : static void calculate_update_time(const struct os_reltime *fetch_time,
     255             :                                   unsigned int age_ms,
     256             :                                   struct os_reltime *update_time)
     257             : {
     258             :         os_time_t usec;
     259             : 
     260        4809 :         update_time->sec = fetch_time->sec;
     261        4809 :         update_time->usec = fetch_time->usec;
     262        4809 :         update_time->sec -= age_ms / 1000;
     263        4809 :         usec = (age_ms % 1000) * 1000;
     264        4809 :         if (update_time->usec < usec) {
     265         379 :                 update_time->sec--;
     266         379 :                 update_time->usec += 1000000;
     267             :         }
     268        4809 :         update_time->usec -= usec;
     269        4809 : }
     270             : 
     271             : 
     272        4791 : static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
     273             :                              struct os_reltime *fetch_time)
     274             : {
     275        4791 :         dst->flags = src->flags;
     276        4791 :         os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
     277        4791 :         dst->freq = src->freq;
     278        4791 :         dst->beacon_int = src->beacon_int;
     279        4791 :         dst->caps = src->caps;
     280        4791 :         dst->qual = src->qual;
     281        4791 :         dst->noise = src->noise;
     282        4791 :         dst->level = src->level;
     283        4791 :         dst->tsf = src->tsf;
     284        4791 :         dst->est_throughput = src->est_throughput;
     285        4791 :         dst->snr = src->snr;
     286             : 
     287        4791 :         calculate_update_time(fetch_time, src->age, &dst->last_update);
     288        4791 : }
     289             : 
     290             : 
     291           0 : static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
     292             : {
     293             :         struct wpa_ssid *ssid;
     294             : 
     295           0 :         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
     296           0 :                 if (ssid->ssid == NULL || ssid->ssid_len == 0)
     297           0 :                         continue;
     298           0 :                 if (ssid->ssid_len == bss->ssid_len &&
     299           0 :                     os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
     300           0 :                         return 1;
     301             :         }
     302             : 
     303           0 :         return 0;
     304             : }
     305             : 
     306             : 
     307        8566 : static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
     308             : {
     309        8566 :         if (bss == wpa_s->current_bss)
     310         392 :                 return 1;
     311             : 
     312        8304 :         if (wpa_s->current_bss &&
     313         217 :             (bss->ssid_len != wpa_s->current_bss->ssid_len ||
     314          87 :              os_memcmp(bss->ssid, wpa_s->current_bss->ssid,
     315             :                        bss->ssid_len) != 0))
     316          59 :                 return 0; /* SSID has changed */
     317             : 
     318       16230 :         return !is_zero_ether_addr(bss->bssid) &&
     319       16230 :                 (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
     320        8115 :                  os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0);
     321             : }
     322             : 
     323             : 
     324           0 : static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
     325             : {
     326             :         struct wpa_bss *bss;
     327             : 
     328           0 :         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
     329           0 :                 if (!wpa_bss_known(wpa_s, bss)) {
     330           0 :                         wpa_bss_remove(wpa_s, bss, __func__);
     331           0 :                         return 0;
     332             :                 }
     333             :         }
     334             : 
     335           0 :         return -1;
     336             : }
     337             : 
     338             : 
     339           0 : static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
     340             : {
     341             :         struct wpa_bss *bss;
     342             : 
     343             :         /*
     344             :          * Remove the oldest entry that does not match with any configured
     345             :          * network.
     346             :          */
     347           0 :         if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
     348           0 :                 return 0;
     349             : 
     350             :         /*
     351             :          * Remove the oldest entry that isn't currently in use.
     352             :          */
     353           0 :         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
     354           0 :                 if (!wpa_bss_in_use(wpa_s, bss)) {
     355           0 :                         wpa_bss_remove(wpa_s, bss, __func__);
     356           0 :                         return 0;
     357             :                 }
     358             :         }
     359             : 
     360           0 :         return -1;
     361             : }
     362             : 
     363             : 
     364        3202 : static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
     365             :                                     const u8 *ssid, size_t ssid_len,
     366             :                                     struct wpa_scan_res *res,
     367             :                                     struct os_reltime *fetch_time)
     368             : {
     369             :         struct wpa_bss *bss;
     370             : 
     371        3202 :         bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
     372        3202 :         if (bss == NULL)
     373           0 :                 return NULL;
     374        3202 :         bss->id = wpa_s->bss_next_id++;
     375        3202 :         bss->last_update_idx = wpa_s->bss_update_idx;
     376        3202 :         wpa_bss_copy_res(bss, res, fetch_time);
     377        3202 :         os_memcpy(bss->ssid, ssid, ssid_len);
     378        3202 :         bss->ssid_len = ssid_len;
     379        3202 :         bss->ie_len = res->ie_len;
     380        3202 :         bss->beacon_ie_len = res->beacon_ie_len;
     381        3202 :         os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
     382        3202 :         wpa_bss_set_hessid(bss);
     383             : 
     384        3202 :         if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count &&
     385           0 :             wpa_bss_remove_oldest(wpa_s) != 0) {
     386           0 :                 wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
     387             :                            "because all BSSes are in use. We should normally "
     388           0 :                            "not get here!", (int) wpa_s->num_bss + 1);
     389           0 :                 wpa_s->conf->bss_max_count = wpa_s->num_bss + 1;
     390             :         }
     391             : 
     392        3202 :         dl_list_add_tail(&wpa_s->bss, &bss->list);
     393        3202 :         dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
     394        3202 :         wpa_s->num_bss++;
     395        3202 :         wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
     396             :                 " SSID '%s' freq %d",
     397             :                 bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len),
     398             :                 bss->freq);
     399        3202 :         wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
     400        3202 :         return bss;
     401             : }
     402             : 
     403             : 
     404         565 : static int are_ies_equal(const struct wpa_bss *old,
     405             :                          const struct wpa_scan_res *new_res, u32 ie)
     406             : {
     407             :         const u8 *old_ie, *new_ie;
     408         565 :         struct wpabuf *old_ie_buff = NULL;
     409         565 :         struct wpabuf *new_ie_buff = NULL;
     410             :         int new_ie_len, old_ie_len, ret, is_multi;
     411             : 
     412         565 :         switch (ie) {
     413             :         case WPA_IE_VENDOR_TYPE:
     414         113 :                 old_ie = wpa_bss_get_vendor_ie(old, ie);
     415         113 :                 new_ie = wpa_scan_get_vendor_ie(new_res, ie);
     416         113 :                 is_multi = 0;
     417         113 :                 break;
     418             :         case WPS_IE_VENDOR_TYPE:
     419         113 :                 old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
     420         113 :                 new_ie_buff = wpa_scan_get_vendor_ie_multi(new_res, ie);
     421         113 :                 is_multi = 1;
     422         113 :                 break;
     423             :         case WLAN_EID_RSN:
     424             :         case WLAN_EID_SUPP_RATES:
     425             :         case WLAN_EID_EXT_SUPP_RATES:
     426         339 :                 old_ie = wpa_bss_get_ie(old, ie);
     427         339 :                 new_ie = wpa_scan_get_ie(new_res, ie);
     428         339 :                 is_multi = 0;
     429         339 :                 break;
     430             :         default:
     431           0 :                 wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
     432           0 :                 return 0;
     433             :         }
     434             : 
     435         565 :         if (is_multi) {
     436             :                 /* in case of multiple IEs stored in buffer */
     437         113 :                 old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
     438         113 :                 new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
     439         113 :                 old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
     440         113 :                 new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
     441             :         } else {
     442             :                 /* in case of single IE */
     443         452 :                 old_ie_len = old_ie ? old_ie[1] + 2 : 0;
     444         452 :                 new_ie_len = new_ie ? new_ie[1] + 2 : 0;
     445             :         }
     446             : 
     447         565 :         if (!old_ie || !new_ie)
     448         221 :                 ret = !old_ie && !new_ie;
     449             :         else
     450         613 :                 ret = (old_ie_len == new_ie_len &&
     451         269 :                        os_memcmp(old_ie, new_ie, old_ie_len) == 0);
     452             : 
     453         565 :         wpabuf_free(old_ie_buff);
     454         565 :         wpabuf_free(new_ie_buff);
     455             : 
     456         565 :         return ret;
     457             : }
     458             : 
     459             : 
     460        1589 : static u32 wpa_bss_compare_res(const struct wpa_bss *old,
     461             :                                const struct wpa_scan_res *new_res)
     462             : {
     463        1589 :         u32 changes = 0;
     464        1589 :         int caps_diff = old->caps ^ new_res->caps;
     465             : 
     466        1589 :         if (old->freq != new_res->freq)
     467           7 :                 changes |= WPA_BSS_FREQ_CHANGED_FLAG;
     468             : 
     469        1589 :         if (old->level != new_res->level)
     470           0 :                 changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
     471             : 
     472        1589 :         if (caps_diff & IEEE80211_CAP_PRIVACY)
     473           9 :                 changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
     474             : 
     475        1589 :         if (caps_diff & IEEE80211_CAP_IBSS)
     476           0 :                 changes |= WPA_BSS_MODE_CHANGED_FLAG;
     477             : 
     478        3096 :         if (old->ie_len == new_res->ie_len &&
     479        1507 :             os_memcmp(old + 1, new_res + 1, old->ie_len) == 0)
     480        1476 :                 return changes;
     481         113 :         changes |= WPA_BSS_IES_CHANGED_FLAG;
     482             : 
     483         113 :         if (!are_ies_equal(old, new_res, WPA_IE_VENDOR_TYPE))
     484           7 :                 changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
     485             : 
     486         113 :         if (!are_ies_equal(old, new_res, WLAN_EID_RSN))
     487           8 :                 changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
     488             : 
     489         113 :         if (!are_ies_equal(old, new_res, WPS_IE_VENDOR_TYPE))
     490          81 :                 changes |= WPA_BSS_WPS_CHANGED_FLAG;
     491             : 
     492         226 :         if (!are_ies_equal(old, new_res, WLAN_EID_SUPP_RATES) ||
     493         113 :             !are_ies_equal(old, new_res, WLAN_EID_EXT_SUPP_RATES))
     494           0 :                 changes |= WPA_BSS_RATES_CHANGED_FLAG;
     495             : 
     496         113 :         return changes;
     497             : }
     498             : 
     499             : 
     500        1589 : static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
     501             :                                const struct wpa_bss *bss)
     502             : {
     503        1589 :         if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
     504           7 :                 wpas_notify_bss_freq_changed(wpa_s, bss->id);
     505             : 
     506        1589 :         if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
     507           0 :                 wpas_notify_bss_signal_changed(wpa_s, bss->id);
     508             : 
     509        1589 :         if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
     510           9 :                 wpas_notify_bss_privacy_changed(wpa_s, bss->id);
     511             : 
     512        1589 :         if (changes & WPA_BSS_MODE_CHANGED_FLAG)
     513           0 :                 wpas_notify_bss_mode_changed(wpa_s, bss->id);
     514             : 
     515        1589 :         if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
     516           7 :                 wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
     517             : 
     518        1589 :         if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
     519           8 :                 wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
     520             : 
     521        1589 :         if (changes & WPA_BSS_WPS_CHANGED_FLAG)
     522          81 :                 wpas_notify_bss_wps_changed(wpa_s, bss->id);
     523             : 
     524        1589 :         if (changes & WPA_BSS_IES_CHANGED_FLAG)
     525         113 :                 wpas_notify_bss_ies_changed(wpa_s, bss->id);
     526             : 
     527        1589 :         if (changes & WPA_BSS_RATES_CHANGED_FLAG)
     528           0 :                 wpas_notify_bss_rates_changed(wpa_s, bss->id);
     529             : 
     530        1589 :         wpas_notify_bss_seen(wpa_s, bss->id);
     531        1589 : }
     532             : 
     533             : 
     534             : static struct wpa_bss *
     535        1589 : wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
     536             :                struct wpa_scan_res *res, struct os_reltime *fetch_time)
     537             : {
     538             :         u32 changes;
     539             : 
     540        1589 :         changes = wpa_bss_compare_res(bss, res);
     541        1589 :         if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
     542          49 :                 wpa_printf(MSG_DEBUG, "BSS: " MACSTR " changed freq %d --> %d",
     543          42 :                            MAC2STR(bss->bssid), bss->freq, res->freq);
     544        1589 :         bss->scan_miss_count = 0;
     545        1589 :         bss->last_update_idx = wpa_s->bss_update_idx;
     546        1589 :         wpa_bss_copy_res(bss, res, fetch_time);
     547             :         /* Move the entry to the end of the list */
     548        1589 :         dl_list_del(&bss->list);
     549             : #ifdef CONFIG_P2P
     550        1932 :         if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
     551         343 :             !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE)) {
     552             :                 /*
     553             :                  * This can happen when non-P2P station interface runs a scan
     554             :                  * without P2P IE in the Probe Request frame. P2P GO would reply
     555             :                  * to that with a Probe Response that does not include P2P IE.
     556             :                  * Do not update the IEs in this BSS entry to avoid such loss of
     557             :                  * information that may be needed for P2P operations to
     558             :                  * determine group information.
     559             :                  */
     560          15 :                 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Do not update scan IEs for "
     561             :                         MACSTR " since that would remove P2P IE information",
     562             :                         MAC2STR(bss->bssid));
     563             :         } else
     564             : #endif /* CONFIG_P2P */
     565        3148 :         if (bss->ie_len + bss->beacon_ie_len >=
     566        1574 :             res->ie_len + res->beacon_ie_len) {
     567        1321 :                 os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
     568        1321 :                 bss->ie_len = res->ie_len;
     569        1321 :                 bss->beacon_ie_len = res->beacon_ie_len;
     570             :         } else {
     571             :                 struct wpa_bss *nbss;
     572         253 :                 struct dl_list *prev = bss->list_id.prev;
     573         253 :                 dl_list_del(&bss->list_id);
     574         506 :                 nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
     575         253 :                                   res->beacon_ie_len);
     576         253 :                 if (nbss) {
     577             :                         unsigned int i;
     578         310 :                         for (i = 0; i < wpa_s->last_scan_res_used; i++) {
     579          57 :                                 if (wpa_s->last_scan_res[i] == bss) {
     580           0 :                                         wpa_s->last_scan_res[i] = nbss;
     581           0 :                                         break;
     582             :                                 }
     583             :                         }
     584         253 :                         if (wpa_s->current_bss == bss)
     585          53 :                                 wpa_s->current_bss = nbss;
     586         253 :                         wpa_bss_update_pending_connect(wpa_s, bss, nbss);
     587         253 :                         bss = nbss;
     588         253 :                         os_memcpy(bss + 1, res + 1,
     589             :                                   res->ie_len + res->beacon_ie_len);
     590         253 :                         bss->ie_len = res->ie_len;
     591         253 :                         bss->beacon_ie_len = res->beacon_ie_len;
     592             :                 }
     593         253 :                 dl_list_add(prev, &bss->list_id);
     594             :         }
     595        1589 :         if (changes & WPA_BSS_IES_CHANGED_FLAG)
     596         113 :                 wpa_bss_set_hessid(bss);
     597        1589 :         dl_list_add_tail(&wpa_s->bss, &bss->list);
     598             : 
     599        1589 :         notify_bss_changes(wpa_s, changes, bss);
     600             : 
     601        1589 :         return bss;
     602             : }
     603             : 
     604             : 
     605             : /**
     606             :  * wpa_bss_update_start - Start a BSS table update from scan results
     607             :  * @wpa_s: Pointer to wpa_supplicant data
     608             :  *
     609             :  * This function is called at the start of each BSS table update round for new
     610             :  * scan results. The actual scan result entries are indicated with calls to
     611             :  * wpa_bss_update_scan_res() and the update round is finished with a call to
     612             :  * wpa_bss_update_end().
     613             :  */
     614        4746 : void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
     615             : {
     616        4746 :         wpa_s->bss_update_idx++;
     617        4746 :         wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
     618             :                 wpa_s->bss_update_idx);
     619        4746 :         wpa_s->last_scan_res_used = 0;
     620        4746 : }
     621             : 
     622             : 
     623             : /**
     624             :  * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
     625             :  * @wpa_s: Pointer to wpa_supplicant data
     626             :  * @res: Scan result
     627             :  * @fetch_time: Time when the result was fetched from the driver
     628             :  *
     629             :  * This function updates a BSS table entry (or adds one) based on a scan result.
     630             :  * This is called separately for each scan result between the calls to
     631             :  * wpa_bss_update_start() and wpa_bss_update_end().
     632             :  */
     633        5913 : void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
     634             :                              struct wpa_scan_res *res,
     635             :                              struct os_reltime *fetch_time)
     636             : {
     637             :         const u8 *ssid, *p2p, *mesh;
     638             :         struct wpa_bss *bss;
     639             : 
     640        5913 :         if (wpa_s->conf->ignore_old_scan_res) {
     641             :                 struct os_reltime update;
     642          18 :                 calculate_update_time(fetch_time, res->age, &update);
     643          18 :                 if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) {
     644             :                         struct os_reltime age;
     645           3 :                         os_reltime_sub(&wpa_s->scan_trigger_time, &update,
     646             :                                        &age);
     647           3 :                         wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS "
     648             :                                 "table entry that is %u.%06u seconds older "
     649             :                                 "than our scan trigger",
     650             :                                 (unsigned int) age.sec,
     651             :                                 (unsigned int) age.usec);
     652           3 :                         return;
     653             :                 }
     654             :         }
     655             : 
     656        5910 :         ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
     657        5910 :         if (ssid == NULL) {
     658           0 :                 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
     659             :                         MACSTR, MAC2STR(res->bssid));
     660           0 :                 return;
     661             :         }
     662        5910 :         if (ssid[1] > SSID_MAX_LEN) {
     663           0 :                 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
     664             :                         MACSTR, MAC2STR(res->bssid));
     665           0 :                 return;
     666             :         }
     667             : 
     668        5910 :         p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
     669             : #ifdef CONFIG_P2P
     670        9998 :         if (p2p == NULL &&
     671        4088 :             wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
     672             :                 /*
     673             :                  * If it's a P2P specific interface, then don't update
     674             :                  * the scan result without a P2P IE.
     675             :                  */
     676         132 :                 wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
     677         132 :                            " update for P2P interface", MAC2STR(res->bssid));
     678          22 :                 return;
     679             :         }
     680             : #endif /* CONFIG_P2P */
     681        6985 :         if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
     682        1097 :             os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
     683        1097 :                 return; /* Skip P2P listen discovery results here */
     684             : 
     685             :         /* TODO: add option for ignoring BSSes we are not interested in
     686             :          * (to save memory) */
     687             : 
     688        4791 :         mesh = wpa_scan_get_ie(res, WLAN_EID_MESH_ID);
     689        4791 :         if (mesh && mesh[1] <= SSID_MAX_LEN)
     690           1 :                 ssid = mesh;
     691             : 
     692        4791 :         bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
     693        4791 :         if (bss == NULL)
     694        3202 :                 bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
     695             :         else {
     696        1589 :                 bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
     697        1589 :                 if (wpa_s->last_scan_res) {
     698             :                         unsigned int i;
     699        1940 :                         for (i = 0; i < wpa_s->last_scan_res_used; i++) {
     700         351 :                                 if (bss == wpa_s->last_scan_res[i]) {
     701             :                                         /* Already in the list */
     702           0 :                                         return;
     703             :                                 }
     704             :                         }
     705             :                 }
     706             :         }
     707             : 
     708        4791 :         if (bss == NULL)
     709           0 :                 return;
     710        4791 :         if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
     711             :                 struct wpa_bss **n;
     712             :                 unsigned int siz;
     713         371 :                 if (wpa_s->last_scan_res_size == 0)
     714         371 :                         siz = 32;
     715             :                 else
     716           0 :                         siz = wpa_s->last_scan_res_size * 2;
     717         371 :                 n = os_realloc_array(wpa_s->last_scan_res, siz,
     718             :                                      sizeof(struct wpa_bss *));
     719         371 :                 if (n == NULL)
     720           0 :                         return;
     721         371 :                 wpa_s->last_scan_res = n;
     722         371 :                 wpa_s->last_scan_res_size = siz;
     723             :         }
     724             : 
     725        4791 :         if (wpa_s->last_scan_res)
     726        4791 :                 wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
     727             : }
     728             : 
     729             : 
     730        4770 : static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
     731             :                                     const struct scan_info *info)
     732             : {
     733             :         int found;
     734             :         size_t i;
     735             : 
     736        4770 :         if (info == NULL)
     737          26 :                 return 1;
     738             : 
     739        4744 :         if (info->num_freqs) {
     740        4744 :                 found = 0;
     741        5809 :                 for (i = 0; i < info->num_freqs; i++) {
     742        5586 :                         if (bss->freq == info->freqs[i]) {
     743        4521 :                                 found = 1;
     744        4521 :                                 break;
     745             :                         }
     746             :                 }
     747        4744 :                 if (!found)
     748         223 :                         return 0;
     749             :         }
     750             : 
     751        4521 :         if (info->num_ssids) {
     752        4474 :                 found = 0;
     753        5270 :                 for (i = 0; i < info->num_ssids; i++) {
     754        4480 :                         const struct wpa_driver_scan_ssid *s = &info->ssids[i];
     755        5548 :                         if ((s->ssid == NULL || s->ssid_len == 0) ||
     756        1428 :                             (s->ssid_len == bss->ssid_len &&
     757         360 :                              os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
     758             :                              0)) {
     759        3684 :                                 found = 1;
     760        3684 :                                 break;
     761             :                         }
     762             :                 }
     763        4474 :                 if (!found)
     764         790 :                         return 0;
     765             :         }
     766             : 
     767        3731 :         return 1;
     768             : }
     769             : 
     770             : 
     771             : /**
     772             :  * wpa_bss_update_end - End a BSS table update from scan results
     773             :  * @wpa_s: Pointer to wpa_supplicant data
     774             :  * @info: Information about scan parameters
     775             :  * @new_scan: Whether this update round was based on a new scan
     776             :  *
     777             :  * This function is called at the end of each BSS table update round for new
     778             :  * scan results. The start of the update was indicated with a call to
     779             :  * wpa_bss_update_start().
     780             :  */
     781        4746 : void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
     782             :                         int new_scan)
     783             : {
     784             :         struct wpa_bss *bss, *n;
     785             : 
     786        4746 :         os_get_reltime(&wpa_s->last_scan);
     787        4746 :         if (!new_scan)
     788        4776 :                 return; /* do not expire entries without new scan */
     789             : 
     790        9664 :         dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
     791        4948 :                 if (wpa_bss_in_use(wpa_s, bss))
     792         178 :                         continue;
     793        4770 :                 if (!wpa_bss_included_in_scan(bss, info))
     794        1013 :                         continue; /* expire only BSSes that were scanned */
     795        3757 :                 if (bss->last_update_idx < wpa_s->bss_update_idx)
     796          25 :                         bss->scan_miss_count++;
     797        7514 :                 if (bss->scan_miss_count >=
     798        3757 :                     wpa_s->conf->bss_expiration_scan_count) {
     799           7 :                         wpa_bss_remove(wpa_s, bss, "no match in scan");
     800             :                 }
     801             :         }
     802             : 
     803        4716 :         wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u",
     804             :                    wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
     805             : }
     806             : 
     807             : 
     808             : /**
     809             :  * wpa_bss_flush_by_age - Flush old BSS entries
     810             :  * @wpa_s: Pointer to wpa_supplicant data
     811             :  * @age: Maximum entry age in seconds
     812             :  *
     813             :  * Remove BSS entries that have not been updated during the last @age seconds.
     814             :  */
     815        1919 : void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
     816             : {
     817             :         struct wpa_bss *bss, *n;
     818             :         struct os_reltime t;
     819             : 
     820        1919 :         if (dl_list_empty(&wpa_s->bss))
     821        3430 :                 return;
     822             : 
     823         408 :         os_get_reltime(&t);
     824         408 :         t.sec -= age;
     825             : 
     826         616 :         dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
     827         417 :                 if (wpa_bss_in_use(wpa_s, bss))
     828         207 :                         continue;
     829             : 
     830         210 :                 if (os_reltime_before(&bss->last_update, &t)) {
     831           1 :                         wpa_bss_remove(wpa_s, bss, __func__);
     832             :                 } else
     833         209 :                         break;
     834             :         }
     835             : }
     836             : 
     837             : 
     838             : /**
     839             :  * wpa_bss_init - Initialize BSS table
     840             :  * @wpa_s: Pointer to wpa_supplicant data
     841             :  * Returns: 0 on success, -1 on failure
     842             :  *
     843             :  * This prepares BSS table lists and timer for periodic updates. The BSS table
     844             :  * is deinitialized with wpa_bss_deinit() once not needed anymore.
     845             :  */
     846         575 : int wpa_bss_init(struct wpa_supplicant *wpa_s)
     847             : {
     848         575 :         dl_list_init(&wpa_s->bss);
     849         575 :         dl_list_init(&wpa_s->bss_id);
     850         575 :         return 0;
     851             : }
     852             : 
     853             : 
     854             : /**
     855             :  * wpa_bss_flush - Flush all unused BSS entries
     856             :  * @wpa_s: Pointer to wpa_supplicant data
     857             :  */
     858        6467 : void wpa_bss_flush(struct wpa_supplicant *wpa_s)
     859             : {
     860             :         struct wpa_bss *bss, *n;
     861             : 
     862        6467 :         wpa_s->clear_driver_scan_cache = 1;
     863             : 
     864        6467 :         if (wpa_s->bss.next == NULL)
     865        6504 :                 return; /* BSS table not yet initialized */
     866             : 
     867        9631 :         dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
     868        3201 :                 if (wpa_bss_in_use(wpa_s, bss))
     869           7 :                         continue;
     870        3194 :                 wpa_bss_remove(wpa_s, bss, __func__);
     871             :         }
     872             : }
     873             : 
     874             : 
     875             : /**
     876             :  * wpa_bss_deinit - Deinitialize BSS table
     877             :  * @wpa_s: Pointer to wpa_supplicant data
     878             :  */
     879         612 : void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
     880             : {
     881         612 :         wpa_bss_flush(wpa_s);
     882         612 : }
     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        3424 : struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
     892             :                                    const u8 *bssid)
     893             : {
     894             :         struct wpa_bss *bss;
     895        3424 :         if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
     896           1 :                 return NULL;
     897        3995 :         dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
     898        3338 :                 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
     899        2766 :                         return bss;
     900             :         }
     901         657 :         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         633 : struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
     917             :                                           const u8 *bssid)
     918             : {
     919         633 :         struct wpa_bss *bss, *found = NULL;
     920         633 :         if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
     921           0 :                 return NULL;
     922        1355 :         dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
     923         722 :                 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
     924          93 :                         continue;
     925         731 :                 if (found == NULL ||
     926         102 :                     os_reltime_before(&found->last_update, &bss->last_update))
     927         532 :                         found = bss;
     928             :         }
     929         633 :         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          33 : 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          37 :         dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
     945             :                 u8 addr[ETH_ALEN];
     946          33 :                 if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
     947          31 :                                        addr) == 0 &&
     948          31 :                     os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
     949          29 :                         return bss;
     950             :         }
     951           4 :         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       18749 : struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
     963             : {
     964             :         struct wpa_bss *bss;
     965       23324 :         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
     966       23322 :                 if (bss->id == id)
     967       18747 :                         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          12 :         dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
     989          11 :                 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       41993 : const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
    1006             : {
    1007             :         const u8 *end, *pos;
    1008             : 
    1009       41993 :         pos = (const u8 *) (bss + 1);
    1010       41993 :         end = pos + bss->ie_len;
    1011             : 
    1012      343900 :         while (pos + 1 < end) {
    1013      287267 :                 if (pos + 2 + pos[1] > end)
    1014           0 :                         break;
    1015      287267 :                 if (pos[0] == ie)
    1016       27353 :                         return pos;
    1017      259914 :                 pos += 2 + pos[1];
    1018             :         }
    1019             : 
    1020       14640 :         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       42730 : const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
    1034             : {
    1035             :         const u8 *end, *pos;
    1036             : 
    1037       42730 :         pos = (const u8 *) (bss + 1);
    1038       42730 :         end = pos + bss->ie_len;
    1039             : 
    1040      521047 :         while (pos + 1 < end) {
    1041      439517 :                 if (pos + 2 + pos[1] > end)
    1042           0 :                         break;
    1043      505046 :                 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
    1044       65529 :                     vendor_type == WPA_GET_BE32(&pos[2]))
    1045        3930 :                         return pos;
    1046      435587 :                 pos += 2 + pos[1];
    1047             :         }
    1048             : 
    1049       38800 :         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        6008 : 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        6008 :         if (bss->beacon_ie_len == 0)
    1071        1402 :                 return NULL;
    1072             : 
    1073        4606 :         pos = (const u8 *) (bss + 1);
    1074        4606 :         pos += bss->ie_len;
    1075        4606 :         end = pos + bss->beacon_ie_len;
    1076             : 
    1077       61393 :         while (pos + 1 < end) {
    1078       52187 :                 if (pos + 2 + pos[1] > end)
    1079           0 :                         break;
    1080       58956 :                 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
    1081        6769 :                     vendor_type == WPA_GET_BE32(&pos[2]))
    1082           6 :                         return pos;
    1083       52181 :                 pos += 2 + pos[1];
    1084             :         }
    1085             : 
    1086        4600 :         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       14230 : 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       14230 :         buf = wpabuf_alloc(bss->ie_len);
    1107       14230 :         if (buf == NULL)
    1108           1 :                 return NULL;
    1109             : 
    1110       14229 :         pos = (const u8 *) (bss + 1);
    1111       14229 :         end = pos + bss->ie_len;
    1112             : 
    1113      177473 :         while (pos + 1 < end) {
    1114      149015 :                 if (pos + 2 + pos[1] > end)
    1115           0 :                         break;
    1116      174527 :                 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
    1117       25512 :                     vendor_type == WPA_GET_BE32(&pos[2]))
    1118        7254 :                         wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
    1119      149015 :                 pos += 2 + pos[1];
    1120             :         }
    1121             : 
    1122       14229 :         if (wpabuf_len(buf) == 0) {
    1123        6991 :                 wpabuf_free(buf);
    1124        6991 :                 buf = NULL;
    1125             :         }
    1126             : 
    1127       14229 :         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        1392 : 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        1392 :         ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
    1220        1392 :         ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
    1221             : 
    1222        1392 :         len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
    1223             : 
    1224        1392 :         r = os_malloc(len);
    1225        1392 :         if (!r)
    1226           0 :                 return -1;
    1227             : 
    1228       12518 :         for (i = 0; ie && i < ie[1]; i++)
    1229       11126 :                 r[i] = ie[i + 2] & 0x7f;
    1230             : 
    1231        6386 :         for (j = 0; ie2 && j < ie2[1]; j++)
    1232        4994 :                 r[i + j] = ie2[j + 2] & 0x7f;
    1233             : 
    1234        1392 :         *rates = r;
    1235        1392 :         return len;
    1236             : }

Generated by: LCOV version 1.10