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 1388338050 Lines: 429 516 83.1 %
Date: 2013-12-29 Functions: 34 39 87.2 %
Branches: 265 382 69.4 %

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

Generated by: LCOV version 1.9