LCOV - code coverage report
Current view: top level - net/wireless - scan.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 1070 0.0 %
Date: 2022-04-01 14:35:51 Functions: 0 49 0.0 %
Branches: 0 801 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * cfg80211 scan result handling
       4                 :            :  *
       5                 :            :  * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
       6                 :            :  * Copyright 2013-2014  Intel Mobile Communications GmbH
       7                 :            :  * Copyright 2016       Intel Deutschland GmbH
       8                 :            :  * Copyright (C) 2018-2019 Intel Corporation
       9                 :            :  */
      10                 :            : #include <linux/kernel.h>
      11                 :            : #include <linux/slab.h>
      12                 :            : #include <linux/module.h>
      13                 :            : #include <linux/netdevice.h>
      14                 :            : #include <linux/wireless.h>
      15                 :            : #include <linux/nl80211.h>
      16                 :            : #include <linux/etherdevice.h>
      17                 :            : #include <net/arp.h>
      18                 :            : #include <net/cfg80211.h>
      19                 :            : #include <net/cfg80211-wext.h>
      20                 :            : #include <net/iw_handler.h>
      21                 :            : #include "core.h"
      22                 :            : #include "nl80211.h"
      23                 :            : #include "wext-compat.h"
      24                 :            : #include "rdev-ops.h"
      25                 :            : 
      26                 :            : /**
      27                 :            :  * DOC: BSS tree/list structure
      28                 :            :  *
      29                 :            :  * At the top level, the BSS list is kept in both a list in each
      30                 :            :  * registered device (@bss_list) as well as an RB-tree for faster
      31                 :            :  * lookup. In the RB-tree, entries can be looked up using their
      32                 :            :  * channel, MESHID, MESHCONF (for MBSSes) or channel, BSSID, SSID
      33                 :            :  * for other BSSes.
      34                 :            :  *
      35                 :            :  * Due to the possibility of hidden SSIDs, there's a second level
      36                 :            :  * structure, the "hidden_list" and "hidden_beacon_bss" pointer.
      37                 :            :  * The hidden_list connects all BSSes belonging to a single AP
      38                 :            :  * that has a hidden SSID, and connects beacon and probe response
      39                 :            :  * entries. For a probe response entry for a hidden SSID, the
      40                 :            :  * hidden_beacon_bss pointer points to the BSS struct holding the
      41                 :            :  * beacon's information.
      42                 :            :  *
      43                 :            :  * Reference counting is done for all these references except for
      44                 :            :  * the hidden_list, so that a beacon BSS struct that is otherwise
      45                 :            :  * not referenced has one reference for being on the bss_list and
      46                 :            :  * one for each probe response entry that points to it using the
      47                 :            :  * hidden_beacon_bss pointer. When a BSS struct that has such a
      48                 :            :  * pointer is get/put, the refcount update is also propagated to
      49                 :            :  * the referenced struct, this ensure that it cannot get removed
      50                 :            :  * while somebody is using the probe response version.
      51                 :            :  *
      52                 :            :  * Note that the hidden_beacon_bss pointer never changes, due to
      53                 :            :  * the reference counting. Therefore, no locking is needed for
      54                 :            :  * it.
      55                 :            :  *
      56                 :            :  * Also note that the hidden_beacon_bss pointer is only relevant
      57                 :            :  * if the driver uses something other than the IEs, e.g. private
      58                 :            :  * data stored stored in the BSS struct, since the beacon IEs are
      59                 :            :  * also linked into the probe response struct.
      60                 :            :  */
      61                 :            : 
      62                 :            : /*
      63                 :            :  * Limit the number of BSS entries stored in mac80211. Each one is
      64                 :            :  * a bit over 4k at most, so this limits to roughly 4-5M of memory.
      65                 :            :  * If somebody wants to really attack this though, they'd likely
      66                 :            :  * use small beacons, and only one type of frame, limiting each of
      67                 :            :  * the entries to a much smaller size (in order to generate more
      68                 :            :  * entries in total, so overhead is bigger.)
      69                 :            :  */
      70                 :            : static int bss_entries_limit = 1000;
      71                 :            : module_param(bss_entries_limit, int, 0644);
      72                 :            : MODULE_PARM_DESC(bss_entries_limit,
      73                 :            :                  "limit to number of scan BSS entries (per wiphy, default 1000)");
      74                 :            : 
      75                 :            : #define IEEE80211_SCAN_RESULT_EXPIRE    (30 * HZ)
      76                 :            : 
      77                 :          0 : static void bss_free(struct cfg80211_internal_bss *bss)
      78                 :            : {
      79                 :          0 :         struct cfg80211_bss_ies *ies;
      80                 :            : 
      81   [ #  #  #  # ]:          0 :         if (WARN_ON(atomic_read(&bss->hold)))
      82                 :            :                 return;
      83                 :            : 
      84         [ #  # ]:          0 :         ies = (void *)rcu_access_pointer(bss->pub.beacon_ies);
      85   [ #  #  #  # ]:          0 :         if (ies && !bss->pub.hidden_beacon_bss)
      86                 :          0 :                 kfree_rcu(ies, rcu_head);
      87         [ #  # ]:          0 :         ies = (void *)rcu_access_pointer(bss->pub.proberesp_ies);
      88         [ #  # ]:          0 :         if (ies)
      89                 :          0 :                 kfree_rcu(ies, rcu_head);
      90                 :            : 
      91                 :            :         /*
      92                 :            :          * This happens when the module is removed, it doesn't
      93                 :            :          * really matter any more save for completeness
      94                 :            :          */
      95         [ #  # ]:          0 :         if (!list_empty(&bss->hidden_list))
      96                 :          0 :                 list_del(&bss->hidden_list);
      97                 :            : 
      98                 :          0 :         kfree(bss);
      99                 :            : }
     100                 :            : 
     101                 :          0 : static inline void bss_ref_get(struct cfg80211_registered_device *rdev,
     102                 :            :                                struct cfg80211_internal_bss *bss)
     103                 :            : {
     104                 :          0 :         lockdep_assert_held(&rdev->bss_lock);
     105                 :            : 
     106                 :          0 :         bss->refcount++;
     107                 :          0 :         if (bss->pub.hidden_beacon_bss) {
     108                 :          0 :                 bss = container_of(bss->pub.hidden_beacon_bss,
     109                 :            :                                    struct cfg80211_internal_bss,
     110                 :            :                                    pub);
     111                 :          0 :                 bss->refcount++;
     112                 :            :         }
     113   [ #  #  #  #  :          0 :         if (bss->pub.transmitted_bss) {
             #  #  #  # ]
     114                 :          0 :                 bss = container_of(bss->pub.transmitted_bss,
     115                 :            :                                    struct cfg80211_internal_bss,
     116                 :            :                                    pub);
     117                 :          0 :                 bss->refcount++;
     118                 :            :         }
     119                 :            : }
     120                 :            : 
     121                 :            : static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
     122                 :            :                                struct cfg80211_internal_bss *bss)
     123                 :            : {
     124                 :            :         lockdep_assert_held(&rdev->bss_lock);
     125                 :            : 
     126                 :            :         if (bss->pub.hidden_beacon_bss) {
     127                 :            :                 struct cfg80211_internal_bss *hbss;
     128                 :            :                 hbss = container_of(bss->pub.hidden_beacon_bss,
     129                 :            :                                     struct cfg80211_internal_bss,
     130                 :            :                                     pub);
     131                 :            :                 hbss->refcount--;
     132                 :            :                 if (hbss->refcount == 0)
     133                 :            :                         bss_free(hbss);
     134                 :            :         }
     135                 :            : 
     136                 :            :         if (bss->pub.transmitted_bss) {
     137                 :            :                 struct cfg80211_internal_bss *tbss;
     138                 :            : 
     139                 :            :                 tbss = container_of(bss->pub.transmitted_bss,
     140                 :            :                                     struct cfg80211_internal_bss,
     141                 :            :                                     pub);
     142                 :            :                 tbss->refcount--;
     143                 :            :                 if (tbss->refcount == 0)
     144                 :            :                         bss_free(tbss);
     145                 :            :         }
     146                 :            : 
     147                 :            :         bss->refcount--;
     148                 :            :         if (bss->refcount == 0)
     149                 :            :                 bss_free(bss);
     150                 :            : }
     151                 :            : 
     152                 :          0 : static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev,
     153                 :            :                                   struct cfg80211_internal_bss *bss)
     154                 :            : {
     155                 :          0 :         lockdep_assert_held(&rdev->bss_lock);
     156                 :            : 
     157         [ #  # ]:          0 :         if (!list_empty(&bss->hidden_list)) {
     158                 :            :                 /*
     159                 :            :                  * don't remove the beacon entry if it has
     160                 :            :                  * probe responses associated with it
     161                 :            :                  */
     162         [ #  # ]:          0 :                 if (!bss->pub.hidden_beacon_bss)
     163                 :            :                         return false;
     164                 :            :                 /*
     165                 :            :                  * if it's a probe response entry break its
     166                 :            :                  * link to the other entries in the group
     167                 :            :                  */
     168                 :          0 :                 list_del_init(&bss->hidden_list);
     169                 :            :         }
     170                 :            : 
     171                 :          0 :         list_del_init(&bss->list);
     172                 :          0 :         list_del_init(&bss->pub.nontrans_list);
     173                 :          0 :         rb_erase(&bss->rbn, &rdev->bss_tree);
     174                 :          0 :         rdev->bss_entries--;
     175   [ #  #  #  # ]:          0 :         WARN_ONCE((rdev->bss_entries == 0) ^ list_empty(&rdev->bss_list),
     176                 :            :                   "rdev bss entries[%d]/list[empty:%d] corruption\n",
     177                 :            :                   rdev->bss_entries, list_empty(&rdev->bss_list));
     178                 :          0 :         bss_ref_put(rdev, bss);
     179                 :          0 :         return true;
     180                 :            : }
     181                 :            : 
     182                 :          0 : bool cfg80211_is_element_inherited(const struct element *elem,
     183                 :            :                                    const struct element *non_inherit_elem)
     184                 :            : {
     185                 :          0 :         u8 id_len, ext_id_len, i, loop_len, id;
     186                 :          0 :         const u8 *list;
     187                 :            : 
     188         [ #  # ]:          0 :         if (elem->id == WLAN_EID_MULTIPLE_BSSID)
     189                 :            :                 return false;
     190                 :            : 
     191   [ #  #  #  # ]:          0 :         if (!non_inherit_elem || non_inherit_elem->datalen < 2)
     192                 :            :                 return true;
     193                 :            : 
     194                 :            :         /*
     195                 :            :          * non inheritance element format is:
     196                 :            :          * ext ID (56) | IDs list len | list | extension IDs list len | list
     197                 :            :          * Both lists are optional. Both lengths are mandatory.
     198                 :            :          * This means valid length is:
     199                 :            :          * elem_len = 1 (extension ID) + 2 (list len fields) + list lengths
     200                 :            :          */
     201                 :          0 :         id_len = non_inherit_elem->data[1];
     202         [ #  # ]:          0 :         if (non_inherit_elem->datalen < 3 + id_len)
     203                 :            :                 return true;
     204                 :            : 
     205                 :          0 :         ext_id_len = non_inherit_elem->data[2 + id_len];
     206         [ #  # ]:          0 :         if (non_inherit_elem->datalen < 3 + id_len + ext_id_len)
     207                 :            :                 return true;
     208                 :            : 
     209         [ #  # ]:          0 :         if (elem->id == WLAN_EID_EXTENSION) {
     210         [ #  # ]:          0 :                 if (!ext_id_len)
     211                 :            :                         return true;
     212                 :          0 :                 loop_len = ext_id_len;
     213                 :          0 :                 list = &non_inherit_elem->data[3 + id_len];
     214                 :          0 :                 id = elem->data[0];
     215                 :            :         } else {
     216         [ #  # ]:          0 :                 if (!id_len)
     217                 :            :                         return true;
     218                 :          0 :                 loop_len = id_len;
     219                 :          0 :                 list = &non_inherit_elem->data[2];
     220                 :          0 :                 id = elem->id;
     221                 :            :         }
     222                 :            : 
     223         [ #  # ]:          0 :         for (i = 0; i < loop_len; i++) {
     224         [ #  # ]:          0 :                 if (list[i] == id)
     225                 :            :                         return false;
     226                 :            :         }
     227                 :            : 
     228                 :            :         return true;
     229                 :            : }
     230                 :            : EXPORT_SYMBOL(cfg80211_is_element_inherited);
     231                 :            : 
     232                 :          0 : static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
     233                 :            :                                   const u8 *subelement, size_t subie_len,
     234                 :            :                                   u8 *new_ie, gfp_t gfp)
     235                 :            : {
     236                 :          0 :         u8 *pos, *tmp;
     237                 :          0 :         const u8 *tmp_old, *tmp_new;
     238                 :          0 :         const struct element *non_inherit_elem;
     239                 :          0 :         u8 *sub_copy;
     240                 :            : 
     241                 :            :         /* copy subelement as we need to change its content to
     242                 :            :          * mark an ie after it is processed.
     243                 :            :          */
     244                 :          0 :         sub_copy = kmemdup(subelement, subie_len, gfp);
     245         [ #  # ]:          0 :         if (!sub_copy)
     246                 :            :                 return 0;
     247                 :            : 
     248                 :          0 :         pos = &new_ie[0];
     249                 :            : 
     250                 :            :         /* set new ssid */
     251                 :          0 :         tmp_new = cfg80211_find_ie(WLAN_EID_SSID, sub_copy, subie_len);
     252         [ #  # ]:          0 :         if (tmp_new) {
     253                 :          0 :                 memcpy(pos, tmp_new, tmp_new[1] + 2);
     254                 :          0 :                 pos += (tmp_new[1] + 2);
     255                 :            :         }
     256                 :            : 
     257                 :            :         /* get non inheritance list if exists */
     258                 :          0 :         non_inherit_elem =
     259                 :          0 :                 cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
     260                 :            :                                        sub_copy, subie_len);
     261                 :            : 
     262                 :            :         /* go through IEs in ie (skip SSID) and subelement,
     263                 :            :          * merge them into new_ie
     264                 :            :          */
     265                 :          0 :         tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
     266         [ #  # ]:          0 :         tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie;
     267                 :            : 
     268         [ #  # ]:          0 :         while (tmp_old + tmp_old[1] + 2 - ie <= ielen) {
     269         [ #  # ]:          0 :                 if (tmp_old[0] == 0) {
     270                 :          0 :                         tmp_old++;
     271                 :          0 :                         continue;
     272                 :            :                 }
     273                 :            : 
     274         [ #  # ]:          0 :                 if (tmp_old[0] == WLAN_EID_EXTENSION)
     275                 :          0 :                         tmp = (u8 *)cfg80211_find_ext_ie(tmp_old[2], sub_copy,
     276                 :            :                                                          subie_len);
     277                 :            :                 else
     278                 :          0 :                         tmp = (u8 *)cfg80211_find_ie(tmp_old[0], sub_copy,
     279                 :            :                                                      subie_len);
     280                 :            : 
     281         [ #  # ]:          0 :                 if (!tmp) {
     282                 :          0 :                         const struct element *old_elem = (void *)tmp_old;
     283                 :            : 
     284                 :            :                         /* ie in old ie but not in subelement */
     285         [ #  # ]:          0 :                         if (cfg80211_is_element_inherited(old_elem,
     286                 :            :                                                           non_inherit_elem)) {
     287                 :          0 :                                 memcpy(pos, tmp_old, tmp_old[1] + 2);
     288                 :          0 :                                 pos += tmp_old[1] + 2;
     289                 :            :                         }
     290                 :            :                 } else {
     291                 :            :                         /* ie in transmitting ie also in subelement,
     292                 :            :                          * copy from subelement and flag the ie in subelement
     293                 :            :                          * as copied (by setting eid field to WLAN_EID_SSID,
     294                 :            :                          * which is skipped anyway).
     295                 :            :                          * For vendor ie, compare OUI + type + subType to
     296                 :            :                          * determine if they are the same ie.
     297                 :            :                          */
     298         [ #  # ]:          0 :                         if (tmp_old[0] == WLAN_EID_VENDOR_SPECIFIC) {
     299         [ #  # ]:          0 :                                 if (!memcmp(tmp_old + 2, tmp + 2, 5)) {
     300                 :            :                                         /* same vendor ie, copy from
     301                 :            :                                          * subelement
     302                 :            :                                          */
     303                 :          0 :                                         memcpy(pos, tmp, tmp[1] + 2);
     304                 :          0 :                                         pos += tmp[1] + 2;
     305                 :          0 :                                         tmp[0] = WLAN_EID_SSID;
     306                 :            :                                 } else {
     307                 :          0 :                                         memcpy(pos, tmp_old, tmp_old[1] + 2);
     308                 :          0 :                                         pos += tmp_old[1] + 2;
     309                 :            :                                 }
     310                 :            :                         } else {
     311                 :            :                                 /* copy ie from subelement into new ie */
     312                 :          0 :                                 memcpy(pos, tmp, tmp[1] + 2);
     313                 :          0 :                                 pos += tmp[1] + 2;
     314                 :          0 :                                 tmp[0] = WLAN_EID_SSID;
     315                 :            :                         }
     316                 :            :                 }
     317                 :            : 
     318         [ #  # ]:          0 :                 if (tmp_old + tmp_old[1] + 2 - ie == ielen)
     319                 :            :                         break;
     320                 :            : 
     321                 :          0 :                 tmp_old += tmp_old[1] + 2;
     322                 :            :         }
     323                 :            : 
     324                 :            :         /* go through subelement again to check if there is any ie not
     325                 :            :          * copied to new ie, skip ssid, capability, bssid-index ie
     326                 :            :          */
     327                 :            :         tmp_new = sub_copy;
     328         [ #  # ]:          0 :         while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
     329         [ #  # ]:          0 :                 if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP ||
     330                 :            :                       tmp_new[0] == WLAN_EID_SSID)) {
     331                 :          0 :                         memcpy(pos, tmp_new, tmp_new[1] + 2);
     332                 :          0 :                         pos += tmp_new[1] + 2;
     333                 :            :                 }
     334         [ #  # ]:          0 :                 if (tmp_new + tmp_new[1] + 2 - sub_copy == subie_len)
     335                 :            :                         break;
     336                 :          0 :                 tmp_new += tmp_new[1] + 2;
     337                 :            :         }
     338                 :            : 
     339                 :          0 :         kfree(sub_copy);
     340                 :          0 :         return pos - new_ie;
     341                 :            : }
     342                 :            : 
     343                 :          0 : static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
     344                 :            :                    const u8 *ssid, size_t ssid_len)
     345                 :            : {
     346                 :          0 :         const struct cfg80211_bss_ies *ies;
     347                 :          0 :         const u8 *ssidie;
     348                 :            : 
     349   [ #  #  #  # ]:          0 :         if (bssid && !ether_addr_equal(a->bssid, bssid))
     350                 :            :                 return false;
     351                 :            : 
     352         [ #  # ]:          0 :         if (!ssid)
     353                 :            :                 return true;
     354                 :            : 
     355         [ #  # ]:          0 :         ies = rcu_access_pointer(a->ies);
     356         [ #  # ]:          0 :         if (!ies)
     357                 :            :                 return false;
     358                 :          0 :         ssidie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
     359         [ #  # ]:          0 :         if (!ssidie)
     360                 :            :                 return false;
     361         [ #  # ]:          0 :         if (ssidie[1] != ssid_len)
     362                 :            :                 return false;
     363                 :          0 :         return memcmp(ssidie + 2, ssid, ssid_len) == 0;
     364                 :            : }
     365                 :            : 
     366                 :            : static int
     367                 :          0 : cfg80211_add_nontrans_list(struct cfg80211_bss *trans_bss,
     368                 :            :                            struct cfg80211_bss *nontrans_bss)
     369                 :            : {
     370                 :          0 :         const u8 *ssid;
     371                 :          0 :         size_t ssid_len;
     372                 :          0 :         struct cfg80211_bss *bss = NULL;
     373                 :            : 
     374                 :          0 :         rcu_read_lock();
     375                 :          0 :         ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID);
     376         [ #  # ]:          0 :         if (!ssid) {
     377                 :          0 :                 rcu_read_unlock();
     378                 :          0 :                 return -EINVAL;
     379                 :            :         }
     380                 :          0 :         ssid_len = ssid[1];
     381                 :          0 :         ssid = ssid + 2;
     382                 :          0 :         rcu_read_unlock();
     383                 :            : 
     384                 :            :         /* check if nontrans_bss is in the list */
     385         [ #  # ]:          0 :         list_for_each_entry(bss, &trans_bss->nontrans_list, nontrans_list) {
     386         [ #  # ]:          0 :                 if (is_bss(bss, nontrans_bss->bssid, ssid, ssid_len))
     387                 :            :                         return 0;
     388                 :            :         }
     389                 :            : 
     390                 :            :         /* add to the list */
     391                 :          0 :         list_add_tail(&nontrans_bss->nontrans_list, &trans_bss->nontrans_list);
     392                 :          0 :         return 0;
     393                 :            : }
     394                 :            : 
     395                 :          0 : static void __cfg80211_bss_expire(struct cfg80211_registered_device *rdev,
     396                 :            :                                   unsigned long expire_time)
     397                 :            : {
     398                 :          0 :         struct cfg80211_internal_bss *bss, *tmp;
     399                 :          0 :         bool expired = false;
     400                 :            : 
     401                 :          0 :         lockdep_assert_held(&rdev->bss_lock);
     402                 :            : 
     403         [ #  # ]:          0 :         list_for_each_entry_safe(bss, tmp, &rdev->bss_list, list) {
     404         [ #  # ]:          0 :                 if (atomic_read(&bss->hold))
     405                 :          0 :                         continue;
     406         [ #  # ]:          0 :                 if (!time_after(expire_time, bss->ts))
     407                 :          0 :                         continue;
     408                 :            : 
     409         [ #  # ]:          0 :                 if (__cfg80211_unlink_bss(rdev, bss))
     410                 :          0 :                         expired = true;
     411                 :            :         }
     412                 :            : 
     413         [ #  # ]:          0 :         if (expired)
     414                 :          0 :                 rdev->bss_generation++;
     415                 :          0 : }
     416                 :            : 
     417                 :          0 : static bool cfg80211_bss_expire_oldest(struct cfg80211_registered_device *rdev)
     418                 :            : {
     419                 :          0 :         struct cfg80211_internal_bss *bss, *oldest = NULL;
     420                 :          0 :         bool ret;
     421                 :            : 
     422                 :          0 :         lockdep_assert_held(&rdev->bss_lock);
     423                 :            : 
     424         [ #  # ]:          0 :         list_for_each_entry(bss, &rdev->bss_list, list) {
     425         [ #  # ]:          0 :                 if (atomic_read(&bss->hold))
     426                 :          0 :                         continue;
     427                 :            : 
     428         [ #  # ]:          0 :                 if (!list_empty(&bss->hidden_list) &&
     429         [ #  # ]:          0 :                     !bss->pub.hidden_beacon_bss)
     430                 :          0 :                         continue;
     431                 :            : 
     432   [ #  #  #  # ]:          0 :                 if (oldest && time_before(oldest->ts, bss->ts))
     433                 :          0 :                         continue;
     434                 :            :                 oldest = bss;
     435                 :            :         }
     436                 :            : 
     437   [ #  #  #  # ]:          0 :         if (WARN_ON(!oldest))
     438                 :            :                 return false;
     439                 :            : 
     440                 :            :         /*
     441                 :            :          * The callers make sure to increase rdev->bss_generation if anything
     442                 :            :          * gets removed (and a new entry added), so there's no need to also do
     443                 :            :          * it here.
     444                 :            :          */
     445                 :            : 
     446                 :          0 :         ret = __cfg80211_unlink_bss(rdev, oldest);
     447         [ #  # ]:          0 :         WARN_ON(!ret);
     448                 :            :         return ret;
     449                 :            : }
     450                 :            : 
     451                 :          0 : void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
     452                 :            :                            bool send_message)
     453                 :            : {
     454                 :          0 :         struct cfg80211_scan_request *request;
     455                 :          0 :         struct wireless_dev *wdev;
     456                 :          0 :         struct sk_buff *msg;
     457                 :            : #ifdef CONFIG_CFG80211_WEXT
     458                 :          0 :         union iwreq_data wrqu;
     459                 :            : #endif
     460                 :            : 
     461   [ #  #  #  # ]:          0 :         ASSERT_RTNL();
     462                 :            : 
     463         [ #  # ]:          0 :         if (rdev->scan_msg) {
     464                 :          0 :                 nl80211_send_scan_msg(rdev, rdev->scan_msg);
     465                 :          0 :                 rdev->scan_msg = NULL;
     466                 :          0 :                 return;
     467                 :            :         }
     468                 :            : 
     469                 :          0 :         request = rdev->scan_req;
     470         [ #  # ]:          0 :         if (!request)
     471                 :            :                 return;
     472                 :            : 
     473                 :          0 :         wdev = request->wdev;
     474                 :            : 
     475                 :            :         /*
     476                 :            :          * This must be before sending the other events!
     477                 :            :          * Otherwise, wpa_supplicant gets completely confused with
     478                 :            :          * wext events.
     479                 :            :          */
     480         [ #  # ]:          0 :         if (wdev->netdev)
     481                 :          0 :                 cfg80211_sme_scan_done(wdev->netdev);
     482                 :            : 
     483         [ #  # ]:          0 :         if (!request->info.aborted &&
     484         [ #  # ]:          0 :             request->flags & NL80211_SCAN_FLAG_FLUSH) {
     485                 :            :                 /* flush entries from previous scans */
     486                 :          0 :                 spin_lock_bh(&rdev->bss_lock);
     487                 :          0 :                 __cfg80211_bss_expire(rdev, request->scan_start);
     488                 :          0 :                 spin_unlock_bh(&rdev->bss_lock);
     489                 :            :         }
     490                 :            : 
     491                 :          0 :         msg = nl80211_build_scan_msg(rdev, wdev, request->info.aborted);
     492                 :            : 
     493                 :            : #ifdef CONFIG_CFG80211_WEXT
     494   [ #  #  #  # ]:          0 :         if (wdev->netdev && !request->info.aborted) {
     495                 :          0 :                 memset(&wrqu, 0, sizeof(wrqu));
     496                 :            : 
     497                 :          0 :                 wireless_send_event(wdev->netdev, SIOCGIWSCAN, &wrqu, NULL);
     498                 :            :         }
     499                 :            : #endif
     500                 :            : 
     501         [ #  # ]:          0 :         if (wdev->netdev)
     502                 :          0 :                 dev_put(wdev->netdev);
     503                 :            : 
     504                 :          0 :         rdev->scan_req = NULL;
     505                 :          0 :         kfree(request);
     506                 :            : 
     507         [ #  # ]:          0 :         if (!send_message)
     508                 :          0 :                 rdev->scan_msg = msg;
     509                 :            :         else
     510                 :          0 :                 nl80211_send_scan_msg(rdev, msg);
     511                 :            : }
     512                 :            : 
     513                 :          0 : void __cfg80211_scan_done(struct work_struct *wk)
     514                 :            : {
     515                 :          0 :         struct cfg80211_registered_device *rdev;
     516                 :            : 
     517                 :          0 :         rdev = container_of(wk, struct cfg80211_registered_device,
     518                 :            :                             scan_done_wk);
     519                 :            : 
     520                 :          0 :         rtnl_lock();
     521                 :          0 :         ___cfg80211_scan_done(rdev, true);
     522                 :          0 :         rtnl_unlock();
     523                 :          0 : }
     524                 :            : 
     525                 :          0 : void cfg80211_scan_done(struct cfg80211_scan_request *request,
     526                 :            :                         struct cfg80211_scan_info *info)
     527                 :            : {
     528                 :          0 :         trace_cfg80211_scan_done(request, info);
     529   [ #  #  #  # ]:          0 :         WARN_ON(request != wiphy_to_rdev(request->wiphy)->scan_req);
     530                 :            : 
     531                 :          0 :         request->info = *info;
     532                 :          0 :         request->notified = true;
     533                 :          0 :         queue_work(cfg80211_wq, &wiphy_to_rdev(request->wiphy)->scan_done_wk);
     534                 :          0 : }
     535                 :            : EXPORT_SYMBOL(cfg80211_scan_done);
     536                 :            : 
     537                 :          0 : void cfg80211_add_sched_scan_req(struct cfg80211_registered_device *rdev,
     538                 :            :                                  struct cfg80211_sched_scan_request *req)
     539                 :            : {
     540   [ #  #  #  # ]:          0 :         ASSERT_RTNL();
     541                 :            : 
     542                 :          0 :         list_add_rcu(&req->list, &rdev->sched_scan_req_list);
     543                 :          0 : }
     544                 :            : 
     545                 :            : static void cfg80211_del_sched_scan_req(struct cfg80211_registered_device *rdev,
     546                 :            :                                         struct cfg80211_sched_scan_request *req)
     547                 :            : {
     548                 :            :         ASSERT_RTNL();
     549                 :            : 
     550                 :            :         list_del_rcu(&req->list);
     551                 :            :         kfree_rcu(req, rcu_head);
     552                 :            : }
     553                 :            : 
     554                 :            : static struct cfg80211_sched_scan_request *
     555                 :          0 : cfg80211_find_sched_scan_req(struct cfg80211_registered_device *rdev, u64 reqid)
     556                 :            : {
     557                 :          0 :         struct cfg80211_sched_scan_request *pos;
     558                 :            : 
     559                 :          0 :         WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held());
     560                 :            : 
     561   [ #  #  #  # ]:          0 :         list_for_each_entry_rcu(pos, &rdev->sched_scan_req_list, list) {
     562   [ #  #  #  # ]:          0 :                 if (pos->reqid == reqid)
     563                 :            :                         return pos;
     564                 :            :         }
     565                 :            :         return NULL;
     566                 :            : }
     567                 :            : 
     568                 :            : /*
     569                 :            :  * Determines if a scheduled scan request can be handled. When a legacy
     570                 :            :  * scheduled scan is running no other scheduled scan is allowed regardless
     571                 :            :  * whether the request is for legacy or multi-support scan. When a multi-support
     572                 :            :  * scheduled scan is running a request for legacy scan is not allowed. In this
     573                 :            :  * case a request for multi-support scan can be handled if resources are
     574                 :            :  * available, ie. struct wiphy::max_sched_scan_reqs limit is not yet reached.
     575                 :            :  */
     576                 :          0 : int cfg80211_sched_scan_req_possible(struct cfg80211_registered_device *rdev,
     577                 :            :                                      bool want_multi)
     578                 :            : {
     579                 :          0 :         struct cfg80211_sched_scan_request *pos;
     580                 :          0 :         int i = 0;
     581                 :            : 
     582         [ #  # ]:          0 :         list_for_each_entry(pos, &rdev->sched_scan_req_list, list) {
     583                 :            :                 /* request id zero means legacy in progress */
     584   [ #  #  #  # ]:          0 :                 if (!i && !pos->reqid)
     585                 :            :                         return -EINPROGRESS;
     586                 :          0 :                 i++;
     587                 :            :         }
     588                 :            : 
     589         [ #  # ]:          0 :         if (i) {
     590                 :            :                 /* no legacy allowed when multi request(s) are active */
     591         [ #  # ]:          0 :                 if (!want_multi)
     592                 :            :                         return -EINPROGRESS;
     593                 :            : 
     594                 :            :                 /* resource limit reached */
     595         [ #  # ]:          0 :                 if (i == rdev->wiphy.max_sched_scan_reqs)
     596                 :          0 :                         return -ENOSPC;
     597                 :            :         }
     598                 :            :         return 0;
     599                 :            : }
     600                 :            : 
     601                 :          0 : void cfg80211_sched_scan_results_wk(struct work_struct *work)
     602                 :            : {
     603                 :          0 :         struct cfg80211_registered_device *rdev;
     604                 :          0 :         struct cfg80211_sched_scan_request *req, *tmp;
     605                 :            : 
     606                 :          0 :         rdev = container_of(work, struct cfg80211_registered_device,
     607                 :            :                            sched_scan_res_wk);
     608                 :            : 
     609                 :          0 :         rtnl_lock();
     610         [ #  # ]:          0 :         list_for_each_entry_safe(req, tmp, &rdev->sched_scan_req_list, list) {
     611         [ #  # ]:          0 :                 if (req->report_results) {
     612                 :          0 :                         req->report_results = false;
     613         [ #  # ]:          0 :                         if (req->flags & NL80211_SCAN_FLAG_FLUSH) {
     614                 :            :                                 /* flush entries from previous scans */
     615                 :          0 :                                 spin_lock_bh(&rdev->bss_lock);
     616                 :          0 :                                 __cfg80211_bss_expire(rdev, req->scan_start);
     617                 :          0 :                                 spin_unlock_bh(&rdev->bss_lock);
     618                 :          0 :                                 req->scan_start = jiffies;
     619                 :            :                         }
     620                 :          0 :                         nl80211_send_sched_scan(req,
     621                 :            :                                                 NL80211_CMD_SCHED_SCAN_RESULTS);
     622                 :            :                 }
     623                 :            :         }
     624                 :          0 :         rtnl_unlock();
     625                 :          0 : }
     626                 :            : 
     627                 :          0 : void cfg80211_sched_scan_results(struct wiphy *wiphy, u64 reqid)
     628                 :            : {
     629         [ #  # ]:          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
     630                 :          0 :         struct cfg80211_sched_scan_request *request;
     631                 :            : 
     632                 :          0 :         trace_cfg80211_sched_scan_results(wiphy, reqid);
     633                 :            :         /* ignore if we're not scanning */
     634                 :            : 
     635                 :          0 :         rcu_read_lock();
     636                 :          0 :         request = cfg80211_find_sched_scan_req(rdev, reqid);
     637         [ #  # ]:          0 :         if (request) {
     638                 :          0 :                 request->report_results = true;
     639                 :          0 :                 queue_work(cfg80211_wq, &rdev->sched_scan_res_wk);
     640                 :            :         }
     641                 :          0 :         rcu_read_unlock();
     642                 :          0 : }
     643                 :            : EXPORT_SYMBOL(cfg80211_sched_scan_results);
     644                 :            : 
     645                 :          0 : void cfg80211_sched_scan_stopped_rtnl(struct wiphy *wiphy, u64 reqid)
     646                 :            : {
     647         [ #  # ]:          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
     648                 :            : 
     649   [ #  #  #  # ]:          0 :         ASSERT_RTNL();
     650                 :            : 
     651                 :          0 :         trace_cfg80211_sched_scan_stopped(wiphy, reqid);
     652                 :            : 
     653                 :          0 :         __cfg80211_stop_sched_scan(rdev, reqid, true);
     654                 :          0 : }
     655                 :            : EXPORT_SYMBOL(cfg80211_sched_scan_stopped_rtnl);
     656                 :            : 
     657                 :          0 : void cfg80211_sched_scan_stopped(struct wiphy *wiphy, u64 reqid)
     658                 :            : {
     659                 :          0 :         rtnl_lock();
     660                 :          0 :         cfg80211_sched_scan_stopped_rtnl(wiphy, reqid);
     661                 :          0 :         rtnl_unlock();
     662                 :          0 : }
     663                 :            : EXPORT_SYMBOL(cfg80211_sched_scan_stopped);
     664                 :            : 
     665                 :          0 : int cfg80211_stop_sched_scan_req(struct cfg80211_registered_device *rdev,
     666                 :            :                                  struct cfg80211_sched_scan_request *req,
     667                 :            :                                  bool driver_initiated)
     668                 :            : {
     669   [ #  #  #  # ]:          0 :         ASSERT_RTNL();
     670                 :            : 
     671         [ #  # ]:          0 :         if (!driver_initiated) {
     672                 :          0 :                 int err = rdev_sched_scan_stop(rdev, req->dev, req->reqid);
     673         [ #  # ]:          0 :                 if (err)
     674                 :            :                         return err;
     675                 :            :         }
     676                 :            : 
     677                 :          0 :         nl80211_send_sched_scan(req, NL80211_CMD_SCHED_SCAN_STOPPED);
     678                 :            : 
     679                 :          0 :         cfg80211_del_sched_scan_req(rdev, req);
     680                 :            : 
     681                 :          0 :         return 0;
     682                 :            : }
     683                 :            : 
     684                 :          0 : int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
     685                 :            :                                u64 reqid, bool driver_initiated)
     686                 :            : {
     687                 :          0 :         struct cfg80211_sched_scan_request *sched_scan_req;
     688                 :            : 
     689   [ #  #  #  # ]:          0 :         ASSERT_RTNL();
     690                 :            : 
     691                 :          0 :         sched_scan_req = cfg80211_find_sched_scan_req(rdev, reqid);
     692         [ #  # ]:          0 :         if (!sched_scan_req)
     693                 :            :                 return -ENOENT;
     694                 :            : 
     695                 :          0 :         return cfg80211_stop_sched_scan_req(rdev, sched_scan_req,
     696                 :            :                                             driver_initiated);
     697                 :            : }
     698                 :            : 
     699                 :          0 : void cfg80211_bss_age(struct cfg80211_registered_device *rdev,
     700                 :            :                       unsigned long age_secs)
     701                 :            : {
     702                 :          0 :         struct cfg80211_internal_bss *bss;
     703         [ #  # ]:          0 :         unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
     704                 :            : 
     705                 :          0 :         spin_lock_bh(&rdev->bss_lock);
     706         [ #  # ]:          0 :         list_for_each_entry(bss, &rdev->bss_list, list)
     707                 :          0 :                 bss->ts -= age_jiffies;
     708                 :          0 :         spin_unlock_bh(&rdev->bss_lock);
     709                 :          0 : }
     710                 :            : 
     711                 :          0 : void cfg80211_bss_expire(struct cfg80211_registered_device *rdev)
     712                 :            : {
     713                 :          0 :         __cfg80211_bss_expire(rdev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE);
     714                 :          0 : }
     715                 :            : 
     716                 :            : const struct element *
     717                 :          0 : cfg80211_find_elem_match(u8 eid, const u8 *ies, unsigned int len,
     718                 :            :                          const u8 *match, unsigned int match_len,
     719                 :            :                          unsigned int match_offset)
     720                 :            : {
     721                 :          0 :         const struct element *elem;
     722                 :            : 
     723   [ #  #  #  #  :          0 :         for_each_element_id(elem, eid, ies, len) {
                   #  # ]
     724         [ #  # ]:          0 :                 if (elem->datalen >= match_offset + match_len &&
     725         [ #  # ]:          0 :                     !memcmp(elem->data + match_offset, match, match_len))
     726                 :          0 :                         return elem;
     727                 :            :         }
     728                 :            : 
     729                 :            :         return NULL;
     730                 :            : }
     731                 :            : EXPORT_SYMBOL(cfg80211_find_elem_match);
     732                 :            : 
     733                 :          0 : const struct element *cfg80211_find_vendor_elem(unsigned int oui, int oui_type,
     734                 :            :                                                 const u8 *ies,
     735                 :            :                                                 unsigned int len)
     736                 :            : {
     737                 :          0 :         const struct element *elem;
     738                 :          0 :         u8 match[] = { oui >> 16, oui >> 8, oui, oui_type };
     739         [ #  # ]:          0 :         int match_len = (oui_type < 0) ? 3 : sizeof(match);
     740                 :            : 
     741   [ #  #  #  # ]:          0 :         if (WARN_ON(oui_type > 0xff))
     742                 :            :                 return NULL;
     743                 :            : 
     744                 :          0 :         elem = cfg80211_find_elem_match(WLAN_EID_VENDOR_SPECIFIC, ies, len,
     745                 :            :                                         match, match_len, 0);
     746                 :            : 
     747   [ #  #  #  # ]:          0 :         if (!elem || elem->datalen < 4)
     748                 :          0 :                 return NULL;
     749                 :            : 
     750                 :            :         return elem;
     751                 :            : }
     752                 :            : EXPORT_SYMBOL(cfg80211_find_vendor_elem);
     753                 :            : 
     754                 :            : /**
     755                 :            :  * enum bss_compare_mode - BSS compare mode
     756                 :            :  * @BSS_CMP_REGULAR: regular compare mode (for insertion and normal find)
     757                 :            :  * @BSS_CMP_HIDE_ZLEN: find hidden SSID with zero-length mode
     758                 :            :  * @BSS_CMP_HIDE_NUL: find hidden SSID with NUL-ed out mode
     759                 :            :  */
     760                 :            : enum bss_compare_mode {
     761                 :            :         BSS_CMP_REGULAR,
     762                 :            :         BSS_CMP_HIDE_ZLEN,
     763                 :            :         BSS_CMP_HIDE_NUL,
     764                 :            : };
     765                 :            : 
     766                 :          0 : static int cmp_bss(struct cfg80211_bss *a,
     767                 :            :                    struct cfg80211_bss *b,
     768                 :            :                    enum bss_compare_mode mode)
     769                 :            : {
     770                 :          0 :         const struct cfg80211_bss_ies *a_ies, *b_ies;
     771                 :          0 :         const u8 *ie1 = NULL;
     772                 :          0 :         const u8 *ie2 = NULL;
     773                 :          0 :         int i, r;
     774                 :            : 
     775         [ #  # ]:          0 :         if (a->channel != b->channel)
     776                 :          0 :                 return b->channel->center_freq - a->channel->center_freq;
     777                 :            : 
     778         [ #  # ]:          0 :         a_ies = rcu_access_pointer(a->ies);
     779         [ #  # ]:          0 :         if (!a_ies)
     780                 :            :                 return -1;
     781         [ #  # ]:          0 :         b_ies = rcu_access_pointer(b->ies);
     782         [ #  # ]:          0 :         if (!b_ies)
     783                 :            :                 return 1;
     784                 :            : 
     785         [ #  # ]:          0 :         if (WLAN_CAPABILITY_IS_STA_BSS(a->capability))
     786                 :          0 :                 ie1 = cfg80211_find_ie(WLAN_EID_MESH_ID,
     787                 :          0 :                                        a_ies->data, a_ies->len);
     788         [ #  # ]:          0 :         if (WLAN_CAPABILITY_IS_STA_BSS(b->capability))
     789                 :          0 :                 ie2 = cfg80211_find_ie(WLAN_EID_MESH_ID,
     790                 :          0 :                                        b_ies->data, b_ies->len);
     791         [ #  # ]:          0 :         if (ie1 && ie2) {
     792                 :          0 :                 int mesh_id_cmp;
     793                 :            : 
     794         [ #  # ]:          0 :                 if (ie1[1] == ie2[1])
     795                 :          0 :                         mesh_id_cmp = memcmp(ie1 + 2, ie2 + 2, ie1[1]);
     796                 :            :                 else
     797                 :          0 :                         mesh_id_cmp = ie2[1] - ie1[1];
     798                 :            : 
     799                 :          0 :                 ie1 = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
     800                 :          0 :                                        a_ies->data, a_ies->len);
     801                 :          0 :                 ie2 = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
     802                 :          0 :                                        b_ies->data, b_ies->len);
     803         [ #  # ]:          0 :                 if (ie1 && ie2) {
     804         [ #  # ]:          0 :                         if (mesh_id_cmp)
     805                 :            :                                 return mesh_id_cmp;
     806         [ #  # ]:          0 :                         if (ie1[1] != ie2[1])
     807                 :          0 :                                 return ie2[1] - ie1[1];
     808                 :          0 :                         return memcmp(ie1 + 2, ie2 + 2, ie1[1]);
     809                 :            :                 }
     810                 :            :         }
     811                 :            : 
     812                 :          0 :         r = memcmp(a->bssid, b->bssid, sizeof(a->bssid));
     813         [ #  # ]:          0 :         if (r)
     814                 :            :                 return r;
     815                 :            : 
     816                 :          0 :         ie1 = cfg80211_find_ie(WLAN_EID_SSID, a_ies->data, a_ies->len);
     817                 :          0 :         ie2 = cfg80211_find_ie(WLAN_EID_SSID, b_ies->data, b_ies->len);
     818                 :            : 
     819         [ #  # ]:          0 :         if (!ie1 && !ie2)
     820                 :            :                 return 0;
     821                 :            : 
     822                 :            :         /*
     823                 :            :          * Note that with "hide_ssid", the function returns a match if
     824                 :            :          * the already-present BSS ("b") is a hidden SSID beacon for
     825                 :            :          * the new BSS ("a").
     826                 :            :          */
     827                 :            : 
     828                 :            :         /* sort missing IE before (left of) present IE */
     829         [ #  # ]:          0 :         if (!ie1)
     830                 :            :                 return -1;
     831         [ #  # ]:          0 :         if (!ie2)
     832                 :            :                 return 1;
     833                 :            : 
     834      [ #  #  # ]:          0 :         switch (mode) {
     835                 :          0 :         case BSS_CMP_HIDE_ZLEN:
     836                 :            :                 /*
     837                 :            :                  * In ZLEN mode we assume the BSS entry we're
     838                 :            :                  * looking for has a zero-length SSID. So if
     839                 :            :                  * the one we're looking at right now has that,
     840                 :            :                  * return 0. Otherwise, return the difference
     841                 :            :                  * in length, but since we're looking for the
     842                 :            :                  * 0-length it's really equivalent to returning
     843                 :            :                  * the length of the one we're looking at.
     844                 :            :                  *
     845                 :            :                  * No content comparison is needed as we assume
     846                 :            :                  * the content length is zero.
     847                 :            :                  */
     848                 :          0 :                 return ie2[1];
     849                 :          0 :         case BSS_CMP_REGULAR:
     850                 :            :         default:
     851                 :            :                 /* sort by length first, then by contents */
     852         [ #  # ]:          0 :                 if (ie1[1] != ie2[1])
     853                 :          0 :                         return ie2[1] - ie1[1];
     854                 :          0 :                 return memcmp(ie1 + 2, ie2 + 2, ie1[1]);
     855                 :          0 :         case BSS_CMP_HIDE_NUL:
     856         [ #  # ]:          0 :                 if (ie1[1] != ie2[1])
     857                 :          0 :                         return ie2[1] - ie1[1];
     858                 :            :                 /* this is equivalent to memcmp(zeroes, ie2 + 2, len) */
     859         [ #  # ]:          0 :                 for (i = 0; i < ie2[1]; i++)
     860         [ #  # ]:          0 :                         if (ie2[i + 2])
     861                 :            :                                 return -1;
     862                 :            :                 return 0;
     863                 :            :         }
     864                 :            : }
     865                 :            : 
     866                 :          0 : static bool cfg80211_bss_type_match(u16 capability,
     867                 :            :                                     enum nl80211_band band,
     868                 :            :                                     enum ieee80211_bss_type bss_type)
     869                 :            : {
     870                 :          0 :         bool ret = true;
     871                 :          0 :         u16 mask, val;
     872                 :            : 
     873                 :          0 :         if (bss_type == IEEE80211_BSS_TYPE_ANY)
     874                 :            :                 return ret;
     875                 :            : 
     876   [ #  #  #  # ]:          0 :         if (band == NL80211_BAND_60GHZ) {
     877                 :          0 :                 mask = WLAN_CAPABILITY_DMG_TYPE_MASK;
     878   [ #  #  #  # ]:          0 :                 switch (bss_type) {
     879                 :            :                 case IEEE80211_BSS_TYPE_ESS:
     880                 :            :                         val = WLAN_CAPABILITY_DMG_TYPE_AP;
     881                 :            :                         break;
     882                 :            :                 case IEEE80211_BSS_TYPE_PBSS:
     883                 :            :                         val = WLAN_CAPABILITY_DMG_TYPE_PBSS;
     884                 :            :                         break;
     885                 :            :                 case IEEE80211_BSS_TYPE_IBSS:
     886                 :            :                         val = WLAN_CAPABILITY_DMG_TYPE_IBSS;
     887                 :            :                         break;
     888                 :            :                 default:
     889                 :            :                         return false;
     890                 :            :                 }
     891                 :            :         } else {
     892                 :          0 :                 mask = WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS;
     893   [ #  #  #  #  :          0 :                 switch (bss_type) {
             #  #  #  # ]
     894                 :            :                 case IEEE80211_BSS_TYPE_ESS:
     895                 :            :                         val = WLAN_CAPABILITY_ESS;
     896                 :            :                         break;
     897                 :          0 :                 case IEEE80211_BSS_TYPE_IBSS:
     898                 :          0 :                         val = WLAN_CAPABILITY_IBSS;
     899                 :          0 :                         break;
     900                 :          0 :                 case IEEE80211_BSS_TYPE_MBSS:
     901                 :          0 :                         val = 0;
     902                 :          0 :                         break;
     903                 :            :                 default:
     904                 :            :                         return false;
     905                 :            :                 }
     906                 :            :         }
     907                 :            : 
     908                 :          0 :         ret = ((capability & mask) == val);
     909                 :          0 :         return ret;
     910                 :            : }
     911                 :            : 
     912                 :            : /* Returned bss is reference counted and must be cleaned up appropriately. */
     913                 :          0 : struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
     914                 :            :                                       struct ieee80211_channel *channel,
     915                 :            :                                       const u8 *bssid,
     916                 :            :                                       const u8 *ssid, size_t ssid_len,
     917                 :            :                                       enum ieee80211_bss_type bss_type,
     918                 :            :                                       enum ieee80211_privacy privacy)
     919                 :            : {
     920         [ #  # ]:          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
     921                 :          0 :         struct cfg80211_internal_bss *bss, *res = NULL;
     922                 :          0 :         unsigned long now = jiffies;
     923                 :          0 :         int bss_privacy;
     924                 :            : 
     925                 :          0 :         trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, bss_type,
     926                 :            :                                privacy);
     927                 :            : 
     928                 :          0 :         spin_lock_bh(&rdev->bss_lock);
     929                 :            : 
     930         [ #  # ]:          0 :         list_for_each_entry(bss, &rdev->bss_list, list) {
     931         [ #  # ]:          0 :                 if (!cfg80211_bss_type_match(bss->pub.capability,
     932         [ #  # ]:          0 :                                              bss->pub.channel->band, bss_type))
     933                 :          0 :                         continue;
     934                 :            : 
     935                 :          0 :                 bss_privacy = (bss->pub.capability & WLAN_CAPABILITY_PRIVACY);
     936         [ #  # ]:          0 :                 if ((privacy == IEEE80211_PRIVACY_ON && !bss_privacy) ||
     937         [ #  # ]:          0 :                     (privacy == IEEE80211_PRIVACY_OFF && bss_privacy))
     938                 :          0 :                         continue;
     939   [ #  #  #  # ]:          0 :                 if (channel && bss->pub.channel != channel)
     940                 :          0 :                         continue;
     941   [ #  #  #  # ]:          0 :                 if (!is_valid_ether_addr(bss->pub.bssid))
     942                 :          0 :                         continue;
     943                 :            :                 /* Don't get expired BSS structs */
     944   [ #  #  #  # ]:          0 :                 if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) &&
     945                 :          0 :                     !atomic_read(&bss->hold))
     946                 :          0 :                         continue;
     947         [ #  # ]:          0 :                 if (is_bss(&bss->pub, bssid, ssid, ssid_len)) {
     948                 :          0 :                         res = bss;
     949         [ #  # ]:          0 :                         bss_ref_get(rdev, res);
     950                 :            :                         break;
     951                 :            :                 }
     952                 :            :         }
     953                 :            : 
     954                 :          0 :         spin_unlock_bh(&rdev->bss_lock);
     955         [ #  # ]:          0 :         if (!res)
     956                 :            :                 return NULL;
     957                 :          0 :         trace_cfg80211_return_bss(&res->pub);
     958                 :          0 :         return &res->pub;
     959                 :            : }
     960                 :            : EXPORT_SYMBOL(cfg80211_get_bss);
     961                 :            : 
     962                 :          0 : static void rb_insert_bss(struct cfg80211_registered_device *rdev,
     963                 :            :                           struct cfg80211_internal_bss *bss)
     964                 :            : {
     965                 :          0 :         struct rb_node **p = &rdev->bss_tree.rb_node;
     966                 :          0 :         struct rb_node *parent = NULL;
     967                 :          0 :         struct cfg80211_internal_bss *tbss;
     968                 :          0 :         int cmp;
     969                 :            : 
     970         [ #  # ]:          0 :         while (*p) {
     971                 :          0 :                 parent = *p;
     972                 :          0 :                 tbss = rb_entry(parent, struct cfg80211_internal_bss, rbn);
     973                 :            : 
     974                 :          0 :                 cmp = cmp_bss(&bss->pub, &tbss->pub, BSS_CMP_REGULAR);
     975                 :            : 
     976   [ #  #  #  # ]:          0 :                 if (WARN_ON(!cmp)) {
     977                 :            :                         /* will sort of leak this BSS */
     978                 :            :                         return;
     979                 :            :                 }
     980                 :            : 
     981         [ #  # ]:          0 :                 if (cmp < 0)
     982                 :          0 :                         p = &(*p)->rb_left;
     983                 :            :                 else
     984                 :          0 :                         p = &(*p)->rb_right;
     985                 :            :         }
     986                 :            : 
     987                 :          0 :         rb_link_node(&bss->rbn, parent, p);
     988                 :          0 :         rb_insert_color(&bss->rbn, &rdev->bss_tree);
     989                 :            : }
     990                 :            : 
     991                 :            : static struct cfg80211_internal_bss *
     992                 :            : rb_find_bss(struct cfg80211_registered_device *rdev,
     993                 :            :             struct cfg80211_internal_bss *res,
     994                 :            :             enum bss_compare_mode mode)
     995                 :            : {
     996                 :            :         struct rb_node *n = rdev->bss_tree.rb_node;
     997                 :            :         struct cfg80211_internal_bss *bss;
     998                 :            :         int r;
     999                 :            : 
    1000                 :            :         while (n) {
    1001                 :            :                 bss = rb_entry(n, struct cfg80211_internal_bss, rbn);
    1002                 :            :                 r = cmp_bss(&res->pub, &bss->pub, mode);
    1003                 :            : 
    1004                 :            :                 if (r == 0)
    1005                 :            :                         return bss;
    1006                 :            :                 else if (r < 0)
    1007                 :            :                         n = n->rb_left;
    1008                 :            :                 else
    1009                 :            :                         n = n->rb_right;
    1010                 :            :         }
    1011                 :            : 
    1012                 :            :         return NULL;
    1013                 :            : }
    1014                 :            : 
    1015                 :          0 : static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
    1016                 :            :                                    struct cfg80211_internal_bss *new)
    1017                 :            : {
    1018                 :          0 :         const struct cfg80211_bss_ies *ies;
    1019                 :          0 :         struct cfg80211_internal_bss *bss;
    1020                 :          0 :         const u8 *ie;
    1021                 :          0 :         int i, ssidlen;
    1022                 :          0 :         u8 fold = 0;
    1023                 :          0 :         u32 n_entries = 0;
    1024                 :            : 
    1025         [ #  # ]:          0 :         ies = rcu_access_pointer(new->pub.beacon_ies);
    1026   [ #  #  #  # ]:          0 :         if (WARN_ON(!ies))
    1027                 :            :                 return false;
    1028                 :            : 
    1029                 :          0 :         ie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
    1030         [ #  # ]:          0 :         if (!ie) {
    1031                 :            :                 /* nothing to do */
    1032                 :            :                 return true;
    1033                 :            :         }
    1034                 :            : 
    1035                 :          0 :         ssidlen = ie[1];
    1036         [ #  # ]:          0 :         for (i = 0; i < ssidlen; i++)
    1037                 :          0 :                 fold |= ie[2 + i];
    1038                 :            : 
    1039         [ #  # ]:          0 :         if (fold) {
    1040                 :            :                 /* not a hidden SSID */
    1041                 :            :                 return true;
    1042                 :            :         }
    1043                 :            : 
    1044                 :            :         /* This is the bad part ... */
    1045                 :            : 
    1046         [ #  # ]:          0 :         list_for_each_entry(bss, &rdev->bss_list, list) {
    1047                 :            :                 /*
    1048                 :            :                  * we're iterating all the entries anyway, so take the
    1049                 :            :                  * opportunity to validate the list length accounting
    1050                 :            :                  */
    1051                 :          0 :                 n_entries++;
    1052                 :            : 
    1053         [ #  # ]:          0 :                 if (!ether_addr_equal(bss->pub.bssid, new->pub.bssid))
    1054                 :          0 :                         continue;
    1055         [ #  # ]:          0 :                 if (bss->pub.channel != new->pub.channel)
    1056                 :          0 :                         continue;
    1057         [ #  # ]:          0 :                 if (bss->pub.scan_width != new->pub.scan_width)
    1058                 :          0 :                         continue;
    1059         [ #  # ]:          0 :                 if (rcu_access_pointer(bss->pub.beacon_ies))
    1060                 :          0 :                         continue;
    1061         [ #  # ]:          0 :                 ies = rcu_access_pointer(bss->pub.ies);
    1062         [ #  # ]:          0 :                 if (!ies)
    1063                 :          0 :                         continue;
    1064                 :          0 :                 ie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
    1065         [ #  # ]:          0 :                 if (!ie)
    1066                 :          0 :                         continue;
    1067   [ #  #  #  # ]:          0 :                 if (ssidlen && ie[1] != ssidlen)
    1068                 :          0 :                         continue;
    1069   [ #  #  #  # ]:          0 :                 if (WARN_ON_ONCE(bss->pub.hidden_beacon_bss))
    1070                 :          0 :                         continue;
    1071   [ #  #  #  # ]:          0 :                 if (WARN_ON_ONCE(!list_empty(&bss->hidden_list)))
    1072                 :          0 :                         list_del(&bss->hidden_list);
    1073                 :            :                 /* combine them */
    1074                 :          0 :                 list_add(&bss->hidden_list, &new->hidden_list);
    1075                 :          0 :                 bss->pub.hidden_beacon_bss = &new->pub;
    1076                 :          0 :                 new->refcount += bss->refcount;
    1077                 :          0 :                 rcu_assign_pointer(bss->pub.beacon_ies,
    1078                 :            :                                    new->pub.beacon_ies);
    1079                 :            :         }
    1080                 :            : 
    1081   [ #  #  #  # ]:          0 :         WARN_ONCE(n_entries != rdev->bss_entries,
    1082                 :            :                   "rdev bss entries[%d]/list[len:%d] corruption\n",
    1083                 :            :                   rdev->bss_entries, n_entries);
    1084                 :            : 
    1085                 :            :         return true;
    1086                 :            : }
    1087                 :            : 
    1088                 :            : struct cfg80211_non_tx_bss {
    1089                 :            :         struct cfg80211_bss *tx_bss;
    1090                 :            :         u8 max_bssid_indicator;
    1091                 :            :         u8 bssid_index;
    1092                 :            : };
    1093                 :            : 
    1094                 :            : static bool
    1095                 :          0 : cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
    1096                 :            :                           struct cfg80211_internal_bss *known,
    1097                 :            :                           struct cfg80211_internal_bss *new,
    1098                 :            :                           bool signal_valid)
    1099                 :            : {
    1100                 :          0 :         lockdep_assert_held(&rdev->bss_lock);
    1101                 :            : 
    1102                 :            :         /* Update IEs */
    1103         [ #  # ]:          0 :         if (rcu_access_pointer(new->pub.proberesp_ies)) {
    1104                 :          0 :                 const struct cfg80211_bss_ies *old;
    1105                 :            : 
    1106                 :          0 :                 old = rcu_access_pointer(known->pub.proberesp_ies);
    1107                 :            : 
    1108                 :          0 :                 rcu_assign_pointer(known->pub.proberesp_ies,
    1109                 :            :                                    new->pub.proberesp_ies);
    1110                 :            :                 /* Override possible earlier Beacon frame IEs */
    1111         [ #  # ]:          0 :                 rcu_assign_pointer(known->pub.ies,
    1112                 :            :                                    new->pub.proberesp_ies);
    1113         [ #  # ]:          0 :                 if (old)
    1114                 :          0 :                         kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
    1115         [ #  # ]:          0 :         } else if (rcu_access_pointer(new->pub.beacon_ies)) {
    1116                 :          0 :                 const struct cfg80211_bss_ies *old;
    1117                 :          0 :                 struct cfg80211_internal_bss *bss;
    1118                 :            : 
    1119   [ #  #  #  # ]:          0 :                 if (known->pub.hidden_beacon_bss &&
    1120         [ #  # ]:          0 :                     !list_empty(&known->hidden_list)) {
    1121                 :          0 :                         const struct cfg80211_bss_ies *f;
    1122                 :            : 
    1123                 :            :                         /* The known BSS struct is one of the probe
    1124                 :            :                          * response members of a group, but we're
    1125                 :            :                          * receiving a beacon (beacon_ies in the new
    1126                 :            :                          * bss is used). This can only mean that the
    1127                 :            :                          * AP changed its beacon from not having an
    1128                 :            :                          * SSID to showing it, which is confusing so
    1129                 :            :                          * drop this information.
    1130                 :            :                          */
    1131                 :            : 
    1132         [ #  # ]:          0 :                         f = rcu_access_pointer(new->pub.beacon_ies);
    1133         [ #  # ]:          0 :                         kfree_rcu((struct cfg80211_bss_ies *)f, rcu_head);
    1134                 :          0 :                         return false;
    1135                 :            :                 }
    1136                 :            : 
    1137                 :          0 :                 old = rcu_access_pointer(known->pub.beacon_ies);
    1138                 :            : 
    1139         [ #  # ]:          0 :                 rcu_assign_pointer(known->pub.beacon_ies, new->pub.beacon_ies);
    1140                 :            : 
    1141                 :            :                 /* Override IEs if they were from a beacon before */
    1142         [ #  # ]:          0 :                 if (old == rcu_access_pointer(known->pub.ies))
    1143                 :          0 :                         rcu_assign_pointer(known->pub.ies, new->pub.beacon_ies);
    1144                 :            : 
    1145                 :            :                 /* Assign beacon IEs to all sub entries */
    1146         [ #  # ]:          0 :                 list_for_each_entry(bss, &known->hidden_list, hidden_list) {
    1147                 :          0 :                         const struct cfg80211_bss_ies *ies;
    1148                 :            : 
    1149         [ #  # ]:          0 :                         ies = rcu_access_pointer(bss->pub.beacon_ies);
    1150         [ #  # ]:          0 :                         WARN_ON(ies != old);
    1151                 :            : 
    1152                 :          0 :                         rcu_assign_pointer(bss->pub.beacon_ies,
    1153                 :            :                                            new->pub.beacon_ies);
    1154                 :            :                 }
    1155                 :            : 
    1156         [ #  # ]:          0 :                 if (old)
    1157                 :          0 :                         kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
    1158                 :            :         }
    1159                 :            : 
    1160                 :          0 :         known->pub.beacon_interval = new->pub.beacon_interval;
    1161                 :            : 
    1162                 :            :         /* don't update the signal if beacon was heard on
    1163                 :            :          * adjacent channel.
    1164                 :            :          */
    1165         [ #  # ]:          0 :         if (signal_valid)
    1166                 :          0 :                 known->pub.signal = new->pub.signal;
    1167                 :          0 :         known->pub.capability = new->pub.capability;
    1168                 :          0 :         known->ts = new->ts;
    1169                 :          0 :         known->ts_boottime = new->ts_boottime;
    1170                 :          0 :         known->parent_tsf = new->parent_tsf;
    1171                 :          0 :         known->pub.chains = new->pub.chains;
    1172                 :          0 :         memcpy(known->pub.chain_signal, new->pub.chain_signal,
    1173                 :            :                IEEE80211_MAX_CHAINS);
    1174                 :          0 :         ether_addr_copy(known->parent_bssid, new->parent_bssid);
    1175                 :          0 :         known->pub.max_bssid_indicator = new->pub.max_bssid_indicator;
    1176                 :          0 :         known->pub.bssid_index = new->pub.bssid_index;
    1177                 :            : 
    1178                 :          0 :         return true;
    1179                 :            : }
    1180                 :            : 
    1181                 :            : /* Returned bss is reference counted and must be cleaned up appropriately. */
    1182                 :            : struct cfg80211_internal_bss *
    1183                 :          0 : cfg80211_bss_update(struct cfg80211_registered_device *rdev,
    1184                 :            :                     struct cfg80211_internal_bss *tmp,
    1185                 :            :                     bool signal_valid, unsigned long ts)
    1186                 :            : {
    1187                 :          0 :         struct cfg80211_internal_bss *found = NULL;
    1188                 :            : 
    1189   [ #  #  #  # ]:          0 :         if (WARN_ON(!tmp->pub.channel))
    1190                 :            :                 return NULL;
    1191                 :            : 
    1192                 :          0 :         tmp->ts = ts;
    1193                 :            : 
    1194                 :          0 :         spin_lock_bh(&rdev->bss_lock);
    1195                 :            : 
    1196   [ #  #  #  # ]:          0 :         if (WARN_ON(!rcu_access_pointer(tmp->pub.ies))) {
    1197                 :          0 :                 spin_unlock_bh(&rdev->bss_lock);
    1198                 :          0 :                 return NULL;
    1199                 :            :         }
    1200                 :            : 
    1201                 :          0 :         found = rb_find_bss(rdev, tmp, BSS_CMP_REGULAR);
    1202                 :            : 
    1203         [ #  # ]:          0 :         if (found) {
    1204         [ #  # ]:          0 :                 if (!cfg80211_update_known_bss(rdev, found, tmp, signal_valid))
    1205                 :          0 :                         goto drop;
    1206                 :            :         } else {
    1207                 :          0 :                 struct cfg80211_internal_bss *new;
    1208                 :          0 :                 struct cfg80211_internal_bss *hidden;
    1209                 :          0 :                 struct cfg80211_bss_ies *ies;
    1210                 :            : 
    1211                 :            :                 /*
    1212                 :            :                  * create a copy -- the "res" variable that is passed in
    1213                 :            :                  * is allocated on the stack since it's not needed in the
    1214                 :            :                  * more common case of an update
    1215                 :            :                  */
    1216                 :          0 :                 new = kzalloc(sizeof(*new) + rdev->wiphy.bss_priv_size,
    1217                 :            :                               GFP_ATOMIC);
    1218         [ #  # ]:          0 :                 if (!new) {
    1219         [ #  # ]:          0 :                         ies = (void *)rcu_dereference(tmp->pub.beacon_ies);
    1220         [ #  # ]:          0 :                         if (ies)
    1221                 :          0 :                                 kfree_rcu(ies, rcu_head);
    1222         [ #  # ]:          0 :                         ies = (void *)rcu_dereference(tmp->pub.proberesp_ies);
    1223         [ #  # ]:          0 :                         if (ies)
    1224                 :          0 :                                 kfree_rcu(ies, rcu_head);
    1225                 :          0 :                         goto drop;
    1226                 :            :                 }
    1227                 :          0 :                 memcpy(new, tmp, sizeof(*new));
    1228                 :          0 :                 new->refcount = 1;
    1229         [ #  # ]:          0 :                 INIT_LIST_HEAD(&new->hidden_list);
    1230                 :          0 :                 INIT_LIST_HEAD(&new->pub.nontrans_list);
    1231                 :            : 
    1232         [ #  # ]:          0 :                 if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
    1233                 :          0 :                         hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN);
    1234         [ #  # ]:          0 :                         if (!hidden)
    1235                 :          0 :                                 hidden = rb_find_bss(rdev, tmp,
    1236                 :            :                                                      BSS_CMP_HIDE_NUL);
    1237         [ #  # ]:          0 :                         if (hidden) {
    1238                 :          0 :                                 new->pub.hidden_beacon_bss = &hidden->pub;
    1239                 :          0 :                                 list_add(&new->hidden_list,
    1240                 :            :                                          &hidden->hidden_list);
    1241                 :          0 :                                 hidden->refcount++;
    1242                 :          0 :                                 rcu_assign_pointer(new->pub.beacon_ies,
    1243                 :            :                                                    hidden->pub.beacon_ies);
    1244                 :            :                         }
    1245                 :            :                 } else {
    1246                 :            :                         /*
    1247                 :            :                          * Ok so we found a beacon, and don't have an entry. If
    1248                 :            :                          * it's a beacon with hidden SSID, we might be in for an
    1249                 :            :                          * expensive search for any probe responses that should
    1250                 :            :                          * be grouped with this beacon for updates ...
    1251                 :            :                          */
    1252         [ #  # ]:          0 :                         if (!cfg80211_combine_bsses(rdev, new)) {
    1253                 :          0 :                                 kfree(new);
    1254                 :          0 :                                 goto drop;
    1255                 :            :                         }
    1256                 :            :                 }
    1257                 :            : 
    1258   [ #  #  #  # ]:          0 :                 if (rdev->bss_entries >= bss_entries_limit &&
    1259                 :          0 :                     !cfg80211_bss_expire_oldest(rdev)) {
    1260                 :          0 :                         kfree(new);
    1261                 :          0 :                         goto drop;
    1262                 :            :                 }
    1263                 :            : 
    1264                 :            :                 /* This must be before the call to bss_ref_get */
    1265         [ #  # ]:          0 :                 if (tmp->pub.transmitted_bss) {
    1266                 :          0 :                         struct cfg80211_internal_bss *pbss =
    1267                 :          0 :                                 container_of(tmp->pub.transmitted_bss,
    1268                 :            :                                              struct cfg80211_internal_bss,
    1269                 :            :                                              pub);
    1270                 :            : 
    1271                 :          0 :                         new->pub.transmitted_bss = tmp->pub.transmitted_bss;
    1272         [ #  # ]:          0 :                         bss_ref_get(rdev, pbss);
    1273                 :            :                 }
    1274                 :            : 
    1275                 :          0 :                 list_add_tail(&new->list, &rdev->bss_list);
    1276                 :          0 :                 rdev->bss_entries++;
    1277                 :          0 :                 rb_insert_bss(rdev, new);
    1278                 :          0 :                 found = new;
    1279                 :            :         }
    1280                 :            : 
    1281                 :          0 :         rdev->bss_generation++;
    1282         [ #  # ]:          0 :         bss_ref_get(rdev, found);
    1283                 :          0 :         spin_unlock_bh(&rdev->bss_lock);
    1284                 :            : 
    1285                 :          0 :         return found;
    1286                 :          0 :  drop:
    1287                 :          0 :         spin_unlock_bh(&rdev->bss_lock);
    1288                 :          0 :         return NULL;
    1289                 :            : }
    1290                 :            : 
    1291                 :            : /*
    1292                 :            :  * Update RX channel information based on the available frame payload
    1293                 :            :  * information. This is mainly for the 2.4 GHz band where frames can be received
    1294                 :            :  * from neighboring channels and the Beacon frames use the DSSS Parameter Set
    1295                 :            :  * element to indicate the current (transmitting) channel, but this might also
    1296                 :            :  * be needed on other bands if RX frequency does not match with the actual
    1297                 :            :  * operating channel of a BSS.
    1298                 :            :  */
    1299                 :            : static struct ieee80211_channel *
    1300                 :          0 : cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
    1301                 :            :                          struct ieee80211_channel *channel,
    1302                 :            :                          enum nl80211_bss_scan_width scan_width)
    1303                 :            : {
    1304                 :          0 :         const u8 *tmp;
    1305                 :          0 :         u32 freq;
    1306                 :          0 :         int channel_number = -1;
    1307                 :          0 :         struct ieee80211_channel *alt_channel;
    1308                 :            : 
    1309                 :          0 :         tmp = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ie, ielen);
    1310   [ #  #  #  # ]:          0 :         if (tmp && tmp[1] == 1) {
    1311                 :          0 :                 channel_number = tmp[2];
    1312                 :            :         } else {
    1313                 :          0 :                 tmp = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ie, ielen);
    1314   [ #  #  #  # ]:          0 :                 if (tmp && tmp[1] >= sizeof(struct ieee80211_ht_operation)) {
    1315                 :          0 :                         struct ieee80211_ht_operation *htop = (void *)(tmp + 2);
    1316                 :            : 
    1317                 :          0 :                         channel_number = htop->primary_chan;
    1318                 :            :                 }
    1319                 :            :         }
    1320                 :            : 
    1321                 :          0 :         if (channel_number < 0) {
    1322                 :            :                 /* No channel information in frame payload */
    1323                 :            :                 return channel;
    1324                 :            :         }
    1325                 :            : 
    1326                 :          0 :         freq = ieee80211_channel_to_frequency(channel_number, channel->band);
    1327                 :          0 :         alt_channel = ieee80211_get_channel(wiphy, freq);
    1328         [ #  # ]:          0 :         if (!alt_channel) {
    1329         [ #  # ]:          0 :                 if (channel->band == NL80211_BAND_2GHZ) {
    1330                 :            :                         /*
    1331                 :            :                          * Better not allow unexpected channels when that could
    1332                 :            :                          * be going beyond the 1-11 range (e.g., discovering
    1333                 :            :                          * BSS on channel 12 when radio is configured for
    1334                 :            :                          * channel 11.
    1335                 :            :                          */
    1336                 :            :                         return NULL;
    1337                 :            :                 }
    1338                 :            : 
    1339                 :            :                 /* No match for the payload channel number - ignore it */
    1340                 :          0 :                 return channel;
    1341                 :            :         }
    1342                 :            : 
    1343         [ #  # ]:          0 :         if (scan_width == NL80211_BSS_CHAN_WIDTH_10 ||
    1344                 :            :             scan_width == NL80211_BSS_CHAN_WIDTH_5) {
    1345                 :            :                 /*
    1346                 :            :                  * Ignore channel number in 5 and 10 MHz channels where there
    1347                 :            :                  * may not be an n:1 or 1:n mapping between frequencies and
    1348                 :            :                  * channel numbers.
    1349                 :            :                  */
    1350                 :            :                 return channel;
    1351                 :            :         }
    1352                 :            : 
    1353                 :            :         /*
    1354                 :            :          * Use the channel determined through the payload channel number
    1355                 :            :          * instead of the RX channel reported by the driver.
    1356                 :            :          */
    1357         [ #  # ]:          0 :         if (alt_channel->flags & IEEE80211_CHAN_DISABLED)
    1358                 :          0 :                 return NULL;
    1359                 :            :         return alt_channel;
    1360                 :            : }
    1361                 :            : 
    1362                 :            : /* Returned bss is reference counted and must be cleaned up appropriately. */
    1363                 :            : static struct cfg80211_bss *
    1364                 :          0 : cfg80211_inform_single_bss_data(struct wiphy *wiphy,
    1365                 :            :                                 struct cfg80211_inform_bss *data,
    1366                 :            :                                 enum cfg80211_bss_frame_type ftype,
    1367                 :            :                                 const u8 *bssid, u64 tsf, u16 capability,
    1368                 :            :                                 u16 beacon_interval, const u8 *ie, size_t ielen,
    1369                 :            :                                 struct cfg80211_non_tx_bss *non_tx_data,
    1370                 :            :                                 gfp_t gfp)
    1371                 :            : {
    1372         [ #  # ]:          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
    1373                 :          0 :         struct cfg80211_bss_ies *ies;
    1374                 :          0 :         struct ieee80211_channel *channel;
    1375                 :          0 :         struct cfg80211_internal_bss tmp = {}, *res;
    1376                 :          0 :         int bss_type;
    1377                 :          0 :         bool signal_valid;
    1378                 :          0 :         unsigned long ts;
    1379                 :            : 
    1380                 :          0 :         if (WARN_ON(!wiphy))
    1381                 :            :                 return NULL;
    1382                 :            : 
    1383   [ #  #  #  #  :          0 :         if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
             #  #  #  # ]
    1384                 :            :                     (data->signal < 0 || data->signal > 100)))
    1385                 :            :                 return NULL;
    1386                 :            : 
    1387                 :          0 :         channel = cfg80211_get_bss_channel(wiphy, ie, ielen, data->chan,
    1388                 :            :                                            data->scan_width);
    1389         [ #  # ]:          0 :         if (!channel)
    1390                 :            :                 return NULL;
    1391                 :            : 
    1392                 :          0 :         memcpy(tmp.pub.bssid, bssid, ETH_ALEN);
    1393                 :          0 :         tmp.pub.channel = channel;
    1394                 :          0 :         tmp.pub.scan_width = data->scan_width;
    1395                 :          0 :         tmp.pub.signal = data->signal;
    1396                 :          0 :         tmp.pub.beacon_interval = beacon_interval;
    1397                 :          0 :         tmp.pub.capability = capability;
    1398                 :          0 :         tmp.ts_boottime = data->boottime_ns;
    1399         [ #  # ]:          0 :         if (non_tx_data) {
    1400                 :          0 :                 tmp.pub.transmitted_bss = non_tx_data->tx_bss;
    1401                 :          0 :                 ts = bss_from_pub(non_tx_data->tx_bss)->ts;
    1402                 :          0 :                 tmp.pub.bssid_index = non_tx_data->bssid_index;
    1403                 :          0 :                 tmp.pub.max_bssid_indicator = non_tx_data->max_bssid_indicator;
    1404                 :            :         } else {
    1405                 :          0 :                 ts = jiffies;
    1406                 :            :         }
    1407                 :            : 
    1408                 :            :         /*
    1409                 :            :          * If we do not know here whether the IEs are from a Beacon or Probe
    1410                 :            :          * Response frame, we need to pick one of the options and only use it
    1411                 :            :          * with the driver that does not provide the full Beacon/Probe Response
    1412                 :            :          * frame. Use Beacon frame pointer to avoid indicating that this should
    1413                 :            :          * override the IEs pointer should we have received an earlier
    1414                 :            :          * indication of Probe Response data.
    1415                 :            :          */
    1416                 :          0 :         ies = kzalloc(sizeof(*ies) + ielen, gfp);
    1417         [ #  # ]:          0 :         if (!ies)
    1418                 :            :                 return NULL;
    1419                 :          0 :         ies->len = ielen;
    1420                 :          0 :         ies->tsf = tsf;
    1421                 :          0 :         ies->from_beacon = false;
    1422                 :          0 :         memcpy(ies->data, ie, ielen);
    1423                 :            : 
    1424   [ #  #  #  # ]:          0 :         switch (ftype) {
    1425                 :          0 :         case CFG80211_BSS_FTYPE_BEACON:
    1426                 :          0 :                 ies->from_beacon = true;
    1427                 :            :                 /* fall through */
    1428                 :          0 :         case CFG80211_BSS_FTYPE_UNKNOWN:
    1429                 :          0 :                 rcu_assign_pointer(tmp.pub.beacon_ies, ies);
    1430                 :            :                 break;
    1431                 :          0 :         case CFG80211_BSS_FTYPE_PRESP:
    1432                 :          0 :                 rcu_assign_pointer(tmp.pub.proberesp_ies, ies);
    1433                 :            :                 break;
    1434                 :            :         }
    1435                 :          0 :         rcu_assign_pointer(tmp.pub.ies, ies);
    1436                 :            : 
    1437                 :          0 :         signal_valid = abs(data->chan->center_freq - channel->center_freq) <=
    1438                 :          0 :                 wiphy->max_adj_channel_rssi_comp;
    1439                 :          0 :         res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid, ts);
    1440         [ #  # ]:          0 :         if (!res)
    1441                 :            :                 return NULL;
    1442                 :            : 
    1443         [ #  # ]:          0 :         if (channel->band == NL80211_BAND_60GHZ) {
    1444                 :          0 :                 bss_type = res->pub.capability & WLAN_CAPABILITY_DMG_TYPE_MASK;
    1445         [ #  # ]:          0 :                 if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP ||
    1446                 :            :                     bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS)
    1447                 :          0 :                         regulatory_hint_found_beacon(wiphy, channel, gfp);
    1448                 :            :         } else {
    1449         [ #  # ]:          0 :                 if (res->pub.capability & WLAN_CAPABILITY_ESS)
    1450                 :          0 :                         regulatory_hint_found_beacon(wiphy, channel, gfp);
    1451                 :            :         }
    1452                 :            : 
    1453         [ #  # ]:          0 :         if (non_tx_data) {
    1454                 :            :                 /* this is a nontransmitting bss, we need to add it to
    1455                 :            :                  * transmitting bss' list if it is not there
    1456                 :            :                  */
    1457         [ #  # ]:          0 :                 if (cfg80211_add_nontrans_list(non_tx_data->tx_bss,
    1458                 :            :                                                &res->pub)) {
    1459         [ #  # ]:          0 :                         if (__cfg80211_unlink_bss(rdev, res))
    1460                 :          0 :                                 rdev->bss_generation++;
    1461                 :            :                 }
    1462                 :            :         }
    1463                 :            : 
    1464                 :          0 :         trace_cfg80211_return_bss(&res->pub);
    1465                 :            :         /* cfg80211_bss_update gives us a referenced result */
    1466                 :          0 :         return &res->pub;
    1467                 :            : }
    1468                 :            : 
    1469                 :            : static const struct element
    1470                 :          0 : *cfg80211_get_profile_continuation(const u8 *ie, size_t ielen,
    1471                 :            :                                    const struct element *mbssid_elem,
    1472                 :            :                                    const struct element *sub_elem)
    1473                 :            : {
    1474                 :          0 :         const u8 *mbssid_end = mbssid_elem->data + mbssid_elem->datalen;
    1475                 :          0 :         const struct element *next_mbssid;
    1476                 :          0 :         const struct element *next_sub;
    1477                 :            : 
    1478                 :          0 :         next_mbssid = cfg80211_find_elem(WLAN_EID_MULTIPLE_BSSID,
    1479                 :            :                                          mbssid_end,
    1480                 :          0 :                                          ielen - (mbssid_end - ie));
    1481                 :            : 
    1482                 :            :         /*
    1483                 :            :          * If is is not the last subelement in current MBSSID IE or there isn't
    1484                 :            :          * a next MBSSID IE - profile is complete.
    1485                 :            :         */
    1486   [ #  #  #  # ]:          0 :         if ((sub_elem->data + sub_elem->datalen < mbssid_end - 1) ||
    1487                 :            :             !next_mbssid)
    1488                 :            :                 return NULL;
    1489                 :            : 
    1490                 :            :         /* For any length error, just return NULL */
    1491                 :            : 
    1492         [ #  # ]:          0 :         if (next_mbssid->datalen < 4)
    1493                 :            :                 return NULL;
    1494                 :            : 
    1495                 :          0 :         next_sub = (void *)&next_mbssid->data[1];
    1496                 :            : 
    1497                 :          0 :         if (next_mbssid->data + next_mbssid->datalen <
    1498         [ #  # ]:          0 :             next_sub->data + next_sub->datalen)
    1499                 :            :                 return NULL;
    1500                 :            : 
    1501   [ #  #  #  # ]:          0 :         if (next_sub->id != 0 || next_sub->datalen < 2)
    1502                 :            :                 return NULL;
    1503                 :            : 
    1504                 :            :         /*
    1505                 :            :          * Check if the first element in the next sub element is a start
    1506                 :            :          * of a new profile
    1507                 :            :          */
    1508                 :          0 :         return next_sub->data[0] == WLAN_EID_NON_TX_BSSID_CAP ?
    1509         [ #  # ]:          0 :                NULL : next_mbssid;
    1510                 :            : }
    1511                 :            : 
    1512                 :          0 : size_t cfg80211_merge_profile(const u8 *ie, size_t ielen,
    1513                 :            :                               const struct element *mbssid_elem,
    1514                 :            :                               const struct element *sub_elem,
    1515                 :            :                               u8 *merged_ie, size_t max_copy_len)
    1516                 :            : {
    1517                 :          0 :         size_t copied_len = sub_elem->datalen;
    1518                 :          0 :         const struct element *next_mbssid;
    1519                 :            : 
    1520         [ #  # ]:          0 :         if (sub_elem->datalen > max_copy_len)
    1521                 :            :                 return 0;
    1522                 :            : 
    1523                 :          0 :         memcpy(merged_ie, sub_elem->data, sub_elem->datalen);
    1524                 :            : 
    1525         [ #  # ]:          0 :         while ((next_mbssid = cfg80211_get_profile_continuation(ie, ielen,
    1526                 :            :                                                                 mbssid_elem,
    1527                 :            :                                                                 sub_elem))) {
    1528                 :          0 :                 const struct element *next_sub = (void *)&next_mbssid->data[1];
    1529                 :            : 
    1530         [ #  # ]:          0 :                 if (copied_len + next_sub->datalen > max_copy_len)
    1531                 :            :                         break;
    1532                 :          0 :                 memcpy(merged_ie + copied_len, next_sub->data,
    1533                 :            :                        next_sub->datalen);
    1534                 :          0 :                 copied_len += next_sub->datalen;
    1535                 :            :         }
    1536                 :            : 
    1537                 :            :         return copied_len;
    1538                 :            : }
    1539                 :            : EXPORT_SYMBOL(cfg80211_merge_profile);
    1540                 :            : 
    1541                 :          0 : static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
    1542                 :            :                                        struct cfg80211_inform_bss *data,
    1543                 :            :                                        enum cfg80211_bss_frame_type ftype,
    1544                 :            :                                        const u8 *bssid, u64 tsf,
    1545                 :            :                                        u16 beacon_interval, const u8 *ie,
    1546                 :            :                                        size_t ielen,
    1547                 :            :                                        struct cfg80211_non_tx_bss *non_tx_data,
    1548                 :            :                                        gfp_t gfp)
    1549                 :            : {
    1550                 :          0 :         const u8 *mbssid_index_ie;
    1551                 :          0 :         const struct element *elem, *sub;
    1552                 :          0 :         size_t new_ie_len;
    1553                 :          0 :         u8 new_bssid[ETH_ALEN];
    1554                 :          0 :         u8 *new_ie, *profile;
    1555                 :          0 :         u64 seen_indices = 0;
    1556                 :          0 :         u16 capability;
    1557                 :          0 :         struct cfg80211_bss *bss;
    1558                 :            : 
    1559         [ #  # ]:          0 :         if (!non_tx_data)
    1560                 :          0 :                 return;
    1561         [ #  # ]:          0 :         if (!cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
    1562                 :            :                 return;
    1563         [ #  # ]:          0 :         if (!wiphy->support_mbssid)
    1564                 :            :                 return;
    1565         [ #  # ]:          0 :         if (wiphy->support_only_he_mbssid &&
    1566         [ #  # ]:          0 :             !cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ie, ielen))
    1567                 :            :                 return;
    1568                 :            : 
    1569         [ #  # ]:          0 :         new_ie = kmalloc(IEEE80211_MAX_DATA_LEN, gfp);
    1570         [ #  # ]:          0 :         if (!new_ie)
    1571                 :            :                 return;
    1572                 :            : 
    1573         [ #  # ]:          0 :         profile = kmalloc(ielen, gfp);
    1574         [ #  # ]:          0 :         if (!profile)
    1575                 :          0 :                 goto out;
    1576                 :            : 
    1577   [ #  #  #  #  :          0 :         for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) {
                   #  # ]
    1578         [ #  # ]:          0 :                 if (elem->datalen < 4)
    1579                 :          0 :                         continue;
    1580   [ #  #  #  # ]:          0 :                 for_each_element(sub, elem->data + 1, elem->datalen - 1) {
    1581                 :          0 :                         u8 profile_len;
    1582                 :            : 
    1583   [ #  #  #  # ]:          0 :                         if (sub->id != 0 || sub->datalen < 4) {
    1584                 :            :                                 /* not a valid BSS profile */
    1585                 :          0 :                                 continue;
    1586                 :            :                         }
    1587                 :            : 
    1588         [ #  # ]:          0 :                         if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP ||
    1589         [ #  # ]:          0 :                             sub->data[1] != 2) {
    1590                 :            :                                 /* The first element within the Nontransmitted
    1591                 :            :                                  * BSSID Profile is not the Nontransmitted
    1592                 :            :                                  * BSSID Capability element.
    1593                 :            :                                  */
    1594                 :          0 :                                 continue;
    1595                 :            :                         }
    1596                 :            : 
    1597                 :          0 :                         memset(profile, 0, ielen);
    1598                 :          0 :                         profile_len = cfg80211_merge_profile(ie, ielen,
    1599                 :            :                                                              elem,
    1600                 :            :                                                              sub,
    1601                 :            :                                                              profile,
    1602                 :            :                                                              ielen);
    1603                 :            : 
    1604                 :            :                         /* found a Nontransmitted BSSID Profile */
    1605                 :          0 :                         mbssid_index_ie = cfg80211_find_ie
    1606                 :            :                                 (WLAN_EID_MULTI_BSSID_IDX,
    1607                 :            :                                  profile, profile_len);
    1608   [ #  #  #  # ]:          0 :                         if (!mbssid_index_ie || mbssid_index_ie[1] < 1 ||
    1609   [ #  #  #  # ]:          0 :                             mbssid_index_ie[2] == 0 ||
    1610                 :            :                             mbssid_index_ie[2] > 46) {
    1611                 :            :                                 /* No valid Multiple BSSID-Index element */
    1612                 :          0 :                                 continue;
    1613                 :            :                         }
    1614                 :            : 
    1615                 :          0 :                         if (seen_indices & BIT_ULL(mbssid_index_ie[2]))
    1616                 :            :                                 /* We don't support legacy split of a profile */
    1617                 :          0 :                                 net_dbg_ratelimited("Partial info for BSSID index %d\n",
    1618                 :            :                                                     mbssid_index_ie[2]);
    1619                 :            : 
    1620                 :          0 :                         seen_indices |= BIT_ULL(mbssid_index_ie[2]);
    1621                 :            : 
    1622                 :          0 :                         non_tx_data->bssid_index = mbssid_index_ie[2];
    1623                 :          0 :                         non_tx_data->max_bssid_indicator = elem->data[0];
    1624                 :            : 
    1625                 :          0 :                         cfg80211_gen_new_bssid(bssid,
    1626                 :            :                                                non_tx_data->max_bssid_indicator,
    1627                 :            :                                                non_tx_data->bssid_index,
    1628                 :            :                                                new_bssid);
    1629                 :          0 :                         memset(new_ie, 0, IEEE80211_MAX_DATA_LEN);
    1630                 :          0 :                         new_ie_len = cfg80211_gen_new_ie(ie, ielen,
    1631                 :            :                                                          profile,
    1632                 :            :                                                          profile_len, new_ie,
    1633                 :            :                                                          gfp);
    1634         [ #  # ]:          0 :                         if (!new_ie_len)
    1635                 :          0 :                                 continue;
    1636                 :            : 
    1637                 :          0 :                         capability = get_unaligned_le16(profile + 2);
    1638                 :          0 :                         bss = cfg80211_inform_single_bss_data(wiphy, data,
    1639                 :            :                                                               ftype,
    1640                 :            :                                                               new_bssid, tsf,
    1641                 :            :                                                               capability,
    1642                 :            :                                                               beacon_interval,
    1643                 :            :                                                               new_ie,
    1644                 :            :                                                               new_ie_len,
    1645                 :            :                                                               non_tx_data,
    1646                 :            :                                                               gfp);
    1647         [ #  # ]:          0 :                         if (!bss)
    1648                 :            :                                 break;
    1649                 :          0 :                         cfg80211_put_bss(wiphy, bss);
    1650                 :            :                 }
    1651                 :            :         }
    1652                 :            : 
    1653                 :          0 : out:
    1654                 :          0 :         kfree(new_ie);
    1655                 :          0 :         kfree(profile);
    1656                 :            : }
    1657                 :            : 
    1658                 :            : struct cfg80211_bss *
    1659                 :          0 : cfg80211_inform_bss_data(struct wiphy *wiphy,
    1660                 :            :                          struct cfg80211_inform_bss *data,
    1661                 :            :                          enum cfg80211_bss_frame_type ftype,
    1662                 :            :                          const u8 *bssid, u64 tsf, u16 capability,
    1663                 :            :                          u16 beacon_interval, const u8 *ie, size_t ielen,
    1664                 :            :                          gfp_t gfp)
    1665                 :            : {
    1666                 :          0 :         struct cfg80211_bss *res;
    1667                 :          0 :         struct cfg80211_non_tx_bss non_tx_data;
    1668                 :            : 
    1669                 :          0 :         res = cfg80211_inform_single_bss_data(wiphy, data, ftype, bssid, tsf,
    1670                 :            :                                               capability, beacon_interval, ie,
    1671                 :            :                                               ielen, NULL, gfp);
    1672         [ #  # ]:          0 :         if (!res)
    1673                 :            :                 return NULL;
    1674                 :          0 :         non_tx_data.tx_bss = res;
    1675                 :          0 :         cfg80211_parse_mbssid_data(wiphy, data, ftype, bssid, tsf,
    1676                 :            :                                    beacon_interval, ie, ielen, &non_tx_data,
    1677                 :            :                                    gfp);
    1678                 :          0 :         return res;
    1679                 :            : }
    1680                 :            : EXPORT_SYMBOL(cfg80211_inform_bss_data);
    1681                 :            : 
    1682                 :            : static void
    1683                 :          0 : cfg80211_parse_mbssid_frame_data(struct wiphy *wiphy,
    1684                 :            :                                  struct cfg80211_inform_bss *data,
    1685                 :            :                                  struct ieee80211_mgmt *mgmt, size_t len,
    1686                 :            :                                  struct cfg80211_non_tx_bss *non_tx_data,
    1687                 :            :                                  gfp_t gfp)
    1688                 :            : {
    1689                 :          0 :         enum cfg80211_bss_frame_type ftype;
    1690                 :          0 :         const u8 *ie = mgmt->u.probe_resp.variable;
    1691                 :          0 :         size_t ielen = len - offsetof(struct ieee80211_mgmt,
    1692                 :            :                                       u.probe_resp.variable);
    1693                 :            : 
    1694         [ #  # ]:          0 :         ftype = ieee80211_is_beacon(mgmt->frame_control) ?
    1695         [ #  # ]:          0 :                 CFG80211_BSS_FTYPE_BEACON : CFG80211_BSS_FTYPE_PRESP;
    1696                 :            : 
    1697                 :          0 :         cfg80211_parse_mbssid_data(wiphy, data, ftype, mgmt->bssid,
    1698                 :          0 :                                    le64_to_cpu(mgmt->u.probe_resp.timestamp),
    1699                 :          0 :                                    le16_to_cpu(mgmt->u.probe_resp.beacon_int),
    1700                 :            :                                    ie, ielen, non_tx_data, gfp);
    1701                 :          0 : }
    1702                 :            : 
    1703                 :            : static void
    1704                 :          0 : cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
    1705                 :            :                                    struct cfg80211_bss *nontrans_bss,
    1706                 :            :                                    struct ieee80211_mgmt *mgmt, size_t len)
    1707                 :            : {
    1708                 :          0 :         u8 *ie, *new_ie, *pos;
    1709                 :          0 :         const u8 *nontrans_ssid, *trans_ssid, *mbssid;
    1710                 :          0 :         size_t ielen = len - offsetof(struct ieee80211_mgmt,
    1711                 :            :                                       u.probe_resp.variable);
    1712                 :          0 :         size_t new_ie_len;
    1713                 :          0 :         struct cfg80211_bss_ies *new_ies;
    1714                 :          0 :         const struct cfg80211_bss_ies *old;
    1715                 :          0 :         u8 cpy_len;
    1716                 :            : 
    1717         [ #  # ]:          0 :         lockdep_assert_held(&wiphy_to_rdev(wiphy)->bss_lock);
    1718                 :            : 
    1719                 :          0 :         ie = mgmt->u.probe_resp.variable;
    1720                 :            : 
    1721                 :          0 :         new_ie_len = ielen;
    1722                 :          0 :         trans_ssid = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
    1723         [ #  # ]:          0 :         if (!trans_ssid)
    1724                 :            :                 return;
    1725                 :          0 :         new_ie_len -= trans_ssid[1];
    1726                 :          0 :         mbssid = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen);
    1727                 :            :         /*
    1728                 :            :          * It's not valid to have the MBSSID element before SSID
    1729                 :            :          * ignore if that happens - the code below assumes it is
    1730                 :            :          * after (while copying things inbetween).
    1731                 :            :          */
    1732         [ #  # ]:          0 :         if (!mbssid || mbssid < trans_ssid)
    1733                 :            :                 return;
    1734                 :          0 :         new_ie_len -= mbssid[1];
    1735                 :            : 
    1736                 :          0 :         nontrans_ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID);
    1737         [ #  # ]:          0 :         if (!nontrans_ssid)
    1738                 :            :                 return;
    1739                 :            : 
    1740                 :          0 :         new_ie_len += nontrans_ssid[1];
    1741                 :            : 
    1742                 :            :         /* generate new ie for nontrans BSS
    1743                 :            :          * 1. replace SSID with nontrans BSS' SSID
    1744                 :            :          * 2. skip MBSSID IE
    1745                 :            :          */
    1746                 :          0 :         new_ie = kzalloc(new_ie_len, GFP_ATOMIC);
    1747         [ #  # ]:          0 :         if (!new_ie)
    1748                 :            :                 return;
    1749                 :            : 
    1750                 :          0 :         new_ies = kzalloc(sizeof(*new_ies) + new_ie_len, GFP_ATOMIC);
    1751         [ #  # ]:          0 :         if (!new_ies)
    1752                 :          0 :                 goto out_free;
    1753                 :            : 
    1754                 :          0 :         pos = new_ie;
    1755                 :            : 
    1756                 :            :         /* copy the nontransmitted SSID */
    1757                 :          0 :         cpy_len = nontrans_ssid[1] + 2;
    1758                 :          0 :         memcpy(pos, nontrans_ssid, cpy_len);
    1759                 :          0 :         pos += cpy_len;
    1760                 :            :         /* copy the IEs between SSID and MBSSID */
    1761                 :          0 :         cpy_len = trans_ssid[1] + 2;
    1762                 :          0 :         memcpy(pos, (trans_ssid + cpy_len), (mbssid - (trans_ssid + cpy_len)));
    1763                 :          0 :         pos += (mbssid - (trans_ssid + cpy_len));
    1764                 :            :         /* copy the IEs after MBSSID */
    1765                 :          0 :         cpy_len = mbssid[1] + 2;
    1766                 :          0 :         memcpy(pos, mbssid + cpy_len, ((ie + ielen) - (mbssid + cpy_len)));
    1767                 :            : 
    1768                 :            :         /* update ie */
    1769                 :          0 :         new_ies->len = new_ie_len;
    1770                 :          0 :         new_ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
    1771         [ #  # ]:          0 :         new_ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control);
    1772                 :          0 :         memcpy(new_ies->data, new_ie, new_ie_len);
    1773         [ #  # ]:          0 :         if (ieee80211_is_probe_resp(mgmt->frame_control)) {
    1774                 :          0 :                 old = rcu_access_pointer(nontrans_bss->proberesp_ies);
    1775                 :          0 :                 rcu_assign_pointer(nontrans_bss->proberesp_ies, new_ies);
    1776         [ #  # ]:          0 :                 rcu_assign_pointer(nontrans_bss->ies, new_ies);
    1777         [ #  # ]:          0 :                 if (old)
    1778                 :          0 :                         kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
    1779                 :            :         } else {
    1780                 :          0 :                 old = rcu_access_pointer(nontrans_bss->beacon_ies);
    1781                 :          0 :                 rcu_assign_pointer(nontrans_bss->beacon_ies, new_ies);
    1782         [ #  # ]:          0 :                 rcu_assign_pointer(nontrans_bss->ies, new_ies);
    1783         [ #  # ]:          0 :                 if (old)
    1784                 :          0 :                         kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
    1785                 :            :         }
    1786                 :            : 
    1787                 :          0 : out_free:
    1788                 :          0 :         kfree(new_ie);
    1789                 :            : }
    1790                 :            : 
    1791                 :            : /* cfg80211_inform_bss_width_frame helper */
    1792                 :            : static struct cfg80211_bss *
    1793                 :          0 : cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
    1794                 :            :                                       struct cfg80211_inform_bss *data,
    1795                 :            :                                       struct ieee80211_mgmt *mgmt, size_t len,
    1796                 :            :                                       gfp_t gfp)
    1797                 :            : {
    1798                 :          0 :         struct cfg80211_internal_bss tmp = {}, *res;
    1799                 :          0 :         struct cfg80211_bss_ies *ies;
    1800                 :          0 :         struct ieee80211_channel *channel;
    1801                 :          0 :         bool signal_valid;
    1802                 :          0 :         size_t ielen = len - offsetof(struct ieee80211_mgmt,
    1803                 :            :                                       u.probe_resp.variable);
    1804                 :          0 :         int bss_type;
    1805                 :            : 
    1806                 :          0 :         BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
    1807                 :            :                         offsetof(struct ieee80211_mgmt, u.beacon.variable));
    1808                 :            : 
    1809                 :          0 :         trace_cfg80211_inform_bss_frame(wiphy, data, mgmt, len);
    1810                 :            : 
    1811   [ #  #  #  # ]:          0 :         if (WARN_ON(!mgmt))
    1812                 :            :                 return NULL;
    1813                 :            : 
    1814   [ #  #  #  # ]:          0 :         if (WARN_ON(!wiphy))
    1815                 :            :                 return NULL;
    1816                 :            : 
    1817   [ #  #  #  #  :          0 :         if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
             #  #  #  # ]
    1818                 :            :                     (data->signal < 0 || data->signal > 100)))
    1819                 :            :                 return NULL;
    1820                 :            : 
    1821   [ #  #  #  # ]:          0 :         if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable)))
    1822                 :            :                 return NULL;
    1823                 :            : 
    1824                 :          0 :         channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable,
    1825                 :            :                                            ielen, data->chan, data->scan_width);
    1826         [ #  # ]:          0 :         if (!channel)
    1827                 :            :                 return NULL;
    1828                 :            : 
    1829                 :          0 :         ies = kzalloc(sizeof(*ies) + ielen, gfp);
    1830         [ #  # ]:          0 :         if (!ies)
    1831                 :            :                 return NULL;
    1832                 :          0 :         ies->len = ielen;
    1833                 :          0 :         ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
    1834         [ #  # ]:          0 :         ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control);
    1835                 :          0 :         memcpy(ies->data, mgmt->u.probe_resp.variable, ielen);
    1836                 :            : 
    1837         [ #  # ]:          0 :         if (ieee80211_is_probe_resp(mgmt->frame_control))
    1838                 :          0 :                 rcu_assign_pointer(tmp.pub.proberesp_ies, ies);
    1839                 :            :         else
    1840                 :          0 :                 rcu_assign_pointer(tmp.pub.beacon_ies, ies);
    1841                 :          0 :         rcu_assign_pointer(tmp.pub.ies, ies);
    1842                 :            : 
    1843                 :          0 :         memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
    1844                 :          0 :         tmp.pub.channel = channel;
    1845                 :          0 :         tmp.pub.scan_width = data->scan_width;
    1846                 :          0 :         tmp.pub.signal = data->signal;
    1847                 :          0 :         tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
    1848                 :          0 :         tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
    1849                 :          0 :         tmp.ts_boottime = data->boottime_ns;
    1850                 :          0 :         tmp.parent_tsf = data->parent_tsf;
    1851                 :          0 :         tmp.pub.chains = data->chains;
    1852                 :          0 :         memcpy(tmp.pub.chain_signal, data->chain_signal, IEEE80211_MAX_CHAINS);
    1853                 :          0 :         ether_addr_copy(tmp.parent_bssid, data->parent_bssid);
    1854                 :            : 
    1855                 :          0 :         signal_valid = abs(data->chan->center_freq - channel->center_freq) <=
    1856                 :          0 :                 wiphy->max_adj_channel_rssi_comp;
    1857                 :          0 :         res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid,
    1858                 :            :                                   jiffies);
    1859         [ #  # ]:          0 :         if (!res)
    1860                 :            :                 return NULL;
    1861                 :            : 
    1862         [ #  # ]:          0 :         if (channel->band == NL80211_BAND_60GHZ) {
    1863                 :          0 :                 bss_type = res->pub.capability & WLAN_CAPABILITY_DMG_TYPE_MASK;
    1864         [ #  # ]:          0 :                 if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP ||
    1865                 :            :                     bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS)
    1866                 :          0 :                         regulatory_hint_found_beacon(wiphy, channel, gfp);
    1867                 :            :         } else {
    1868         [ #  # ]:          0 :                 if (res->pub.capability & WLAN_CAPABILITY_ESS)
    1869                 :          0 :                         regulatory_hint_found_beacon(wiphy, channel, gfp);
    1870                 :            :         }
    1871                 :            : 
    1872                 :          0 :         trace_cfg80211_return_bss(&res->pub);
    1873                 :            :         /* cfg80211_bss_update gives us a referenced result */
    1874                 :          0 :         return &res->pub;
    1875                 :            : }
    1876                 :            : 
    1877                 :            : struct cfg80211_bss *
    1878                 :          0 : cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
    1879                 :            :                                struct cfg80211_inform_bss *data,
    1880                 :            :                                struct ieee80211_mgmt *mgmt, size_t len,
    1881                 :            :                                gfp_t gfp)
    1882                 :            : {
    1883                 :          0 :         struct cfg80211_bss *res, *tmp_bss;
    1884                 :          0 :         const u8 *ie = mgmt->u.probe_resp.variable;
    1885                 :          0 :         const struct cfg80211_bss_ies *ies1, *ies2;
    1886                 :          0 :         size_t ielen = len - offsetof(struct ieee80211_mgmt,
    1887                 :            :                                       u.probe_resp.variable);
    1888                 :          0 :         struct cfg80211_non_tx_bss non_tx_data;
    1889                 :            : 
    1890                 :          0 :         res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt,
    1891                 :            :                                                     len, gfp);
    1892   [ #  #  #  #  :          0 :         if (!res || !wiphy->support_mbssid ||
                   #  # ]
    1893                 :            :             !cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
    1894                 :          0 :                 return res;
    1895         [ #  # ]:          0 :         if (wiphy->support_only_he_mbssid &&
    1896         [ #  # ]:          0 :             !cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ie, ielen))
    1897                 :            :                 return res;
    1898                 :            : 
    1899                 :          0 :         non_tx_data.tx_bss = res;
    1900                 :            :         /* process each non-transmitting bss */
    1901                 :          0 :         cfg80211_parse_mbssid_frame_data(wiphy, data, mgmt, len,
    1902                 :            :                                          &non_tx_data, gfp);
    1903                 :            : 
    1904         [ #  # ]:          0 :         spin_lock_bh(&wiphy_to_rdev(wiphy)->bss_lock);
    1905                 :            : 
    1906                 :            :         /* check if the res has other nontransmitting bss which is not
    1907                 :            :          * in MBSSID IE
    1908                 :            :          */
    1909                 :          0 :         ies1 = rcu_access_pointer(res->ies);
    1910                 :            : 
    1911                 :            :         /* go through nontrans_list, if the timestamp of the BSS is
    1912                 :            :          * earlier than the timestamp of the transmitting BSS then
    1913                 :            :          * update it
    1914                 :            :          */
    1915         [ #  # ]:          0 :         list_for_each_entry(tmp_bss, &res->nontrans_list,
    1916                 :            :                             nontrans_list) {
    1917         [ #  # ]:          0 :                 ies2 = rcu_access_pointer(tmp_bss->ies);
    1918         [ #  # ]:          0 :                 if (ies2->tsf < ies1->tsf)
    1919                 :          0 :                         cfg80211_update_notlisted_nontrans(wiphy, tmp_bss,
    1920                 :            :                                                            mgmt, len);
    1921                 :            :         }
    1922                 :          0 :         spin_unlock_bh(&wiphy_to_rdev(wiphy)->bss_lock);
    1923                 :            : 
    1924                 :          0 :         return res;
    1925                 :            : }
    1926                 :            : EXPORT_SYMBOL(cfg80211_inform_bss_frame_data);
    1927                 :            : 
    1928                 :          0 : void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
    1929                 :            : {
    1930         [ #  # ]:          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
    1931                 :          0 :         struct cfg80211_internal_bss *bss;
    1932                 :            : 
    1933         [ #  # ]:          0 :         if (!pub)
    1934                 :            :                 return;
    1935                 :            : 
    1936                 :          0 :         bss = container_of(pub, struct cfg80211_internal_bss, pub);
    1937                 :            : 
    1938                 :          0 :         spin_lock_bh(&rdev->bss_lock);
    1939         [ #  # ]:          0 :         bss_ref_get(rdev, bss);
    1940                 :          0 :         spin_unlock_bh(&rdev->bss_lock);
    1941                 :            : }
    1942                 :            : EXPORT_SYMBOL(cfg80211_ref_bss);
    1943                 :            : 
    1944                 :          0 : void cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
    1945                 :            : {
    1946         [ #  # ]:          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
    1947                 :          0 :         struct cfg80211_internal_bss *bss;
    1948                 :            : 
    1949         [ #  # ]:          0 :         if (!pub)
    1950                 :            :                 return;
    1951                 :            : 
    1952                 :          0 :         bss = container_of(pub, struct cfg80211_internal_bss, pub);
    1953                 :            : 
    1954                 :          0 :         spin_lock_bh(&rdev->bss_lock);
    1955                 :          0 :         bss_ref_put(rdev, bss);
    1956                 :          0 :         spin_unlock_bh(&rdev->bss_lock);
    1957                 :            : }
    1958                 :            : EXPORT_SYMBOL(cfg80211_put_bss);
    1959                 :            : 
    1960                 :          0 : void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
    1961                 :            : {
    1962         [ #  # ]:          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
    1963                 :          0 :         struct cfg80211_internal_bss *bss, *tmp1;
    1964                 :          0 :         struct cfg80211_bss *nontrans_bss, *tmp;
    1965                 :            : 
    1966   [ #  #  #  # ]:          0 :         if (WARN_ON(!pub))
    1967                 :            :                 return;
    1968                 :            : 
    1969                 :          0 :         bss = container_of(pub, struct cfg80211_internal_bss, pub);
    1970                 :            : 
    1971                 :          0 :         spin_lock_bh(&rdev->bss_lock);
    1972         [ #  # ]:          0 :         if (list_empty(&bss->list))
    1973                 :          0 :                 goto out;
    1974                 :            : 
    1975         [ #  # ]:          0 :         list_for_each_entry_safe(nontrans_bss, tmp,
    1976                 :            :                                  &pub->nontrans_list,
    1977                 :            :                                  nontrans_list) {
    1978                 :          0 :                 tmp1 = container_of(nontrans_bss,
    1979                 :            :                                     struct cfg80211_internal_bss, pub);
    1980         [ #  # ]:          0 :                 if (__cfg80211_unlink_bss(rdev, tmp1))
    1981                 :          0 :                         rdev->bss_generation++;
    1982                 :            :         }
    1983                 :            : 
    1984         [ #  # ]:          0 :         if (__cfg80211_unlink_bss(rdev, bss))
    1985                 :          0 :                 rdev->bss_generation++;
    1986                 :          0 : out:
    1987                 :          0 :         spin_unlock_bh(&rdev->bss_lock);
    1988                 :            : }
    1989                 :            : EXPORT_SYMBOL(cfg80211_unlink_bss);
    1990                 :            : 
    1991                 :          0 : void cfg80211_bss_iter(struct wiphy *wiphy,
    1992                 :            :                        struct cfg80211_chan_def *chandef,
    1993                 :            :                        void (*iter)(struct wiphy *wiphy,
    1994                 :            :                                     struct cfg80211_bss *bss,
    1995                 :            :                                     void *data),
    1996                 :            :                        void *iter_data)
    1997                 :            : {
    1998         [ #  # ]:          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
    1999                 :          0 :         struct cfg80211_internal_bss *bss;
    2000                 :            : 
    2001                 :          0 :         spin_lock_bh(&rdev->bss_lock);
    2002                 :            : 
    2003         [ #  # ]:          0 :         list_for_each_entry(bss, &rdev->bss_list, list) {
    2004   [ #  #  #  # ]:          0 :                 if (!chandef || cfg80211_is_sub_chan(chandef, bss->pub.channel))
    2005                 :          0 :                         iter(wiphy, &bss->pub, iter_data);
    2006                 :            :         }
    2007                 :            : 
    2008                 :          0 :         spin_unlock_bh(&rdev->bss_lock);
    2009                 :          0 : }
    2010                 :            : EXPORT_SYMBOL(cfg80211_bss_iter);
    2011                 :            : 
    2012                 :          0 : void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev,
    2013                 :            :                                      struct ieee80211_channel *chan)
    2014                 :            : {
    2015                 :          0 :         struct wiphy *wiphy = wdev->wiphy;
    2016         [ #  # ]:          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
    2017                 :          0 :         struct cfg80211_internal_bss *cbss = wdev->current_bss;
    2018                 :          0 :         struct cfg80211_internal_bss *new = NULL;
    2019                 :          0 :         struct cfg80211_internal_bss *bss;
    2020                 :          0 :         struct cfg80211_bss *nontrans_bss;
    2021                 :          0 :         struct cfg80211_bss *tmp;
    2022                 :            : 
    2023                 :          0 :         spin_lock_bh(&rdev->bss_lock);
    2024                 :            : 
    2025                 :            :         /*
    2026                 :            :          * Some APs use CSA also for bandwidth changes, i.e., without actually
    2027                 :            :          * changing the control channel, so no need to update in such a case.
    2028                 :            :          */
    2029         [ #  # ]:          0 :         if (cbss->pub.channel == chan)
    2030                 :          0 :                 goto done;
    2031                 :            : 
    2032                 :            :         /* use transmitting bss */
    2033         [ #  # ]:          0 :         if (cbss->pub.transmitted_bss)
    2034                 :          0 :                 cbss = container_of(cbss->pub.transmitted_bss,
    2035                 :            :                                     struct cfg80211_internal_bss,
    2036                 :            :                                     pub);
    2037                 :            : 
    2038                 :          0 :         cbss->pub.channel = chan;
    2039                 :            : 
    2040         [ #  # ]:          0 :         list_for_each_entry(bss, &rdev->bss_list, list) {
    2041         [ #  # ]:          0 :                 if (!cfg80211_bss_type_match(bss->pub.capability,
    2042         [ #  # ]:          0 :                                              bss->pub.channel->band,
    2043                 :            :                                              wdev->conn_bss_type))
    2044                 :          0 :                         continue;
    2045                 :            : 
    2046         [ #  # ]:          0 :                 if (bss == cbss)
    2047                 :          0 :                         continue;
    2048                 :            : 
    2049         [ #  # ]:          0 :                 if (!cmp_bss(&bss->pub, &cbss->pub, BSS_CMP_REGULAR)) {
    2050                 :            :                         new = bss;
    2051                 :            :                         break;
    2052                 :            :                 }
    2053                 :            :         }
    2054                 :            : 
    2055         [ #  # ]:          0 :         if (new) {
    2056                 :            :                 /* to save time, update IEs for transmitting bss only */
    2057         [ #  # ]:          0 :                 if (cfg80211_update_known_bss(rdev, cbss, new, false)) {
    2058                 :          0 :                         new->pub.proberesp_ies = NULL;
    2059                 :          0 :                         new->pub.beacon_ies = NULL;
    2060                 :            :                 }
    2061                 :            : 
    2062         [ #  # ]:          0 :                 list_for_each_entry_safe(nontrans_bss, tmp,
    2063                 :            :                                          &new->pub.nontrans_list,
    2064                 :            :                                          nontrans_list) {
    2065                 :          0 :                         bss = container_of(nontrans_bss,
    2066                 :            :                                            struct cfg80211_internal_bss, pub);
    2067         [ #  # ]:          0 :                         if (__cfg80211_unlink_bss(rdev, bss))
    2068                 :          0 :                                 rdev->bss_generation++;
    2069                 :            :                 }
    2070                 :            : 
    2071         [ #  # ]:          0 :                 WARN_ON(atomic_read(&new->hold));
    2072   [ #  #  #  # ]:          0 :                 if (!WARN_ON(!__cfg80211_unlink_bss(rdev, new)))
    2073                 :          0 :                         rdev->bss_generation++;
    2074                 :            :         }
    2075                 :            : 
    2076                 :          0 :         rb_erase(&cbss->rbn, &rdev->bss_tree);
    2077                 :          0 :         rb_insert_bss(rdev, cbss);
    2078                 :          0 :         rdev->bss_generation++;
    2079                 :            : 
    2080         [ #  # ]:          0 :         list_for_each_entry_safe(nontrans_bss, tmp,
    2081                 :            :                                  &cbss->pub.nontrans_list,
    2082                 :            :                                  nontrans_list) {
    2083                 :          0 :                 bss = container_of(nontrans_bss,
    2084                 :            :                                    struct cfg80211_internal_bss, pub);
    2085                 :          0 :                 bss->pub.channel = chan;
    2086                 :          0 :                 rb_erase(&bss->rbn, &rdev->bss_tree);
    2087                 :          0 :                 rb_insert_bss(rdev, bss);
    2088                 :          0 :                 rdev->bss_generation++;
    2089                 :            :         }
    2090                 :            : 
    2091                 :          0 : done:
    2092                 :          0 :         spin_unlock_bh(&rdev->bss_lock);
    2093                 :          0 : }
    2094                 :            : 
    2095                 :            : #ifdef CONFIG_CFG80211_WEXT
    2096                 :            : static struct cfg80211_registered_device *
    2097                 :          0 : cfg80211_get_dev_from_ifindex(struct net *net, int ifindex)
    2098                 :            : {
    2099                 :          0 :         struct cfg80211_registered_device *rdev;
    2100                 :          0 :         struct net_device *dev;
    2101                 :            : 
    2102   [ #  #  #  # ]:          0 :         ASSERT_RTNL();
    2103                 :            : 
    2104                 :          0 :         dev = dev_get_by_index(net, ifindex);
    2105         [ #  # ]:          0 :         if (!dev)
    2106                 :            :                 return ERR_PTR(-ENODEV);
    2107         [ #  # ]:          0 :         if (dev->ieee80211_ptr)
    2108         [ #  # ]:          0 :                 rdev = wiphy_to_rdev(dev->ieee80211_ptr->wiphy);
    2109                 :            :         else
    2110                 :            :                 rdev = ERR_PTR(-ENODEV);
    2111                 :          0 :         dev_put(dev);
    2112                 :          0 :         return rdev;
    2113                 :            : }
    2114                 :            : 
    2115                 :          0 : int cfg80211_wext_siwscan(struct net_device *dev,
    2116                 :            :                           struct iw_request_info *info,
    2117                 :            :                           union iwreq_data *wrqu, char *extra)
    2118                 :            : {
    2119                 :          0 :         struct cfg80211_registered_device *rdev;
    2120                 :          0 :         struct wiphy *wiphy;
    2121                 :          0 :         struct iw_scan_req *wreq = NULL;
    2122                 :          0 :         struct cfg80211_scan_request *creq = NULL;
    2123                 :          0 :         int i, err, n_channels = 0;
    2124                 :          0 :         enum nl80211_band band;
    2125                 :            : 
    2126         [ #  # ]:          0 :         if (!netif_running(dev))
    2127                 :            :                 return -ENETDOWN;
    2128                 :            : 
    2129         [ #  # ]:          0 :         if (wrqu->data.length == sizeof(struct iw_scan_req))
    2130                 :          0 :                 wreq = (struct iw_scan_req *)extra;
    2131                 :            : 
    2132                 :          0 :         rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex);
    2133                 :            : 
    2134         [ #  # ]:          0 :         if (IS_ERR(rdev))
    2135                 :          0 :                 return PTR_ERR(rdev);
    2136                 :            : 
    2137   [ #  #  #  # ]:          0 :         if (rdev->scan_req || rdev->scan_msg) {
    2138                 :          0 :                 err = -EBUSY;
    2139                 :          0 :                 goto out;
    2140                 :            :         }
    2141                 :            : 
    2142                 :          0 :         wiphy = &rdev->wiphy;
    2143                 :            : 
    2144                 :            :         /* Determine number of channels, needed to allocate creq */
    2145   [ #  #  #  # ]:          0 :         if (wreq && wreq->num_channels)
    2146                 :          0 :                 n_channels = wreq->num_channels;
    2147                 :            :         else
    2148                 :          0 :                 n_channels = ieee80211_get_num_supported_channels(wiphy);
    2149                 :            : 
    2150                 :          0 :         creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
    2151                 :          0 :                        n_channels * sizeof(void *),
    2152                 :            :                        GFP_ATOMIC);
    2153         [ #  # ]:          0 :         if (!creq) {
    2154                 :          0 :                 err = -ENOMEM;
    2155                 :          0 :                 goto out;
    2156                 :            :         }
    2157                 :            : 
    2158                 :          0 :         creq->wiphy = wiphy;
    2159                 :          0 :         creq->wdev = dev->ieee80211_ptr;
    2160                 :            :         /* SSIDs come after channels */
    2161                 :          0 :         creq->ssids = (void *)&creq->channels[n_channels];
    2162                 :          0 :         creq->n_channels = n_channels;
    2163                 :          0 :         creq->n_ssids = 1;
    2164                 :          0 :         creq->scan_start = jiffies;
    2165                 :            : 
    2166                 :            :         /* translate "Scan on frequencies" request */
    2167                 :          0 :         i = 0;
    2168         [ #  # ]:          0 :         for (band = 0; band < NUM_NL80211_BANDS; band++) {
    2169                 :          0 :                 int j;
    2170                 :            : 
    2171         [ #  # ]:          0 :                 if (!wiphy->bands[band])
    2172                 :          0 :                         continue;
    2173                 :            : 
    2174         [ #  # ]:          0 :                 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
    2175                 :            :                         /* ignore disabled channels */
    2176         [ #  # ]:          0 :                         if (wiphy->bands[band]->channels[j].flags &
    2177                 :            :                                                 IEEE80211_CHAN_DISABLED)
    2178                 :          0 :                                 continue;
    2179                 :            : 
    2180                 :            :                         /* If we have a wireless request structure and the
    2181                 :            :                          * wireless request specifies frequencies, then search
    2182                 :            :                          * for the matching hardware channel.
    2183                 :            :                          */
    2184   [ #  #  #  # ]:          0 :                         if (wreq && wreq->num_channels) {
    2185                 :          0 :                                 int k;
    2186                 :          0 :                                 int wiphy_freq = wiphy->bands[band]->channels[j].center_freq;
    2187         [ #  # ]:          0 :                                 for (k = 0; k < wreq->num_channels; k++) {
    2188                 :          0 :                                         struct iw_freq *freq =
    2189                 :            :                                                 &wreq->channel_list[k];
    2190                 :          0 :                                         int wext_freq =
    2191                 :          0 :                                                 cfg80211_wext_freq(freq);
    2192                 :            : 
    2193         [ #  # ]:          0 :                                         if (wext_freq == wiphy_freq)
    2194                 :          0 :                                                 goto wext_freq_found;
    2195                 :            :                                 }
    2196                 :          0 :                                 goto wext_freq_not_found;
    2197                 :            :                         }
    2198                 :            : 
    2199                 :          0 :                 wext_freq_found:
    2200                 :          0 :                         creq->channels[i] = &wiphy->bands[band]->channels[j];
    2201                 :          0 :                         i++;
    2202                 :          0 :                 wext_freq_not_found: ;
    2203                 :            :                 }
    2204                 :            :         }
    2205                 :            :         /* No channels found? */
    2206         [ #  # ]:          0 :         if (!i) {
    2207                 :          0 :                 err = -EINVAL;
    2208                 :          0 :                 goto out;
    2209                 :            :         }
    2210                 :            : 
    2211                 :            :         /* Set real number of channels specified in creq->channels[] */
    2212                 :          0 :         creq->n_channels = i;
    2213                 :            : 
    2214                 :            :         /* translate "Scan for SSID" request */
    2215         [ #  # ]:          0 :         if (wreq) {
    2216         [ #  # ]:          0 :                 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
    2217         [ #  # ]:          0 :                         if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) {
    2218                 :          0 :                                 err = -EINVAL;
    2219                 :          0 :                                 goto out;
    2220                 :            :                         }
    2221                 :          0 :                         memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len);
    2222                 :          0 :                         creq->ssids[0].ssid_len = wreq->essid_len;
    2223                 :            :                 }
    2224         [ #  # ]:          0 :                 if (wreq->scan_type == IW_SCAN_TYPE_PASSIVE)
    2225                 :          0 :                         creq->n_ssids = 0;
    2226                 :            :         }
    2227                 :            : 
    2228         [ #  # ]:          0 :         for (i = 0; i < NUM_NL80211_BANDS; i++)
    2229         [ #  # ]:          0 :                 if (wiphy->bands[i])
    2230                 :          0 :                         creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
    2231                 :            : 
    2232                 :          0 :         eth_broadcast_addr(creq->bssid);
    2233                 :            : 
    2234                 :          0 :         rdev->scan_req = creq;
    2235                 :          0 :         err = rdev_scan(rdev, creq);
    2236         [ #  # ]:          0 :         if (err) {
    2237                 :          0 :                 rdev->scan_req = NULL;
    2238                 :            :                 /* creq will be freed below */
    2239                 :            :         } else {
    2240                 :          0 :                 nl80211_send_scan_start(rdev, dev->ieee80211_ptr);
    2241                 :            :                 /* creq now owned by driver */
    2242                 :          0 :                 creq = NULL;
    2243                 :          0 :                 dev_hold(dev);
    2244                 :            :         }
    2245                 :          0 :  out:
    2246                 :          0 :         kfree(creq);
    2247                 :          0 :         return err;
    2248                 :            : }
    2249                 :            : EXPORT_WEXT_HANDLER(cfg80211_wext_siwscan);
    2250                 :            : 
    2251                 :          0 : static char *ieee80211_scan_add_ies(struct iw_request_info *info,
    2252                 :            :                                     const struct cfg80211_bss_ies *ies,
    2253                 :            :                                     char *current_ev, char *end_buf)
    2254                 :            : {
    2255                 :          0 :         const u8 *pos, *end, *next;
    2256                 :          0 :         struct iw_event iwe;
    2257                 :            : 
    2258         [ #  # ]:          0 :         if (!ies)
    2259                 :            :                 return current_ev;
    2260                 :            : 
    2261                 :            :         /*
    2262                 :            :          * If needed, fragment the IEs buffer (at IE boundaries) into short
    2263                 :            :          * enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
    2264                 :            :          */
    2265                 :          0 :         pos = ies->data;
    2266                 :          0 :         end = pos + ies->len;
    2267                 :            : 
    2268         [ #  # ]:          0 :         while (end - pos > IW_GENERIC_IE_MAX) {
    2269                 :          0 :                 next = pos + 2 + pos[1];
    2270         [ #  # ]:          0 :                 while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
    2271                 :            :                         next = next + 2 + next[1];
    2272                 :            : 
    2273                 :          0 :                 memset(&iwe, 0, sizeof(iwe));
    2274                 :          0 :                 iwe.cmd = IWEVGENIE;
    2275                 :          0 :                 iwe.u.data.length = next - pos;
    2276                 :          0 :                 current_ev = iwe_stream_add_point_check(info, current_ev,
    2277                 :            :                                                         end_buf, &iwe,
    2278                 :            :                                                         (void *)pos);
    2279         [ #  # ]:          0 :                 if (IS_ERR(current_ev))
    2280                 :          0 :                         return current_ev;
    2281                 :            :                 pos = next;
    2282                 :            :         }
    2283                 :            : 
    2284         [ #  # ]:          0 :         if (end > pos) {
    2285                 :          0 :                 memset(&iwe, 0, sizeof(iwe));
    2286                 :          0 :                 iwe.cmd = IWEVGENIE;
    2287                 :          0 :                 iwe.u.data.length = end - pos;
    2288                 :          0 :                 current_ev = iwe_stream_add_point_check(info, current_ev,
    2289                 :            :                                                         end_buf, &iwe,
    2290                 :            :                                                         (void *)pos);
    2291                 :          0 :                 if (IS_ERR(current_ev))
    2292                 :            :                         return current_ev;
    2293                 :            :         }
    2294                 :            : 
    2295                 :            :         return current_ev;
    2296                 :            : }
    2297                 :            : 
    2298                 :            : static char *
    2299                 :            : ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
    2300                 :            :               struct cfg80211_internal_bss *bss, char *current_ev,
    2301                 :            :               char *end_buf)
    2302                 :            : {
    2303                 :            :         const struct cfg80211_bss_ies *ies;
    2304                 :            :         struct iw_event iwe;
    2305                 :            :         const u8 *ie;
    2306                 :            :         u8 buf[50];
    2307                 :            :         u8 *cfg, *p, *tmp;
    2308                 :            :         int rem, i, sig;
    2309                 :            :         bool ismesh = false;
    2310                 :            : 
    2311                 :            :         memset(&iwe, 0, sizeof(iwe));
    2312                 :            :         iwe.cmd = SIOCGIWAP;
    2313                 :            :         iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
    2314                 :            :         memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN);
    2315                 :            :         current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
    2316                 :            :                                                 IW_EV_ADDR_LEN);
    2317                 :            :         if (IS_ERR(current_ev))
    2318                 :            :                 return current_ev;
    2319                 :            : 
    2320                 :            :         memset(&iwe, 0, sizeof(iwe));
    2321                 :            :         iwe.cmd = SIOCGIWFREQ;
    2322                 :            :         iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq);
    2323                 :            :         iwe.u.freq.e = 0;
    2324                 :            :         current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
    2325                 :            :                                                 IW_EV_FREQ_LEN);
    2326                 :            :         if (IS_ERR(current_ev))
    2327                 :            :                 return current_ev;
    2328                 :            : 
    2329                 :            :         memset(&iwe, 0, sizeof(iwe));
    2330                 :            :         iwe.cmd = SIOCGIWFREQ;
    2331                 :            :         iwe.u.freq.m = bss->pub.channel->center_freq;
    2332                 :            :         iwe.u.freq.e = 6;
    2333                 :            :         current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
    2334                 :            :                                                 IW_EV_FREQ_LEN);
    2335                 :            :         if (IS_ERR(current_ev))
    2336                 :            :                 return current_ev;
    2337                 :            : 
    2338                 :            :         if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) {
    2339                 :            :                 memset(&iwe, 0, sizeof(iwe));
    2340                 :            :                 iwe.cmd = IWEVQUAL;
    2341                 :            :                 iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED |
    2342                 :            :                                      IW_QUAL_NOISE_INVALID |
    2343                 :            :                                      IW_QUAL_QUAL_UPDATED;
    2344                 :            :                 switch (wiphy->signal_type) {
    2345                 :            :                 case CFG80211_SIGNAL_TYPE_MBM:
    2346                 :            :                         sig = bss->pub.signal / 100;
    2347                 :            :                         iwe.u.qual.level = sig;
    2348                 :            :                         iwe.u.qual.updated |= IW_QUAL_DBM;
    2349                 :            :                         if (sig < -110)              /* rather bad */
    2350                 :            :                                 sig = -110;
    2351                 :            :                         else if (sig > -40)  /* perfect */
    2352                 :            :                                 sig = -40;
    2353                 :            :                         /* will give a range of 0 .. 70 */
    2354                 :            :                         iwe.u.qual.qual = sig + 110;
    2355                 :            :                         break;
    2356                 :            :                 case CFG80211_SIGNAL_TYPE_UNSPEC:
    2357                 :            :                         iwe.u.qual.level = bss->pub.signal;
    2358                 :            :                         /* will give range 0 .. 100 */
    2359                 :            :                         iwe.u.qual.qual = bss->pub.signal;
    2360                 :            :                         break;
    2361                 :            :                 default:
    2362                 :            :                         /* not reached */
    2363                 :            :                         break;
    2364                 :            :                 }
    2365                 :            :                 current_ev = iwe_stream_add_event_check(info, current_ev,
    2366                 :            :                                                         end_buf, &iwe,
    2367                 :            :                                                         IW_EV_QUAL_LEN);
    2368                 :            :                 if (IS_ERR(current_ev))
    2369                 :            :                         return current_ev;
    2370                 :            :         }
    2371                 :            : 
    2372                 :            :         memset(&iwe, 0, sizeof(iwe));
    2373                 :            :         iwe.cmd = SIOCGIWENCODE;
    2374                 :            :         if (bss->pub.capability & WLAN_CAPABILITY_PRIVACY)
    2375                 :            :                 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
    2376                 :            :         else
    2377                 :            :                 iwe.u.data.flags = IW_ENCODE_DISABLED;
    2378                 :            :         iwe.u.data.length = 0;
    2379                 :            :         current_ev = iwe_stream_add_point_check(info, current_ev, end_buf,
    2380                 :            :                                                 &iwe, "");
    2381                 :            :         if (IS_ERR(current_ev))
    2382                 :            :                 return current_ev;
    2383                 :            : 
    2384                 :            :         rcu_read_lock();
    2385                 :            :         ies = rcu_dereference(bss->pub.ies);
    2386                 :            :         rem = ies->len;
    2387                 :            :         ie = ies->data;
    2388                 :            : 
    2389                 :            :         while (rem >= 2) {
    2390                 :            :                 /* invalid data */
    2391                 :            :                 if (ie[1] > rem - 2)
    2392                 :            :                         break;
    2393                 :            : 
    2394                 :            :                 switch (ie[0]) {
    2395                 :            :                 case WLAN_EID_SSID:
    2396                 :            :                         memset(&iwe, 0, sizeof(iwe));
    2397                 :            :                         iwe.cmd = SIOCGIWESSID;
    2398                 :            :                         iwe.u.data.length = ie[1];
    2399                 :            :                         iwe.u.data.flags = 1;
    2400                 :            :                         current_ev = iwe_stream_add_point_check(info,
    2401                 :            :                                                                 current_ev,
    2402                 :            :                                                                 end_buf, &iwe,
    2403                 :            :                                                                 (u8 *)ie + 2);
    2404                 :            :                         if (IS_ERR(current_ev))
    2405                 :            :                                 goto unlock;
    2406                 :            :                         break;
    2407                 :            :                 case WLAN_EID_MESH_ID:
    2408                 :            :                         memset(&iwe, 0, sizeof(iwe));
    2409                 :            :                         iwe.cmd = SIOCGIWESSID;
    2410                 :            :                         iwe.u.data.length = ie[1];
    2411                 :            :                         iwe.u.data.flags = 1;
    2412                 :            :                         current_ev = iwe_stream_add_point_check(info,
    2413                 :            :                                                                 current_ev,
    2414                 :            :                                                                 end_buf, &iwe,
    2415                 :            :                                                                 (u8 *)ie + 2);
    2416                 :            :                         if (IS_ERR(current_ev))
    2417                 :            :                                 goto unlock;
    2418                 :            :                         break;
    2419                 :            :                 case WLAN_EID_MESH_CONFIG:
    2420                 :            :                         ismesh = true;
    2421                 :            :                         if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
    2422                 :            :                                 break;
    2423                 :            :                         cfg = (u8 *)ie + 2;
    2424                 :            :                         memset(&iwe, 0, sizeof(iwe));
    2425                 :            :                         iwe.cmd = IWEVCUSTOM;
    2426                 :            :                         sprintf(buf, "Mesh Network Path Selection Protocol ID: "
    2427                 :            :                                 "0x%02X", cfg[0]);
    2428                 :            :                         iwe.u.data.length = strlen(buf);
    2429                 :            :                         current_ev = iwe_stream_add_point_check(info,
    2430                 :            :                                                                 current_ev,
    2431                 :            :                                                                 end_buf,
    2432                 :            :                                                                 &iwe, buf);
    2433                 :            :                         if (IS_ERR(current_ev))
    2434                 :            :                                 goto unlock;
    2435                 :            :                         sprintf(buf, "Path Selection Metric ID: 0x%02X",
    2436                 :            :                                 cfg[1]);
    2437                 :            :                         iwe.u.data.length = strlen(buf);
    2438                 :            :                         current_ev = iwe_stream_add_point_check(info,
    2439                 :            :                                                                 current_ev,
    2440                 :            :                                                                 end_buf,
    2441                 :            :                                                                 &iwe, buf);
    2442                 :            :                         if (IS_ERR(current_ev))
    2443                 :            :                                 goto unlock;
    2444                 :            :                         sprintf(buf, "Congestion Control Mode ID: 0x%02X",
    2445                 :            :                                 cfg[2]);
    2446                 :            :                         iwe.u.data.length = strlen(buf);
    2447                 :            :                         current_ev = iwe_stream_add_point_check(info,
    2448                 :            :                                                                 current_ev,
    2449                 :            :                                                                 end_buf,
    2450                 :            :                                                                 &iwe, buf);
    2451                 :            :                         if (IS_ERR(current_ev))
    2452                 :            :                                 goto unlock;
    2453                 :            :                         sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]);
    2454                 :            :                         iwe.u.data.length = strlen(buf);
    2455                 :            :                         current_ev = iwe_stream_add_point_check(info,
    2456                 :            :                                                                 current_ev,
    2457                 :            :                                                                 end_buf,
    2458                 :            :                                                                 &iwe, buf);
    2459                 :            :                         if (IS_ERR(current_ev))
    2460                 :            :                                 goto unlock;
    2461                 :            :                         sprintf(buf, "Authentication ID: 0x%02X", cfg[4]);
    2462                 :            :                         iwe.u.data.length = strlen(buf);
    2463                 :            :                         current_ev = iwe_stream_add_point_check(info,
    2464                 :            :                                                                 current_ev,
    2465                 :            :                                                                 end_buf,
    2466                 :            :                                                                 &iwe, buf);
    2467                 :            :                         if (IS_ERR(current_ev))
    2468                 :            :                                 goto unlock;
    2469                 :            :                         sprintf(buf, "Formation Info: 0x%02X", cfg[5]);
    2470                 :            :                         iwe.u.data.length = strlen(buf);
    2471                 :            :                         current_ev = iwe_stream_add_point_check(info,
    2472                 :            :                                                                 current_ev,
    2473                 :            :                                                                 end_buf,
    2474                 :            :                                                                 &iwe, buf);
    2475                 :            :                         if (IS_ERR(current_ev))
    2476                 :            :                                 goto unlock;
    2477                 :            :                         sprintf(buf, "Capabilities: 0x%02X", cfg[6]);
    2478                 :            :                         iwe.u.data.length = strlen(buf);
    2479                 :            :                         current_ev = iwe_stream_add_point_check(info,
    2480                 :            :                                                                 current_ev,
    2481                 :            :                                                                 end_buf,
    2482                 :            :                                                                 &iwe, buf);
    2483                 :            :                         if (IS_ERR(current_ev))
    2484                 :            :                                 goto unlock;
    2485                 :            :                         break;
    2486                 :            :                 case WLAN_EID_SUPP_RATES:
    2487                 :            :                 case WLAN_EID_EXT_SUPP_RATES:
    2488                 :            :                         /* display all supported rates in readable format */
    2489                 :            :                         p = current_ev + iwe_stream_lcp_len(info);
    2490                 :            : 
    2491                 :            :                         memset(&iwe, 0, sizeof(iwe));
    2492                 :            :                         iwe.cmd = SIOCGIWRATE;
    2493                 :            :                         /* Those two flags are ignored... */
    2494                 :            :                         iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
    2495                 :            : 
    2496                 :            :                         for (i = 0; i < ie[1]; i++) {
    2497                 :            :                                 iwe.u.bitrate.value =
    2498                 :            :                                         ((ie[i + 2] & 0x7f) * 500000);
    2499                 :            :                                 tmp = p;
    2500                 :            :                                 p = iwe_stream_add_value(info, current_ev, p,
    2501                 :            :                                                          end_buf, &iwe,
    2502                 :            :                                                          IW_EV_PARAM_LEN);
    2503                 :            :                                 if (p == tmp) {
    2504                 :            :                                         current_ev = ERR_PTR(-E2BIG);
    2505                 :            :                                         goto unlock;
    2506                 :            :                                 }
    2507                 :            :                         }
    2508                 :            :                         current_ev = p;
    2509                 :            :                         break;
    2510                 :            :                 }
    2511                 :            :                 rem -= ie[1] + 2;
    2512                 :            :                 ie += ie[1] + 2;
    2513                 :            :         }
    2514                 :            : 
    2515                 :            :         if (bss->pub.capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) ||
    2516                 :            :             ismesh) {
    2517                 :            :                 memset(&iwe, 0, sizeof(iwe));
    2518                 :            :                 iwe.cmd = SIOCGIWMODE;
    2519                 :            :                 if (ismesh)
    2520                 :            :                         iwe.u.mode = IW_MODE_MESH;
    2521                 :            :                 else if (bss->pub.capability & WLAN_CAPABILITY_ESS)
    2522                 :            :                         iwe.u.mode = IW_MODE_MASTER;
    2523                 :            :                 else
    2524                 :            :                         iwe.u.mode = IW_MODE_ADHOC;
    2525                 :            :                 current_ev = iwe_stream_add_event_check(info, current_ev,
    2526                 :            :                                                         end_buf, &iwe,
    2527                 :            :                                                         IW_EV_UINT_LEN);
    2528                 :            :                 if (IS_ERR(current_ev))
    2529                 :            :                         goto unlock;
    2530                 :            :         }
    2531                 :            : 
    2532                 :            :         memset(&iwe, 0, sizeof(iwe));
    2533                 :            :         iwe.cmd = IWEVCUSTOM;
    2534                 :            :         sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf));
    2535                 :            :         iwe.u.data.length = strlen(buf);
    2536                 :            :         current_ev = iwe_stream_add_point_check(info, current_ev, end_buf,
    2537                 :            :                                                 &iwe, buf);
    2538                 :            :         if (IS_ERR(current_ev))
    2539                 :            :                 goto unlock;
    2540                 :            :         memset(&iwe, 0, sizeof(iwe));
    2541                 :            :         iwe.cmd = IWEVCUSTOM;
    2542                 :            :         sprintf(buf, " Last beacon: %ums ago",
    2543                 :            :                 elapsed_jiffies_msecs(bss->ts));
    2544                 :            :         iwe.u.data.length = strlen(buf);
    2545                 :            :         current_ev = iwe_stream_add_point_check(info, current_ev,
    2546                 :            :                                                 end_buf, &iwe, buf);
    2547                 :            :         if (IS_ERR(current_ev))
    2548                 :            :                 goto unlock;
    2549                 :            : 
    2550                 :            :         current_ev = ieee80211_scan_add_ies(info, ies, current_ev, end_buf);
    2551                 :            : 
    2552                 :            :  unlock:
    2553                 :            :         rcu_read_unlock();
    2554                 :            :         return current_ev;
    2555                 :            : }
    2556                 :            : 
    2557                 :            : 
    2558                 :          0 : static int ieee80211_scan_results(struct cfg80211_registered_device *rdev,
    2559                 :            :                                   struct iw_request_info *info,
    2560                 :            :                                   char *buf, size_t len)
    2561                 :            : {
    2562                 :          0 :         char *current_ev = buf;
    2563                 :          0 :         char *end_buf = buf + len;
    2564                 :          0 :         struct cfg80211_internal_bss *bss;
    2565                 :          0 :         int err = 0;
    2566                 :            : 
    2567                 :          0 :         spin_lock_bh(&rdev->bss_lock);
    2568                 :          0 :         cfg80211_bss_expire(rdev);
    2569                 :            : 
    2570         [ #  # ]:          0 :         list_for_each_entry(bss, &rdev->bss_list, list) {
    2571         [ #  # ]:          0 :                 if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
    2572                 :            :                         err = -E2BIG;
    2573                 :            :                         break;
    2574                 :            :                 }
    2575                 :          0 :                 current_ev = ieee80211_bss(&rdev->wiphy, info, bss,
    2576                 :            :                                            current_ev, end_buf);
    2577         [ #  # ]:          0 :                 if (IS_ERR(current_ev)) {
    2578                 :          0 :                         err = PTR_ERR(current_ev);
    2579                 :          0 :                         break;
    2580                 :            :                 }
    2581                 :            :         }
    2582                 :          0 :         spin_unlock_bh(&rdev->bss_lock);
    2583                 :            : 
    2584         [ #  # ]:          0 :         if (err)
    2585                 :            :                 return err;
    2586                 :          0 :         return current_ev - buf;
    2587                 :            : }
    2588                 :            : 
    2589                 :            : 
    2590                 :          0 : int cfg80211_wext_giwscan(struct net_device *dev,
    2591                 :            :                           struct iw_request_info *info,
    2592                 :            :                           struct iw_point *data, char *extra)
    2593                 :            : {
    2594                 :          0 :         struct cfg80211_registered_device *rdev;
    2595                 :          0 :         int res;
    2596                 :            : 
    2597         [ #  # ]:          0 :         if (!netif_running(dev))
    2598                 :            :                 return -ENETDOWN;
    2599                 :            : 
    2600                 :          0 :         rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex);
    2601                 :            : 
    2602         [ #  # ]:          0 :         if (IS_ERR(rdev))
    2603                 :          0 :                 return PTR_ERR(rdev);
    2604                 :            : 
    2605   [ #  #  #  # ]:          0 :         if (rdev->scan_req || rdev->scan_msg)
    2606                 :            :                 return -EAGAIN;
    2607                 :            : 
    2608                 :          0 :         res = ieee80211_scan_results(rdev, info, extra, data->length);
    2609                 :          0 :         data->length = 0;
    2610         [ #  # ]:          0 :         if (res >= 0) {
    2611                 :          0 :                 data->length = res;
    2612                 :          0 :                 res = 0;
    2613                 :            :         }
    2614                 :            : 
    2615                 :            :         return res;
    2616                 :            : }
    2617                 :            : EXPORT_WEXT_HANDLER(cfg80211_wext_giwscan);
    2618                 :            : #endif

Generated by: LCOV version 1.14