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 1393793999 Lines: 432 519 83.2 %
Date: 2014-03-02 Functions: 34 39 87.2 %
Branches: 264 384 68.8 %

           Branch data     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                 :        780 : static void wpa_bss_set_hessid(struct wpa_bss *bss)
      39                 :            : {
      40                 :            : #ifdef CONFIG_INTERWORKING
      41                 :        780 :         const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
      42 [ +  + ][ +  + ]:        780 :         if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
                 [ +  + ]
      43                 :        737 :                 os_memset(bss->hessid, 0, ETH_ALEN);
      44                 :        780 :                 return;
      45                 :            :         }
      46         [ +  + ]:         43 :         if (ie[1] == 7)
      47                 :          1 :                 os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
      48                 :            :         else
      49                 :         42 :                 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                 :         87 : struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
      63                 :            : {
      64                 :            :         struct wpa_bss_anqp *anqp;
      65                 :         87 :         anqp = os_zalloc(sizeof(*anqp));
      66         [ -  + ]:         87 :         if (anqp == NULL)
      67                 :          0 :                 return NULL;
      68                 :         87 :         anqp->users = 1;
      69                 :         87 :         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                 :         21 : int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
     118                 :            : {
     119                 :            :         struct wpa_bss_anqp *anqp;
     120                 :            : 
     121 [ +  + ][ +  + ]:         21 :         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         [ +  + ]:         20 :         if (bss->anqp)
     133                 :         12 :                 return 0; /* already allocated and not shared */
     134                 :            : 
     135                 :            :         /* not allocated - allocate a new storage area */
     136                 :          8 :         bss->anqp = wpa_bss_anqp_alloc();
     137         [ +  - ]:         21 :         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                 :        734 : static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
     146                 :            : {
     147         [ +  + ]:        734 :         if (anqp == NULL)
     148                 :        646 :                 return;
     149                 :            : 
     150                 :         88 :         anqp->users--;
     151         [ -  + ]:         88 :         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                 :         88 :         wpabuf_free(anqp->venue_name);
     158                 :         88 :         wpabuf_free(anqp->network_auth_type);
     159                 :         88 :         wpabuf_free(anqp->roaming_consortium);
     160                 :         88 :         wpabuf_free(anqp->ip_addr_type_availability);
     161                 :         88 :         wpabuf_free(anqp->nai_realm);
     162                 :         88 :         wpabuf_free(anqp->anqp_3gpp);
     163                 :         88 :         wpabuf_free(anqp->domain_name);
     164                 :            : #endif /* CONFIG_INTERWORKING */
     165                 :            : #ifdef CONFIG_HS20
     166                 :         88 :         wpabuf_free(anqp->hs20_operator_friendly_name);
     167                 :         88 :         wpabuf_free(anqp->hs20_wan_metrics);
     168                 :         88 :         wpabuf_free(anqp->hs20_connection_capability);
     169                 :         88 :         wpabuf_free(anqp->hs20_operating_class);
     170                 :         88 :         wpabuf_free(anqp->hs20_osu_providers_list);
     171                 :            : #endif /* CONFIG_HS20 */
     172                 :            : 
     173                 :        734 :         os_free(anqp);
     174                 :            : }
     175                 :            : 
     176                 :            : 
     177                 :        734 : static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
     178                 :            :                            const char *reason)
     179                 :            : {
     180         [ +  - ]:        734 :         if (wpa_s->last_scan_res) {
     181                 :            :                 unsigned int i;
     182         [ +  + ]:        779 :                 for (i = 0; i < wpa_s->last_scan_res_used; i++) {
     183         [ +  + ]:        737 :                         if (wpa_s->last_scan_res[i] == bss) {
     184                 :        692 :                                 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                 :        692 :                                 wpa_s->last_scan_res_used--;
     189                 :        692 :                                 break;
     190                 :            :                         }
     191                 :            :                 }
     192                 :            :         }
     193                 :        734 :         dl_list_del(&bss->list);
     194                 :        734 :         dl_list_del(&bss->list_id);
     195                 :        734 :         wpa_s->num_bss--;
     196                 :        734 :         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                 :        734 :         wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
     200                 :        734 :         wpa_bss_anqp_free(bss->anqp);
     201                 :        734 :         os_free(bss);
     202                 :        734 : }
     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                 :       1855 : 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         [ -  + ]:       1855 :         if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
     218                 :          0 :                 return NULL;
     219         [ +  + ]:       2453 :         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
     220 [ +  + ][ +  + ]:       1594 :                 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
     221         [ +  + ]:       1085 :                     bss->ssid_len == ssid_len &&
     222                 :       1085 :                     os_memcmp(bss->ssid, ssid, ssid_len) == 0)
     223                 :        996 :                         return bss;
     224                 :            :         }
     225                 :       1855 :         return NULL;
     226                 :            : }
     227                 :            : 
     228                 :            : 
     229                 :       2385 : 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                 :       2385 :         update_time->sec = fetch_time->sec;
     236                 :       2385 :         update_time->usec = fetch_time->usec;
     237                 :       2385 :         update_time->sec -= age_ms / 1000;
     238                 :       2385 :         usec = (age_ms % 1000) * 1000;
     239         [ +  + ]:       2385 :         if (update_time->usec < usec) {
     240                 :        471 :                 update_time->sec--;
     241                 :        471 :                 update_time->usec += 1000000;
     242                 :            :         }
     243                 :       2385 :         update_time->usec -= usec;
     244                 :       2385 : }
     245                 :            : 
     246                 :            : 
     247                 :       1457 : static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
     248                 :            :                              struct os_reltime *fetch_time)
     249                 :            : {
     250                 :       1457 :         dst->flags = src->flags;
     251                 :       1457 :         os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
     252                 :       1457 :         dst->freq = src->freq;
     253                 :       1457 :         dst->beacon_int = src->beacon_int;
     254                 :       1457 :         dst->caps = src->caps;
     255                 :       1457 :         dst->qual = src->qual;
     256                 :       1457 :         dst->noise = src->noise;
     257                 :       1457 :         dst->level = src->level;
     258                 :       1457 :         dst->tsf = src->tsf;
     259                 :            : 
     260                 :       1457 :         calculate_update_time(fetch_time, src->age, &dst->last_update);
     261                 :       1457 : }
     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                 :       2398 : static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
     281                 :            : {
     282 [ +  + ][ +  + ]:       4687 :         return bss == wpa_s->current_bss ||
     283         [ +  + ]:       2289 :                 os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
     284                 :       2289 :                 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                 :        734 : 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                 :        734 :         bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
     336         [ -  + ]:        734 :         if (bss == NULL)
     337                 :          0 :                 return NULL;
     338                 :        734 :         bss->id = wpa_s->bss_next_id++;
     339                 :        734 :         bss->last_update_idx = wpa_s->bss_update_idx;
     340                 :        734 :         wpa_bss_copy_res(bss, res, fetch_time);
     341                 :        734 :         os_memcpy(bss->ssid, ssid, ssid_len);
     342                 :        734 :         bss->ssid_len = ssid_len;
     343                 :        734 :         bss->ie_len = res->ie_len;
     344                 :        734 :         bss->beacon_ie_len = res->beacon_ie_len;
     345                 :        734 :         os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
     346                 :        734 :         wpa_bss_set_hessid(bss);
     347                 :            : 
     348   [ -  +  #  # ]:        734 :         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                 :        734 :         dl_list_add_tail(&wpa_s->bss, &bss->list);
     357                 :        734 :         dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
     358                 :        734 :         wpa_s->num_bss++;
     359                 :        734 :         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                 :        734 :         wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
     363                 :        734 :         return bss;
     364                 :            : }
     365                 :            : 
     366                 :            : 
     367                 :        230 : 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                 :        230 :         struct wpabuf *old_ie_buff = NULL;
     372                 :        230 :         struct wpabuf *new_ie_buff = NULL;
     373                 :            :         int new_ie_len, old_ie_len, ret, is_multi;
     374                 :            : 
     375   [ +  +  +  - ]:        230 :         switch (ie) {
     376                 :            :         case WPA_IE_VENDOR_TYPE:
     377                 :         46 :                 old_ie = wpa_bss_get_vendor_ie(old, ie);
     378                 :         46 :                 new_ie = wpa_scan_get_vendor_ie(new, ie);
     379                 :         46 :                 is_multi = 0;
     380                 :         46 :                 break;
     381                 :            :         case WPS_IE_VENDOR_TYPE:
     382                 :         46 :                 old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
     383                 :         46 :                 new_ie_buff = wpa_scan_get_vendor_ie_multi(new, ie);
     384                 :         46 :                 is_multi = 1;
     385                 :         46 :                 break;
     386                 :            :         case WLAN_EID_RSN:
     387                 :            :         case WLAN_EID_SUPP_RATES:
     388                 :            :         case WLAN_EID_EXT_SUPP_RATES:
     389                 :        138 :                 old_ie = wpa_bss_get_ie(old, ie);
     390                 :        138 :                 new_ie = wpa_scan_get_ie(new, ie);
     391                 :        138 :                 is_multi = 0;
     392                 :        138 :                 break;
     393                 :            :         default:
     394                 :          0 :                 wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
     395                 :          0 :                 return 0;
     396                 :            :         }
     397                 :            : 
     398         [ +  + ]:        230 :         if (is_multi) {
     399                 :            :                 /* in case of multiple IEs stored in buffer */
     400         [ +  + ]:         46 :                 old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
     401         [ +  + ]:         46 :                 new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
     402         [ +  + ]:         46 :                 old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
     403         [ +  + ]:         46 :                 new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
     404                 :            :         } else {
     405                 :            :                 /* in case of single IE */
     406         [ +  + ]:        184 :                 old_ie_len = old_ie ? old_ie[1] + 2 : 0;
     407         [ +  + ]:        184 :                 new_ie_len = new_ie ? new_ie[1] + 2 : 0;
     408                 :            :         }
     409                 :            : 
     410 [ +  + ][ -  + ]:        230 :         if (!old_ie || !new_ie)
     411 [ +  - ][ +  + ]:         93 :                 ret = !old_ie && !new_ie;
     412                 :            :         else
     413 [ +  + ][ +  + ]:        137 :                 ret = (old_ie_len == new_ie_len &&
     414                 :        112 :                        os_memcmp(old_ie, new_ie, old_ie_len) == 0);
     415                 :            : 
     416                 :        230 :         wpabuf_free(old_ie_buff);
     417                 :        230 :         wpabuf_free(new_ie_buff);
     418                 :            : 
     419                 :        230 :         return ret;
     420                 :            : }
     421                 :            : 
     422                 :            : 
     423                 :        723 : static u32 wpa_bss_compare_res(const struct wpa_bss *old,
     424                 :            :                                const struct wpa_scan_res *new)
     425                 :            : {
     426                 :        723 :         u32 changes = 0;
     427                 :        723 :         int caps_diff = old->caps ^ new->caps;
     428                 :            : 
     429         [ +  + ]:        723 :         if (old->freq != new->freq)
     430                 :          3 :                 changes |= WPA_BSS_FREQ_CHANGED_FLAG;
     431                 :            : 
     432         [ -  + ]:        723 :         if (old->level != new->level)
     433                 :          0 :                 changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
     434                 :            : 
     435         [ +  + ]:        723 :         if (caps_diff & IEEE80211_CAP_PRIVACY)
     436                 :          8 :                 changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
     437                 :            : 
     438         [ -  + ]:        723 :         if (caps_diff & IEEE80211_CAP_IBSS)
     439                 :          0 :                 changes |= WPA_BSS_MODE_CHANGED_FLAG;
     440                 :            : 
     441 [ +  + ][ +  + ]:        723 :         if (old->ie_len == new->ie_len &&
     442                 :        696 :             os_memcmp(old + 1, new + 1, old->ie_len) == 0)
     443                 :        677 :                 return changes;
     444                 :         46 :         changes |= WPA_BSS_IES_CHANGED_FLAG;
     445                 :            : 
     446         [ +  + ]:         46 :         if (!are_ies_equal(old, new, WPA_IE_VENDOR_TYPE))
     447                 :          8 :                 changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
     448                 :            : 
     449         [ +  + ]:         46 :         if (!are_ies_equal(old, new, WLAN_EID_RSN))
     450                 :          9 :                 changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
     451                 :            : 
     452         [ +  + ]:         46 :         if (!are_ies_equal(old, new, WPS_IE_VENDOR_TYPE))
     453                 :         28 :                 changes |= WPA_BSS_WPS_CHANGED_FLAG;
     454                 :            : 
     455   [ +  -  -  + ]:         92 :         if (!are_ies_equal(old, new, WLAN_EID_SUPP_RATES) ||
     456                 :         46 :             !are_ies_equal(old, new, WLAN_EID_EXT_SUPP_RATES))
     457                 :          0 :                 changes |= WPA_BSS_RATES_CHANGED_FLAG;
     458                 :            : 
     459                 :        723 :         return changes;
     460                 :            : }
     461                 :            : 
     462                 :            : 
     463                 :        723 : static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
     464                 :            :                                const struct wpa_bss *bss)
     465                 :            : {
     466         [ +  + ]:        723 :         if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
     467                 :          3 :                 wpas_notify_bss_freq_changed(wpa_s, bss->id);
     468                 :            : 
     469         [ -  + ]:        723 :         if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
     470                 :          0 :                 wpas_notify_bss_signal_changed(wpa_s, bss->id);
     471                 :            : 
     472         [ +  + ]:        723 :         if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
     473                 :          8 :                 wpas_notify_bss_privacy_changed(wpa_s, bss->id);
     474                 :            : 
     475         [ -  + ]:        723 :         if (changes & WPA_BSS_MODE_CHANGED_FLAG)
     476                 :          0 :                 wpas_notify_bss_mode_changed(wpa_s, bss->id);
     477                 :            : 
     478         [ +  + ]:        723 :         if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
     479                 :          8 :                 wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
     480                 :            : 
     481         [ +  + ]:        723 :         if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
     482                 :          9 :                 wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
     483                 :            : 
     484         [ +  + ]:        723 :         if (changes & WPA_BSS_WPS_CHANGED_FLAG)
     485                 :         28 :                 wpas_notify_bss_wps_changed(wpa_s, bss->id);
     486                 :            : 
     487         [ +  + ]:        723 :         if (changes & WPA_BSS_IES_CHANGED_FLAG)
     488                 :         46 :                 wpas_notify_bss_ies_changed(wpa_s, bss->id);
     489                 :            : 
     490         [ -  + ]:        723 :         if (changes & WPA_BSS_RATES_CHANGED_FLAG)
     491                 :          0 :                 wpas_notify_bss_rates_changed(wpa_s, bss->id);
     492                 :        723 : }
     493                 :            : 
     494                 :            : 
     495                 :            : static struct wpa_bss *
     496                 :        723 : 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                 :        723 :         changes = wpa_bss_compare_res(bss, res);
     502                 :        723 :         bss->scan_miss_count = 0;
     503                 :        723 :         bss->last_update_idx = wpa_s->bss_update_idx;
     504                 :        723 :         wpa_bss_copy_res(bss, res, fetch_time);
     505                 :            :         /* Move the entry to the end of the list */
     506                 :        723 :         dl_list_del(&bss->list);
     507                 :            : #ifdef CONFIG_P2P
     508   [ +  +  -  + ]:       1140 :         if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
     509                 :        417 :             !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         [ +  + ]:        723 :         if (bss->ie_len + bss->beacon_ie_len >=
     524                 :        723 :             res->ie_len + res->beacon_ie_len) {
     525                 :        679 :                 os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
     526                 :        679 :                 bss->ie_len = res->ie_len;
     527                 :        679 :                 bss->beacon_ie_len = res->beacon_ie_len;
     528                 :            :         } else {
     529                 :            :                 struct wpa_bss *nbss;
     530                 :         44 :                 struct dl_list *prev = bss->list_id.prev;
     531                 :         44 :                 dl_list_del(&bss->list_id);
     532                 :         44 :                 nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
     533                 :         44 :                                   res->beacon_ie_len);
     534         [ +  - ]:         44 :                 if (nbss) {
     535                 :            :                         unsigned int i;
     536         [ +  + ]:         53 :                         for (i = 0; i < wpa_s->last_scan_res_used; i++) {
     537         [ -  + ]:          9 :                                 if (wpa_s->last_scan_res[i] == bss) {
     538                 :          0 :                                         wpa_s->last_scan_res[i] = nbss;
     539                 :          0 :                                         break;
     540                 :            :                                 }
     541                 :            :                         }
     542         [ +  + ]:         44 :                         if (wpa_s->current_bss == bss)
     543                 :          4 :                                 wpa_s->current_bss = nbss;
     544                 :         44 :                         bss = nbss;
     545                 :         44 :                         os_memcpy(bss + 1, res + 1,
     546                 :            :                                   res->ie_len + res->beacon_ie_len);
     547                 :         44 :                         bss->ie_len = res->ie_len;
     548                 :         44 :                         bss->beacon_ie_len = res->beacon_ie_len;
     549                 :            :                 }
     550                 :         44 :                 dl_list_add(prev, &bss->list_id);
     551                 :            :         }
     552         [ +  + ]:        723 :         if (changes & WPA_BSS_IES_CHANGED_FLAG)
     553                 :         46 :                 wpa_bss_set_hessid(bss);
     554                 :        723 :         dl_list_add_tail(&wpa_s->bss, &bss->list);
     555                 :            : 
     556                 :        723 :         notify_bss_changes(wpa_s, changes, bss);
     557                 :            : 
     558                 :        723 :         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                 :       1357 : void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
     572                 :            : {
     573                 :       1357 :         wpa_s->bss_update_idx++;
     574                 :       1357 :         wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
     575                 :            :                 wpa_s->bss_update_idx);
     576                 :       1357 :         wpa_s->last_scan_res_used = 0;
     577                 :       1357 : }
     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                 :       2293 : 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         [ +  + ]:       2293 :         if (wpa_s->conf->ignore_old_scan_res) {
     598                 :            :                 struct os_reltime update;
     599                 :        928 :                 calculate_update_time(fetch_time, res->age, &update);
     600         [ +  + ]:        928 :                 if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) {
     601                 :            :                         struct os_reltime age;
     602                 :        314 :                         os_reltime_sub(&wpa_s->scan_trigger_time, &update,
     603                 :            :                                        &age);
     604                 :        314 :                         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                 :        314 :                         return;
     610                 :            :                 }
     611                 :            :         }
     612                 :            : 
     613                 :       1979 :         ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
     614         [ -  + ]:       1979 :         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         [ -  + ]:       1979 :         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                 :       1979 :         p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
     626                 :            : #ifdef CONFIG_P2P
     627 [ +  + ][ +  + ]:       1979 :         if (p2p == NULL &&
     628                 :        881 :             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                 :          5 :                 wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
     634                 :         30 :                            " update for P2P interface", MAC2STR(res->bssid));
     635                 :          5 :                 return;
     636                 :            :         }
     637                 :            : #endif /* CONFIG_P2P */
     638 [ +  + ][ +  + ]:       1974 :         if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
                 [ +  - ]
     639                 :        517 :             os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
     640                 :        517 :                 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                 :       1457 :         bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
     645         [ +  + ]:       1457 :         if (bss == NULL)
     646                 :        734 :                 bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
     647                 :            :         else {
     648                 :        723 :                 bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
     649         [ +  - ]:        723 :                 if (wpa_s->last_scan_res) {
     650                 :            :                         unsigned int i;
     651         [ +  + ]:        970 :                         for (i = 0; i < wpa_s->last_scan_res_used; i++) {
     652         [ -  + ]:        247 :                                 if (bss == wpa_s->last_scan_res[i]) {
     653                 :            :                                         /* Already in the list */
     654                 :          0 :                                         return;
     655                 :            :                                 }
     656                 :            :                         }
     657                 :            :                 }
     658                 :            :         }
     659                 :            : 
     660         [ -  + ]:       1457 :         if (bss == NULL)
     661                 :          0 :                 return;
     662         [ +  + ]:       1457 :         if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
     663                 :            :                 struct wpa_bss **n;
     664                 :            :                 unsigned int siz;
     665         [ +  - ]:         23 :                 if (wpa_s->last_scan_res_size == 0)
     666                 :         23 :                         siz = 32;
     667                 :            :                 else
     668                 :          0 :                         siz = wpa_s->last_scan_res_size * 2;
     669                 :         23 :                 n = os_realloc_array(wpa_s->last_scan_res, siz,
     670                 :            :                                      sizeof(struct wpa_bss *));
     671         [ -  + ]:         23 :                 if (n == NULL)
     672                 :          0 :                         return;
     673                 :         23 :                 wpa_s->last_scan_res = n;
     674                 :         23 :                 wpa_s->last_scan_res_size = siz;
     675                 :            :         }
     676                 :            : 
     677                 :       2293 :         wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
     678                 :            : }
     679                 :            : 
     680                 :            : 
     681                 :       1500 : static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
     682                 :            :                                     const struct scan_info *info)
     683                 :            : {
     684                 :            :         int found;
     685                 :            :         size_t i;
     686                 :            : 
     687         [ -  + ]:       1500 :         if (info == NULL)
     688                 :          0 :                 return 1;
     689                 :            : 
     690         [ +  - ]:       1500 :         if (info->num_freqs) {
     691                 :       1500 :                 found = 0;
     692         [ +  + ]:       2199 :                 for (i = 0; i < info->num_freqs; i++) {
     693         [ +  + ]:       2139 :                         if (bss->freq == info->freqs[i]) {
     694                 :       1440 :                                 found = 1;
     695                 :       1440 :                                 break;
     696                 :            :                         }
     697                 :            :                 }
     698         [ +  + ]:       1500 :                 if (!found)
     699                 :         60 :                         return 0;
     700                 :            :         }
     701                 :            : 
     702         [ +  - ]:       1440 :         if (info->num_ssids) {
     703                 :       1440 :                 found = 0;
     704         [ +  + ]:       2089 :                 for (i = 0; i < info->num_ssids; i++) {
     705                 :       1444 :                         const struct wpa_driver_scan_ssid *s = &info->ssids[i];
     706 [ +  - ][ +  + ]:       1444 :                         if ((s->ssid == NULL || s->ssid_len == 0) ||
                 [ +  + ]
     707         [ +  + ]:        140 :                             (s->ssid_len == bss->ssid_len &&
     708                 :        140 :                              os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
     709                 :            :                              0)) {
     710                 :        795 :                                 found = 1;
     711                 :        795 :                                 break;
     712                 :            :                         }
     713                 :            :                 }
     714         [ +  + ]:       1440 :                 if (!found)
     715                 :        645 :                         return 0;
     716                 :            :         }
     717                 :            : 
     718                 :       1500 :         return 1;
     719                 :            : }
     720                 :            : 
     721                 :            : 
     722                 :            : /**
     723                 :            :  * wpa_bss_update_end - End a BSS table update from scan results
     724                 :            :  * @wpa_s: Pointer to wpa_supplicant data
     725                 :            :  * @info: Information about scan parameters
     726                 :            :  * @new_scan: Whether this update round was based on a new scan
     727                 :            :  *
     728                 :            :  * This function is called at the end of each BSS table update round for new
     729                 :            :  * scan results. The start of the update was indicated with a call to
     730                 :            :  * wpa_bss_update_start().
     731                 :            :  */
     732                 :       1357 : void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
     733                 :            :                         int new_scan)
     734                 :            : {
     735                 :            :         struct wpa_bss *bss, *n;
     736                 :            : 
     737                 :       1357 :         os_get_reltime(&wpa_s->last_scan);
     738         [ -  + ]:       1357 :         if (!new_scan)
     739                 :       1357 :                 return; /* do not expire entries without new scan */
     740                 :            : 
     741         [ +  + ]:       2903 :         dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
     742         [ +  + ]:       1546 :                 if (wpa_bss_in_use(wpa_s, bss))
     743                 :         46 :                         continue;
     744         [ +  + ]:       1500 :                 if (!wpa_bss_included_in_scan(bss, info))
     745                 :        705 :                         continue; /* expire only BSSes that were scanned */
     746         [ +  + ]:        795 :                 if (bss->last_update_idx < wpa_s->bss_update_idx)
     747                 :         22 :                         bss->scan_miss_count++;
     748         [ +  + ]:        795 :                 if (bss->scan_miss_count >=
     749                 :        795 :                     wpa_s->conf->bss_expiration_scan_count) {
     750                 :          2 :                         wpa_bss_remove(wpa_s, bss, "no match in scan");
     751                 :            :                 }
     752                 :            :         }
     753                 :            : 
     754                 :       1357 :         wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u",
     755                 :            :                    wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
     756                 :            : }
     757                 :            : 
     758                 :            : 
     759                 :            : /**
     760                 :            :  * wpa_bss_flush_by_age - Flush old BSS entries
     761                 :            :  * @wpa_s: Pointer to wpa_supplicant data
     762                 :            :  * @age: Maximum entry age in seconds
     763                 :            :  *
     764                 :            :  * Remove BSS entries that have not been updated during the last @age seconds.
     765                 :            :  */
     766                 :        439 : void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
     767                 :            : {
     768                 :            :         struct wpa_bss *bss, *n;
     769                 :            :         struct os_reltime t;
     770                 :            : 
     771         [ +  + ]:        439 :         if (dl_list_empty(&wpa_s->bss))
     772                 :        439 :                 return;
     773                 :            : 
     774                 :        110 :         os_get_reltime(&t);
     775                 :        110 :         t.sec -= age;
     776                 :            : 
     777         [ +  + ]:        176 :         dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
     778         [ +  + ]:        118 :                 if (wpa_bss_in_use(wpa_s, bss))
     779                 :         66 :                         continue;
     780                 :            : 
     781         [ -  + ]:         52 :                 if (os_reltime_before(&bss->last_update, &t)) {
     782                 :          0 :                         wpa_bss_remove(wpa_s, bss, __func__);
     783                 :            :                 } else
     784                 :         52 :                         break;
     785                 :            :         }
     786                 :            : }
     787                 :            : 
     788                 :            : 
     789                 :        439 : static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
     790                 :            : {
     791                 :        439 :         struct wpa_supplicant *wpa_s = eloop_ctx;
     792                 :            : 
     793                 :        439 :         wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
     794                 :        439 :         eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
     795                 :            :                                wpa_bss_timeout, wpa_s, NULL);
     796                 :        439 : }
     797                 :            : 
     798                 :            : 
     799                 :            : /**
     800                 :            :  * wpa_bss_init - Initialize BSS table
     801                 :            :  * @wpa_s: Pointer to wpa_supplicant data
     802                 :            :  * Returns: 0 on success, -1 on failure
     803                 :            :  *
     804                 :            :  * This prepares BSS table lists and timer for periodic updates. The BSS table
     805                 :            :  * is deinitialized with wpa_bss_deinit() once not needed anymore.
     806                 :            :  */
     807                 :         39 : int wpa_bss_init(struct wpa_supplicant *wpa_s)
     808                 :            : {
     809                 :         39 :         dl_list_init(&wpa_s->bss);
     810                 :         39 :         dl_list_init(&wpa_s->bss_id);
     811                 :         39 :         eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
     812                 :            :                                wpa_bss_timeout, wpa_s, NULL);
     813                 :         39 :         return 0;
     814                 :            : }
     815                 :            : 
     816                 :            : 
     817                 :            : /**
     818                 :            :  * wpa_bss_flush - Flush all unused BSS entries
     819                 :            :  * @wpa_s: Pointer to wpa_supplicant data
     820                 :            :  */
     821                 :       1304 : void wpa_bss_flush(struct wpa_supplicant *wpa_s)
     822                 :            : {
     823                 :            :         struct wpa_bss *bss, *n;
     824                 :            : 
     825                 :       1304 :         wpa_s->clear_driver_scan_cache = 1;
     826                 :            : 
     827         [ +  + ]:       1304 :         if (wpa_s->bss.next == NULL)
     828                 :       1304 :                 return; /* BSS table not yet initialized */
     829                 :            : 
     830         [ +  + ]:       2037 :         dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
     831         [ +  + ]:        734 :                 if (wpa_bss_in_use(wpa_s, bss))
     832                 :          2 :                         continue;
     833                 :        732 :                 wpa_bss_remove(wpa_s, bss, __func__);
     834                 :            :         }
     835                 :            : }
     836                 :            : 
     837                 :            : 
     838                 :            : /**
     839                 :            :  * wpa_bss_deinit - Deinitialize BSS table
     840                 :            :  * @wpa_s: Pointer to wpa_supplicant data
     841                 :            :  */
     842                 :         40 : void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
     843                 :            : {
     844                 :         40 :         eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
     845                 :         40 :         wpa_bss_flush(wpa_s);
     846                 :         40 : }
     847                 :            : 
     848                 :            : 
     849                 :            : /**
     850                 :            :  * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
     851                 :            :  * @wpa_s: Pointer to wpa_supplicant data
     852                 :            :  * @bssid: BSSID
     853                 :            :  * Returns: Pointer to the BSS entry or %NULL if not found
     854                 :            :  */
     855                 :        330 : struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
     856                 :            :                                    const u8 *bssid)
     857                 :            : {
     858                 :            :         struct wpa_bss *bss;
     859         [ -  + ]:        330 :         if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
     860                 :          0 :                 return NULL;
     861         [ +  - ]:        406 :         dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
     862         [ +  + ]:        406 :                 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
     863                 :        330 :                         return bss;
     864                 :            :         }
     865                 :        330 :         return NULL;
     866                 :            : }
     867                 :            : 
     868                 :            : 
     869                 :            : /**
     870                 :            :  * wpa_bss_get_bssid_latest - Fetch the latest BSS table entry based on BSSID
     871                 :            :  * @wpa_s: Pointer to wpa_supplicant data
     872                 :            :  * @bssid: BSSID
     873                 :            :  * Returns: Pointer to the BSS entry or %NULL if not found
     874                 :            :  *
     875                 :            :  * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to
     876                 :            :  * find the entry that has the most recent update. This can help in finding the
     877                 :            :  * correct entry in cases where the SSID of the AP may have changed recently
     878                 :            :  * (e.g., in WPS reconfiguration cases).
     879                 :            :  */
     880                 :        157 : struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
     881                 :            :                                           const u8 *bssid)
     882                 :            : {
     883                 :        157 :         struct wpa_bss *bss, *found = NULL;
     884         [ -  + ]:        157 :         if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
     885                 :          0 :                 return NULL;
     886         [ +  + ]:        303 :         dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
     887         [ +  + ]:        146 :                 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
     888                 :         32 :                         continue;
     889   [ +  +  -  + ]:        122 :                 if (found == NULL ||
     890                 :          8 :                     os_reltime_before(&found->last_update, &bss->last_update))
     891                 :        106 :                         found = bss;
     892                 :            :         }
     893                 :        157 :         return found;
     894                 :            : }
     895                 :            : 
     896                 :            : 
     897                 :            : #ifdef CONFIG_P2P
     898                 :            : /**
     899                 :            :  * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
     900                 :            :  * @wpa_s: Pointer to wpa_supplicant data
     901                 :            :  * @dev_addr: P2P Device Address of the GO
     902                 :            :  * Returns: Pointer to the BSS entry or %NULL if not found
     903                 :            :  */
     904                 :         15 : struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
     905                 :            :                                           const u8 *dev_addr)
     906                 :            : {
     907                 :            :         struct wpa_bss *bss;
     908         [ +  - ]:         17 :         dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
     909                 :            :                 u8 addr[ETH_ALEN];
     910         [ +  + ]:         17 :                 if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
     911         [ +  - ]:         15 :                                        addr) == 0 &&
     912                 :         15 :                     os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
     913                 :         15 :                         return bss;
     914                 :            :         }
     915                 :         15 :         return NULL;
     916                 :            : }
     917                 :            : #endif /* CONFIG_P2P */
     918                 :            : 
     919                 :            : 
     920                 :            : /**
     921                 :            :  * wpa_bss_get_id - Fetch a BSS table entry based on identifier
     922                 :            :  * @wpa_s: Pointer to wpa_supplicant data
     923                 :            :  * @id: Unique identifier (struct wpa_bss::id) assigned for the entry
     924                 :            :  * Returns: Pointer to the BSS entry or %NULL if not found
     925                 :            :  */
     926                 :          1 : struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
     927                 :            : {
     928                 :            :         struct wpa_bss *bss;
     929         [ +  - ]:          1 :         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
     930         [ +  - ]:          1 :                 if (bss->id == id)
     931                 :          1 :                         return bss;
     932                 :            :         }
     933                 :          1 :         return NULL;
     934                 :            : }
     935                 :            : 
     936                 :            : 
     937                 :            : /**
     938                 :            :  * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range
     939                 :            :  * @wpa_s: Pointer to wpa_supplicant data
     940                 :            :  * @idf: Smallest allowed identifier assigned for the entry
     941                 :            :  * @idf: Largest allowed identifier assigned for the entry
     942                 :            :  * Returns: Pointer to the BSS entry or %NULL if not found
     943                 :            :  *
     944                 :            :  * This function is similar to wpa_bss_get_id() but allows a BSS entry with the
     945                 :            :  * smallest id value to be fetched within the specified range without the
     946                 :            :  * caller having to know the exact id.
     947                 :            :  */
     948                 :          1 : struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
     949                 :            :                                       unsigned int idf, unsigned int idl)
     950                 :            : {
     951                 :            :         struct wpa_bss *bss;
     952         [ +  - ]:          1 :         dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
     953 [ +  - ][ +  - ]:          1 :                 if (bss->id >= idf && bss->id <= idl)
     954                 :          1 :                         return bss;
     955                 :            :         }
     956                 :          1 :         return NULL;
     957                 :            : }
     958                 :            : 
     959                 :            : 
     960                 :            : /**
     961                 :            :  * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
     962                 :            :  * @bss: BSS table entry
     963                 :            :  * @ie: Information element identitifier (WLAN_EID_*)
     964                 :            :  * Returns: Pointer to the information element (id field) or %NULL if not found
     965                 :            :  *
     966                 :            :  * This function returns the first matching information element in the BSS
     967                 :            :  * entry.
     968                 :            :  */
     969                 :       7841 : const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
     970                 :            : {
     971                 :            :         const u8 *end, *pos;
     972                 :            : 
     973                 :       7841 :         pos = (const u8 *) (bss + 1);
     974                 :       7841 :         end = pos + bss->ie_len;
     975                 :            : 
     976         [ +  + ]:      58013 :         while (pos + 1 < end) {
     977         [ -  + ]:      55755 :                 if (pos + 2 + pos[1] > end)
     978                 :          0 :                         break;
     979         [ +  + ]:      55755 :                 if (pos[0] == ie)
     980                 :       5583 :                         return pos;
     981                 :      50172 :                 pos += 2 + pos[1];
     982                 :            :         }
     983                 :            : 
     984                 :       7841 :         return NULL;
     985                 :            : }
     986                 :            : 
     987                 :            : 
     988                 :            : /**
     989                 :            :  * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
     990                 :            :  * @bss: BSS table entry
     991                 :            :  * @vendor_type: Vendor type (four octets starting the IE payload)
     992                 :            :  * Returns: Pointer to the information element (id field) or %NULL if not found
     993                 :            :  *
     994                 :            :  * This function returns the first matching information element in the BSS
     995                 :            :  * entry.
     996                 :            :  */
     997                 :       8617 : const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
     998                 :            : {
     999                 :            :         const u8 *end, *pos;
    1000                 :            : 
    1001                 :       8617 :         pos = (const u8 *) (bss + 1);
    1002                 :       8617 :         end = pos + bss->ie_len;
    1003                 :            : 
    1004         [ +  + ]:     100820 :         while (pos + 1 < end) {
    1005         [ -  + ]:      94177 :                 if (pos + 2 + pos[1] > end)
    1006                 :          0 :                         break;
    1007         [ +  + ]:     112090 :                 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
           [ +  -  +  + ]
    1008                 :      17913 :                     vendor_type == WPA_GET_BE32(&pos[2]))
    1009                 :       1974 :                         return pos;
    1010                 :      92203 :                 pos += 2 + pos[1];
    1011                 :            :         }
    1012                 :            : 
    1013                 :       8617 :         return NULL;
    1014                 :            : }
    1015                 :            : 
    1016                 :            : 
    1017                 :            : /**
    1018                 :            :  * wpa_bss_get_vendor_ie_beacon - Fetch a vendor information from a BSS entry
    1019                 :            :  * @bss: BSS table entry
    1020                 :            :  * @vendor_type: Vendor type (four octets starting the IE payload)
    1021                 :            :  * Returns: Pointer to the information element (id field) or %NULL if not found
    1022                 :            :  *
    1023                 :            :  * This function returns the first matching information element in the BSS
    1024                 :            :  * entry.
    1025                 :            :  *
    1026                 :            :  * This function is like wpa_bss_get_vendor_ie(), but uses IE buffer only
    1027                 :            :  * from Beacon frames instead of either Beacon or Probe Response frames.
    1028                 :            :  */
    1029                 :        942 : const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
    1030                 :            :                                         u32 vendor_type)
    1031                 :            : {
    1032                 :            :         const u8 *end, *pos;
    1033                 :            : 
    1034         [ +  + ]:        942 :         if (bss->beacon_ie_len == 0)
    1035                 :        268 :                 return NULL;
    1036                 :            : 
    1037                 :        674 :         pos = (const u8 *) (bss + 1);
    1038                 :        674 :         pos += bss->ie_len;
    1039                 :        674 :         end = pos + bss->beacon_ie_len;
    1040                 :            : 
    1041         [ +  + ]:       8620 :         while (pos + 1 < end) {
    1042         [ -  + ]:       7952 :                 if (pos + 2 + pos[1] > end)
    1043                 :          0 :                         break;
    1044         [ +  + ]:       8969 :                 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
           [ +  -  +  + ]
    1045                 :       1017 :                     vendor_type == WPA_GET_BE32(&pos[2]))
    1046                 :          6 :                         return pos;
    1047                 :       7946 :                 pos += 2 + pos[1];
    1048                 :            :         }
    1049                 :            : 
    1050                 :        942 :         return NULL;
    1051                 :            : }
    1052                 :            : 
    1053                 :            : 
    1054                 :            : /**
    1055                 :            :  * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
    1056                 :            :  * @bss: BSS table entry
    1057                 :            :  * @vendor_type: Vendor type (four octets starting the IE payload)
    1058                 :            :  * Returns: Pointer to the information element payload or %NULL if not found
    1059                 :            :  *
    1060                 :            :  * This function returns concatenated payload of possibly fragmented vendor
    1061                 :            :  * specific information elements in the BSS entry. The caller is responsible for
    1062                 :            :  * freeing the returned buffer.
    1063                 :            :  */
    1064                 :       2251 : struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
    1065                 :            :                                             u32 vendor_type)
    1066                 :            : {
    1067                 :            :         struct wpabuf *buf;
    1068                 :            :         const u8 *end, *pos;
    1069                 :            : 
    1070                 :       2251 :         buf = wpabuf_alloc(bss->ie_len);
    1071         [ -  + ]:       2251 :         if (buf == NULL)
    1072                 :          0 :                 return NULL;
    1073                 :            : 
    1074                 :       2251 :         pos = (const u8 *) (bss + 1);
    1075                 :       2251 :         end = pos + bss->ie_len;
    1076                 :            : 
    1077         [ +  + ]:      27109 :         while (pos + 1 < end) {
    1078         [ -  + ]:      24858 :                 if (pos + 2 + pos[1] > end)
    1079                 :          0 :                         break;
    1080         [ +  + ]:      30476 :                 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
           [ +  -  +  + ]
    1081                 :       5618 :                     vendor_type == WPA_GET_BE32(&pos[2]))
    1082                 :       1268 :                         wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
    1083                 :      24858 :                 pos += 2 + pos[1];
    1084                 :            :         }
    1085                 :            : 
    1086         [ +  + ]:       2251 :         if (wpabuf_len(buf) == 0) {
    1087                 :        989 :                 wpabuf_free(buf);
    1088                 :        989 :                 buf = NULL;
    1089                 :            :         }
    1090                 :            : 
    1091                 :       2251 :         return buf;
    1092                 :            : }
    1093                 :            : 
    1094                 :            : 
    1095                 :            : /**
    1096                 :            :  * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry
    1097                 :            :  * @bss: BSS table entry
    1098                 :            :  * @vendor_type: Vendor type (four octets starting the IE payload)
    1099                 :            :  * Returns: Pointer to the information element payload or %NULL if not found
    1100                 :            :  *
    1101                 :            :  * This function returns concatenated payload of possibly fragmented vendor
    1102                 :            :  * specific information elements in the BSS entry. The caller is responsible for
    1103                 :            :  * freeing the returned buffer.
    1104                 :            :  *
    1105                 :            :  * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only
    1106                 :            :  * from Beacon frames instead of either Beacon or Probe Response frames.
    1107                 :            :  */
    1108                 :          1 : struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
    1109                 :            :                                                    u32 vendor_type)
    1110                 :            : {
    1111                 :            :         struct wpabuf *buf;
    1112                 :            :         const u8 *end, *pos;
    1113                 :            : 
    1114                 :          1 :         buf = wpabuf_alloc(bss->beacon_ie_len);
    1115         [ -  + ]:          1 :         if (buf == NULL)
    1116                 :          0 :                 return NULL;
    1117                 :            : 
    1118                 :          1 :         pos = (const u8 *) (bss + 1);
    1119                 :          1 :         pos += bss->ie_len;
    1120                 :          1 :         end = pos + bss->beacon_ie_len;
    1121                 :            : 
    1122         [ +  + ]:         11 :         while (pos + 1 < end) {
    1123         [ -  + ]:         10 :                 if (pos + 2 + pos[1] > end)
    1124                 :          0 :                         break;
    1125         [ +  + ]:         11 :                 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
           [ +  -  -  + ]
    1126                 :          1 :                     vendor_type == WPA_GET_BE32(&pos[2]))
    1127                 :          0 :                         wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
    1128                 :         10 :                 pos += 2 + pos[1];
    1129                 :            :         }
    1130                 :            : 
    1131         [ +  - ]:          1 :         if (wpabuf_len(buf) == 0) {
    1132                 :          1 :                 wpabuf_free(buf);
    1133                 :          1 :                 buf = NULL;
    1134                 :            :         }
    1135                 :            : 
    1136                 :          1 :         return buf;
    1137                 :            : }
    1138                 :            : 
    1139                 :            : 
    1140                 :            : /**
    1141                 :            :  * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS
    1142                 :            :  * @bss: BSS table entry
    1143                 :            :  * Returns: Maximum legacy rate in units of 500 kbps
    1144                 :            :  */
    1145                 :          0 : int wpa_bss_get_max_rate(const struct wpa_bss *bss)
    1146                 :            : {
    1147                 :          0 :         int rate = 0;
    1148                 :            :         const u8 *ie;
    1149                 :            :         int i;
    1150                 :            : 
    1151                 :          0 :         ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
    1152 [ #  # ][ #  # ]:          0 :         for (i = 0; ie && i < ie[1]; i++) {
    1153         [ #  # ]:          0 :                 if ((ie[i + 2] & 0x7f) > rate)
    1154                 :          0 :                         rate = ie[i + 2] & 0x7f;
    1155                 :            :         }
    1156                 :            : 
    1157                 :          0 :         ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
    1158 [ #  # ][ #  # ]:          0 :         for (i = 0; ie && i < ie[1]; i++) {
    1159         [ #  # ]:          0 :                 if ((ie[i + 2] & 0x7f) > rate)
    1160                 :          0 :                         rate = ie[i + 2] & 0x7f;
    1161                 :            :         }
    1162                 :            : 
    1163                 :          0 :         return rate;
    1164                 :            : }
    1165                 :            : 
    1166                 :            : 
    1167                 :            : /**
    1168                 :            :  * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS
    1169                 :            :  * @bss: BSS table entry
    1170                 :            :  * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps)
    1171                 :            :  * Returns: number of legacy TX rates or -1 on failure
    1172                 :            :  *
    1173                 :            :  * The caller is responsible for freeing the returned buffer with os_free() in
    1174                 :            :  * case of success.
    1175                 :            :  */
    1176                 :          0 : int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
    1177                 :            : {
    1178                 :            :         const u8 *ie, *ie2;
    1179                 :            :         int i, j;
    1180                 :            :         unsigned int len;
    1181                 :            :         u8 *r;
    1182                 :            : 
    1183                 :          0 :         ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
    1184                 :          0 :         ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
    1185                 :            : 
    1186 [ #  # ][ #  # ]:          0 :         len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
    1187                 :            : 
    1188                 :          0 :         r = os_malloc(len);
    1189         [ #  # ]:          0 :         if (!r)
    1190                 :          0 :                 return -1;
    1191                 :            : 
    1192 [ #  # ][ #  # ]:          0 :         for (i = 0; ie && i < ie[1]; i++)
    1193                 :          0 :                 r[i] = ie[i + 2] & 0x7f;
    1194                 :            : 
    1195 [ #  # ][ #  # ]:          0 :         for (j = 0; ie2 && j < ie2[1]; j++)
    1196                 :          0 :                 r[i + j] = ie2[j + 2] & 0x7f;
    1197                 :            : 
    1198                 :          0 :         *rates = r;
    1199                 :          0 :         return len;
    1200                 :            : }

Generated by: LCOV version 1.9