LCOV - code coverage report
Current view: top level - net/mac80211 - mlme.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 2431 0.0 %
Date: 2022-04-01 13:59:58 Functions: 0 85 0.0 %
Branches: 0 1497 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * BSS client mode implementation
       4                 :            :  * Copyright 2003-2008, Jouni Malinen <j@w1.fi>
       5                 :            :  * Copyright 2004, Instant802 Networks, Inc.
       6                 :            :  * Copyright 2005, Devicescape Software, Inc.
       7                 :            :  * Copyright 2006-2007  Jiri Benc <jbenc@suse.cz>
       8                 :            :  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
       9                 :            :  * Copyright 2013-2014  Intel Mobile Communications GmbH
      10                 :            :  * Copyright (C) 2015 - 2017 Intel Deutschland GmbH
      11                 :            :  * Copyright (C) 2018 - 2020 Intel Corporation
      12                 :            :  */
      13                 :            : 
      14                 :            : #include <linux/delay.h>
      15                 :            : #include <linux/fips.h>
      16                 :            : #include <linux/if_ether.h>
      17                 :            : #include <linux/skbuff.h>
      18                 :            : #include <linux/if_arp.h>
      19                 :            : #include <linux/etherdevice.h>
      20                 :            : #include <linux/moduleparam.h>
      21                 :            : #include <linux/rtnetlink.h>
      22                 :            : #include <linux/crc32.h>
      23                 :            : #include <linux/slab.h>
      24                 :            : #include <linux/export.h>
      25                 :            : #include <net/mac80211.h>
      26                 :            : #include <asm/unaligned.h>
      27                 :            : 
      28                 :            : #include "ieee80211_i.h"
      29                 :            : #include "driver-ops.h"
      30                 :            : #include "rate.h"
      31                 :            : #include "led.h"
      32                 :            : #include "fils_aead.h"
      33                 :            : 
      34                 :            : #define IEEE80211_AUTH_TIMEOUT          (HZ / 5)
      35                 :            : #define IEEE80211_AUTH_TIMEOUT_LONG     (HZ / 2)
      36                 :            : #define IEEE80211_AUTH_TIMEOUT_SHORT    (HZ / 10)
      37                 :            : #define IEEE80211_AUTH_TIMEOUT_SAE      (HZ * 2)
      38                 :            : #define IEEE80211_AUTH_MAX_TRIES        3
      39                 :            : #define IEEE80211_AUTH_WAIT_ASSOC       (HZ * 5)
      40                 :            : #define IEEE80211_ASSOC_TIMEOUT         (HZ / 5)
      41                 :            : #define IEEE80211_ASSOC_TIMEOUT_LONG    (HZ / 2)
      42                 :            : #define IEEE80211_ASSOC_TIMEOUT_SHORT   (HZ / 10)
      43                 :            : #define IEEE80211_ASSOC_MAX_TRIES       3
      44                 :            : 
      45                 :            : static int max_nullfunc_tries = 2;
      46                 :            : module_param(max_nullfunc_tries, int, 0644);
      47                 :            : MODULE_PARM_DESC(max_nullfunc_tries,
      48                 :            :                  "Maximum nullfunc tx tries before disconnecting (reason 4).");
      49                 :            : 
      50                 :            : static int max_probe_tries = 5;
      51                 :            : module_param(max_probe_tries, int, 0644);
      52                 :            : MODULE_PARM_DESC(max_probe_tries,
      53                 :            :                  "Maximum probe tries before disconnecting (reason 4).");
      54                 :            : 
      55                 :            : /*
      56                 :            :  * Beacon loss timeout is calculated as N frames times the
      57                 :            :  * advertised beacon interval.  This may need to be somewhat
      58                 :            :  * higher than what hardware might detect to account for
      59                 :            :  * delays in the host processing frames. But since we also
      60                 :            :  * probe on beacon miss before declaring the connection lost
      61                 :            :  * default to what we want.
      62                 :            :  */
      63                 :            : static int beacon_loss_count = 7;
      64                 :            : module_param(beacon_loss_count, int, 0644);
      65                 :            : MODULE_PARM_DESC(beacon_loss_count,
      66                 :            :                  "Number of beacon intervals before we decide beacon was lost.");
      67                 :            : 
      68                 :            : /*
      69                 :            :  * Time the connection can be idle before we probe
      70                 :            :  * it to see if we can still talk to the AP.
      71                 :            :  */
      72                 :            : #define IEEE80211_CONNECTION_IDLE_TIME  (30 * HZ)
      73                 :            : /*
      74                 :            :  * Time we wait for a probe response after sending
      75                 :            :  * a probe request because of beacon loss or for
      76                 :            :  * checking the connection still works.
      77                 :            :  */
      78                 :            : static int probe_wait_ms = 500;
      79                 :            : module_param(probe_wait_ms, int, 0644);
      80                 :            : MODULE_PARM_DESC(probe_wait_ms,
      81                 :            :                  "Maximum time(ms) to wait for probe response"
      82                 :            :                  " before disconnecting (reason 4).");
      83                 :            : 
      84                 :            : /*
      85                 :            :  * How many Beacon frames need to have been used in average signal strength
      86                 :            :  * before starting to indicate signal change events.
      87                 :            :  */
      88                 :            : #define IEEE80211_SIGNAL_AVE_MIN_COUNT  4
      89                 :            : 
      90                 :            : /*
      91                 :            :  * We can have multiple work items (and connection probing)
      92                 :            :  * scheduling this timer, but we need to take care to only
      93                 :            :  * reschedule it when it should fire _earlier_ than it was
      94                 :            :  * asked for before, or if it's not pending right now. This
      95                 :            :  * function ensures that. Note that it then is required to
      96                 :            :  * run this function for all timeouts after the first one
      97                 :            :  * has happened -- the work that runs from this timer will
      98                 :            :  * do that.
      99                 :            :  */
     100                 :          0 : static void run_again(struct ieee80211_sub_if_data *sdata,
     101                 :            :                       unsigned long timeout)
     102                 :            : {
     103                 :          0 :         sdata_assert_lock(sdata);
     104                 :            : 
     105   [ #  #  #  #  :          0 :         if (!timer_pending(&sdata->u.mgd.timer) ||
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     106   [ #  #  #  #  :          0 :             time_before(timeout, sdata->u.mgd.timer.expires))
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     107                 :          0 :                 mod_timer(&sdata->u.mgd.timer, timeout);
     108                 :            : }
     109                 :            : 
     110                 :          0 : void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata)
     111                 :            : {
     112         [ #  # ]:          0 :         if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)
     113                 :            :                 return;
     114                 :            : 
     115         [ #  # ]:          0 :         if (ieee80211_hw_check(&sdata->local->hw, CONNECTION_MONITOR))
     116                 :            :                 return;
     117                 :            : 
     118                 :          0 :         mod_timer(&sdata->u.mgd.bcn_mon_timer,
     119                 :          0 :                   round_jiffies_up(jiffies + sdata->u.mgd.beacon_timeout));
     120                 :            : }
     121                 :            : 
     122                 :          0 : void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata)
     123                 :            : {
     124                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
     125                 :            : 
     126         [ #  # ]:          0 :         if (unlikely(!ifmgd->associated))
     127                 :            :                 return;
     128                 :            : 
     129         [ #  # ]:          0 :         if (ifmgd->probe_send_count)
     130                 :          0 :                 ifmgd->probe_send_count = 0;
     131                 :            : 
     132         [ #  # ]:          0 :         if (ieee80211_hw_check(&sdata->local->hw, CONNECTION_MONITOR))
     133                 :            :                 return;
     134                 :            : 
     135                 :          0 :         mod_timer(&ifmgd->conn_mon_timer,
     136                 :            :                   round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME));
     137                 :            : }
     138                 :            : 
     139                 :          0 : static int ecw2cw(int ecw)
     140                 :            : {
     141                 :          0 :         return (1 << ecw) - 1;
     142                 :            : }
     143                 :            : 
     144                 :            : static u32
     145                 :          0 : ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
     146                 :            :                              struct ieee80211_supported_band *sband,
     147                 :            :                              struct ieee80211_channel *channel,
     148                 :            :                              const struct ieee80211_ht_operation *ht_oper,
     149                 :            :                              const struct ieee80211_vht_operation *vht_oper,
     150                 :            :                              const struct ieee80211_he_operation *he_oper,
     151                 :            :                              struct cfg80211_chan_def *chandef, bool tracking)
     152                 :            : {
     153                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
     154                 :          0 :         struct cfg80211_chan_def vht_chandef;
     155                 :          0 :         struct ieee80211_sta_ht_cap sta_ht_cap;
     156                 :          0 :         u32 ht_cfreq, ret;
     157                 :            : 
     158                 :          0 :         memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
     159                 :          0 :         ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
     160                 :            : 
     161                 :          0 :         memset(chandef, 0, sizeof(struct cfg80211_chan_def));
     162                 :          0 :         chandef->chan = channel;
     163                 :          0 :         chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
     164                 :          0 :         chandef->center_freq1 = channel->center_freq;
     165                 :            : 
     166   [ #  #  #  # ]:          0 :         if (!ht_oper || !sta_ht_cap.ht_supported) {
     167                 :          0 :                 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
     168                 :          0 :                 goto out;
     169                 :            :         }
     170                 :            : 
     171                 :          0 :         chandef->width = NL80211_CHAN_WIDTH_20;
     172                 :            : 
     173                 :          0 :         ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan,
     174                 :            :                                                   channel->band);
     175                 :            :         /* check that channel matches the right operating channel */
     176   [ #  #  #  # ]:          0 :         if (!tracking && channel->center_freq != ht_cfreq) {
     177                 :            :                 /*
     178                 :            :                  * It's possible that some APs are confused here;
     179                 :            :                  * Netgear WNDR3700 sometimes reports 4 higher than
     180                 :            :                  * the actual channel in association responses, but
     181                 :            :                  * since we look at probe response/beacon data here
     182                 :            :                  * it should be OK.
     183                 :            :                  */
     184                 :          0 :                 sdata_info(sdata,
     185                 :            :                            "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
     186                 :            :                            channel->center_freq, ht_cfreq,
     187                 :            :                            ht_oper->primary_chan, channel->band);
     188                 :          0 :                 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
     189                 :          0 :                 goto out;
     190                 :            :         }
     191                 :            : 
     192                 :            :         /* check 40 MHz support, if we have it */
     193         [ #  # ]:          0 :         if (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
     194                 :          0 :                 ieee80211_chandef_ht_oper(ht_oper, chandef);
     195                 :            :         } else {
     196                 :            :                 /* 40 MHz (and 80 MHz) must be supported for VHT */
     197                 :          0 :                 ret = IEEE80211_STA_DISABLE_VHT;
     198                 :            :                 /* also mark 40 MHz disabled */
     199                 :          0 :                 ret |= IEEE80211_STA_DISABLE_40MHZ;
     200                 :          0 :                 goto out;
     201                 :            :         }
     202                 :            : 
     203   [ #  #  #  # ]:          0 :         if (!vht_oper || !sband->vht_cap.vht_supported) {
     204                 :          0 :                 ret = IEEE80211_STA_DISABLE_VHT;
     205                 :          0 :                 goto out;
     206                 :            :         }
     207                 :            : 
     208                 :          0 :         vht_chandef = *chandef;
     209   [ #  #  #  # ]:          0 :         if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && he_oper &&
     210         [ #  # ]:          0 :             (le32_to_cpu(he_oper->he_oper_params) &
     211                 :          0 :              IEEE80211_HE_OPERATION_VHT_OPER_INFO)) {
     212                 :          0 :                 struct ieee80211_vht_operation he_oper_vht_cap;
     213                 :            : 
     214                 :            :                 /*
     215                 :            :                  * Set only first 3 bytes (other 2 aren't used in
     216                 :            :                  * ieee80211_chandef_vht_oper() anyway)
     217                 :            :                  */
     218                 :          0 :                 memcpy(&he_oper_vht_cap, he_oper->optional, 3);
     219                 :          0 :                 he_oper_vht_cap.basic_mcs_set = cpu_to_le16(0);
     220                 :            : 
     221         [ #  # ]:          0 :                 if (!ieee80211_chandef_vht_oper(&sdata->local->hw,
     222                 :            :                                                 &he_oper_vht_cap, ht_oper,
     223                 :            :                                                 &vht_chandef)) {
     224         [ #  # ]:          0 :                         if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
     225                 :          0 :                                 sdata_info(sdata,
     226                 :            :                                            "HE AP VHT information is invalid, disable HE\n");
     227                 :          0 :                         ret = IEEE80211_STA_DISABLE_HE;
     228                 :          0 :                         goto out;
     229                 :            :                 }
     230         [ #  # ]:          0 :         } else if (!ieee80211_chandef_vht_oper(&sdata->local->hw, vht_oper,
     231                 :            :                                                ht_oper, &vht_chandef)) {
     232         [ #  # ]:          0 :                 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
     233                 :          0 :                         sdata_info(sdata,
     234                 :            :                                    "AP VHT information is invalid, disable VHT\n");
     235                 :          0 :                 ret = IEEE80211_STA_DISABLE_VHT;
     236                 :          0 :                 goto out;
     237                 :            :         }
     238                 :            : 
     239         [ #  # ]:          0 :         if (!cfg80211_chandef_valid(&vht_chandef)) {
     240         [ #  # ]:          0 :                 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
     241                 :          0 :                         sdata_info(sdata,
     242                 :            :                                    "AP VHT information is invalid, disable VHT\n");
     243                 :          0 :                 ret = IEEE80211_STA_DISABLE_VHT;
     244                 :          0 :                 goto out;
     245                 :            :         }
     246                 :            : 
     247   [ #  #  #  # ]:          0 :         if (cfg80211_chandef_identical(chandef, &vht_chandef)) {
     248                 :          0 :                 ret = 0;
     249                 :          0 :                 goto out;
     250                 :            :         }
     251                 :            : 
     252         [ #  # ]:          0 :         if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) {
     253         [ #  # ]:          0 :                 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
     254                 :          0 :                         sdata_info(sdata,
     255                 :            :                                    "AP VHT information doesn't match HT, disable VHT\n");
     256                 :          0 :                 ret = IEEE80211_STA_DISABLE_VHT;
     257                 :          0 :                 goto out;
     258                 :            :         }
     259                 :            : 
     260                 :          0 :         *chandef = vht_chandef;
     261                 :            : 
     262                 :          0 :         ret = 0;
     263                 :            : 
     264                 :          0 : out:
     265                 :            :         /*
     266                 :            :          * When tracking the current AP, don't do any further checks if the
     267                 :            :          * new chandef is identical to the one we're currently using for the
     268                 :            :          * connection. This keeps us from playing ping-pong with regulatory,
     269                 :            :          * without it the following can happen (for example):
     270                 :            :          *  - connect to an AP with 80 MHz, world regdom allows 80 MHz
     271                 :            :          *  - AP advertises regdom US
     272                 :            :          *  - CRDA loads regdom US with 80 MHz prohibited (old database)
     273                 :            :          *  - the code below detects an unsupported channel, downgrades, and
     274                 :            :          *    we disconnect from the AP in the caller
     275                 :            :          *  - disconnect causes CRDA to reload world regdomain and the game
     276                 :            :          *    starts anew.
     277                 :            :          * (see https://bugzilla.kernel.org/show_bug.cgi?id=70881)
     278                 :            :          *
     279                 :            :          * It seems possible that there are still scenarios with CSA or real
     280                 :            :          * bandwidth changes where a this could happen, but those cases are
     281                 :            :          * less common and wouldn't completely prevent using the AP.
     282                 :            :          */
     283   [ #  #  #  # ]:          0 :         if (tracking &&
     284                 :            :             cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef))
     285                 :            :                 return ret;
     286                 :            : 
     287                 :            :         /* don't print the message below for VHT mismatch if VHT is disabled */
     288         [ #  # ]:          0 :         if (ret & IEEE80211_STA_DISABLE_VHT)
     289                 :          0 :                 vht_chandef = *chandef;
     290                 :            : 
     291                 :            :         /*
     292                 :            :          * Ignore the DISABLED flag when we're already connected and only
     293                 :            :          * tracking the APs beacon for bandwidth changes - otherwise we
     294                 :            :          * might get disconnected here if we connect to an AP, update our
     295                 :            :          * regulatory information based on the AP's country IE and the
     296                 :            :          * information we have is wrong/outdated and disables the channel
     297                 :            :          * that we're actually using for the connection to the AP.
     298                 :            :          */
     299         [ #  # ]:          0 :         while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
     300                 :          0 :                                         tracking ? 0 :
     301                 :            :                                                    IEEE80211_CHAN_DISABLED)) {
     302   [ #  #  #  # ]:          0 :                 if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) {
     303                 :            :                         ret = IEEE80211_STA_DISABLE_HT |
     304                 :            :                               IEEE80211_STA_DISABLE_VHT;
     305                 :            :                         break;
     306                 :            :                 }
     307                 :            : 
     308                 :          0 :                 ret |= ieee80211_chandef_downgrade(chandef);
     309                 :            :         }
     310                 :            : 
     311   [ #  #  #  # ]:          0 :         if (chandef->width != vht_chandef.width && !tracking)
     312                 :          0 :                 sdata_info(sdata,
     313                 :            :                            "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n");
     314                 :            : 
     315         [ #  # ]:          0 :         WARN_ON_ONCE(!cfg80211_chandef_valid(chandef));
     316                 :            :         return ret;
     317                 :            : }
     318                 :            : 
     319                 :            : static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
     320                 :            :                                struct sta_info *sta,
     321                 :            :                                const struct ieee80211_ht_cap *ht_cap,
     322                 :            :                                const struct ieee80211_ht_operation *ht_oper,
     323                 :            :                                const struct ieee80211_vht_operation *vht_oper,
     324                 :            :                                const struct ieee80211_he_operation *he_oper,
     325                 :            :                                const u8 *bssid, u32 *changed)
     326                 :            : {
     327                 :            :         struct ieee80211_local *local = sdata->local;
     328                 :            :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
     329                 :            :         struct ieee80211_channel *chan = sdata->vif.bss_conf.chandef.chan;
     330                 :            :         struct ieee80211_supported_band *sband =
     331                 :            :                 local->hw.wiphy->bands[chan->band];
     332                 :            :         struct cfg80211_chan_def chandef;
     333                 :            :         u16 ht_opmode;
     334                 :            :         u32 flags;
     335                 :            :         enum ieee80211_sta_rx_bandwidth new_sta_bw;
     336                 :            :         int ret;
     337                 :            : 
     338                 :            :         /* if HT was/is disabled, don't track any bandwidth changes */
     339                 :            :         if (ifmgd->flags & IEEE80211_STA_DISABLE_HT || !ht_oper)
     340                 :            :                 return 0;
     341                 :            : 
     342                 :            :         /* don't check VHT if we associated as non-VHT station */
     343                 :            :         if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
     344                 :            :                 vht_oper = NULL;
     345                 :            : 
     346                 :            :         /* don't check HE if we associated as non-HE station */
     347                 :            :         if (ifmgd->flags & IEEE80211_STA_DISABLE_HE ||
     348                 :            :             !ieee80211_get_he_sta_cap(sband))
     349                 :            :                 he_oper = NULL;
     350                 :            : 
     351                 :            :         if (WARN_ON_ONCE(!sta))
     352                 :            :                 return -EINVAL;
     353                 :            : 
     354                 :            :         /*
     355                 :            :          * if bss configuration changed store the new one -
     356                 :            :          * this may be applicable even if channel is identical
     357                 :            :          */
     358                 :            :         ht_opmode = le16_to_cpu(ht_oper->operation_mode);
     359                 :            :         if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
     360                 :            :                 *changed |= BSS_CHANGED_HT;
     361                 :            :                 sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
     362                 :            :         }
     363                 :            : 
     364                 :            :         /* calculate new channel (type) based on HT/VHT/HE operation IEs */
     365                 :            :         flags = ieee80211_determine_chantype(sdata, sband, chan,
     366                 :            :                                              ht_oper, vht_oper, he_oper,
     367                 :            :                                              &chandef, true);
     368                 :            : 
     369                 :            :         /*
     370                 :            :          * Downgrade the new channel if we associated with restricted
     371                 :            :          * capabilities. For example, if we associated as a 20 MHz STA
     372                 :            :          * to a 40 MHz AP (due to regulatory, capabilities or config
     373                 :            :          * reasons) then switching to a 40 MHz channel now won't do us
     374                 :            :          * any good -- we couldn't use it with the AP.
     375                 :            :          */
     376                 :            :         if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ &&
     377                 :            :             chandef.width == NL80211_CHAN_WIDTH_80P80)
     378                 :            :                 flags |= ieee80211_chandef_downgrade(&chandef);
     379                 :            :         if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ &&
     380                 :            :             chandef.width == NL80211_CHAN_WIDTH_160)
     381                 :            :                 flags |= ieee80211_chandef_downgrade(&chandef);
     382                 :            :         if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ &&
     383                 :            :             chandef.width > NL80211_CHAN_WIDTH_20)
     384                 :            :                 flags |= ieee80211_chandef_downgrade(&chandef);
     385                 :            : 
     386                 :            :         if (cfg80211_chandef_identical(&chandef, &sdata->vif.bss_conf.chandef))
     387                 :            :                 return 0;
     388                 :            : 
     389                 :            :         sdata_info(sdata,
     390                 :            :                    "AP %pM changed bandwidth, new config is %d MHz, width %d (%d/%d MHz)\n",
     391                 :            :                    ifmgd->bssid, chandef.chan->center_freq, chandef.width,
     392                 :            :                    chandef.center_freq1, chandef.center_freq2);
     393                 :            : 
     394                 :            :         if (flags != (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
     395                 :            :                                       IEEE80211_STA_DISABLE_VHT |
     396                 :            :                                       IEEE80211_STA_DISABLE_40MHZ |
     397                 :            :                                       IEEE80211_STA_DISABLE_80P80MHZ |
     398                 :            :                                       IEEE80211_STA_DISABLE_160MHZ)) ||
     399                 :            :             !cfg80211_chandef_valid(&chandef)) {
     400                 :            :                 sdata_info(sdata,
     401                 :            :                            "AP %pM changed bandwidth in a way we can't support - disconnect\n",
     402                 :            :                            ifmgd->bssid);
     403                 :            :                 return -EINVAL;
     404                 :            :         }
     405                 :            : 
     406                 :            :         switch (chandef.width) {
     407                 :            :         case NL80211_CHAN_WIDTH_20_NOHT:
     408                 :            :         case NL80211_CHAN_WIDTH_20:
     409                 :            :                 new_sta_bw = IEEE80211_STA_RX_BW_20;
     410                 :            :                 break;
     411                 :            :         case NL80211_CHAN_WIDTH_40:
     412                 :            :                 new_sta_bw = IEEE80211_STA_RX_BW_40;
     413                 :            :                 break;
     414                 :            :         case NL80211_CHAN_WIDTH_80:
     415                 :            :                 new_sta_bw = IEEE80211_STA_RX_BW_80;
     416                 :            :                 break;
     417                 :            :         case NL80211_CHAN_WIDTH_80P80:
     418                 :            :         case NL80211_CHAN_WIDTH_160:
     419                 :            :                 new_sta_bw = IEEE80211_STA_RX_BW_160;
     420                 :            :                 break;
     421                 :            :         default:
     422                 :            :                 return -EINVAL;
     423                 :            :         }
     424                 :            : 
     425                 :            :         if (new_sta_bw > sta->cur_max_bandwidth)
     426                 :            :                 new_sta_bw = sta->cur_max_bandwidth;
     427                 :            : 
     428                 :            :         if (new_sta_bw < sta->sta.bandwidth) {
     429                 :            :                 sta->sta.bandwidth = new_sta_bw;
     430                 :            :                 rate_control_rate_update(local, sband, sta,
     431                 :            :                                          IEEE80211_RC_BW_CHANGED);
     432                 :            :         }
     433                 :            : 
     434                 :            :         ret = ieee80211_vif_change_bandwidth(sdata, &chandef, changed);
     435                 :            :         if (ret) {
     436                 :            :                 sdata_info(sdata,
     437                 :            :                            "AP %pM changed bandwidth to incompatible one - disconnect\n",
     438                 :            :                            ifmgd->bssid);
     439                 :            :                 return ret;
     440                 :            :         }
     441                 :            : 
     442                 :            :         if (new_sta_bw > sta->sta.bandwidth) {
     443                 :            :                 sta->sta.bandwidth = new_sta_bw;
     444                 :            :                 rate_control_rate_update(local, sband, sta,
     445                 :            :                                          IEEE80211_RC_BW_CHANGED);
     446                 :            :         }
     447                 :            : 
     448                 :            :         return 0;
     449                 :            : }
     450                 :            : 
     451                 :            : /* frame sending functions */
     452                 :            : 
     453                 :          0 : static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
     454                 :            :                                 struct sk_buff *skb, u8 ap_ht_param,
     455                 :            :                                 struct ieee80211_supported_band *sband,
     456                 :            :                                 struct ieee80211_channel *channel,
     457                 :            :                                 enum ieee80211_smps_mode smps)
     458                 :            : {
     459                 :          0 :         u8 *pos;
     460                 :          0 :         u32 flags = channel->flags;
     461                 :          0 :         u16 cap;
     462                 :          0 :         struct ieee80211_sta_ht_cap ht_cap;
     463                 :            : 
     464                 :          0 :         BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));
     465                 :            : 
     466                 :          0 :         memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
     467                 :          0 :         ieee80211_apply_htcap_overrides(sdata, &ht_cap);
     468                 :            : 
     469                 :            :         /* determine capability flags */
     470                 :          0 :         cap = ht_cap.cap;
     471                 :            : 
     472      [ #  #  # ]:          0 :         switch (ap_ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
     473                 :          0 :         case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
     474         [ #  # ]:          0 :                 if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
     475                 :          0 :                         cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
     476                 :          0 :                         cap &= ~IEEE80211_HT_CAP_SGI_40;
     477                 :            :                 }
     478                 :            :                 break;
     479                 :          0 :         case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
     480         [ #  # ]:          0 :                 if (flags & IEEE80211_CHAN_NO_HT40MINUS) {
     481                 :          0 :                         cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
     482                 :          0 :                         cap &= ~IEEE80211_HT_CAP_SGI_40;
     483                 :            :                 }
     484                 :            :                 break;
     485                 :            :         }
     486                 :            : 
     487                 :            :         /*
     488                 :            :          * If 40 MHz was disabled associate as though we weren't
     489                 :            :          * capable of 40 MHz -- some broken APs will never fall
     490                 :            :          * back to trying to transmit in 20 MHz.
     491                 :            :          */
     492         [ #  # ]:          0 :         if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_40MHZ) {
     493                 :          0 :                 cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
     494                 :          0 :                 cap &= ~IEEE80211_HT_CAP_SGI_40;
     495                 :            :         }
     496                 :            : 
     497                 :            :         /* set SM PS mode properly */
     498                 :          0 :         cap &= ~IEEE80211_HT_CAP_SM_PS;
     499   [ #  #  #  # ]:          0 :         switch (smps) {
     500                 :            :         case IEEE80211_SMPS_AUTOMATIC:
     501                 :            :         case IEEE80211_SMPS_NUM_MODES:
     502                 :          0 :                 WARN_ON(1);
     503                 :            :                 /* fall through */
     504                 :          0 :         case IEEE80211_SMPS_OFF:
     505                 :          0 :                 cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
     506                 :            :                         IEEE80211_HT_CAP_SM_PS_SHIFT;
     507                 :          0 :                 break;
     508                 :            :         case IEEE80211_SMPS_STATIC:
     509                 :            :                 cap |= WLAN_HT_CAP_SM_PS_STATIC <<
     510                 :            :                         IEEE80211_HT_CAP_SM_PS_SHIFT;
     511                 :            :                 break;
     512                 :          0 :         case IEEE80211_SMPS_DYNAMIC:
     513                 :          0 :                 cap |= WLAN_HT_CAP_SM_PS_DYNAMIC <<
     514                 :            :                         IEEE80211_HT_CAP_SM_PS_SHIFT;
     515                 :          0 :                 break;
     516                 :            :         }
     517                 :            : 
     518                 :            :         /* reserve and fill IE */
     519                 :          0 :         pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
     520                 :          0 :         ieee80211_ie_build_ht_cap(pos, &ht_cap, cap);
     521                 :          0 : }
     522                 :            : 
     523                 :            : /* This function determines vht capability flags for the association
     524                 :            :  * and builds the IE.
     525                 :            :  * Note - the function may set the owner of the MU-MIMO capability
     526                 :            :  */
     527                 :          0 : static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
     528                 :            :                                  struct sk_buff *skb,
     529                 :            :                                  struct ieee80211_supported_band *sband,
     530                 :            :                                  struct ieee80211_vht_cap *ap_vht_cap)
     531                 :            : {
     532                 :          0 :         struct ieee80211_local *local = sdata->local;
     533                 :          0 :         u8 *pos;
     534                 :          0 :         u32 cap;
     535                 :          0 :         struct ieee80211_sta_vht_cap vht_cap;
     536                 :          0 :         u32 mask, ap_bf_sts, our_bf_sts;
     537                 :            : 
     538                 :          0 :         BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap));
     539                 :            : 
     540                 :          0 :         memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap));
     541                 :          0 :         ieee80211_apply_vhtcap_overrides(sdata, &vht_cap);
     542                 :            : 
     543                 :            :         /* determine capability flags */
     544                 :          0 :         cap = vht_cap.cap;
     545                 :            : 
     546         [ #  # ]:          0 :         if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_80P80MHZ) {
     547                 :          0 :                 u32 bw = cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
     548                 :            : 
     549                 :          0 :                 cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
     550                 :          0 :                 if (bw == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ||
     551         [ #  # ]:          0 :                     bw == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
     552                 :          0 :                         cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
     553                 :            :         }
     554                 :            : 
     555         [ #  # ]:          0 :         if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_160MHZ) {
     556                 :          0 :                 cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160;
     557                 :          0 :                 cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
     558                 :            :         }
     559                 :            : 
     560                 :            :         /*
     561                 :            :          * Some APs apparently get confused if our capabilities are better
     562                 :            :          * than theirs, so restrict what we advertise in the assoc request.
     563                 :            :          */
     564         [ #  # ]:          0 :         if (!(ap_vht_cap->vht_cap_info &
     565                 :            :                         cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)))
     566                 :          0 :                 cap &= ~(IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
     567                 :            :                          IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
     568         [ #  # ]:          0 :         else if (!(ap_vht_cap->vht_cap_info &
     569                 :            :                         cpu_to_le32(IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)))
     570                 :          0 :                 cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
     571                 :            : 
     572                 :            :         /*
     573                 :            :          * If some other vif is using the MU-MIMO capablity we cannot associate
     574                 :            :          * using MU-MIMO - this will lead to contradictions in the group-id
     575                 :            :          * mechanism.
     576                 :            :          * Ownership is defined since association request, in order to avoid
     577                 :            :          * simultaneous associations with MU-MIMO.
     578                 :            :          */
     579         [ #  # ]:          0 :         if (cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) {
     580                 :          0 :                 bool disable_mu_mimo = false;
     581                 :          0 :                 struct ieee80211_sub_if_data *other;
     582                 :            : 
     583         [ #  # ]:          0 :                 list_for_each_entry_rcu(other, &local->interfaces, list) {
     584         [ #  # ]:          0 :                         if (other->vif.mu_mimo_owner) {
     585                 :            :                                 disable_mu_mimo = true;
     586                 :            :                                 break;
     587                 :            :                         }
     588                 :            :                 }
     589         [ #  # ]:          0 :                 if (disable_mu_mimo)
     590                 :          0 :                         cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
     591                 :            :                 else
     592                 :          0 :                         sdata->vif.mu_mimo_owner = true;
     593                 :            :         }
     594                 :            : 
     595                 :          0 :         mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
     596                 :            : 
     597                 :          0 :         ap_bf_sts = le32_to_cpu(ap_vht_cap->vht_cap_info) & mask;
     598                 :          0 :         our_bf_sts = cap & mask;
     599                 :            : 
     600         [ #  # ]:          0 :         if (ap_bf_sts < our_bf_sts) {
     601                 :          0 :                 cap &= ~mask;
     602                 :          0 :                 cap |= ap_bf_sts;
     603                 :            :         }
     604                 :            : 
     605                 :            :         /* reserve and fill IE */
     606                 :          0 :         pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
     607                 :          0 :         ieee80211_ie_build_vht_cap(pos, &vht_cap, cap);
     608                 :          0 : }
     609                 :            : 
     610                 :            : /* This function determines HE capability flags for the association
     611                 :            :  * and builds the IE.
     612                 :            :  */
     613                 :            : static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
     614                 :            :                                 struct sk_buff *skb,
     615                 :            :                                 struct ieee80211_supported_band *sband)
     616                 :            : {
     617                 :            :         u8 *pos;
     618                 :            :         const struct ieee80211_sta_he_cap *he_cap = NULL;
     619                 :            :         u8 he_cap_size;
     620                 :            : 
     621                 :            :         he_cap = ieee80211_get_he_sta_cap(sband);
     622                 :            :         if (!he_cap)
     623                 :            :                 return;
     624                 :            : 
     625                 :            :         /*
     626                 :            :          * TODO: the 1 added is because this temporarily is under the EXTENSION
     627                 :            :          * IE. Get rid of it when it moves.
     628                 :            :          */
     629                 :            :         he_cap_size =
     630                 :            :                 2 + 1 + sizeof(he_cap->he_cap_elem) +
     631                 :            :                 ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem) +
     632                 :            :                 ieee80211_he_ppe_size(he_cap->ppe_thres[0],
     633                 :            :                                       he_cap->he_cap_elem.phy_cap_info);
     634                 :            :         pos = skb_put(skb, he_cap_size);
     635                 :            :         ieee80211_ie_build_he_cap(pos, he_cap, pos + he_cap_size);
     636                 :            : }
     637                 :            : 
     638                 :          0 : static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
     639                 :            : {
     640                 :          0 :         struct ieee80211_local *local = sdata->local;
     641                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
     642                 :          0 :         struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
     643                 :          0 :         struct sk_buff *skb;
     644                 :          0 :         struct ieee80211_mgmt *mgmt;
     645                 :          0 :         u8 *pos, qos_info, *ie_start;
     646                 :          0 :         size_t offset = 0, noffset;
     647                 :          0 :         int i, count, rates_len, supp_rates_len, shift;
     648                 :          0 :         u16 capab;
     649                 :          0 :         struct ieee80211_supported_band *sband;
     650                 :          0 :         struct ieee80211_chanctx_conf *chanctx_conf;
     651                 :          0 :         struct ieee80211_channel *chan;
     652                 :          0 :         u32 rates = 0;
     653                 :            : 
     654                 :          0 :         sdata_assert_lock(sdata);
     655                 :            : 
     656                 :          0 :         rcu_read_lock();
     657         [ #  # ]:          0 :         chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
     658   [ #  #  #  # ]:          0 :         if (WARN_ON(!chanctx_conf)) {
     659                 :          0 :                 rcu_read_unlock();
     660                 :          0 :                 return;
     661                 :            :         }
     662                 :          0 :         chan = chanctx_conf->def.chan;
     663                 :          0 :         rcu_read_unlock();
     664                 :          0 :         sband = local->hw.wiphy->bands[chan->band];
     665                 :          0 :         shift = ieee80211_vif_get_shift(&sdata->vif);
     666                 :            : 
     667         [ #  # ]:          0 :         if (assoc_data->supp_rates_len) {
     668                 :            :                 /*
     669                 :            :                  * Get all rates supported by the device and the AP as
     670                 :            :                  * some APs don't like getting a superset of their rates
     671                 :            :                  * in the association request (e.g. D-Link DAP 1353 in
     672                 :            :                  * b-only mode)...
     673                 :            :                  */
     674                 :          0 :                 rates_len = ieee80211_parse_bitrates(&chanctx_conf->def, sband,
     675                 :            :                                                      assoc_data->supp_rates,
     676                 :            :                                                      assoc_data->supp_rates_len,
     677                 :            :                                                      &rates);
     678                 :            :         } else {
     679                 :            :                 /*
     680                 :            :                  * In case AP not provide any supported rates information
     681                 :            :                  * before association, we send information element(s) with
     682                 :            :                  * all rates that we support.
     683                 :            :                  */
     684                 :            :                 rates_len = 0;
     685         [ #  # ]:          0 :                 for (i = 0; i < sband->n_bitrates; i++) {
     686                 :          0 :                         rates |= BIT(i);
     687                 :          0 :                         rates_len++;
     688                 :            :                 }
     689                 :            :         }
     690                 :            : 
     691                 :          0 :         skb = alloc_skb(local->hw.extra_tx_headroom +
     692                 :            :                         sizeof(*mgmt) + /* bit too much but doesn't matter */
     693                 :          0 :                         2 + assoc_data->ssid_len + /* SSID */
     694                 :          0 :                         4 + rates_len + /* (extended) rates */
     695                 :            :                         4 + /* power capability */
     696                 :          0 :                         2 + 2 * sband->n_channels + /* supported channels */
     697                 :            :                         2 + sizeof(struct ieee80211_ht_cap) + /* HT */
     698                 :            :                         2 + sizeof(struct ieee80211_vht_cap) + /* VHT */
     699                 :            :                         2 + 1 + sizeof(struct ieee80211_he_cap_elem) + /* HE */
     700                 :            :                                 sizeof(struct ieee80211_he_mcs_nss_supp) +
     701                 :          0 :                                 IEEE80211_HE_PPE_THRES_MAX_LEN +
     702                 :          0 :                         assoc_data->ie_len + /* extra IEs */
     703         [ #  # ]:          0 :                         (assoc_data->fils_kek_len ? 16 /* AES-SIV */ : 0) +
     704                 :            :                         9, /* WMM */
     705                 :            :                         GFP_KERNEL);
     706         [ #  # ]:          0 :         if (!skb)
     707                 :            :                 return;
     708                 :            : 
     709         [ #  # ]:          0 :         skb_reserve(skb, local->hw.extra_tx_headroom);
     710                 :            : 
     711                 :          0 :         capab = WLAN_CAPABILITY_ESS;
     712                 :            : 
     713         [ #  # ]:          0 :         if (sband->band == NL80211_BAND_2GHZ) {
     714                 :          0 :                 capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
     715                 :          0 :                 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
     716                 :            :         }
     717                 :            : 
     718         [ #  # ]:          0 :         if (assoc_data->capability & WLAN_CAPABILITY_PRIVACY)
     719                 :          0 :                 capab |= WLAN_CAPABILITY_PRIVACY;
     720                 :            : 
     721   [ #  #  #  # ]:          0 :         if ((assoc_data->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
     722                 :            :             ieee80211_hw_check(&local->hw, SPECTRUM_MGMT))
     723                 :          0 :                 capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
     724                 :            : 
     725         [ #  # ]:          0 :         if (ifmgd->flags & IEEE80211_STA_ENABLE_RRM)
     726                 :          0 :                 capab |= WLAN_CAPABILITY_RADIO_MEASURE;
     727                 :            : 
     728                 :          0 :         mgmt = skb_put_zero(skb, 24);
     729                 :          0 :         memcpy(mgmt->da, assoc_data->bss->bssid, ETH_ALEN);
     730                 :          0 :         memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
     731                 :          0 :         memcpy(mgmt->bssid, assoc_data->bss->bssid, ETH_ALEN);
     732                 :            : 
     733         [ #  # ]:          0 :         if (!is_zero_ether_addr(assoc_data->prev_bssid)) {
     734                 :          0 :                 skb_put(skb, 10);
     735                 :          0 :                 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
     736                 :            :                                                   IEEE80211_STYPE_REASSOC_REQ);
     737                 :          0 :                 mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
     738                 :          0 :                 mgmt->u.reassoc_req.listen_interval =
     739                 :          0 :                                 cpu_to_le16(local->hw.conf.listen_interval);
     740                 :          0 :                 memcpy(mgmt->u.reassoc_req.current_ap, assoc_data->prev_bssid,
     741                 :            :                        ETH_ALEN);
     742                 :            :         } else {
     743                 :          0 :                 skb_put(skb, 4);
     744                 :          0 :                 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
     745                 :            :                                                   IEEE80211_STYPE_ASSOC_REQ);
     746                 :          0 :                 mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
     747                 :          0 :                 mgmt->u.assoc_req.listen_interval =
     748                 :          0 :                                 cpu_to_le16(local->hw.conf.listen_interval);
     749                 :            :         }
     750                 :            : 
     751                 :            :         /* SSID */
     752                 :          0 :         pos = skb_put(skb, 2 + assoc_data->ssid_len);
     753                 :          0 :         ie_start = pos;
     754                 :          0 :         *pos++ = WLAN_EID_SSID;
     755                 :          0 :         *pos++ = assoc_data->ssid_len;
     756                 :          0 :         memcpy(pos, assoc_data->ssid, assoc_data->ssid_len);
     757                 :            : 
     758                 :            :         /* add all rates which were marked to be used above */
     759                 :          0 :         supp_rates_len = rates_len;
     760                 :          0 :         if (supp_rates_len > 8)
     761                 :            :                 supp_rates_len = 8;
     762                 :            : 
     763                 :          0 :         pos = skb_put(skb, supp_rates_len + 2);
     764                 :          0 :         *pos++ = WLAN_EID_SUPP_RATES;
     765                 :          0 :         *pos++ = supp_rates_len;
     766                 :            : 
     767                 :          0 :         count = 0;
     768         [ #  # ]:          0 :         for (i = 0; i < sband->n_bitrates; i++) {
     769         [ #  # ]:          0 :                 if (BIT(i) & rates) {
     770                 :          0 :                         int rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
     771                 :            :                                                 5 * (1 << shift));
     772                 :          0 :                         *pos++ = (u8) rate;
     773         [ #  # ]:          0 :                         if (++count == 8)
     774                 :            :                                 break;
     775                 :            :                 }
     776                 :            :         }
     777                 :            : 
     778         [ #  # ]:          0 :         if (rates_len > count) {
     779                 :          0 :                 pos = skb_put(skb, rates_len - count + 2);
     780                 :          0 :                 *pos++ = WLAN_EID_EXT_SUPP_RATES;
     781                 :          0 :                 *pos++ = rates_len - count;
     782                 :            : 
     783         [ #  # ]:          0 :                 for (i++; i < sband->n_bitrates; i++) {
     784         [ #  # ]:          0 :                         if (BIT(i) & rates) {
     785                 :          0 :                                 int rate;
     786                 :          0 :                                 rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
     787                 :            :                                                     5 * (1 << shift));
     788                 :          0 :                                 *pos++ = (u8) rate;
     789                 :            :                         }
     790                 :            :                 }
     791                 :            :         }
     792                 :            : 
     793         [ #  # ]:          0 :         if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT ||
     794                 :            :             capab & WLAN_CAPABILITY_RADIO_MEASURE) {
     795                 :          0 :                 pos = skb_put(skb, 4);
     796                 :          0 :                 *pos++ = WLAN_EID_PWR_CAPABILITY;
     797                 :          0 :                 *pos++ = 2;
     798                 :          0 :                 *pos++ = 0; /* min tx power */
     799                 :            :                  /* max tx power */
     800      [ #  #  # ]:          0 :                 *pos++ = ieee80211_chandef_max_power(&chanctx_conf->def);
     801                 :            :         }
     802                 :            : 
     803         [ #  # ]:          0 :         if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
     804                 :            :                 /* TODO: get this in reg domain format */
     805                 :          0 :                 pos = skb_put(skb, 2 * sband->n_channels + 2);
     806                 :          0 :                 *pos++ = WLAN_EID_SUPPORTED_CHANNELS;
     807                 :          0 :                 *pos++ = 2 * sband->n_channels;
     808         [ #  # ]:          0 :                 for (i = 0; i < sband->n_channels; i++) {
     809                 :          0 :                         *pos++ = ieee80211_frequency_to_channel(
     810                 :          0 :                                         sband->channels[i].center_freq);
     811                 :          0 :                         *pos++ = 1; /* one channel in the subband*/
     812                 :            :                 }
     813                 :            :         }
     814                 :            : 
     815                 :            :         /* Set MBSSID support for HE AP if needed */
     816         [ #  # ]:          0 :         if (ieee80211_hw_check(&local->hw, SUPPORTS_ONLY_HE_MULTI_BSSID) &&
     817   [ #  #  #  # ]:          0 :             !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && assoc_data->ie_len) {
     818                 :          0 :                 struct element *elem;
     819                 :            : 
     820                 :            :                 /* we know it's writable, cast away the const */
     821                 :          0 :                 elem = (void *)cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY,
     822                 :          0 :                                                   assoc_data->ie,
     823                 :            :                                                   assoc_data->ie_len);
     824                 :            : 
     825                 :            :                 /* We can probably assume both always true */
     826   [ #  #  #  # ]:          0 :                 if (elem && elem->datalen >= 3)
     827                 :          0 :                         elem->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT;
     828                 :            :         }
     829                 :            : 
     830                 :            :         /* if present, add any custom IEs that go before HT */
     831         [ #  # ]:          0 :         if (assoc_data->ie_len) {
     832                 :          0 :                 static const u8 before_ht[] = {
     833                 :            :                         WLAN_EID_SSID,
     834                 :            :                         WLAN_EID_SUPP_RATES,
     835                 :            :                         WLAN_EID_EXT_SUPP_RATES,
     836                 :            :                         WLAN_EID_PWR_CAPABILITY,
     837                 :            :                         WLAN_EID_SUPPORTED_CHANNELS,
     838                 :            :                         WLAN_EID_RSN,
     839                 :            :                         WLAN_EID_QOS_CAPA,
     840                 :            :                         WLAN_EID_RRM_ENABLED_CAPABILITIES,
     841                 :            :                         WLAN_EID_MOBILITY_DOMAIN,
     842                 :            :                         WLAN_EID_FAST_BSS_TRANSITION,   /* reassoc only */
     843                 :            :                         WLAN_EID_RIC_DATA,              /* reassoc only */
     844                 :            :                         WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
     845                 :            :                 };
     846                 :          0 :                 static const u8 after_ric[] = {
     847                 :            :                         WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
     848                 :            :                         WLAN_EID_HT_CAPABILITY,
     849                 :            :                         WLAN_EID_BSS_COEX_2040,
     850                 :            :                         /* luckily this is almost always there */
     851                 :            :                         WLAN_EID_EXT_CAPABILITY,
     852                 :            :                         WLAN_EID_QOS_TRAFFIC_CAPA,
     853                 :            :                         WLAN_EID_TIM_BCAST_REQ,
     854                 :            :                         WLAN_EID_INTERWORKING,
     855                 :            :                         /* 60 GHz (Multi-band, DMG, MMS) can't happen */
     856                 :            :                         WLAN_EID_VHT_CAPABILITY,
     857                 :            :                         WLAN_EID_OPMODE_NOTIF,
     858                 :            :                 };
     859                 :            : 
     860                 :          0 :                 noffset = ieee80211_ie_split_ric(assoc_data->ie,
     861                 :            :                                                  assoc_data->ie_len,
     862                 :            :                                                  before_ht,
     863                 :            :                                                  ARRAY_SIZE(before_ht),
     864                 :            :                                                  after_ric,
     865                 :            :                                                  ARRAY_SIZE(after_ric),
     866                 :            :                                                  offset);
     867                 :          0 :                 skb_put_data(skb, assoc_data->ie + offset, noffset - offset);
     868                 :          0 :                 offset = noffset;
     869                 :            :         }
     870                 :            : 
     871   [ #  #  #  # ]:          0 :         if (WARN_ON_ONCE((ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
     872                 :            :                          !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)))
     873                 :          0 :                 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
     874                 :            : 
     875         [ #  # ]:          0 :         if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
     876                 :          0 :                 ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
     877                 :            :                                     sband, chan, sdata->smps_mode);
     878                 :            : 
     879                 :            :         /* if present, add any custom IEs that go before VHT */
     880         [ #  # ]:          0 :         if (assoc_data->ie_len) {
     881                 :          0 :                 static const u8 before_vht[] = {
     882                 :            :                         /*
     883                 :            :                          * no need to list the ones split off before HT
     884                 :            :                          * or generated here
     885                 :            :                          */
     886                 :            :                         WLAN_EID_BSS_COEX_2040,
     887                 :            :                         WLAN_EID_EXT_CAPABILITY,
     888                 :            :                         WLAN_EID_QOS_TRAFFIC_CAPA,
     889                 :            :                         WLAN_EID_TIM_BCAST_REQ,
     890                 :            :                         WLAN_EID_INTERWORKING,
     891                 :            :                         /* 60 GHz (Multi-band, DMG, MMS) can't happen */
     892                 :            :                 };
     893                 :            : 
     894                 :            :                 /* RIC already taken above, so no need to handle here anymore */
     895                 :          0 :                 noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len,
     896                 :            :                                              before_vht, ARRAY_SIZE(before_vht),
     897                 :            :                                              offset);
     898                 :          0 :                 skb_put_data(skb, assoc_data->ie + offset, noffset - offset);
     899                 :          0 :                 offset = noffset;
     900                 :            :         }
     901                 :            : 
     902                 :            :         /* if present, add any custom IEs that go before HE */
     903         [ #  # ]:          0 :         if (assoc_data->ie_len) {
     904                 :          0 :                 static const u8 before_he[] = {
     905                 :            :                         /*
     906                 :            :                          * no need to list the ones split off before VHT
     907                 :            :                          * or generated here
     908                 :            :                          */
     909                 :            :                         WLAN_EID_OPMODE_NOTIF,
     910                 :            :                         WLAN_EID_EXTENSION, WLAN_EID_EXT_FUTURE_CHAN_GUIDANCE,
     911                 :            :                         /* 11ai elements */
     912                 :            :                         WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_SESSION,
     913                 :            :                         WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_PUBLIC_KEY,
     914                 :            :                         WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_KEY_CONFIRM,
     915                 :            :                         WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_HLP_CONTAINER,
     916                 :            :                         WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN,
     917                 :            :                         /* TODO: add 11ah/11aj/11ak elements */
     918                 :            :                 };
     919                 :            : 
     920                 :            :                 /* RIC already taken above, so no need to handle here anymore */
     921                 :          0 :                 noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len,
     922                 :            :                                              before_he, ARRAY_SIZE(before_he),
     923                 :            :                                              offset);
     924                 :          0 :                 pos = skb_put(skb, noffset - offset);
     925                 :          0 :                 memcpy(pos, assoc_data->ie + offset, noffset - offset);
     926                 :          0 :                 offset = noffset;
     927                 :            :         }
     928                 :            : 
     929         [ #  # ]:          0 :         if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
     930                 :          0 :                 ieee80211_add_vht_ie(sdata, skb, sband,
     931                 :            :                                      &assoc_data->ap_vht_cap);
     932                 :            : 
     933                 :            :         /*
     934                 :            :          * If AP doesn't support HT, mark HE as disabled.
     935                 :            :          * If on the 5GHz band, make sure it supports VHT.
     936                 :            :          */
     937         [ #  # ]:          0 :         if (ifmgd->flags & IEEE80211_STA_DISABLE_HT ||
     938         [ #  # ]:          0 :             (sband->band == NL80211_BAND_5GHZ &&
     939         [ #  # ]:          0 :              ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
     940                 :          0 :                 ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
     941                 :            : 
     942         [ #  # ]:          0 :         if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
     943                 :          0 :                 ieee80211_add_he_ie(sdata, skb, sband);
     944                 :            : 
     945                 :            :         /* if present, add any custom non-vendor IEs that go after HE */
     946         [ #  # ]:          0 :         if (assoc_data->ie_len) {
     947                 :          0 :                 noffset = ieee80211_ie_split_vendor(assoc_data->ie,
     948                 :            :                                                     assoc_data->ie_len,
     949                 :            :                                                     offset);
     950                 :          0 :                 skb_put_data(skb, assoc_data->ie + offset, noffset - offset);
     951                 :          0 :                 offset = noffset;
     952                 :            :         }
     953                 :            : 
     954         [ #  # ]:          0 :         if (assoc_data->wmm) {
     955         [ #  # ]:          0 :                 if (assoc_data->uapsd) {
     956                 :          0 :                         qos_info = ifmgd->uapsd_queues;
     957                 :          0 :                         qos_info |= (ifmgd->uapsd_max_sp_len <<
     958                 :            :                                      IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT);
     959                 :            :                 } else {
     960                 :            :                         qos_info = 0;
     961                 :            :                 }
     962                 :            : 
     963                 :          0 :                 pos = ieee80211_add_wmm_info_ie(skb_put(skb, 9), qos_info);
     964                 :            :         }
     965                 :            : 
     966                 :            :         /* add any remaining custom (i.e. vendor specific here) IEs */
     967         [ #  # ]:          0 :         if (assoc_data->ie_len) {
     968                 :          0 :                 noffset = assoc_data->ie_len;
     969                 :          0 :                 skb_put_data(skb, assoc_data->ie + offset, noffset - offset);
     970                 :            :         }
     971                 :            : 
     972   [ #  #  #  # ]:          0 :         if (assoc_data->fils_kek_len &&
     973                 :          0 :             fils_encrypt_assoc_req(skb, assoc_data) < 0) {
     974                 :          0 :                 dev_kfree_skb(skb);
     975                 :          0 :                 return;
     976                 :            :         }
     977                 :            : 
     978                 :          0 :         pos = skb_tail_pointer(skb);
     979                 :          0 :         kfree(ifmgd->assoc_req_ies);
     980                 :          0 :         ifmgd->assoc_req_ies = kmemdup(ie_start, pos - ie_start, GFP_ATOMIC);
     981                 :          0 :         ifmgd->assoc_req_ies_len = pos - ie_start;
     982                 :            : 
     983                 :          0 :         drv_mgd_prepare_tx(local, sdata, 0);
     984                 :            : 
     985                 :          0 :         IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
     986         [ #  # ]:          0 :         if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
     987                 :          0 :                 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
     988                 :            :                                                 IEEE80211_TX_INTFL_MLME_CONN_TX;
     989                 :          0 :         ieee80211_tx_skb(sdata, skb);
     990                 :            : }
     991                 :            : 
     992                 :          0 : void ieee80211_send_pspoll(struct ieee80211_local *local,
     993                 :            :                            struct ieee80211_sub_if_data *sdata)
     994                 :            : {
     995                 :          0 :         struct ieee80211_pspoll *pspoll;
     996                 :          0 :         struct sk_buff *skb;
     997                 :            : 
     998                 :          0 :         skb = ieee80211_pspoll_get(&local->hw, &sdata->vif);
     999         [ #  # ]:          0 :         if (!skb)
    1000                 :            :                 return;
    1001                 :            : 
    1002                 :          0 :         pspoll = (struct ieee80211_pspoll *) skb->data;
    1003                 :          0 :         pspoll->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
    1004                 :            : 
    1005                 :          0 :         IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
    1006                 :          0 :         ieee80211_tx_skb(sdata, skb);
    1007                 :            : }
    1008                 :            : 
    1009                 :          0 : void ieee80211_send_nullfunc(struct ieee80211_local *local,
    1010                 :            :                              struct ieee80211_sub_if_data *sdata,
    1011                 :            :                              bool powersave)
    1012                 :            : {
    1013                 :          0 :         struct sk_buff *skb;
    1014                 :          0 :         struct ieee80211_hdr_3addr *nullfunc;
    1015                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    1016                 :            : 
    1017                 :            :         /* Don't send NDPs when STA is connected HE */
    1018         [ #  # ]:          0 :         if (sdata->vif.type == NL80211_IFTYPE_STATION &&
    1019         [ #  # ]:          0 :             !(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
    1020                 :            :                 return;
    1021                 :            : 
    1022                 :          0 :         skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif,
    1023                 :          0 :                 !ieee80211_hw_check(&local->hw, DOESNT_SUPPORT_QOS_NDP));
    1024         [ #  # ]:          0 :         if (!skb)
    1025                 :            :                 return;
    1026                 :            : 
    1027                 :          0 :         nullfunc = (struct ieee80211_hdr_3addr *) skb->data;
    1028         [ #  # ]:          0 :         if (powersave)
    1029                 :          0 :                 nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
    1030                 :            : 
    1031                 :          0 :         IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
    1032                 :            :                                         IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
    1033                 :            : 
    1034         [ #  # ]:          0 :         if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
    1035                 :          0 :                 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
    1036                 :            : 
    1037         [ #  # ]:          0 :         if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL)
    1038                 :          0 :                 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE;
    1039                 :            : 
    1040                 :          0 :         ieee80211_tx_skb(sdata, skb);
    1041                 :            : }
    1042                 :            : 
    1043                 :            : static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
    1044                 :            :                                           struct ieee80211_sub_if_data *sdata)
    1045                 :            : {
    1046                 :            :         struct sk_buff *skb;
    1047                 :            :         struct ieee80211_hdr *nullfunc;
    1048                 :            :         __le16 fc;
    1049                 :            : 
    1050                 :            :         if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
    1051                 :            :                 return;
    1052                 :            : 
    1053                 :            :         /* Don't send NDPs when connected HE */
    1054                 :            :         if (!(sdata->u.mgd.flags & IEEE80211_STA_DISABLE_HE))
    1055                 :            :                 return;
    1056                 :            : 
    1057                 :            :         skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30);
    1058                 :            :         if (!skb)
    1059                 :            :                 return;
    1060                 :            : 
    1061                 :            :         skb_reserve(skb, local->hw.extra_tx_headroom);
    1062                 :            : 
    1063                 :            :         nullfunc = skb_put_zero(skb, 30);
    1064                 :            :         fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
    1065                 :            :                          IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
    1066                 :            :         nullfunc->frame_control = fc;
    1067                 :            :         memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN);
    1068                 :            :         memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
    1069                 :            :         memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN);
    1070                 :            :         memcpy(nullfunc->addr4, sdata->vif.addr, ETH_ALEN);
    1071                 :            : 
    1072                 :            :         IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
    1073                 :            :         ieee80211_tx_skb(sdata, skb);
    1074                 :            : }
    1075                 :            : 
    1076                 :            : /* spectrum management related things */
    1077                 :          0 : static void ieee80211_chswitch_work(struct work_struct *work)
    1078                 :            : {
    1079                 :          0 :         struct ieee80211_sub_if_data *sdata =
    1080                 :          0 :                 container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
    1081                 :          0 :         struct ieee80211_local *local = sdata->local;
    1082                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    1083                 :          0 :         int ret;
    1084                 :            : 
    1085         [ #  # ]:          0 :         if (!ieee80211_sdata_running(sdata))
    1086                 :            :                 return;
    1087                 :            : 
    1088                 :          0 :         sdata_lock(sdata);
    1089                 :          0 :         mutex_lock(&local->mtx);
    1090                 :          0 :         mutex_lock(&local->chanctx_mtx);
    1091                 :            : 
    1092         [ #  # ]:          0 :         if (!ifmgd->associated)
    1093                 :          0 :                 goto out;
    1094                 :            : 
    1095         [ #  # ]:          0 :         if (!sdata->vif.csa_active)
    1096                 :          0 :                 goto out;
    1097                 :            : 
    1098                 :            :         /*
    1099                 :            :          * using reservation isn't immediate as it may be deferred until later
    1100                 :            :          * with multi-vif. once reservation is complete it will re-schedule the
    1101                 :            :          * work with no reserved_chanctx so verify chandef to check if it
    1102                 :            :          * completed successfully
    1103                 :            :          */
    1104                 :            : 
    1105         [ #  # ]:          0 :         if (sdata->reserved_chanctx) {
    1106                 :          0 :                 struct ieee80211_supported_band *sband = NULL;
    1107                 :          0 :                 struct sta_info *mgd_sta = NULL;
    1108                 :          0 :                 enum ieee80211_sta_rx_bandwidth bw = IEEE80211_STA_RX_BW_20;
    1109                 :            : 
    1110                 :            :                 /*
    1111                 :            :                  * with multi-vif csa driver may call ieee80211_csa_finish()
    1112                 :            :                  * many times while waiting for other interfaces to use their
    1113                 :            :                  * reservations
    1114                 :            :                  */
    1115         [ #  # ]:          0 :                 if (sdata->reserved_ready)
    1116                 :          0 :                         goto out;
    1117                 :            : 
    1118                 :          0 :                 if (sdata->vif.bss_conf.chandef.width !=
    1119         [ #  # ]:          0 :                     sdata->csa_chandef.width) {
    1120                 :            :                         /*
    1121                 :            :                          * For managed interface, we need to also update the AP
    1122                 :            :                          * station bandwidth and align the rate scale algorithm
    1123                 :            :                          * on the bandwidth change. Here we only consider the
    1124                 :            :                          * bandwidth of the new channel definition (as channel
    1125                 :            :                          * switch flow does not have the full HT/VHT/HE
    1126                 :            :                          * information), assuming that if additional changes are
    1127                 :            :                          * required they would be done as part of the processing
    1128                 :            :                          * of the next beacon from the AP.
    1129                 :            :                          */
    1130         [ #  # ]:          0 :                         switch (sdata->csa_chandef.width) {
    1131                 :            :                         case NL80211_CHAN_WIDTH_20_NOHT:
    1132                 :            :                         case NL80211_CHAN_WIDTH_20:
    1133                 :            :                         default:
    1134                 :            :                                 bw = IEEE80211_STA_RX_BW_20;
    1135                 :            :                                 break;
    1136                 :            :                         case NL80211_CHAN_WIDTH_40:
    1137                 :            :                                 bw = IEEE80211_STA_RX_BW_40;
    1138                 :            :                                 break;
    1139                 :            :                         case NL80211_CHAN_WIDTH_80:
    1140                 :            :                                 bw = IEEE80211_STA_RX_BW_80;
    1141                 :            :                                 break;
    1142                 :            :                         case NL80211_CHAN_WIDTH_80P80:
    1143                 :            :                         case NL80211_CHAN_WIDTH_160:
    1144                 :            :                                 bw = IEEE80211_STA_RX_BW_160;
    1145                 :            :                                 break;
    1146                 :            :                         }
    1147                 :            : 
    1148                 :          0 :                         mgd_sta = sta_info_get(sdata, ifmgd->bssid);
    1149                 :          0 :                         sband =
    1150                 :          0 :                                 local->hw.wiphy->bands[sdata->csa_chandef.chan->band];
    1151                 :            :                 }
    1152                 :            : 
    1153                 :          0 :                 if (sdata->vif.bss_conf.chandef.width >
    1154         [ #  # ]:          0 :                     sdata->csa_chandef.width) {
    1155                 :          0 :                         mgd_sta->sta.bandwidth = bw;
    1156                 :          0 :                         rate_control_rate_update(local, sband, mgd_sta,
    1157                 :            :                                                  IEEE80211_RC_BW_CHANGED);
    1158                 :            :                 }
    1159                 :            : 
    1160                 :          0 :                 ret = ieee80211_vif_use_reserved_context(sdata);
    1161         [ #  # ]:          0 :                 if (ret) {
    1162                 :          0 :                         sdata_info(sdata,
    1163                 :            :                                    "failed to use reserved channel context, disconnecting (err=%d)\n",
    1164                 :            :                                    ret);
    1165                 :          0 :                         ieee80211_queue_work(&sdata->local->hw,
    1166                 :            :                                              &ifmgd->csa_connection_drop_work);
    1167                 :          0 :                         goto out;
    1168                 :            :                 }
    1169                 :            : 
    1170                 :          0 :                 if (sdata->vif.bss_conf.chandef.width <
    1171         [ #  # ]:          0 :                     sdata->csa_chandef.width) {
    1172                 :          0 :                         mgd_sta->sta.bandwidth = bw;
    1173                 :          0 :                         rate_control_rate_update(local, sband, mgd_sta,
    1174                 :            :                                                  IEEE80211_RC_BW_CHANGED);
    1175                 :            :                 }
    1176                 :            : 
    1177                 :          0 :                 goto out;
    1178                 :            :         }
    1179                 :            : 
    1180   [ #  #  #  # ]:          0 :         if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
    1181                 :            :                                         &sdata->csa_chandef)) {
    1182                 :          0 :                 sdata_info(sdata,
    1183                 :            :                            "failed to finalize channel switch, disconnecting\n");
    1184                 :          0 :                 ieee80211_queue_work(&sdata->local->hw,
    1185                 :            :                                      &ifmgd->csa_connection_drop_work);
    1186                 :          0 :                 goto out;
    1187                 :            :         }
    1188                 :            : 
    1189                 :          0 :         ifmgd->csa_waiting_bcn = true;
    1190                 :            : 
    1191                 :          0 :         ieee80211_sta_reset_beacon_monitor(sdata);
    1192                 :          0 :         ieee80211_sta_reset_conn_monitor(sdata);
    1193                 :            : 
    1194                 :          0 : out:
    1195                 :          0 :         mutex_unlock(&local->chanctx_mtx);
    1196                 :          0 :         mutex_unlock(&local->mtx);
    1197                 :          0 :         sdata_unlock(sdata);
    1198                 :            : }
    1199                 :            : 
    1200                 :          0 : static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata)
    1201                 :            : {
    1202                 :          0 :         struct ieee80211_local *local = sdata->local;
    1203                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    1204                 :          0 :         int ret;
    1205                 :            : 
    1206         [ #  # ]:          0 :         sdata_assert_lock(sdata);
    1207                 :            : 
    1208         [ #  # ]:          0 :         WARN_ON(!sdata->vif.csa_active);
    1209                 :            : 
    1210         [ #  # ]:          0 :         if (sdata->csa_block_tx) {
    1211                 :          0 :                 ieee80211_wake_vif_queues(local, sdata,
    1212                 :            :                                           IEEE80211_QUEUE_STOP_REASON_CSA);
    1213                 :          0 :                 sdata->csa_block_tx = false;
    1214                 :            :         }
    1215                 :            : 
    1216                 :          0 :         sdata->vif.csa_active = false;
    1217                 :          0 :         ifmgd->csa_waiting_bcn = false;
    1218                 :            : 
    1219                 :          0 :         ret = drv_post_channel_switch(sdata);
    1220         [ #  # ]:          0 :         if (ret) {
    1221                 :          0 :                 sdata_info(sdata,
    1222                 :            :                            "driver post channel switch failed, disconnecting\n");
    1223                 :          0 :                 ieee80211_queue_work(&local->hw,
    1224                 :            :                                      &ifmgd->csa_connection_drop_work);
    1225                 :          0 :                 return;
    1226                 :            :         }
    1227                 :            : 
    1228                 :          0 :         cfg80211_ch_switch_notify(sdata->dev, &sdata->reserved_chandef);
    1229                 :            : }
    1230                 :            : 
    1231                 :          0 : void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
    1232                 :            : {
    1233                 :          0 :         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
    1234                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    1235                 :            : 
    1236                 :          0 :         trace_api_chswitch_done(sdata, success);
    1237         [ #  # ]:          0 :         if (!success) {
    1238                 :          0 :                 sdata_info(sdata,
    1239                 :            :                            "driver channel switch failed, disconnecting\n");
    1240                 :          0 :                 ieee80211_queue_work(&sdata->local->hw,
    1241                 :            :                                      &ifmgd->csa_connection_drop_work);
    1242                 :            :         } else {
    1243                 :          0 :                 ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
    1244                 :            :         }
    1245                 :          0 : }
    1246                 :            : EXPORT_SYMBOL(ieee80211_chswitch_done);
    1247                 :            : 
    1248                 :          0 : static void ieee80211_chswitch_timer(struct timer_list *t)
    1249                 :            : {
    1250                 :          0 :         struct ieee80211_sub_if_data *sdata =
    1251                 :          0 :                 from_timer(sdata, t, u.mgd.chswitch_timer);
    1252                 :            : 
    1253                 :          0 :         ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work);
    1254                 :          0 : }
    1255                 :            : 
    1256                 :            : static void
    1257                 :          0 : ieee80211_sta_abort_chanswitch(struct ieee80211_sub_if_data *sdata)
    1258                 :            : {
    1259                 :          0 :         struct ieee80211_local *local = sdata->local;
    1260                 :            : 
    1261         [ #  # ]:          0 :         if (!local->ops->abort_channel_switch)
    1262                 :            :                 return;
    1263                 :            : 
    1264                 :          0 :         mutex_lock(&local->mtx);
    1265                 :            : 
    1266                 :          0 :         mutex_lock(&local->chanctx_mtx);
    1267                 :          0 :         ieee80211_vif_unreserve_chanctx(sdata);
    1268                 :          0 :         mutex_unlock(&local->chanctx_mtx);
    1269                 :            : 
    1270         [ #  # ]:          0 :         if (sdata->csa_block_tx)
    1271                 :          0 :                 ieee80211_wake_vif_queues(local, sdata,
    1272                 :            :                                           IEEE80211_QUEUE_STOP_REASON_CSA);
    1273                 :            : 
    1274                 :          0 :         sdata->csa_block_tx = false;
    1275                 :          0 :         sdata->vif.csa_active = false;
    1276                 :            : 
    1277                 :          0 :         mutex_unlock(&local->mtx);
    1278                 :            : 
    1279                 :          0 :         drv_abort_channel_switch(sdata);
    1280                 :            : }
    1281                 :            : 
    1282                 :            : static void
    1283                 :          0 : ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
    1284                 :            :                                  u64 timestamp, u32 device_timestamp,
    1285                 :            :                                  struct ieee802_11_elems *elems,
    1286                 :            :                                  bool beacon)
    1287                 :            : {
    1288                 :          0 :         struct ieee80211_local *local = sdata->local;
    1289                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    1290                 :          0 :         struct cfg80211_bss *cbss = ifmgd->associated;
    1291                 :          0 :         struct ieee80211_chanctx_conf *conf;
    1292                 :          0 :         struct ieee80211_chanctx *chanctx;
    1293                 :          0 :         enum nl80211_band current_band;
    1294                 :          0 :         struct ieee80211_csa_ie csa_ie;
    1295                 :          0 :         struct ieee80211_channel_switch ch_switch;
    1296                 :          0 :         int res;
    1297                 :            : 
    1298         [ #  # ]:          0 :         sdata_assert_lock(sdata);
    1299                 :            : 
    1300         [ #  # ]:          0 :         if (!cbss)
    1301                 :          0 :                 return;
    1302                 :            : 
    1303         [ #  # ]:          0 :         if (local->scanning)
    1304                 :            :                 return;
    1305                 :            : 
    1306                 :          0 :         current_band = cbss->channel->band;
    1307                 :          0 :         res = ieee80211_parse_ch_switch_ie(sdata, elems, current_band,
    1308                 :            :                                            ifmgd->flags,
    1309                 :          0 :                                            ifmgd->associated->bssid, &csa_ie);
    1310                 :            : 
    1311         [ #  # ]:          0 :         if (!res) {
    1312                 :          0 :                 ch_switch.timestamp = timestamp;
    1313                 :          0 :                 ch_switch.device_timestamp = device_timestamp;
    1314                 :          0 :                 ch_switch.block_tx = csa_ie.mode;
    1315                 :          0 :                 ch_switch.chandef = csa_ie.chandef;
    1316                 :          0 :                 ch_switch.count = csa_ie.count;
    1317                 :          0 :                 ch_switch.delay = csa_ie.max_switch_time;
    1318                 :            :         }
    1319                 :            : 
    1320         [ #  # ]:          0 :         if (res < 0) {
    1321                 :          0 :                 ieee80211_queue_work(&local->hw,
    1322                 :            :                                      &ifmgd->csa_connection_drop_work);
    1323                 :          0 :                 return;
    1324                 :            :         }
    1325                 :            : 
    1326   [ #  #  #  #  :          0 :         if (beacon && sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) {
                   #  # ]
    1327         [ #  # ]:          0 :                 if (res)
    1328                 :          0 :                         ieee80211_sta_abort_chanswitch(sdata);
    1329                 :            :                 else
    1330                 :          0 :                         drv_channel_switch_rx_beacon(sdata, &ch_switch);
    1331                 :          0 :                 return;
    1332   [ #  #  #  # ]:          0 :         } else if (sdata->vif.csa_active || res) {
    1333                 :            :                 /* disregard subsequent announcements if already processing */
    1334                 :            :                 return;
    1335                 :            :         }
    1336                 :            : 
    1337         [ #  # ]:          0 :         if (!cfg80211_chandef_usable(local->hw.wiphy, &csa_ie.chandef,
    1338                 :            :                                      IEEE80211_CHAN_DISABLED)) {
    1339                 :          0 :                 sdata_info(sdata,
    1340                 :            :                            "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
    1341                 :            :                            ifmgd->associated->bssid,
    1342                 :            :                            csa_ie.chandef.chan->center_freq,
    1343                 :            :                            csa_ie.chandef.width, csa_ie.chandef.center_freq1,
    1344                 :            :                            csa_ie.chandef.center_freq2);
    1345                 :          0 :                 ieee80211_queue_work(&local->hw,
    1346                 :            :                                      &ifmgd->csa_connection_drop_work);
    1347                 :          0 :                 return;
    1348                 :            :         }
    1349                 :            : 
    1350   [ #  #  #  # ]:          0 :         if (cfg80211_chandef_identical(&csa_ie.chandef,
    1351                 :          0 :                                        &sdata->vif.bss_conf.chandef) &&
    1352   [ #  #  #  # ]:          0 :             (!csa_ie.mode || !beacon)) {
    1353         [ #  # ]:          0 :                 if (ifmgd->csa_ignored_same_chan)
    1354                 :            :                         return;
    1355                 :          0 :                 sdata_info(sdata,
    1356                 :            :                            "AP %pM tries to chanswitch to same channel, ignore\n",
    1357                 :            :                            ifmgd->associated->bssid);
    1358                 :          0 :                 ifmgd->csa_ignored_same_chan = true;
    1359                 :          0 :                 return;
    1360                 :            :         }
    1361                 :            : 
    1362                 :            :         /*
    1363                 :            :          * Drop all TDLS peers - either we disconnect or move to a different
    1364                 :            :          * channel from this point on. There's no telling what our peer will do.
    1365                 :            :          * The TDLS WIDER_BW scenario is also problematic, as peers might now
    1366                 :            :          * have an incompatible wider chandef.
    1367                 :            :          */
    1368                 :          0 :         ieee80211_teardown_tdls_peers(sdata);
    1369                 :            : 
    1370                 :          0 :         mutex_lock(&local->mtx);
    1371                 :          0 :         mutex_lock(&local->chanctx_mtx);
    1372                 :          0 :         conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
    1373                 :            :                                          lockdep_is_held(&local->chanctx_mtx));
    1374         [ #  # ]:          0 :         if (!conf) {
    1375                 :          0 :                 sdata_info(sdata,
    1376                 :            :                            "no channel context assigned to vif?, disconnecting\n");
    1377                 :          0 :                 goto drop_connection;
    1378                 :            :         }
    1379                 :            : 
    1380                 :          0 :         chanctx = container_of(conf, struct ieee80211_chanctx, conf);
    1381                 :            : 
    1382   [ #  #  #  # ]:          0 :         if (local->use_chanctx &&
    1383                 :            :             !ieee80211_hw_check(&local->hw, CHANCTX_STA_CSA)) {
    1384                 :          0 :                 sdata_info(sdata,
    1385                 :            :                            "driver doesn't support chan-switch with channel contexts\n");
    1386                 :          0 :                 goto drop_connection;
    1387                 :            :         }
    1388                 :            : 
    1389         [ #  # ]:          0 :         if (drv_pre_channel_switch(sdata, &ch_switch)) {
    1390                 :          0 :                 sdata_info(sdata,
    1391                 :            :                            "preparing for channel switch failed, disconnecting\n");
    1392                 :          0 :                 goto drop_connection;
    1393                 :            :         }
    1394                 :            : 
    1395                 :          0 :         res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef,
    1396                 :            :                                             chanctx->mode, false);
    1397         [ #  # ]:          0 :         if (res) {
    1398                 :          0 :                 sdata_info(sdata,
    1399                 :            :                            "failed to reserve channel context for channel switch, disconnecting (err=%d)\n",
    1400                 :            :                            res);
    1401                 :          0 :                 goto drop_connection;
    1402                 :            :         }
    1403                 :          0 :         mutex_unlock(&local->chanctx_mtx);
    1404                 :            : 
    1405                 :          0 :         sdata->vif.csa_active = true;
    1406                 :          0 :         sdata->csa_chandef = csa_ie.chandef;
    1407                 :          0 :         sdata->csa_block_tx = csa_ie.mode;
    1408                 :          0 :         ifmgd->csa_ignored_same_chan = false;
    1409                 :            : 
    1410         [ #  # ]:          0 :         if (sdata->csa_block_tx)
    1411                 :          0 :                 ieee80211_stop_vif_queues(local, sdata,
    1412                 :            :                                           IEEE80211_QUEUE_STOP_REASON_CSA);
    1413                 :          0 :         mutex_unlock(&local->mtx);
    1414                 :            : 
    1415                 :          0 :         cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chandef,
    1416                 :          0 :                                           csa_ie.count);
    1417                 :            : 
    1418         [ #  # ]:          0 :         if (local->ops->channel_switch) {
    1419                 :            :                 /* use driver's channel switch callback */
    1420                 :          0 :                 drv_channel_switch(local, sdata, &ch_switch);
    1421                 :          0 :                 return;
    1422                 :            :         }
    1423                 :            : 
    1424                 :            :         /* channel switch handled in software */
    1425         [ #  # ]:          0 :         if (csa_ie.count <= 1)
    1426                 :          0 :                 ieee80211_queue_work(&local->hw, &ifmgd->chswitch_work);
    1427                 :            :         else
    1428                 :          0 :                 mod_timer(&ifmgd->chswitch_timer,
    1429         [ #  # ]:          0 :                           TU_TO_EXP_TIME((csa_ie.count - 1) *
    1430                 :            :                                          cbss->beacon_interval));
    1431                 :            :         return;
    1432                 :          0 :  drop_connection:
    1433                 :            :         /*
    1434                 :            :          * This is just so that the disconnect flow will know that
    1435                 :            :          * we were trying to switch channel and failed. In case the
    1436                 :            :          * mode is 1 (we are not allowed to Tx), we will know not to
    1437                 :            :          * send a deauthentication frame. Those two fields will be
    1438                 :            :          * reset when the disconnection worker runs.
    1439                 :            :          */
    1440                 :          0 :         sdata->vif.csa_active = true;
    1441                 :          0 :         sdata->csa_block_tx = csa_ie.mode;
    1442                 :            : 
    1443                 :          0 :         ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work);
    1444                 :          0 :         mutex_unlock(&local->chanctx_mtx);
    1445                 :          0 :         mutex_unlock(&local->mtx);
    1446                 :            : }
    1447                 :            : 
    1448                 :            : static bool
    1449                 :          0 : ieee80211_find_80211h_pwr_constr(struct ieee80211_sub_if_data *sdata,
    1450                 :            :                                  struct ieee80211_channel *channel,
    1451                 :            :                                  const u8 *country_ie, u8 country_ie_len,
    1452                 :            :                                  const u8 *pwr_constr_elem,
    1453                 :            :                                  int *chan_pwr, int *pwr_reduction)
    1454                 :            : {
    1455                 :          0 :         struct ieee80211_country_ie_triplet *triplet;
    1456                 :          0 :         int chan = ieee80211_frequency_to_channel(channel->center_freq);
    1457                 :          0 :         int i, chan_increment;
    1458                 :          0 :         bool have_chan_pwr = false;
    1459                 :            : 
    1460                 :            :         /* Invalid IE */
    1461   [ #  #  #  # ]:          0 :         if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
    1462                 :            :                 return false;
    1463                 :            : 
    1464                 :          0 :         triplet = (void *)(country_ie + 3);
    1465                 :          0 :         country_ie_len -= 3;
    1466                 :            : 
    1467      [ #  #  # ]:          0 :         switch (channel->band) {
    1468                 :            :         default:
    1469                 :          0 :                 WARN_ON_ONCE(1);
    1470                 :            :                 /* fall through */
    1471                 :            :         case NL80211_BAND_2GHZ:
    1472                 :            :         case NL80211_BAND_60GHZ:
    1473                 :            :                 chan_increment = 1;
    1474                 :            :                 break;
    1475                 :          0 :         case NL80211_BAND_5GHZ:
    1476                 :          0 :                 chan_increment = 4;
    1477                 :          0 :                 break;
    1478                 :            :         }
    1479                 :            : 
    1480                 :            :         /* find channel */
    1481         [ #  # ]:          0 :         while (country_ie_len >= 3) {
    1482                 :          0 :                 u8 first_channel = triplet->chans.first_channel;
    1483                 :            : 
    1484         [ #  # ]:          0 :                 if (first_channel >= IEEE80211_COUNTRY_EXTENSION_ID)
    1485                 :          0 :                         goto next;
    1486                 :            : 
    1487         [ #  # ]:          0 :                 for (i = 0; i < triplet->chans.num_channels; i++) {
    1488         [ #  # ]:          0 :                         if (first_channel + i * chan_increment == chan) {
    1489                 :          0 :                                 have_chan_pwr = true;
    1490                 :          0 :                                 *chan_pwr = triplet->chans.max_power;
    1491                 :          0 :                                 break;
    1492                 :            :                         }
    1493                 :            :                 }
    1494                 :          0 :                 if (have_chan_pwr)
    1495                 :            :                         break;
    1496                 :            : 
    1497                 :          0 :  next:
    1498                 :          0 :                 triplet++;
    1499                 :          0 :                 country_ie_len -= 3;
    1500                 :            :         }
    1501                 :            : 
    1502         [ #  # ]:          0 :         if (have_chan_pwr && pwr_constr_elem)
    1503                 :          0 :                 *pwr_reduction = *pwr_constr_elem;
    1504                 :            :         else
    1505                 :          0 :                 *pwr_reduction = 0;
    1506                 :            : 
    1507                 :            :         return have_chan_pwr;
    1508                 :            : }
    1509                 :            : 
    1510                 :          0 : static void ieee80211_find_cisco_dtpc(struct ieee80211_sub_if_data *sdata,
    1511                 :            :                                       struct ieee80211_channel *channel,
    1512                 :            :                                       const u8 *cisco_dtpc_ie,
    1513                 :            :                                       int *pwr_level)
    1514                 :            : {
    1515                 :            :         /* From practical testing, the first data byte of the DTPC element
    1516                 :            :          * seems to contain the requested dBm level, and the CLI on Cisco
    1517                 :            :          * APs clearly state the range is -127 to 127 dBm, which indicates
    1518                 :            :          * a signed byte, although it seemingly never actually goes negative.
    1519                 :            :          * The other byte seems to always be zero.
    1520                 :            :          */
    1521                 :          0 :         *pwr_level = (__s8)cisco_dtpc_ie[4];
    1522                 :            : }
    1523                 :            : 
    1524                 :          0 : static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
    1525                 :            :                                        struct ieee80211_channel *channel,
    1526                 :            :                                        struct ieee80211_mgmt *mgmt,
    1527                 :            :                                        const u8 *country_ie, u8 country_ie_len,
    1528                 :            :                                        const u8 *pwr_constr_ie,
    1529                 :            :                                        const u8 *cisco_dtpc_ie)
    1530                 :            : {
    1531                 :          0 :         bool has_80211h_pwr = false, has_cisco_pwr = false;
    1532                 :          0 :         int chan_pwr = 0, pwr_reduction_80211h = 0;
    1533                 :          0 :         int pwr_level_cisco, pwr_level_80211h;
    1534                 :          0 :         int new_ap_level;
    1535                 :          0 :         __le16 capab = mgmt->u.probe_resp.capab_info;
    1536                 :            : 
    1537   [ #  #  #  # ]:          0 :         if (country_ie &&
    1538                 :            :             (capab & cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT) ||
    1539                 :            :              capab & cpu_to_le16(WLAN_CAPABILITY_RADIO_MEASURE))) {
    1540                 :          0 :                 has_80211h_pwr = ieee80211_find_80211h_pwr_constr(
    1541                 :            :                         sdata, channel, country_ie, country_ie_len,
    1542                 :            :                         pwr_constr_ie, &chan_pwr, &pwr_reduction_80211h);
    1543                 :          0 :                 pwr_level_80211h =
    1544                 :          0 :                         max_t(int, 0, chan_pwr - pwr_reduction_80211h);
    1545                 :            :         }
    1546                 :            : 
    1547         [ #  # ]:          0 :         if (cisco_dtpc_ie) {
    1548                 :          0 :                 ieee80211_find_cisco_dtpc(
    1549                 :            :                         sdata, channel, cisco_dtpc_ie, &pwr_level_cisco);
    1550                 :          0 :                 has_cisco_pwr = true;
    1551                 :            :         }
    1552                 :            : 
    1553         [ #  # ]:          0 :         if (!has_80211h_pwr && !has_cisco_pwr)
    1554                 :            :                 return 0;
    1555                 :            : 
    1556                 :            :         /* If we have both 802.11h and Cisco DTPC, apply both limits
    1557                 :            :          * by picking the smallest of the two power levels advertised.
    1558                 :            :          */
    1559   [ #  #  #  # ]:          0 :         if (has_80211h_pwr &&
    1560         [ #  # ]:          0 :             (!has_cisco_pwr || pwr_level_80211h <= pwr_level_cisco)) {
    1561                 :          0 :                 new_ap_level = pwr_level_80211h;
    1562                 :            : 
    1563         [ #  # ]:          0 :                 if (sdata->ap_power_level == new_ap_level)
    1564                 :            :                         return 0;
    1565                 :            : 
    1566                 :          0 :                 sdata_dbg(sdata,
    1567                 :            :                           "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
    1568                 :            :                           pwr_level_80211h, chan_pwr, pwr_reduction_80211h,
    1569                 :            :                           sdata->u.mgd.bssid);
    1570                 :            :         } else {  /* has_cisco_pwr is always true here. */
    1571                 :          0 :                 new_ap_level = pwr_level_cisco;
    1572                 :            : 
    1573         [ #  # ]:          0 :                 if (sdata->ap_power_level == new_ap_level)
    1574                 :            :                         return 0;
    1575                 :            : 
    1576                 :          0 :                 sdata_dbg(sdata,
    1577                 :            :                           "Limiting TX power to %d dBm as advertised by %pM\n",
    1578                 :            :                           pwr_level_cisco, sdata->u.mgd.bssid);
    1579                 :            :         }
    1580                 :            : 
    1581                 :          0 :         sdata->ap_power_level = new_ap_level;
    1582         [ #  # ]:          0 :         if (__ieee80211_recalc_txpower(sdata))
    1583                 :          0 :                 return BSS_CHANGED_TXPOWER;
    1584                 :            :         return 0;
    1585                 :            : }
    1586                 :            : 
    1587                 :            : /* powersave */
    1588                 :          0 : static void ieee80211_enable_ps(struct ieee80211_local *local,
    1589                 :            :                                 struct ieee80211_sub_if_data *sdata)
    1590                 :            : {
    1591                 :          0 :         struct ieee80211_conf *conf = &local->hw.conf;
    1592                 :            : 
    1593                 :            :         /*
    1594                 :            :          * If we are scanning right now then the parameters will
    1595                 :            :          * take effect when scan finishes.
    1596                 :            :          */
    1597         [ #  # ]:          0 :         if (local->scanning)
    1598                 :            :                 return;
    1599                 :            : 
    1600   [ #  #  #  # ]:          0 :         if (conf->dynamic_ps_timeout > 0 &&
    1601                 :            :             !ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS)) {
    1602                 :          0 :                 mod_timer(&local->dynamic_ps_timer, jiffies +
    1603         [ #  # ]:          0 :                           msecs_to_jiffies(conf->dynamic_ps_timeout));
    1604                 :            :         } else {
    1605         [ #  # ]:          0 :                 if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK))
    1606                 :          0 :                         ieee80211_send_nullfunc(local, sdata, true);
    1607                 :            : 
    1608   [ #  #  #  # ]:          0 :                 if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
    1609                 :            :                     ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
    1610                 :            :                         return;
    1611                 :            : 
    1612                 :          0 :                 conf->flags |= IEEE80211_CONF_PS;
    1613                 :          0 :                 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
    1614                 :            :         }
    1615                 :            : }
    1616                 :            : 
    1617                 :          0 : static void ieee80211_change_ps(struct ieee80211_local *local)
    1618                 :            : {
    1619                 :          0 :         struct ieee80211_conf *conf = &local->hw.conf;
    1620                 :            : 
    1621         [ #  # ]:          0 :         if (local->ps_sdata) {
    1622                 :          0 :                 ieee80211_enable_ps(local, local->ps_sdata);
    1623         [ #  # ]:          0 :         } else if (conf->flags & IEEE80211_CONF_PS) {
    1624                 :          0 :                 conf->flags &= ~IEEE80211_CONF_PS;
    1625                 :          0 :                 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
    1626                 :          0 :                 del_timer_sync(&local->dynamic_ps_timer);
    1627                 :          0 :                 cancel_work_sync(&local->dynamic_ps_enable_work);
    1628                 :            :         }
    1629                 :          0 : }
    1630                 :            : 
    1631                 :          0 : static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
    1632                 :            : {
    1633                 :          0 :         struct ieee80211_if_managed *mgd = &sdata->u.mgd;
    1634                 :          0 :         struct sta_info *sta = NULL;
    1635                 :          0 :         bool authorized = false;
    1636                 :            : 
    1637         [ #  # ]:          0 :         if (!mgd->powersave)
    1638                 :            :                 return false;
    1639                 :            : 
    1640         [ #  # ]:          0 :         if (mgd->broken_ap)
    1641                 :            :                 return false;
    1642                 :            : 
    1643         [ #  # ]:          0 :         if (!mgd->associated)
    1644                 :            :                 return false;
    1645                 :            : 
    1646         [ #  # ]:          0 :         if (mgd->flags & IEEE80211_STA_CONNECTION_POLL)
    1647                 :            :                 return false;
    1648                 :            : 
    1649         [ #  # ]:          0 :         if (!mgd->have_beacon)
    1650                 :            :                 return false;
    1651                 :            : 
    1652                 :          0 :         rcu_read_lock();
    1653                 :          0 :         sta = sta_info_get(sdata, mgd->bssid);
    1654         [ #  # ]:          0 :         if (sta)
    1655                 :          0 :                 authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
    1656                 :          0 :         rcu_read_unlock();
    1657                 :            : 
    1658                 :          0 :         return authorized;
    1659                 :            : }
    1660                 :            : 
    1661                 :            : /* need to hold RTNL or interface lock */
    1662                 :          0 : void ieee80211_recalc_ps(struct ieee80211_local *local)
    1663                 :            : {
    1664                 :          0 :         struct ieee80211_sub_if_data *sdata, *found = NULL;
    1665                 :          0 :         int count = 0;
    1666                 :          0 :         int timeout;
    1667                 :            : 
    1668         [ #  # ]:          0 :         if (!ieee80211_hw_check(&local->hw, SUPPORTS_PS)) {
    1669                 :          0 :                 local->ps_sdata = NULL;
    1670                 :          0 :                 return;
    1671                 :            :         }
    1672                 :            : 
    1673         [ #  # ]:          0 :         list_for_each_entry(sdata, &local->interfaces, list) {
    1674         [ #  # ]:          0 :                 if (!ieee80211_sdata_running(sdata))
    1675                 :          0 :                         continue;
    1676         [ #  # ]:          0 :                 if (sdata->vif.type == NL80211_IFTYPE_AP) {
    1677                 :            :                         /* If an AP vif is found, then disable PS
    1678                 :            :                          * by setting the count to zero thereby setting
    1679                 :            :                          * ps_sdata to NULL.
    1680                 :            :                          */
    1681                 :            :                         count = 0;
    1682                 :            :                         break;
    1683                 :            :                 }
    1684         [ #  # ]:          0 :                 if (sdata->vif.type != NL80211_IFTYPE_STATION)
    1685                 :          0 :                         continue;
    1686                 :          0 :                 found = sdata;
    1687                 :          0 :                 count++;
    1688                 :            :         }
    1689                 :            : 
    1690   [ #  #  #  # ]:          0 :         if (count == 1 && ieee80211_powersave_allowed(found)) {
    1691                 :          0 :                 u8 dtimper = found->u.mgd.dtim_period;
    1692                 :            : 
    1693                 :          0 :                 timeout = local->dynamic_ps_forced_timeout;
    1694         [ #  # ]:          0 :                 if (timeout < 0)
    1695                 :          0 :                         timeout = 100;
    1696                 :          0 :                 local->hw.conf.dynamic_ps_timeout = timeout;
    1697                 :            : 
    1698                 :            :                 /* If the TIM IE is invalid, pretend the value is 1 */
    1699                 :          0 :                 if (!dtimper)
    1700                 :            :                         dtimper = 1;
    1701                 :            : 
    1702                 :          0 :                 local->hw.conf.ps_dtim_period = dtimper;
    1703                 :          0 :                 local->ps_sdata = found;
    1704                 :            :         } else {
    1705                 :          0 :                 local->ps_sdata = NULL;
    1706                 :            :         }
    1707                 :            : 
    1708                 :          0 :         ieee80211_change_ps(local);
    1709                 :            : }
    1710                 :            : 
    1711                 :          0 : void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata)
    1712                 :            : {
    1713                 :          0 :         bool ps_allowed = ieee80211_powersave_allowed(sdata);
    1714                 :            : 
    1715         [ #  # ]:          0 :         if (sdata->vif.bss_conf.ps != ps_allowed) {
    1716                 :          0 :                 sdata->vif.bss_conf.ps = ps_allowed;
    1717                 :          0 :                 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_PS);
    1718                 :            :         }
    1719                 :          0 : }
    1720                 :            : 
    1721                 :          0 : void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
    1722                 :            : {
    1723                 :          0 :         struct ieee80211_local *local =
    1724                 :          0 :                 container_of(work, struct ieee80211_local,
    1725                 :            :                              dynamic_ps_disable_work);
    1726                 :            : 
    1727         [ #  # ]:          0 :         if (local->hw.conf.flags & IEEE80211_CONF_PS) {
    1728                 :          0 :                 local->hw.conf.flags &= ~IEEE80211_CONF_PS;
    1729                 :          0 :                 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
    1730                 :            :         }
    1731                 :            : 
    1732                 :          0 :         ieee80211_wake_queues_by_reason(&local->hw,
    1733                 :            :                                         IEEE80211_MAX_QUEUE_MAP,
    1734                 :            :                                         IEEE80211_QUEUE_STOP_REASON_PS,
    1735                 :            :                                         false);
    1736                 :          0 : }
    1737                 :            : 
    1738                 :          0 : void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
    1739                 :            : {
    1740                 :          0 :         struct ieee80211_local *local =
    1741                 :          0 :                 container_of(work, struct ieee80211_local,
    1742                 :            :                              dynamic_ps_enable_work);
    1743                 :          0 :         struct ieee80211_sub_if_data *sdata = local->ps_sdata;
    1744                 :          0 :         struct ieee80211_if_managed *ifmgd;
    1745                 :          0 :         unsigned long flags;
    1746                 :          0 :         int q;
    1747                 :            : 
    1748                 :            :         /* can only happen when PS was just disabled anyway */
    1749         [ #  # ]:          0 :         if (!sdata)
    1750                 :            :                 return;
    1751                 :            : 
    1752                 :          0 :         ifmgd = &sdata->u.mgd;
    1753                 :            : 
    1754         [ #  # ]:          0 :         if (local->hw.conf.flags & IEEE80211_CONF_PS)
    1755                 :            :                 return;
    1756                 :            : 
    1757         [ #  # ]:          0 :         if (local->hw.conf.dynamic_ps_timeout > 0) {
    1758                 :            :                 /* don't enter PS if TX frames are pending */
    1759         [ #  # ]:          0 :                 if (drv_tx_frames_pending(local)) {
    1760                 :          0 :                         mod_timer(&local->dynamic_ps_timer, jiffies +
    1761                 :          0 :                                   msecs_to_jiffies(
    1762         [ #  # ]:          0 :                                   local->hw.conf.dynamic_ps_timeout));
    1763                 :          0 :                         return;
    1764                 :            :                 }
    1765                 :            : 
    1766                 :            :                 /*
    1767                 :            :                  * transmission can be stopped by others which leads to
    1768                 :            :                  * dynamic_ps_timer expiry. Postpone the ps timer if it
    1769                 :            :                  * is not the actual idle state.
    1770                 :            :                  */
    1771                 :          0 :                 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
    1772         [ #  # ]:          0 :                 for (q = 0; q < local->hw.queues; q++) {
    1773         [ #  # ]:          0 :                         if (local->queue_stop_reasons[q]) {
    1774                 :          0 :                                 spin_unlock_irqrestore(&local->queue_stop_reason_lock,
    1775                 :            :                                                        flags);
    1776                 :          0 :                                 mod_timer(&local->dynamic_ps_timer, jiffies +
    1777                 :          0 :                                           msecs_to_jiffies(
    1778         [ #  # ]:          0 :                                           local->hw.conf.dynamic_ps_timeout));
    1779                 :          0 :                                 return;
    1780                 :            :                         }
    1781                 :            :                 }
    1782                 :          0 :                 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
    1783                 :            :         }
    1784                 :            : 
    1785         [ #  # ]:          0 :         if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
    1786         [ #  # ]:          0 :             !(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) {
    1787         [ #  # ]:          0 :                 if (drv_tx_frames_pending(local)) {
    1788                 :          0 :                         mod_timer(&local->dynamic_ps_timer, jiffies +
    1789                 :          0 :                                   msecs_to_jiffies(
    1790         [ #  # ]:          0 :                                   local->hw.conf.dynamic_ps_timeout));
    1791                 :            :                 } else {
    1792                 :          0 :                         ieee80211_send_nullfunc(local, sdata, true);
    1793                 :            :                         /* Flush to get the tx status of nullfunc frame */
    1794                 :          0 :                         ieee80211_flush_queues(local, sdata, false);
    1795                 :            :                 }
    1796                 :            :         }
    1797                 :            : 
    1798   [ #  #  #  # ]:          0 :         if (!(ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS) &&
    1799                 :          0 :               ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK)) ||
    1800         [ #  # ]:          0 :             (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) {
    1801                 :          0 :                 ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
    1802                 :          0 :                 local->hw.conf.flags |= IEEE80211_CONF_PS;
    1803                 :          0 :                 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
    1804                 :            :         }
    1805                 :            : }
    1806                 :            : 
    1807                 :          0 : void ieee80211_dynamic_ps_timer(struct timer_list *t)
    1808                 :            : {
    1809                 :          0 :         struct ieee80211_local *local = from_timer(local, t, dynamic_ps_timer);
    1810                 :            : 
    1811                 :          0 :         ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work);
    1812                 :          0 : }
    1813                 :            : 
    1814                 :          0 : void ieee80211_dfs_cac_timer_work(struct work_struct *work)
    1815                 :            : {
    1816                 :          0 :         struct delayed_work *delayed_work = to_delayed_work(work);
    1817                 :          0 :         struct ieee80211_sub_if_data *sdata =
    1818                 :          0 :                 container_of(delayed_work, struct ieee80211_sub_if_data,
    1819                 :            :                              dfs_cac_timer_work);
    1820                 :          0 :         struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chandef;
    1821                 :            : 
    1822                 :          0 :         mutex_lock(&sdata->local->mtx);
    1823         [ #  # ]:          0 :         if (sdata->wdev.cac_started) {
    1824                 :          0 :                 ieee80211_vif_release_channel(sdata);
    1825                 :          0 :                 cfg80211_cac_event(sdata->dev, &chandef,
    1826                 :            :                                    NL80211_RADAR_CAC_FINISHED,
    1827                 :            :                                    GFP_KERNEL);
    1828                 :            :         }
    1829                 :          0 :         mutex_unlock(&sdata->local->mtx);
    1830                 :          0 : }
    1831                 :            : 
    1832                 :            : static bool
    1833                 :          0 : __ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata)
    1834                 :            : {
    1835                 :          0 :         struct ieee80211_local *local = sdata->local;
    1836                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    1837                 :          0 :         bool ret = false;
    1838                 :          0 :         int ac;
    1839                 :            : 
    1840         [ #  # ]:          0 :         if (local->hw.queues < IEEE80211_NUM_ACS)
    1841                 :            :                 return false;
    1842                 :            : 
    1843         [ #  # ]:          0 :         for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
    1844                 :          0 :                 struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
    1845                 :          0 :                 int non_acm_ac;
    1846                 :          0 :                 unsigned long now = jiffies;
    1847                 :            : 
    1848         [ #  # ]:          0 :                 if (tx_tspec->action == TX_TSPEC_ACTION_NONE &&
    1849         [ #  # ]:          0 :                     tx_tspec->admitted_time &&
    1850         [ #  # ]:          0 :                     time_after(now, tx_tspec->time_slice_start + HZ)) {
    1851                 :          0 :                         tx_tspec->consumed_tx_time = 0;
    1852                 :          0 :                         tx_tspec->time_slice_start = now;
    1853                 :            : 
    1854         [ #  # ]:          0 :                         if (tx_tspec->downgraded)
    1855                 :          0 :                                 tx_tspec->action =
    1856                 :            :                                         TX_TSPEC_ACTION_STOP_DOWNGRADE;
    1857                 :            :                 }
    1858                 :            : 
    1859      [ #  #  # ]:          0 :                 switch (tx_tspec->action) {
    1860                 :          0 :                 case TX_TSPEC_ACTION_STOP_DOWNGRADE:
    1861                 :            :                         /* take the original parameters */
    1862         [ #  # ]:          0 :                         if (drv_conf_tx(local, sdata, ac, &sdata->tx_conf[ac]))
    1863                 :          0 :                                 sdata_err(sdata,
    1864                 :            :                                           "failed to set TX queue parameters for queue %d\n",
    1865                 :            :                                           ac);
    1866                 :          0 :                         tx_tspec->action = TX_TSPEC_ACTION_NONE;
    1867                 :          0 :                         tx_tspec->downgraded = false;
    1868                 :          0 :                         ret = true;
    1869                 :          0 :                         break;
    1870                 :            :                 case TX_TSPEC_ACTION_DOWNGRADE:
    1871         [ #  # ]:          0 :                         if (time_after(now, tx_tspec->time_slice_start + HZ)) {
    1872                 :          0 :                                 tx_tspec->action = TX_TSPEC_ACTION_NONE;
    1873                 :          0 :                                 ret = true;
    1874                 :          0 :                                 break;
    1875                 :            :                         }
    1876                 :            :                         /* downgrade next lower non-ACM AC */
    1877                 :          0 :                         for (non_acm_ac = ac + 1;
    1878         [ #  # ]:          0 :                              non_acm_ac < IEEE80211_NUM_ACS;
    1879                 :          0 :                              non_acm_ac++)
    1880         [ #  # ]:          0 :                                 if (!(sdata->wmm_acm & BIT(7 - 2 * non_acm_ac)))
    1881                 :            :                                         break;
    1882                 :            :                         /* Usually the loop will result in using BK even if it
    1883                 :            :                          * requires admission control, but such a configuration
    1884                 :            :                          * makes no sense and we have to transmit somehow - the
    1885                 :            :                          * AC selection does the same thing.
    1886                 :            :                          * If we started out trying to downgrade from BK, then
    1887                 :            :                          * the extra condition here might be needed.
    1888                 :            :                          */
    1889                 :          0 :                         if (non_acm_ac >= IEEE80211_NUM_ACS)
    1890                 :            :                                 non_acm_ac = IEEE80211_AC_BK;
    1891         [ #  # ]:          0 :                         if (drv_conf_tx(local, sdata, ac,
    1892                 :          0 :                                         &sdata->tx_conf[non_acm_ac]))
    1893                 :          0 :                                 sdata_err(sdata,
    1894                 :            :                                           "failed to set TX queue parameters for queue %d\n",
    1895                 :            :                                           ac);
    1896                 :          0 :                         tx_tspec->action = TX_TSPEC_ACTION_NONE;
    1897                 :          0 :                         ret = true;
    1898                 :          0 :                         schedule_delayed_work(&ifmgd->tx_tspec_wk,
    1899                 :          0 :                                 tx_tspec->time_slice_start + HZ - now + 1);
    1900                 :            :                         break;
    1901                 :            :                 case TX_TSPEC_ACTION_NONE:
    1902                 :            :                         /* nothing now */
    1903                 :            :                         break;
    1904                 :            :                 }
    1905                 :          0 :         }
    1906                 :            : 
    1907                 :            :         return ret;
    1908                 :            : }
    1909                 :            : 
    1910                 :          0 : void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata)
    1911                 :            : {
    1912         [ #  # ]:          0 :         if (__ieee80211_sta_handle_tspec_ac_params(sdata))
    1913                 :          0 :                 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
    1914                 :          0 : }
    1915                 :            : 
    1916                 :          0 : static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work)
    1917                 :            : {
    1918                 :          0 :         struct ieee80211_sub_if_data *sdata;
    1919                 :            : 
    1920                 :          0 :         sdata = container_of(work, struct ieee80211_sub_if_data,
    1921                 :            :                              u.mgd.tx_tspec_wk.work);
    1922                 :          0 :         ieee80211_sta_handle_tspec_ac_params(sdata);
    1923                 :          0 : }
    1924                 :            : 
    1925                 :            : /* MLME */
    1926                 :            : static bool
    1927                 :          0 : ieee80211_sta_wmm_params(struct ieee80211_local *local,
    1928                 :            :                          struct ieee80211_sub_if_data *sdata,
    1929                 :            :                          const u8 *wmm_param, size_t wmm_param_len,
    1930                 :            :                          const struct ieee80211_mu_edca_param_set *mu_edca)
    1931                 :            : {
    1932                 :          0 :         struct ieee80211_tx_queue_params params[IEEE80211_NUM_ACS];
    1933                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    1934                 :          0 :         size_t left;
    1935                 :          0 :         int count, mu_edca_count, ac;
    1936                 :          0 :         const u8 *pos;
    1937                 :          0 :         u8 uapsd_queues = 0;
    1938                 :            : 
    1939         [ #  # ]:          0 :         if (!local->ops->conf_tx)
    1940                 :            :                 return false;
    1941                 :            : 
    1942         [ #  # ]:          0 :         if (local->hw.queues < IEEE80211_NUM_ACS)
    1943                 :            :                 return false;
    1944                 :            : 
    1945         [ #  # ]:          0 :         if (!wmm_param)
    1946                 :            :                 return false;
    1947                 :            : 
    1948   [ #  #  #  # ]:          0 :         if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
    1949                 :            :                 return false;
    1950                 :            : 
    1951         [ #  # ]:          0 :         if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
    1952                 :          0 :                 uapsd_queues = ifmgd->uapsd_queues;
    1953                 :            : 
    1954                 :          0 :         count = wmm_param[6] & 0x0f;
    1955                 :            :         /* -1 is the initial value of ifmgd->mu_edca_last_param_set.
    1956                 :            :          * if mu_edca was preset before and now it disappeared tell
    1957                 :            :          * the driver about it.
    1958                 :            :          */
    1959         [ #  # ]:          0 :         mu_edca_count = mu_edca ? mu_edca->mu_qos_info & 0x0f : -1;
    1960         [ #  # ]:          0 :         if (count == ifmgd->wmm_last_param_set &&
    1961         [ #  # ]:          0 :             mu_edca_count == ifmgd->mu_edca_last_param_set)
    1962                 :            :                 return false;
    1963                 :          0 :         ifmgd->wmm_last_param_set = count;
    1964                 :          0 :         ifmgd->mu_edca_last_param_set = mu_edca_count;
    1965                 :            : 
    1966                 :          0 :         pos = wmm_param + 8;
    1967                 :          0 :         left = wmm_param_len - 8;
    1968                 :            : 
    1969                 :          0 :         memset(&params, 0, sizeof(params));
    1970                 :            : 
    1971                 :          0 :         sdata->wmm_acm = 0;
    1972         [ #  # ]:          0 :         for (; left >= 4; left -= 4, pos += 4) {
    1973                 :          0 :                 int aci = (pos[0] >> 5) & 0x03;
    1974                 :          0 :                 int acm = (pos[0] >> 4) & 0x01;
    1975                 :          0 :                 bool uapsd = false;
    1976                 :            : 
    1977   [ #  #  #  # ]:          0 :                 switch (aci) {
    1978                 :          0 :                 case 1: /* AC_BK */
    1979                 :          0 :                         ac = IEEE80211_AC_BK;
    1980         [ #  # ]:          0 :                         if (acm)
    1981                 :          0 :                                 sdata->wmm_acm |= BIT(1) | BIT(2); /* BK/- */
    1982         [ #  # ]:          0 :                         if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
    1983                 :          0 :                                 uapsd = true;
    1984                 :          0 :                         params[ac].mu_edca = !!mu_edca;
    1985         [ #  # ]:          0 :                         if (mu_edca)
    1986                 :          0 :                                 params[ac].mu_edca_param_rec = mu_edca->ac_bk;
    1987                 :            :                         break;
    1988                 :          0 :                 case 2: /* AC_VI */
    1989                 :          0 :                         ac = IEEE80211_AC_VI;
    1990         [ #  # ]:          0 :                         if (acm)
    1991                 :          0 :                                 sdata->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
    1992         [ #  # ]:          0 :                         if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
    1993                 :          0 :                                 uapsd = true;
    1994                 :          0 :                         params[ac].mu_edca = !!mu_edca;
    1995         [ #  # ]:          0 :                         if (mu_edca)
    1996                 :          0 :                                 params[ac].mu_edca_param_rec = mu_edca->ac_vi;
    1997                 :            :                         break;
    1998                 :          0 :                 case 3: /* AC_VO */
    1999                 :          0 :                         ac = IEEE80211_AC_VO;
    2000         [ #  # ]:          0 :                         if (acm)
    2001                 :          0 :                                 sdata->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
    2002                 :          0 :                         if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
    2003                 :            :                                 uapsd = true;
    2004                 :          0 :                         params[ac].mu_edca = !!mu_edca;
    2005         [ #  # ]:          0 :                         if (mu_edca)
    2006                 :          0 :                                 params[ac].mu_edca_param_rec = mu_edca->ac_vo;
    2007                 :            :                         break;
    2008                 :          0 :                 case 0: /* AC_BE */
    2009                 :            :                 default:
    2010                 :          0 :                         ac = IEEE80211_AC_BE;
    2011         [ #  # ]:          0 :                         if (acm)
    2012                 :          0 :                                 sdata->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
    2013         [ #  # ]:          0 :                         if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
    2014                 :          0 :                                 uapsd = true;
    2015                 :          0 :                         params[ac].mu_edca = !!mu_edca;
    2016         [ #  # ]:          0 :                         if (mu_edca)
    2017                 :          0 :                                 params[ac].mu_edca_param_rec = mu_edca->ac_be;
    2018                 :            :                         break;
    2019                 :            :                 }
    2020                 :            : 
    2021                 :          0 :                 params[ac].aifs = pos[0] & 0x0f;
    2022                 :            : 
    2023         [ #  # ]:          0 :                 if (params[ac].aifs < 2) {
    2024                 :          0 :                         sdata_info(sdata,
    2025                 :            :                                    "AP has invalid WMM params (AIFSN=%d for ACI %d), will use 2\n",
    2026                 :            :                                    params[ac].aifs, aci);
    2027                 :          0 :                         params[ac].aifs = 2;
    2028                 :            :                 }
    2029                 :          0 :                 params[ac].cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
    2030                 :          0 :                 params[ac].cw_min = ecw2cw(pos[1] & 0x0f);
    2031         [ #  # ]:          0 :                 params[ac].txop = get_unaligned_le16(pos + 2);
    2032                 :          0 :                 params[ac].acm = acm;
    2033                 :          0 :                 params[ac].uapsd = uapsd;
    2034                 :            : 
    2035   [ #  #  #  # ]:          0 :                 if (params[ac].cw_min == 0 ||
    2036                 :            :                     params[ac].cw_min > params[ac].cw_max) {
    2037                 :          0 :                         sdata_info(sdata,
    2038                 :            :                                    "AP has invalid WMM params (CWmin/max=%d/%d for ACI %d), using defaults\n",
    2039                 :            :                                    params[ac].cw_min, params[ac].cw_max, aci);
    2040                 :          0 :                         return false;
    2041                 :            :                 }
    2042                 :          0 :                 ieee80211_regulatory_limit_wmm_params(sdata, &params[ac], ac);
    2043                 :            :         }
    2044                 :            : 
    2045                 :            :         /* WMM specification requires all 4 ACIs. */
    2046         [ #  # ]:          0 :         for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
    2047         [ #  # ]:          0 :                 if (params[ac].cw_min == 0) {
    2048                 :          0 :                         sdata_info(sdata,
    2049                 :            :                                    "AP has invalid WMM params (missing AC %d), using defaults\n",
    2050                 :            :                                    ac);
    2051                 :          0 :                         return false;
    2052                 :            :                 }
    2053                 :            :         }
    2054                 :            : 
    2055         [ #  # ]:          0 :         for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
    2056                 :          0 :                 mlme_dbg(sdata,
    2057                 :            :                          "WMM AC=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n",
    2058                 :            :                          ac, params[ac].acm,
    2059                 :            :                          params[ac].aifs, params[ac].cw_min, params[ac].cw_max,
    2060                 :            :                          params[ac].txop, params[ac].uapsd,
    2061                 :            :                          ifmgd->tx_tspec[ac].downgraded);
    2062                 :          0 :                 sdata->tx_conf[ac] = params[ac];
    2063   [ #  #  #  # ]:          0 :                 if (!ifmgd->tx_tspec[ac].downgraded &&
    2064                 :          0 :                     drv_conf_tx(local, sdata, ac, &params[ac]))
    2065                 :          0 :                         sdata_err(sdata,
    2066                 :            :                                   "failed to set TX queue parameters for AC %d\n",
    2067                 :            :                                   ac);
    2068                 :            :         }
    2069                 :            : 
    2070                 :            :         /* enable WMM or activate new settings */
    2071                 :          0 :         sdata->vif.bss_conf.qos = true;
    2072                 :          0 :         return true;
    2073                 :            : }
    2074                 :            : 
    2075                 :          0 : static void __ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata)
    2076                 :            : {
    2077                 :          0 :         lockdep_assert_held(&sdata->local->mtx);
    2078                 :            : 
    2079                 :          0 :         sdata->u.mgd.flags &= ~IEEE80211_STA_CONNECTION_POLL;
    2080                 :          0 :         ieee80211_run_deferred_scan(sdata->local);
    2081                 :            : }
    2082                 :            : 
    2083                 :          0 : static void ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata)
    2084                 :            : {
    2085                 :          0 :         mutex_lock(&sdata->local->mtx);
    2086                 :          0 :         __ieee80211_stop_poll(sdata);
    2087                 :          0 :         mutex_unlock(&sdata->local->mtx);
    2088                 :          0 : }
    2089                 :            : 
    2090                 :          0 : static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
    2091                 :            :                                            u16 capab, bool erp_valid, u8 erp)
    2092                 :            : {
    2093                 :          0 :         struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
    2094                 :          0 :         struct ieee80211_supported_band *sband;
    2095                 :          0 :         u32 changed = 0;
    2096                 :          0 :         bool use_protection;
    2097                 :          0 :         bool use_short_preamble;
    2098                 :          0 :         bool use_short_slot;
    2099                 :            : 
    2100                 :          0 :         sband = ieee80211_get_sband(sdata);
    2101         [ #  # ]:          0 :         if (!sband)
    2102                 :            :                 return changed;
    2103                 :            : 
    2104         [ #  # ]:          0 :         if (erp_valid) {
    2105                 :          0 :                 use_protection = (erp & WLAN_ERP_USE_PROTECTION) != 0;
    2106                 :          0 :                 use_short_preamble = (erp & WLAN_ERP_BARKER_PREAMBLE) == 0;
    2107                 :            :         } else {
    2108                 :          0 :                 use_protection = false;
    2109                 :          0 :                 use_short_preamble = !!(capab & WLAN_CAPABILITY_SHORT_PREAMBLE);
    2110                 :            :         }
    2111                 :            : 
    2112                 :          0 :         use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME);
    2113         [ #  # ]:          0 :         if (sband->band == NL80211_BAND_5GHZ)
    2114                 :          0 :                 use_short_slot = true;
    2115                 :            : 
    2116         [ #  # ]:          0 :         if (use_protection != bss_conf->use_cts_prot) {
    2117                 :          0 :                 bss_conf->use_cts_prot = use_protection;
    2118                 :          0 :                 changed |= BSS_CHANGED_ERP_CTS_PROT;
    2119                 :            :         }
    2120                 :            : 
    2121         [ #  # ]:          0 :         if (use_short_preamble != bss_conf->use_short_preamble) {
    2122                 :          0 :                 bss_conf->use_short_preamble = use_short_preamble;
    2123                 :          0 :                 changed |= BSS_CHANGED_ERP_PREAMBLE;
    2124                 :            :         }
    2125                 :            : 
    2126         [ #  # ]:          0 :         if (use_short_slot != bss_conf->use_short_slot) {
    2127                 :          0 :                 bss_conf->use_short_slot = use_short_slot;
    2128                 :          0 :                 changed |= BSS_CHANGED_ERP_SLOT;
    2129                 :            :         }
    2130                 :            : 
    2131                 :            :         return changed;
    2132                 :            : }
    2133                 :            : 
    2134                 :          0 : static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
    2135                 :            :                                      struct cfg80211_bss *cbss,
    2136                 :            :                                      u32 bss_info_changed)
    2137                 :            : {
    2138                 :          0 :         struct ieee80211_bss *bss = (void *)cbss->priv;
    2139                 :          0 :         struct ieee80211_local *local = sdata->local;
    2140                 :          0 :         struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
    2141                 :            : 
    2142                 :          0 :         bss_info_changed |= BSS_CHANGED_ASSOC;
    2143                 :          0 :         bss_info_changed |= ieee80211_handle_bss_capability(sdata,
    2144                 :          0 :                 bss_conf->assoc_capability, bss->has_erp_value, bss->erp_value);
    2145                 :            : 
    2146                 :          0 :         sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec(
    2147         [ #  # ]:          0 :                 beacon_loss_count * bss_conf->beacon_int));
    2148                 :            : 
    2149                 :          0 :         sdata->u.mgd.associated = cbss;
    2150                 :          0 :         memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN);
    2151                 :            : 
    2152                 :          0 :         ieee80211_check_rate_mask(sdata);
    2153                 :            : 
    2154                 :          0 :         sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;
    2155                 :            : 
    2156         [ #  # ]:          0 :         if (sdata->vif.p2p ||
    2157         [ #  # ]:          0 :             sdata->vif.driver_flags & IEEE80211_VIF_GET_NOA_UPDATE) {
    2158                 :          0 :                 const struct cfg80211_bss_ies *ies;
    2159                 :            : 
    2160                 :          0 :                 rcu_read_lock();
    2161         [ #  # ]:          0 :                 ies = rcu_dereference(cbss->ies);
    2162         [ #  # ]:          0 :                 if (ies) {
    2163                 :          0 :                         int ret;
    2164                 :            : 
    2165                 :          0 :                         ret = cfg80211_get_p2p_attr(
    2166                 :          0 :                                         ies->data, ies->len,
    2167                 :            :                                         IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
    2168                 :          0 :                                         (u8 *) &bss_conf->p2p_noa_attr,
    2169                 :            :                                         sizeof(bss_conf->p2p_noa_attr));
    2170         [ #  # ]:          0 :                         if (ret >= 2) {
    2171                 :          0 :                                 sdata->u.mgd.p2p_noa_index =
    2172                 :          0 :                                         bss_conf->p2p_noa_attr.index;
    2173                 :          0 :                                 bss_info_changed |= BSS_CHANGED_P2P_PS;
    2174                 :            :                         }
    2175                 :            :                 }
    2176                 :          0 :                 rcu_read_unlock();
    2177                 :            :         }
    2178                 :            : 
    2179                 :            :         /* just to be sure */
    2180                 :          0 :         ieee80211_stop_poll(sdata);
    2181                 :            : 
    2182                 :          0 :         ieee80211_led_assoc(local, 1);
    2183                 :            : 
    2184         [ #  # ]:          0 :         if (sdata->u.mgd.have_beacon) {
    2185                 :            :                 /*
    2186                 :            :                  * If the AP is buggy we may get here with no DTIM period
    2187                 :            :                  * known, so assume it's 1 which is the only safe assumption
    2188                 :            :                  * in that case, although if the TIM IE is broken powersave
    2189                 :            :                  * probably just won't work at all.
    2190                 :            :                  */
    2191                 :          0 :                 bss_conf->dtim_period = sdata->u.mgd.dtim_period ?: 1;
    2192                 :          0 :                 bss_conf->beacon_rate = bss->beacon_rate;
    2193                 :          0 :                 bss_info_changed |= BSS_CHANGED_BEACON_INFO;
    2194                 :            :         } else {
    2195                 :          0 :                 bss_conf->beacon_rate = NULL;
    2196                 :          0 :                 bss_conf->dtim_period = 0;
    2197                 :            :         }
    2198                 :            : 
    2199                 :          0 :         bss_conf->assoc = 1;
    2200                 :            : 
    2201                 :            :         /* Tell the driver to monitor connection quality (if supported) */
    2202         [ #  # ]:          0 :         if (sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI &&
    2203         [ #  # ]:          0 :             bss_conf->cqm_rssi_thold)
    2204                 :          0 :                 bss_info_changed |= BSS_CHANGED_CQM;
    2205                 :            : 
    2206                 :            :         /* Enable ARP filtering */
    2207         [ #  # ]:          0 :         if (bss_conf->arp_addr_cnt)
    2208                 :          0 :                 bss_info_changed |= BSS_CHANGED_ARP_FILTER;
    2209                 :            : 
    2210                 :          0 :         ieee80211_bss_info_change_notify(sdata, bss_info_changed);
    2211                 :            : 
    2212                 :          0 :         mutex_lock(&local->iflist_mtx);
    2213                 :          0 :         ieee80211_recalc_ps(local);
    2214                 :          0 :         mutex_unlock(&local->iflist_mtx);
    2215                 :            : 
    2216                 :          0 :         ieee80211_recalc_smps(sdata);
    2217                 :          0 :         ieee80211_recalc_ps_vif(sdata);
    2218                 :            : 
    2219                 :          0 :         netif_carrier_on(sdata->dev);
    2220                 :          0 : }
    2221                 :            : 
    2222                 :          0 : static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
    2223                 :            :                                    u16 stype, u16 reason, bool tx,
    2224                 :            :                                    u8 *frame_buf)
    2225                 :            : {
    2226                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    2227                 :          0 :         struct ieee80211_local *local = sdata->local;
    2228                 :          0 :         u32 changed = 0;
    2229                 :            : 
    2230         [ #  # ]:          0 :         sdata_assert_lock(sdata);
    2231                 :            : 
    2232   [ #  #  #  # ]:          0 :         if (WARN_ON_ONCE(tx && !frame_buf))
    2233                 :            :                 return;
    2234                 :            : 
    2235   [ #  #  #  # ]:          0 :         if (WARN_ON(!ifmgd->associated))
    2236                 :            :                 return;
    2237                 :            : 
    2238                 :          0 :         ieee80211_stop_poll(sdata);
    2239                 :            : 
    2240                 :          0 :         ifmgd->associated = NULL;
    2241                 :          0 :         netif_carrier_off(sdata->dev);
    2242                 :            : 
    2243                 :            :         /*
    2244                 :            :          * if we want to get out of ps before disassoc (why?) we have
    2245                 :            :          * to do it before sending disassoc, as otherwise the null-packet
    2246                 :            :          * won't be valid.
    2247                 :            :          */
    2248         [ #  # ]:          0 :         if (local->hw.conf.flags & IEEE80211_CONF_PS) {
    2249                 :          0 :                 local->hw.conf.flags &= ~IEEE80211_CONF_PS;
    2250                 :          0 :                 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
    2251                 :            :         }
    2252                 :          0 :         local->ps_sdata = NULL;
    2253                 :            : 
    2254                 :            :         /* disable per-vif ps */
    2255                 :          0 :         ieee80211_recalc_ps_vif(sdata);
    2256                 :            : 
    2257                 :            :         /* make sure ongoing transmission finishes */
    2258                 :          0 :         synchronize_net();
    2259                 :            : 
    2260                 :            :         /*
    2261                 :            :          * drop any frame before deauth/disassoc, this can be data or
    2262                 :            :          * management frame. Since we are disconnecting, we should not
    2263                 :            :          * insist sending these frames which can take time and delay
    2264                 :            :          * the disconnection and possible the roaming.
    2265                 :            :          */
    2266         [ #  # ]:          0 :         if (tx)
    2267                 :          0 :                 ieee80211_flush_queues(local, sdata, true);
    2268                 :            : 
    2269                 :            :         /* deauthenticate/disassociate now */
    2270         [ #  # ]:          0 :         if (tx || frame_buf) {
    2271                 :            :                 /*
    2272                 :            :                  * In multi channel scenarios guarantee that the virtual
    2273                 :            :                  * interface is granted immediate airtime to transmit the
    2274                 :            :                  * deauthentication frame by calling mgd_prepare_tx, if the
    2275                 :            :                  * driver requested so.
    2276                 :            :                  */
    2277         [ #  # ]:          0 :                 if (ieee80211_hw_check(&local->hw, DEAUTH_NEED_MGD_TX_PREP) &&
    2278         [ #  # ]:          0 :                     !ifmgd->have_beacon)
    2279                 :          0 :                         drv_mgd_prepare_tx(sdata->local, sdata, 0);
    2280                 :            : 
    2281                 :          0 :                 ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid,
    2282                 :          0 :                                                ifmgd->bssid, stype, reason,
    2283                 :            :                                                tx, frame_buf);
    2284                 :            :         }
    2285                 :            : 
    2286                 :            :         /* flush out frame - make sure the deauth was actually sent */
    2287         [ #  # ]:          0 :         if (tx)
    2288                 :          0 :                 ieee80211_flush_queues(local, sdata, false);
    2289                 :            : 
    2290                 :            :         /* clear bssid only after building the needed mgmt frames */
    2291                 :          0 :         eth_zero_addr(ifmgd->bssid);
    2292                 :            : 
    2293                 :            :         /* remove AP and TDLS peers */
    2294                 :          0 :         sta_info_flush(sdata);
    2295                 :            : 
    2296                 :            :         /* finally reset all BSS / config parameters */
    2297                 :          0 :         changed |= ieee80211_reset_erp_info(sdata);
    2298                 :            : 
    2299                 :          0 :         ieee80211_led_assoc(local, 0);
    2300                 :          0 :         changed |= BSS_CHANGED_ASSOC;
    2301                 :          0 :         sdata->vif.bss_conf.assoc = false;
    2302                 :            : 
    2303                 :          0 :         ifmgd->p2p_noa_index = -1;
    2304                 :          0 :         memset(&sdata->vif.bss_conf.p2p_noa_attr, 0,
    2305                 :            :                sizeof(sdata->vif.bss_conf.p2p_noa_attr));
    2306                 :            : 
    2307                 :            :         /* on the next assoc, re-program HT/VHT parameters */
    2308                 :          0 :         memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
    2309                 :          0 :         memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
    2310                 :          0 :         memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa));
    2311                 :          0 :         memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask));
    2312                 :            : 
    2313                 :            :         /* reset MU-MIMO ownership and group data */
    2314                 :          0 :         memset(sdata->vif.bss_conf.mu_group.membership, 0,
    2315                 :            :                sizeof(sdata->vif.bss_conf.mu_group.membership));
    2316                 :          0 :         memset(sdata->vif.bss_conf.mu_group.position, 0,
    2317                 :            :                sizeof(sdata->vif.bss_conf.mu_group.position));
    2318                 :          0 :         changed |= BSS_CHANGED_MU_GROUPS;
    2319                 :          0 :         sdata->vif.mu_mimo_owner = false;
    2320                 :            : 
    2321                 :          0 :         sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
    2322                 :            : 
    2323                 :          0 :         del_timer_sync(&local->dynamic_ps_timer);
    2324                 :          0 :         cancel_work_sync(&local->dynamic_ps_enable_work);
    2325                 :            : 
    2326                 :            :         /* Disable ARP filtering */
    2327         [ #  # ]:          0 :         if (sdata->vif.bss_conf.arp_addr_cnt)
    2328                 :          0 :                 changed |= BSS_CHANGED_ARP_FILTER;
    2329                 :            : 
    2330                 :          0 :         sdata->vif.bss_conf.qos = false;
    2331                 :          0 :         changed |= BSS_CHANGED_QOS;
    2332                 :            : 
    2333                 :            :         /* The BSSID (not really interesting) and HT changed */
    2334                 :          0 :         changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
    2335                 :          0 :         ieee80211_bss_info_change_notify(sdata, changed);
    2336                 :            : 
    2337                 :            :         /* disassociated - set to defaults now */
    2338                 :          0 :         ieee80211_set_wmm_default(sdata, false, false);
    2339                 :            : 
    2340                 :          0 :         del_timer_sync(&sdata->u.mgd.conn_mon_timer);
    2341                 :          0 :         del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
    2342                 :          0 :         del_timer_sync(&sdata->u.mgd.timer);
    2343                 :          0 :         del_timer_sync(&sdata->u.mgd.chswitch_timer);
    2344                 :            : 
    2345                 :          0 :         sdata->vif.bss_conf.dtim_period = 0;
    2346                 :          0 :         sdata->vif.bss_conf.beacon_rate = NULL;
    2347                 :            : 
    2348                 :          0 :         ifmgd->have_beacon = false;
    2349                 :            : 
    2350                 :          0 :         ifmgd->flags = 0;
    2351                 :          0 :         mutex_lock(&local->mtx);
    2352                 :          0 :         ieee80211_vif_release_channel(sdata);
    2353                 :            : 
    2354                 :          0 :         sdata->vif.csa_active = false;
    2355                 :          0 :         ifmgd->csa_waiting_bcn = false;
    2356                 :          0 :         ifmgd->csa_ignored_same_chan = false;
    2357         [ #  # ]:          0 :         if (sdata->csa_block_tx) {
    2358                 :          0 :                 ieee80211_wake_vif_queues(local, sdata,
    2359                 :            :                                           IEEE80211_QUEUE_STOP_REASON_CSA);
    2360                 :          0 :                 sdata->csa_block_tx = false;
    2361                 :            :         }
    2362                 :          0 :         mutex_unlock(&local->mtx);
    2363                 :            : 
    2364                 :            :         /* existing TX TSPEC sessions no longer exist */
    2365                 :          0 :         memset(ifmgd->tx_tspec, 0, sizeof(ifmgd->tx_tspec));
    2366                 :          0 :         cancel_delayed_work_sync(&ifmgd->tx_tspec_wk);
    2367                 :            : 
    2368                 :          0 :         sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
    2369                 :            : }
    2370                 :            : 
    2371                 :          0 : void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
    2372                 :            :                              struct ieee80211_hdr *hdr)
    2373                 :            : {
    2374                 :            :         /*
    2375                 :            :          * We can postpone the mgd.timer whenever receiving unicast frames
    2376                 :            :          * from AP because we know that the connection is working both ways
    2377                 :            :          * at that time. But multicast frames (and hence also beacons) must
    2378                 :            :          * be ignored here, because we need to trigger the timer during
    2379                 :            :          * data idle periods for sending the periodic probe request to the
    2380                 :            :          * AP we're connected to.
    2381                 :            :          */
    2382         [ #  # ]:          0 :         if (is_multicast_ether_addr(hdr->addr1))
    2383                 :            :                 return;
    2384                 :            : 
    2385                 :          0 :         ieee80211_sta_reset_conn_monitor(sdata);
    2386                 :            : }
    2387                 :            : 
    2388                 :          0 : static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
    2389                 :            : {
    2390                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    2391                 :          0 :         struct ieee80211_local *local = sdata->local;
    2392                 :            : 
    2393                 :          0 :         mutex_lock(&local->mtx);
    2394         [ #  # ]:          0 :         if (!(ifmgd->flags & IEEE80211_STA_CONNECTION_POLL))
    2395                 :          0 :                 goto out;
    2396                 :            : 
    2397                 :          0 :         __ieee80211_stop_poll(sdata);
    2398                 :            : 
    2399                 :          0 :         mutex_lock(&local->iflist_mtx);
    2400                 :          0 :         ieee80211_recalc_ps(local);
    2401                 :          0 :         mutex_unlock(&local->iflist_mtx);
    2402                 :            : 
    2403         [ #  # ]:          0 :         if (ieee80211_hw_check(&sdata->local->hw, CONNECTION_MONITOR))
    2404                 :          0 :                 goto out;
    2405                 :            : 
    2406                 :            :         /*
    2407                 :            :          * We've received a probe response, but are not sure whether
    2408                 :            :          * we have or will be receiving any beacons or data, so let's
    2409                 :            :          * schedule the timers again, just in case.
    2410                 :            :          */
    2411                 :          0 :         ieee80211_sta_reset_beacon_monitor(sdata);
    2412                 :            : 
    2413                 :          0 :         mod_timer(&ifmgd->conn_mon_timer,
    2414                 :            :                   round_jiffies_up(jiffies +
    2415                 :            :                                    IEEE80211_CONNECTION_IDLE_TIME));
    2416                 :          0 : out:
    2417                 :          0 :         mutex_unlock(&local->mtx);
    2418                 :          0 : }
    2419                 :            : 
    2420                 :          0 : static void ieee80211_sta_tx_wmm_ac_notify(struct ieee80211_sub_if_data *sdata,
    2421                 :            :                                            struct ieee80211_hdr *hdr,
    2422                 :            :                                            u16 tx_time)
    2423                 :            : {
    2424                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    2425         [ #  # ]:          0 :         u16 tid = ieee80211_get_tid(hdr);
    2426         [ #  # ]:          0 :         int ac = ieee80211_ac_from_tid(tid);
    2427                 :          0 :         struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
    2428                 :          0 :         unsigned long now = jiffies;
    2429                 :            : 
    2430         [ #  # ]:          0 :         if (likely(!tx_tspec->admitted_time))
    2431                 :            :                 return;
    2432                 :            : 
    2433         [ #  # ]:          0 :         if (time_after(now, tx_tspec->time_slice_start + HZ)) {
    2434                 :          0 :                 tx_tspec->consumed_tx_time = 0;
    2435                 :          0 :                 tx_tspec->time_slice_start = now;
    2436                 :            : 
    2437         [ #  # ]:          0 :                 if (tx_tspec->downgraded) {
    2438                 :          0 :                         tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE;
    2439                 :          0 :                         schedule_delayed_work(&ifmgd->tx_tspec_wk, 0);
    2440                 :            :                 }
    2441                 :            :         }
    2442                 :            : 
    2443         [ #  # ]:          0 :         if (tx_tspec->downgraded)
    2444                 :            :                 return;
    2445                 :            : 
    2446                 :          0 :         tx_tspec->consumed_tx_time += tx_time;
    2447                 :            : 
    2448         [ #  # ]:          0 :         if (tx_tspec->consumed_tx_time >= tx_tspec->admitted_time) {
    2449                 :          0 :                 tx_tspec->downgraded = true;
    2450                 :          0 :                 tx_tspec->action = TX_TSPEC_ACTION_DOWNGRADE;
    2451                 :          0 :                 schedule_delayed_work(&ifmgd->tx_tspec_wk, 0);
    2452                 :            :         }
    2453                 :            : }
    2454                 :            : 
    2455                 :          0 : void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
    2456                 :            :                              struct ieee80211_hdr *hdr, bool ack, u16 tx_time)
    2457                 :            : {
    2458                 :          0 :         ieee80211_sta_tx_wmm_ac_notify(sdata, hdr, tx_time);
    2459                 :            : 
    2460         [ #  # ]:          0 :         if (!ieee80211_is_data(hdr->frame_control))
    2461                 :            :             return;
    2462                 :            : 
    2463         [ #  # ]:          0 :         if (ieee80211_is_nullfunc(hdr->frame_control) &&
    2464         [ #  # ]:          0 :             sdata->u.mgd.probe_send_count > 0) {
    2465         [ #  # ]:          0 :                 if (ack)
    2466                 :          0 :                         ieee80211_sta_reset_conn_monitor(sdata);
    2467                 :            :                 else
    2468                 :          0 :                         sdata->u.mgd.nullfunc_failed = true;
    2469                 :          0 :                 ieee80211_queue_work(&sdata->local->hw, &sdata->work);
    2470                 :          0 :                 return;
    2471                 :            :         }
    2472                 :            : 
    2473         [ #  # ]:          0 :         if (ack)
    2474                 :          0 :                 ieee80211_sta_reset_conn_monitor(sdata);
    2475                 :            : }
    2476                 :            : 
    2477                 :          0 : static void ieee80211_mlme_send_probe_req(struct ieee80211_sub_if_data *sdata,
    2478                 :            :                                           const u8 *src, const u8 *dst,
    2479                 :            :                                           const u8 *ssid, size_t ssid_len,
    2480                 :            :                                           struct ieee80211_channel *channel)
    2481                 :            : {
    2482                 :          0 :         struct sk_buff *skb;
    2483                 :            : 
    2484                 :          0 :         skb = ieee80211_build_probe_req(sdata, src, dst, (u32)-1, channel,
    2485                 :            :                                         ssid, ssid_len, NULL, 0,
    2486                 :            :                                         IEEE80211_PROBE_FLAG_DIRECTED);
    2487         [ #  # ]:          0 :         if (skb)
    2488                 :          0 :                 ieee80211_tx_skb(sdata, skb);
    2489                 :          0 : }
    2490                 :            : 
    2491                 :          0 : static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
    2492                 :            : {
    2493                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    2494                 :          0 :         const u8 *ssid;
    2495                 :          0 :         u8 *dst = ifmgd->associated->bssid;
    2496                 :          0 :         u8 unicast_limit = max(1, max_probe_tries - 3);
    2497                 :          0 :         struct sta_info *sta;
    2498                 :            : 
    2499                 :            :         /*
    2500                 :            :          * Try sending broadcast probe requests for the last three
    2501                 :            :          * probe requests after the first ones failed since some
    2502                 :            :          * buggy APs only support broadcast probe requests.
    2503                 :            :          */
    2504         [ #  # ]:          0 :         if (ifmgd->probe_send_count >= unicast_limit)
    2505                 :          0 :                 dst = NULL;
    2506                 :            : 
    2507                 :            :         /*
    2508                 :            :          * When the hardware reports an accurate Tx ACK status, it's
    2509                 :            :          * better to send a nullfunc frame instead of a probe request,
    2510                 :            :          * as it will kick us off the AP quickly if we aren't associated
    2511                 :            :          * anymore. The timeout will be reset if the frame is ACKed by
    2512                 :            :          * the AP.
    2513                 :            :          */
    2514                 :          0 :         ifmgd->probe_send_count++;
    2515                 :            : 
    2516         [ #  # ]:          0 :         if (dst) {
    2517                 :          0 :                 mutex_lock(&sdata->local->sta_mtx);
    2518                 :          0 :                 sta = sta_info_get(sdata, dst);
    2519   [ #  #  #  # ]:          0 :                 if (!WARN_ON(!sta))
    2520                 :          0 :                         ieee80211_check_fast_rx(sta);
    2521                 :          0 :                 mutex_unlock(&sdata->local->sta_mtx);
    2522                 :            :         }
    2523                 :            : 
    2524         [ #  # ]:          0 :         if (ieee80211_hw_check(&sdata->local->hw, REPORTS_TX_ACK_STATUS)) {
    2525                 :          0 :                 ifmgd->nullfunc_failed = false;
    2526         [ #  # ]:          0 :                 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
    2527                 :          0 :                         ifmgd->probe_send_count--;
    2528                 :            :                 else
    2529                 :          0 :                         ieee80211_send_nullfunc(sdata->local, sdata, false);
    2530                 :            :         } else {
    2531                 :          0 :                 int ssid_len;
    2532                 :            : 
    2533                 :          0 :                 rcu_read_lock();
    2534                 :          0 :                 ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
    2535   [ #  #  #  # ]:          0 :                 if (WARN_ON_ONCE(ssid == NULL))
    2536                 :            :                         ssid_len = 0;
    2537                 :            :                 else
    2538                 :          0 :                         ssid_len = ssid[1];
    2539                 :            : 
    2540                 :          0 :                 ieee80211_mlme_send_probe_req(sdata, sdata->vif.addr, dst,
    2541                 :            :                                               ssid + 2, ssid_len,
    2542                 :          0 :                                               ifmgd->associated->channel);
    2543                 :          0 :                 rcu_read_unlock();
    2544                 :            :         }
    2545                 :            : 
    2546         [ #  # ]:          0 :         ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
    2547         [ #  # ]:          0 :         run_again(sdata, ifmgd->probe_timeout);
    2548                 :          0 : }
    2549                 :            : 
    2550                 :          0 : static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
    2551                 :            :                                    bool beacon)
    2552                 :            : {
    2553                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    2554                 :          0 :         bool already = false;
    2555                 :            : 
    2556         [ #  # ]:          0 :         if (!ieee80211_sdata_running(sdata))
    2557                 :            :                 return;
    2558                 :            : 
    2559                 :          0 :         sdata_lock(sdata);
    2560                 :            : 
    2561         [ #  # ]:          0 :         if (!ifmgd->associated)
    2562                 :          0 :                 goto out;
    2563                 :            : 
    2564                 :          0 :         mutex_lock(&sdata->local->mtx);
    2565                 :            : 
    2566   [ #  #  #  # ]:          0 :         if (sdata->local->tmp_channel || sdata->local->scanning) {
    2567                 :          0 :                 mutex_unlock(&sdata->local->mtx);
    2568                 :          0 :                 goto out;
    2569                 :            :         }
    2570                 :            : 
    2571         [ #  # ]:          0 :         if (beacon) {
    2572                 :          0 :                 mlme_dbg_ratelimited(sdata,
    2573                 :            :                                      "detected beacon loss from AP (missed %d beacons) - probing\n",
    2574                 :            :                                      beacon_loss_count);
    2575                 :            : 
    2576                 :          0 :                 ieee80211_cqm_beacon_loss_notify(&sdata->vif, GFP_KERNEL);
    2577                 :            :         }
    2578                 :            : 
    2579                 :            :         /*
    2580                 :            :          * The driver/our work has already reported this event or the
    2581                 :            :          * connection monitoring has kicked in and we have already sent
    2582                 :            :          * a probe request. Or maybe the AP died and the driver keeps
    2583                 :            :          * reporting until we disassociate...
    2584                 :            :          *
    2585                 :            :          * In either case we have to ignore the current call to this
    2586                 :            :          * function (except for setting the correct probe reason bit)
    2587                 :            :          * because otherwise we would reset the timer every time and
    2588                 :            :          * never check whether we received a probe response!
    2589                 :            :          */
    2590         [ #  # ]:          0 :         if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL)
    2591                 :          0 :                 already = true;
    2592                 :            : 
    2593                 :          0 :         ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL;
    2594                 :            : 
    2595                 :          0 :         mutex_unlock(&sdata->local->mtx);
    2596                 :            : 
    2597         [ #  # ]:          0 :         if (already)
    2598                 :          0 :                 goto out;
    2599                 :            : 
    2600                 :          0 :         mutex_lock(&sdata->local->iflist_mtx);
    2601                 :          0 :         ieee80211_recalc_ps(sdata->local);
    2602                 :          0 :         mutex_unlock(&sdata->local->iflist_mtx);
    2603                 :            : 
    2604                 :          0 :         ifmgd->probe_send_count = 0;
    2605                 :          0 :         ieee80211_mgd_probe_ap_send(sdata);
    2606                 :          0 :  out:
    2607                 :          0 :         sdata_unlock(sdata);
    2608                 :            : }
    2609                 :            : 
    2610                 :          0 : struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
    2611                 :            :                                           struct ieee80211_vif *vif)
    2612                 :            : {
    2613         [ #  # ]:          0 :         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
    2614                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    2615                 :          0 :         struct cfg80211_bss *cbss;
    2616                 :          0 :         struct sk_buff *skb;
    2617                 :          0 :         const u8 *ssid;
    2618                 :          0 :         int ssid_len;
    2619                 :            : 
    2620   [ #  #  #  # ]:          0 :         if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
    2621                 :            :                 return NULL;
    2622                 :            : 
    2623         [ #  # ]:          0 :         sdata_assert_lock(sdata);
    2624                 :            : 
    2625         [ #  # ]:          0 :         if (ifmgd->associated)
    2626                 :            :                 cbss = ifmgd->associated;
    2627         [ #  # ]:          0 :         else if (ifmgd->auth_data)
    2628                 :          0 :                 cbss = ifmgd->auth_data->bss;
    2629         [ #  # ]:          0 :         else if (ifmgd->assoc_data)
    2630                 :          0 :                 cbss = ifmgd->assoc_data->bss;
    2631                 :            :         else
    2632                 :            :                 return NULL;
    2633                 :            : 
    2634                 :          0 :         rcu_read_lock();
    2635                 :          0 :         ssid = ieee80211_bss_get_ie(cbss, WLAN_EID_SSID);
    2636   [ #  #  #  #  :          0 :         if (WARN_ONCE(!ssid || ssid[1] > IEEE80211_MAX_SSID_LEN,
          #  #  #  #  #  
                #  #  # ]
    2637                 :            :                       "invalid SSID element (len=%d)", ssid ? ssid[1] : -1))
    2638                 :            :                 ssid_len = 0;
    2639                 :            :         else
    2640                 :          0 :                 ssid_len = ssid[1];
    2641                 :            : 
    2642                 :          0 :         skb = ieee80211_build_probe_req(sdata, sdata->vif.addr, cbss->bssid,
    2643                 :            :                                         (u32) -1, cbss->channel,
    2644                 :            :                                         ssid + 2, ssid_len,
    2645                 :            :                                         NULL, 0, IEEE80211_PROBE_FLAG_DIRECTED);
    2646                 :          0 :         rcu_read_unlock();
    2647                 :            : 
    2648                 :          0 :         return skb;
    2649                 :            : }
    2650                 :            : EXPORT_SYMBOL(ieee80211_ap_probereq_get);
    2651                 :            : 
    2652                 :          0 : static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata,
    2653                 :            :                                         const u8 *buf, size_t len, bool tx,
    2654                 :            :                                         u16 reason)
    2655                 :            : {
    2656                 :          0 :         struct ieee80211_event event = {
    2657                 :            :                 .type = MLME_EVENT,
    2658         [ #  # ]:          0 :                 .u.mlme.data = tx ? DEAUTH_TX_EVENT : DEAUTH_RX_EVENT,
    2659                 :            :                 .u.mlme.reason = reason,
    2660                 :            :         };
    2661                 :            : 
    2662         [ #  # ]:          0 :         if (tx)
    2663                 :          0 :                 cfg80211_tx_mlme_mgmt(sdata->dev, buf, len);
    2664                 :            :         else
    2665                 :          0 :                 cfg80211_rx_mlme_mgmt(sdata->dev, buf, len);
    2666                 :            : 
    2667                 :          0 :         drv_event_callback(sdata->local, sdata, &event);
    2668                 :          0 : }
    2669                 :            : 
    2670                 :          0 : static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
    2671                 :            : {
    2672                 :          0 :         struct ieee80211_local *local = sdata->local;
    2673                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    2674                 :          0 :         u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
    2675                 :          0 :         bool tx;
    2676                 :            : 
    2677                 :          0 :         sdata_lock(sdata);
    2678         [ #  # ]:          0 :         if (!ifmgd->associated) {
    2679                 :          0 :                 sdata_unlock(sdata);
    2680                 :          0 :                 return;
    2681                 :            :         }
    2682                 :            : 
    2683                 :          0 :         tx = !sdata->csa_block_tx;
    2684                 :            : 
    2685                 :            :         /* AP is probably out of range (or not reachable for another reason) so
    2686                 :            :          * remove the bss struct for that AP.
    2687                 :            :          */
    2688                 :          0 :         cfg80211_unlink_bss(local->hw.wiphy, ifmgd->associated);
    2689                 :            : 
    2690                 :          0 :         ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
    2691                 :            :                                WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
    2692                 :            :                                tx, frame_buf);
    2693                 :          0 :         mutex_lock(&local->mtx);
    2694                 :          0 :         sdata->vif.csa_active = false;
    2695                 :          0 :         ifmgd->csa_waiting_bcn = false;
    2696         [ #  # ]:          0 :         if (sdata->csa_block_tx) {
    2697                 :          0 :                 ieee80211_wake_vif_queues(local, sdata,
    2698                 :            :                                           IEEE80211_QUEUE_STOP_REASON_CSA);
    2699                 :          0 :                 sdata->csa_block_tx = false;
    2700                 :            :         }
    2701                 :          0 :         mutex_unlock(&local->mtx);
    2702                 :            : 
    2703                 :          0 :         ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), tx,
    2704                 :            :                                     WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
    2705                 :            : 
    2706                 :          0 :         sdata_unlock(sdata);
    2707                 :            : }
    2708                 :            : 
    2709                 :          0 : static void ieee80211_beacon_connection_loss_work(struct work_struct *work)
    2710                 :            : {
    2711                 :          0 :         struct ieee80211_sub_if_data *sdata =
    2712                 :          0 :                 container_of(work, struct ieee80211_sub_if_data,
    2713                 :            :                              u.mgd.beacon_connection_loss_work);
    2714                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    2715                 :            : 
    2716         [ #  # ]:          0 :         if (ifmgd->associated)
    2717                 :          0 :                 ifmgd->beacon_loss_count++;
    2718                 :            : 
    2719         [ #  # ]:          0 :         if (ifmgd->connection_loss) {
    2720                 :          0 :                 sdata_info(sdata, "Connection to AP %pM lost\n",
    2721                 :            :                            ifmgd->bssid);
    2722                 :          0 :                 __ieee80211_disconnect(sdata);
    2723                 :            :         } else {
    2724                 :          0 :                 ieee80211_mgd_probe_ap(sdata, true);
    2725                 :            :         }
    2726                 :          0 : }
    2727                 :            : 
    2728                 :          0 : static void ieee80211_csa_connection_drop_work(struct work_struct *work)
    2729                 :            : {
    2730                 :          0 :         struct ieee80211_sub_if_data *sdata =
    2731                 :          0 :                 container_of(work, struct ieee80211_sub_if_data,
    2732                 :            :                              u.mgd.csa_connection_drop_work);
    2733                 :            : 
    2734                 :          0 :         __ieee80211_disconnect(sdata);
    2735                 :          0 : }
    2736                 :            : 
    2737                 :          0 : void ieee80211_beacon_loss(struct ieee80211_vif *vif)
    2738                 :            : {
    2739                 :          0 :         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
    2740                 :          0 :         struct ieee80211_hw *hw = &sdata->local->hw;
    2741                 :            : 
    2742                 :          0 :         trace_api_beacon_loss(sdata);
    2743                 :            : 
    2744                 :          0 :         sdata->u.mgd.connection_loss = false;
    2745                 :          0 :         ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
    2746                 :          0 : }
    2747                 :            : EXPORT_SYMBOL(ieee80211_beacon_loss);
    2748                 :            : 
    2749                 :          0 : void ieee80211_connection_loss(struct ieee80211_vif *vif)
    2750                 :            : {
    2751                 :          0 :         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
    2752                 :          0 :         struct ieee80211_hw *hw = &sdata->local->hw;
    2753                 :            : 
    2754                 :          0 :         trace_api_connection_loss(sdata);
    2755                 :            : 
    2756                 :          0 :         sdata->u.mgd.connection_loss = true;
    2757                 :          0 :         ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
    2758                 :          0 : }
    2759                 :            : EXPORT_SYMBOL(ieee80211_connection_loss);
    2760                 :            : 
    2761                 :            : 
    2762                 :          0 : static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
    2763                 :            :                                         bool assoc)
    2764                 :            : {
    2765                 :          0 :         struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data;
    2766                 :            : 
    2767         [ #  # ]:          0 :         sdata_assert_lock(sdata);
    2768                 :            : 
    2769         [ #  # ]:          0 :         if (!assoc) {
    2770                 :            :                 /*
    2771                 :            :                  * we are not authenticated yet, the only timer that could be
    2772                 :            :                  * running is the timeout for the authentication response which
    2773                 :            :                  * which is not relevant anymore.
    2774                 :            :                  */
    2775                 :          0 :                 del_timer_sync(&sdata->u.mgd.timer);
    2776                 :          0 :                 sta_info_destroy_addr(sdata, auth_data->bss->bssid);
    2777                 :            : 
    2778                 :          0 :                 eth_zero_addr(sdata->u.mgd.bssid);
    2779                 :          0 :                 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
    2780                 :          0 :                 sdata->u.mgd.flags = 0;
    2781                 :          0 :                 mutex_lock(&sdata->local->mtx);
    2782                 :          0 :                 ieee80211_vif_release_channel(sdata);
    2783                 :          0 :                 mutex_unlock(&sdata->local->mtx);
    2784                 :            :         }
    2785                 :            : 
    2786                 :          0 :         cfg80211_put_bss(sdata->local->hw.wiphy, auth_data->bss);
    2787                 :          0 :         kfree(auth_data);
    2788                 :          0 :         sdata->u.mgd.auth_data = NULL;
    2789                 :          0 : }
    2790                 :            : 
    2791                 :          0 : static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
    2792                 :            :                                          bool assoc, bool abandon)
    2793                 :            : {
    2794                 :          0 :         struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data;
    2795                 :            : 
    2796         [ #  # ]:          0 :         sdata_assert_lock(sdata);
    2797                 :            : 
    2798         [ #  # ]:          0 :         if (!assoc) {
    2799                 :            :                 /*
    2800                 :            :                  * we are not associated yet, the only timer that could be
    2801                 :            :                  * running is the timeout for the association response which
    2802                 :            :                  * which is not relevant anymore.
    2803                 :            :                  */
    2804                 :          0 :                 del_timer_sync(&sdata->u.mgd.timer);
    2805                 :          0 :                 sta_info_destroy_addr(sdata, assoc_data->bss->bssid);
    2806                 :            : 
    2807                 :          0 :                 eth_zero_addr(sdata->u.mgd.bssid);
    2808                 :          0 :                 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
    2809                 :          0 :                 sdata->u.mgd.flags = 0;
    2810                 :          0 :                 sdata->vif.mu_mimo_owner = false;
    2811                 :            : 
    2812                 :          0 :                 mutex_lock(&sdata->local->mtx);
    2813                 :          0 :                 ieee80211_vif_release_channel(sdata);
    2814                 :          0 :                 mutex_unlock(&sdata->local->mtx);
    2815                 :            : 
    2816         [ #  # ]:          0 :                 if (abandon)
    2817                 :          0 :                         cfg80211_abandon_assoc(sdata->dev, assoc_data->bss);
    2818                 :            :         }
    2819                 :            : 
    2820                 :          0 :         kfree(assoc_data);
    2821                 :          0 :         sdata->u.mgd.assoc_data = NULL;
    2822                 :          0 : }
    2823                 :            : 
    2824                 :          0 : static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
    2825                 :            :                                      struct ieee80211_mgmt *mgmt, size_t len)
    2826                 :            : {
    2827                 :          0 :         struct ieee80211_local *local = sdata->local;
    2828                 :          0 :         struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data;
    2829                 :          0 :         u8 *pos;
    2830                 :          0 :         struct ieee802_11_elems elems;
    2831                 :          0 :         u32 tx_flags = 0;
    2832                 :            : 
    2833                 :          0 :         pos = mgmt->u.auth.variable;
    2834                 :          0 :         ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
    2835                 :          0 :                                mgmt->bssid, auth_data->bss->bssid);
    2836         [ #  # ]:          0 :         if (!elems.challenge)
    2837                 :          0 :                 return;
    2838                 :          0 :         auth_data->expected_transaction = 4;
    2839                 :          0 :         drv_mgd_prepare_tx(sdata->local, sdata, 0);
    2840         [ #  # ]:          0 :         if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
    2841                 :          0 :                 tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
    2842                 :            :                            IEEE80211_TX_INTFL_MLME_CONN_TX;
    2843                 :          0 :         ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0,
    2844                 :          0 :                             elems.challenge - 2, elems.challenge_len + 2,
    2845                 :          0 :                             auth_data->bss->bssid, auth_data->bss->bssid,
    2846                 :          0 :                             auth_data->key, auth_data->key_len,
    2847                 :          0 :                             auth_data->key_idx, tx_flags);
    2848                 :            : }
    2849                 :            : 
    2850                 :          0 : static bool ieee80211_mark_sta_auth(struct ieee80211_sub_if_data *sdata,
    2851                 :            :                                     const u8 *bssid)
    2852                 :            : {
    2853                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    2854                 :          0 :         struct sta_info *sta;
    2855                 :          0 :         bool result = true;
    2856                 :            : 
    2857                 :          0 :         sdata_info(sdata, "authenticated\n");
    2858                 :          0 :         ifmgd->auth_data->done = true;
    2859                 :          0 :         ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC;
    2860                 :          0 :         ifmgd->auth_data->timeout_started = true;
    2861         [ #  # ]:          0 :         run_again(sdata, ifmgd->auth_data->timeout);
    2862                 :            : 
    2863                 :            :         /* move station state to auth */
    2864                 :          0 :         mutex_lock(&sdata->local->sta_mtx);
    2865                 :          0 :         sta = sta_info_get(sdata, bssid);
    2866         [ #  # ]:          0 :         if (!sta) {
    2867         [ #  # ]:          0 :                 WARN_ONCE(1, "%s: STA %pM not found", sdata->name, bssid);
    2868                 :          0 :                 result = false;
    2869                 :          0 :                 goto out;
    2870                 :            :         }
    2871         [ #  # ]:          0 :         if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) {
    2872                 :          0 :                 sdata_info(sdata, "failed moving %pM to auth\n", bssid);
    2873                 :          0 :                 result = false;
    2874                 :          0 :                 goto out;
    2875                 :            :         }
    2876                 :            : 
    2877                 :          0 : out:
    2878                 :          0 :         mutex_unlock(&sdata->local->sta_mtx);
    2879                 :          0 :         return result;
    2880                 :            : }
    2881                 :            : 
    2882                 :          0 : static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
    2883                 :            :                                    struct ieee80211_mgmt *mgmt, size_t len)
    2884                 :            : {
    2885                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    2886                 :          0 :         u8 bssid[ETH_ALEN];
    2887                 :          0 :         u16 auth_alg, auth_transaction, status_code;
    2888                 :          0 :         struct ieee80211_event event = {
    2889                 :            :                 .type = MLME_EVENT,
    2890                 :            :                 .u.mlme.data = AUTH_EVENT,
    2891                 :            :         };
    2892                 :            : 
    2893         [ #  # ]:          0 :         sdata_assert_lock(sdata);
    2894                 :            : 
    2895         [ #  # ]:          0 :         if (len < 24 + 6)
    2896                 :          0 :                 return;
    2897                 :            : 
    2898   [ #  #  #  # ]:          0 :         if (!ifmgd->auth_data || ifmgd->auth_data->done)
    2899                 :            :                 return;
    2900                 :            : 
    2901                 :          0 :         memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN);
    2902                 :            : 
    2903         [ #  # ]:          0 :         if (!ether_addr_equal(bssid, mgmt->bssid))
    2904                 :            :                 return;
    2905                 :            : 
    2906                 :          0 :         auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
    2907                 :          0 :         auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
    2908                 :          0 :         status_code = le16_to_cpu(mgmt->u.auth.status_code);
    2909                 :            : 
    2910   [ #  #  #  # ]:          0 :         if (auth_alg != ifmgd->auth_data->algorithm ||
    2911                 :          0 :             (auth_alg != WLAN_AUTH_SAE &&
    2912   [ #  #  #  # ]:          0 :              auth_transaction != ifmgd->auth_data->expected_transaction) ||
    2913                 :          0 :             (auth_alg == WLAN_AUTH_SAE &&
    2914   [ #  #  #  # ]:          0 :              (auth_transaction < ifmgd->auth_data->expected_transaction ||
    2915                 :            :               auth_transaction > 2))) {
    2916                 :          0 :                 sdata_info(sdata, "%pM unexpected authentication state: alg %d (expected %d) transact %d (expected %d)\n",
    2917                 :            :                            mgmt->sa, auth_alg, ifmgd->auth_data->algorithm,
    2918                 :            :                            auth_transaction,
    2919                 :            :                            ifmgd->auth_data->expected_transaction);
    2920                 :          0 :                 return;
    2921                 :            :         }
    2922                 :            : 
    2923         [ #  # ]:          0 :         if (status_code != WLAN_STATUS_SUCCESS) {
    2924                 :          0 :                 sdata_info(sdata, "%pM denied authentication (status %d)\n",
    2925                 :            :                            mgmt->sa, status_code);
    2926                 :          0 :                 ieee80211_destroy_auth_data(sdata, false);
    2927                 :          0 :                 cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
    2928                 :          0 :                 event.u.mlme.status = MLME_DENIED;
    2929                 :          0 :                 event.u.mlme.reason = status_code;
    2930                 :          0 :                 drv_event_callback(sdata->local, sdata, &event);
    2931                 :          0 :                 return;
    2932                 :            :         }
    2933                 :            : 
    2934      [ #  #  # ]:          0 :         switch (ifmgd->auth_data->algorithm) {
    2935                 :            :         case WLAN_AUTH_OPEN:
    2936                 :            :         case WLAN_AUTH_LEAP:
    2937                 :            :         case WLAN_AUTH_FT:
    2938                 :            :         case WLAN_AUTH_SAE:
    2939                 :            :         case WLAN_AUTH_FILS_SK:
    2940                 :            :         case WLAN_AUTH_FILS_SK_PFS:
    2941                 :            :         case WLAN_AUTH_FILS_PK:
    2942                 :            :                 break;
    2943                 :          0 :         case WLAN_AUTH_SHARED_KEY:
    2944         [ #  # ]:          0 :                 if (ifmgd->auth_data->expected_transaction != 4) {
    2945                 :          0 :                         ieee80211_auth_challenge(sdata, mgmt, len);
    2946                 :            :                         /* need another frame */
    2947                 :          0 :                         return;
    2948                 :            :                 }
    2949                 :            :                 break;
    2950                 :            :         default:
    2951         [ #  # ]:          0 :                 WARN_ONCE(1, "invalid auth alg %d",
    2952                 :            :                           ifmgd->auth_data->algorithm);
    2953                 :            :                 return;
    2954                 :            :         }
    2955                 :            : 
    2956                 :          0 :         event.u.mlme.status = MLME_SUCCESS;
    2957                 :          0 :         drv_event_callback(sdata->local, sdata, &event);
    2958   [ #  #  #  # ]:          0 :         if (ifmgd->auth_data->algorithm != WLAN_AUTH_SAE ||
    2959                 :          0 :             (auth_transaction == 2 &&
    2960         [ #  # ]:          0 :              ifmgd->auth_data->expected_transaction == 2)) {
    2961         [ #  # ]:          0 :                 if (!ieee80211_mark_sta_auth(sdata, bssid))
    2962                 :            :                         return; /* ignore frame -- wait for timeout */
    2963         [ #  # ]:          0 :         } else if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE &&
    2964                 :            :                    auth_transaction == 2) {
    2965                 :          0 :                 sdata_info(sdata, "SAE peer confirmed\n");
    2966                 :          0 :                 ifmgd->auth_data->peer_confirmed = true;
    2967                 :            :         }
    2968                 :            : 
    2969                 :          0 :         cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
    2970                 :            : }
    2971                 :            : 
    2972                 :            : #define case_WLAN(type) \
    2973                 :            :         case WLAN_REASON_##type: return #type
    2974                 :            : 
    2975                 :          0 : const char *ieee80211_get_reason_code_string(u16 reason_code)
    2976                 :            : {
    2977         [ #  # ]:          0 :         switch (reason_code) {
    2978                 :            :         case_WLAN(UNSPECIFIED);
    2979                 :            :         case_WLAN(PREV_AUTH_NOT_VALID);
    2980                 :            :         case_WLAN(DEAUTH_LEAVING);
    2981                 :            :         case_WLAN(DISASSOC_DUE_TO_INACTIVITY);
    2982                 :            :         case_WLAN(DISASSOC_AP_BUSY);
    2983                 :            :         case_WLAN(CLASS2_FRAME_FROM_NONAUTH_STA);
    2984                 :            :         case_WLAN(CLASS3_FRAME_FROM_NONASSOC_STA);
    2985                 :            :         case_WLAN(DISASSOC_STA_HAS_LEFT);
    2986                 :            :         case_WLAN(STA_REQ_ASSOC_WITHOUT_AUTH);
    2987                 :            :         case_WLAN(DISASSOC_BAD_POWER);
    2988                 :            :         case_WLAN(DISASSOC_BAD_SUPP_CHAN);
    2989                 :            :         case_WLAN(INVALID_IE);
    2990                 :            :         case_WLAN(MIC_FAILURE);
    2991                 :            :         case_WLAN(4WAY_HANDSHAKE_TIMEOUT);
    2992                 :            :         case_WLAN(GROUP_KEY_HANDSHAKE_TIMEOUT);
    2993                 :            :         case_WLAN(IE_DIFFERENT);
    2994                 :            :         case_WLAN(INVALID_GROUP_CIPHER);
    2995                 :            :         case_WLAN(INVALID_PAIRWISE_CIPHER);
    2996                 :            :         case_WLAN(INVALID_AKMP);
    2997                 :            :         case_WLAN(UNSUPP_RSN_VERSION);
    2998                 :            :         case_WLAN(INVALID_RSN_IE_CAP);
    2999                 :            :         case_WLAN(IEEE8021X_FAILED);
    3000                 :            :         case_WLAN(CIPHER_SUITE_REJECTED);
    3001                 :            :         case_WLAN(DISASSOC_UNSPECIFIED_QOS);
    3002                 :            :         case_WLAN(DISASSOC_QAP_NO_BANDWIDTH);
    3003                 :            :         case_WLAN(DISASSOC_LOW_ACK);
    3004                 :            :         case_WLAN(DISASSOC_QAP_EXCEED_TXOP);
    3005                 :            :         case_WLAN(QSTA_LEAVE_QBSS);
    3006                 :            :         case_WLAN(QSTA_NOT_USE);
    3007                 :            :         case_WLAN(QSTA_REQUIRE_SETUP);
    3008                 :            :         case_WLAN(QSTA_TIMEOUT);
    3009                 :            :         case_WLAN(QSTA_CIPHER_NOT_SUPP);
    3010                 :            :         case_WLAN(MESH_PEER_CANCELED);
    3011                 :            :         case_WLAN(MESH_MAX_PEERS);
    3012                 :            :         case_WLAN(MESH_CONFIG);
    3013                 :            :         case_WLAN(MESH_CLOSE);
    3014                 :            :         case_WLAN(MESH_MAX_RETRIES);
    3015                 :            :         case_WLAN(MESH_CONFIRM_TIMEOUT);
    3016                 :            :         case_WLAN(MESH_INVALID_GTK);
    3017                 :            :         case_WLAN(MESH_INCONSISTENT_PARAM);
    3018                 :            :         case_WLAN(MESH_INVALID_SECURITY);
    3019                 :            :         case_WLAN(MESH_PATH_ERROR);
    3020                 :            :         case_WLAN(MESH_PATH_NOFORWARD);
    3021                 :            :         case_WLAN(MESH_PATH_DEST_UNREACHABLE);
    3022                 :            :         case_WLAN(MAC_EXISTS_IN_MBSS);
    3023                 :            :         case_WLAN(MESH_CHAN_REGULATORY);
    3024                 :            :         case_WLAN(MESH_CHAN);
    3025                 :            :         default: return "<unknown>";
    3026                 :            :         }
    3027                 :            : }
    3028                 :            : 
    3029                 :          0 : static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
    3030                 :            :                                      struct ieee80211_mgmt *mgmt, size_t len)
    3031                 :            : {
    3032                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    3033                 :          0 :         u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
    3034                 :            : 
    3035         [ #  # ]:          0 :         sdata_assert_lock(sdata);
    3036                 :            : 
    3037         [ #  # ]:          0 :         if (len < 24 + 2)
    3038                 :            :                 return;
    3039                 :            : 
    3040         [ #  # ]:          0 :         if (!ether_addr_equal(mgmt->bssid, mgmt->sa)) {
    3041                 :          0 :                 ieee80211_tdls_handle_disconnect(sdata, mgmt->sa, reason_code);
    3042                 :          0 :                 return;
    3043                 :            :         }
    3044                 :            : 
    3045   [ #  #  #  # ]:          0 :         if (ifmgd->associated &&
    3046                 :            :             ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) {
    3047                 :          0 :                 const u8 *bssid = ifmgd->associated->bssid;
    3048                 :            : 
    3049         [ #  # ]:          0 :                 sdata_info(sdata, "deauthenticated from %pM (Reason: %u=%s)\n",
    3050                 :            :                            bssid, reason_code,
    3051                 :            :                            ieee80211_get_reason_code_string(reason_code));
    3052                 :            : 
    3053                 :          0 :                 ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
    3054                 :            : 
    3055                 :          0 :                 ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false,
    3056                 :            :                                             reason_code);
    3057                 :          0 :                 return;
    3058                 :            :         }
    3059                 :            : 
    3060   [ #  #  #  # ]:          0 :         if (ifmgd->assoc_data &&
    3061         [ #  # ]:          0 :             ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
    3062                 :          0 :                 const u8 *bssid = ifmgd->assoc_data->bss->bssid;
    3063                 :            : 
    3064         [ #  # ]:          0 :                 sdata_info(sdata,
    3065                 :            :                            "deauthenticated from %pM while associating (Reason: %u=%s)\n",
    3066                 :            :                            bssid, reason_code,
    3067                 :            :                            ieee80211_get_reason_code_string(reason_code));
    3068                 :            : 
    3069                 :          0 :                 ieee80211_destroy_assoc_data(sdata, false, true);
    3070                 :            : 
    3071                 :          0 :                 cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
    3072                 :          0 :                 return;
    3073                 :            :         }
    3074                 :            : }
    3075                 :            : 
    3076                 :            : 
    3077                 :          0 : static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
    3078                 :            :                                        struct ieee80211_mgmt *mgmt, size_t len)
    3079                 :            : {
    3080                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    3081                 :          0 :         u16 reason_code;
    3082                 :            : 
    3083         [ #  # ]:          0 :         sdata_assert_lock(sdata);
    3084                 :            : 
    3085         [ #  # ]:          0 :         if (len < 24 + 2)
    3086                 :            :                 return;
    3087                 :            : 
    3088   [ #  #  #  # ]:          0 :         if (!ifmgd->associated ||
    3089                 :            :             !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
    3090                 :            :                 return;
    3091                 :            : 
    3092                 :          0 :         reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
    3093                 :            : 
    3094         [ #  # ]:          0 :         if (!ether_addr_equal(mgmt->bssid, mgmt->sa)) {
    3095                 :          0 :                 ieee80211_tdls_handle_disconnect(sdata, mgmt->sa, reason_code);
    3096                 :          0 :                 return;
    3097                 :            :         }
    3098                 :            : 
    3099         [ #  # ]:          0 :         sdata_info(sdata, "disassociated from %pM (Reason: %u=%s)\n",
    3100                 :            :                    mgmt->sa, reason_code,
    3101                 :            :                    ieee80211_get_reason_code_string(reason_code));
    3102                 :            : 
    3103                 :          0 :         ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
    3104                 :            : 
    3105                 :          0 :         ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code);
    3106                 :            : }
    3107                 :            : 
    3108                 :            : static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
    3109                 :            :                                 u8 *supp_rates, unsigned int supp_rates_len,
    3110                 :            :                                 u32 *rates, u32 *basic_rates,
    3111                 :            :                                 bool *have_higher_than_11mbit,
    3112                 :            :                                 int *min_rate, int *min_rate_index,
    3113                 :            :                                 int shift)
    3114                 :            : {
    3115                 :            :         int i, j;
    3116                 :            : 
    3117                 :            :         for (i = 0; i < supp_rates_len; i++) {
    3118                 :            :                 int rate = supp_rates[i] & 0x7f;
    3119                 :            :                 bool is_basic = !!(supp_rates[i] & 0x80);
    3120                 :            : 
    3121                 :            :                 if ((rate * 5 * (1 << shift)) > 110)
    3122                 :            :                         *have_higher_than_11mbit = true;
    3123                 :            : 
    3124                 :            :                 /*
    3125                 :            :                  * Skip HT and VHT BSS membership selectors since they're not
    3126                 :            :                  * rates.
    3127                 :            :                  *
    3128                 :            :                  * Note: Even though the membership selector and the basic
    3129                 :            :                  *       rate flag share the same bit, they are not exactly
    3130                 :            :                  *       the same.
    3131                 :            :                  */
    3132                 :            :                 if (supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY) ||
    3133                 :            :                     supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY))
    3134                 :            :                         continue;
    3135                 :            : 
    3136                 :            :                 for (j = 0; j < sband->n_bitrates; j++) {
    3137                 :            :                         struct ieee80211_rate *br;
    3138                 :            :                         int brate;
    3139                 :            : 
    3140                 :            :                         br = &sband->bitrates[j];
    3141                 :            : 
    3142                 :            :                         brate = DIV_ROUND_UP(br->bitrate, (1 << shift) * 5);
    3143                 :            :                         if (brate == rate) {
    3144                 :            :                                 *rates |= BIT(j);
    3145                 :            :                                 if (is_basic)
    3146                 :            :                                         *basic_rates |= BIT(j);
    3147                 :            :                                 if ((rate * 5) < *min_rate) {
    3148                 :            :                                         *min_rate = rate * 5;
    3149                 :            :                                         *min_rate_index = j;
    3150                 :            :                                 }
    3151                 :            :                                 break;
    3152                 :            :                         }
    3153                 :            :                 }
    3154                 :            :         }
    3155                 :            : }
    3156                 :            : 
    3157                 :          0 : static bool ieee80211_twt_req_supported(const struct sta_info *sta,
    3158                 :            :                                         const struct ieee802_11_elems *elems)
    3159                 :            : {
    3160                 :          0 :         if (elems->ext_capab_len < 10)
    3161                 :            :                 return false;
    3162                 :            : 
    3163         [ #  # ]:          0 :         if (!(elems->ext_capab[9] & WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT))
    3164                 :            :                 return false;
    3165                 :            : 
    3166                 :          0 :         return sta->sta.he_cap.he_cap_elem.mac_cap_info[0] &
    3167                 :            :                 IEEE80211_HE_MAC_CAP0_TWT_RES;
    3168                 :            : }
    3169                 :            : 
    3170                 :          0 : static int ieee80211_recalc_twt_req(struct ieee80211_sub_if_data *sdata,
    3171                 :            :                                     struct sta_info *sta,
    3172                 :            :                                     struct ieee802_11_elems *elems)
    3173                 :            : {
    3174                 :          0 :         bool twt = ieee80211_twt_req_supported(sta, elems);
    3175                 :            : 
    3176         [ #  # ]:          0 :         if (sdata->vif.bss_conf.twt_requester != twt) {
    3177                 :          0 :                 sdata->vif.bss_conf.twt_requester = twt;
    3178                 :          0 :                 return BSS_CHANGED_TWT;
    3179                 :            :         }
    3180                 :            :         return 0;
    3181                 :            : }
    3182                 :            : 
    3183                 :            : static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
    3184                 :            :                                     struct cfg80211_bss *cbss,
    3185                 :            :                                     struct ieee80211_mgmt *mgmt, size_t len,
    3186                 :            :                                     struct ieee802_11_elems *elems)
    3187                 :            : {
    3188                 :            :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    3189                 :            :         struct ieee80211_local *local = sdata->local;
    3190                 :            :         struct ieee80211_supported_band *sband;
    3191                 :            :         struct sta_info *sta;
    3192                 :            :         u16 capab_info, aid;
    3193                 :            :         struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
    3194                 :            :         const struct cfg80211_bss_ies *bss_ies = NULL;
    3195                 :            :         struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
    3196                 :            :         u32 changed = 0;
    3197                 :            :         int err;
    3198                 :            :         bool ret;
    3199                 :            : 
    3200                 :            :         /* AssocResp and ReassocResp have identical structure */
    3201                 :            : 
    3202                 :            :         aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
    3203                 :            :         capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
    3204                 :            : 
    3205                 :            :         /*
    3206                 :            :          * The 5 MSB of the AID field are reserved
    3207                 :            :          * (802.11-2016 9.4.1.8 AID field)
    3208                 :            :          */
    3209                 :            :         aid &= 0x7ff;
    3210                 :            : 
    3211                 :            :         ifmgd->broken_ap = false;
    3212                 :            : 
    3213                 :            :         if (aid == 0 || aid > IEEE80211_MAX_AID) {
    3214                 :            :                 sdata_info(sdata, "invalid AID value %d (out of range), turn off PS\n",
    3215                 :            :                            aid);
    3216                 :            :                 aid = 0;
    3217                 :            :                 ifmgd->broken_ap = true;
    3218                 :            :         }
    3219                 :            : 
    3220                 :            :         if (!elems->supp_rates) {
    3221                 :            :                 sdata_info(sdata, "no SuppRates element in AssocResp\n");
    3222                 :            :                 return false;
    3223                 :            :         }
    3224                 :            : 
    3225                 :            :         ifmgd->aid = aid;
    3226                 :            :         ifmgd->tdls_chan_switch_prohibited =
    3227                 :            :                 elems->ext_capab && elems->ext_capab_len >= 5 &&
    3228                 :            :                 (elems->ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED);
    3229                 :            : 
    3230                 :            :         /*
    3231                 :            :          * Some APs are erroneously not including some information in their
    3232                 :            :          * (re)association response frames. Try to recover by using the data
    3233                 :            :          * from the beacon or probe response. This seems to afflict mobile
    3234                 :            :          * 2G/3G/4G wifi routers, reported models include the "Onda PN51T",
    3235                 :            :          * "Vodafone PocketWiFi 2", "ZTE MF60" and a similar T-Mobile device.
    3236                 :            :          */
    3237                 :            :         if ((assoc_data->wmm && !elems->wmm_param) ||
    3238                 :            :             (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
    3239                 :            :              (!elems->ht_cap_elem || !elems->ht_operation)) ||
    3240                 :            :             (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
    3241                 :            :              (!elems->vht_cap_elem || !elems->vht_operation))) {
    3242                 :            :                 const struct cfg80211_bss_ies *ies;
    3243                 :            :                 struct ieee802_11_elems bss_elems;
    3244                 :            : 
    3245                 :            :                 rcu_read_lock();
    3246                 :            :                 ies = rcu_dereference(cbss->ies);
    3247                 :            :                 if (ies)
    3248                 :            :                         bss_ies = kmemdup(ies, sizeof(*ies) + ies->len,
    3249                 :            :                                           GFP_ATOMIC);
    3250                 :            :                 rcu_read_unlock();
    3251                 :            :                 if (!bss_ies)
    3252                 :            :                         return false;
    3253                 :            : 
    3254                 :            :                 ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
    3255                 :            :                                        false, &bss_elems,
    3256                 :            :                                        mgmt->bssid,
    3257                 :            :                                        assoc_data->bss->bssid);
    3258                 :            :                 if (assoc_data->wmm &&
    3259                 :            :                     !elems->wmm_param && bss_elems.wmm_param) {
    3260                 :            :                         elems->wmm_param = bss_elems.wmm_param;
    3261                 :            :                         sdata_info(sdata,
    3262                 :            :                                    "AP bug: WMM param missing from AssocResp\n");
    3263                 :            :                 }
    3264                 :            : 
    3265                 :            :                 /*
    3266                 :            :                  * Also check if we requested HT/VHT, otherwise the AP doesn't
    3267                 :            :                  * have to include the IEs in the (re)association response.
    3268                 :            :                  */
    3269                 :            :                 if (!elems->ht_cap_elem && bss_elems.ht_cap_elem &&
    3270                 :            :                     !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
    3271                 :            :                         elems->ht_cap_elem = bss_elems.ht_cap_elem;
    3272                 :            :                         sdata_info(sdata,
    3273                 :            :                                    "AP bug: HT capability missing from AssocResp\n");
    3274                 :            :                 }
    3275                 :            :                 if (!elems->ht_operation && bss_elems.ht_operation &&
    3276                 :            :                     !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
    3277                 :            :                         elems->ht_operation = bss_elems.ht_operation;
    3278                 :            :                         sdata_info(sdata,
    3279                 :            :                                    "AP bug: HT operation missing from AssocResp\n");
    3280                 :            :                 }
    3281                 :            :                 if (!elems->vht_cap_elem && bss_elems.vht_cap_elem &&
    3282                 :            :                     !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
    3283                 :            :                         elems->vht_cap_elem = bss_elems.vht_cap_elem;
    3284                 :            :                         sdata_info(sdata,
    3285                 :            :                                    "AP bug: VHT capa missing from AssocResp\n");
    3286                 :            :                 }
    3287                 :            :                 if (!elems->vht_operation && bss_elems.vht_operation &&
    3288                 :            :                     !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
    3289                 :            :                         elems->vht_operation = bss_elems.vht_operation;
    3290                 :            :                         sdata_info(sdata,
    3291                 :            :                                    "AP bug: VHT operation missing from AssocResp\n");
    3292                 :            :                 }
    3293                 :            :         }
    3294                 :            : 
    3295                 :            :         /*
    3296                 :            :          * We previously checked these in the beacon/probe response, so
    3297                 :            :          * they should be present here. This is just a safety net.
    3298                 :            :          */
    3299                 :            :         if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
    3300                 :            :             (!elems->wmm_param || !elems->ht_cap_elem || !elems->ht_operation)) {
    3301                 :            :                 sdata_info(sdata,
    3302                 :            :                            "HT AP is missing WMM params or HT capability/operation\n");
    3303                 :            :                 ret = false;
    3304                 :            :                 goto out;
    3305                 :            :         }
    3306                 :            : 
    3307                 :            :         if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
    3308                 :            :             (!elems->vht_cap_elem || !elems->vht_operation)) {
    3309                 :            :                 sdata_info(sdata,
    3310                 :            :                            "VHT AP is missing VHT capability/operation\n");
    3311                 :            :                 ret = false;
    3312                 :            :                 goto out;
    3313                 :            :         }
    3314                 :            : 
    3315                 :            :         mutex_lock(&sdata->local->sta_mtx);
    3316                 :            :         /*
    3317                 :            :          * station info was already allocated and inserted before
    3318                 :            :          * the association and should be available to us
    3319                 :            :          */
    3320                 :            :         sta = sta_info_get(sdata, cbss->bssid);
    3321                 :            :         if (WARN_ON(!sta)) {
    3322                 :            :                 mutex_unlock(&sdata->local->sta_mtx);
    3323                 :            :                 ret = false;
    3324                 :            :                 goto out;
    3325                 :            :         }
    3326                 :            : 
    3327                 :            :         sband = ieee80211_get_sband(sdata);
    3328                 :            :         if (!sband) {
    3329                 :            :                 mutex_unlock(&sdata->local->sta_mtx);
    3330                 :            :                 ret = false;
    3331                 :            :                 goto out;
    3332                 :            :         }
    3333                 :            : 
    3334                 :            :         if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) &&
    3335                 :            :             (!elems->he_cap || !elems->he_operation)) {
    3336                 :            :                 mutex_unlock(&sdata->local->sta_mtx);
    3337                 :            :                 sdata_info(sdata,
    3338                 :            :                            "HE AP is missing HE capability/operation\n");
    3339                 :            :                 ret = false;
    3340                 :            :                 goto out;
    3341                 :            :         }
    3342                 :            : 
    3343                 :            :         /* Set up internal HT/VHT capabilities */
    3344                 :            :         if (elems->ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
    3345                 :            :                 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
    3346                 :            :                                                   elems->ht_cap_elem, sta);
    3347                 :            : 
    3348                 :            :         if (elems->vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
    3349                 :            :                 ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
    3350                 :            :                                                     elems->vht_cap_elem, sta);
    3351                 :            : 
    3352                 :            :         if (elems->he_operation && !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) &&
    3353                 :            :             elems->he_cap) {
    3354                 :            :                 ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
    3355                 :            :                                                   elems->he_cap,
    3356                 :            :                                                   elems->he_cap_len,
    3357                 :            :                                                   sta);
    3358                 :            : 
    3359                 :            :                 bss_conf->he_support = sta->sta.he_cap.has_he;
    3360                 :            :                 changed |= ieee80211_recalc_twt_req(sdata, sta, elems);
    3361                 :            :         } else {
    3362                 :            :                 bss_conf->he_support = false;
    3363                 :            :                 bss_conf->twt_requester = false;
    3364                 :            :         }
    3365                 :            : 
    3366                 :            :         if (bss_conf->he_support) {
    3367                 :            :                 bss_conf->bss_color =
    3368                 :            :                         le32_get_bits(elems->he_operation->he_oper_params,
    3369                 :            :                                       IEEE80211_HE_OPERATION_BSS_COLOR_MASK);
    3370                 :            : 
    3371                 :            :                 bss_conf->htc_trig_based_pkt_ext =
    3372                 :            :                         le32_get_bits(elems->he_operation->he_oper_params,
    3373                 :            :                               IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK);
    3374                 :            :                 bss_conf->frame_time_rts_th =
    3375                 :            :                         le32_get_bits(elems->he_operation->he_oper_params,
    3376                 :            :                               IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK);
    3377                 :            : 
    3378                 :            :                 bss_conf->multi_sta_back_32bit =
    3379                 :            :                         sta->sta.he_cap.he_cap_elem.mac_cap_info[2] &
    3380                 :            :                         IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP;
    3381                 :            : 
    3382                 :            :                 bss_conf->ack_enabled =
    3383                 :            :                         sta->sta.he_cap.he_cap_elem.mac_cap_info[2] &
    3384                 :            :                         IEEE80211_HE_MAC_CAP2_ACK_EN;
    3385                 :            : 
    3386                 :            :                 bss_conf->uora_exists = !!elems->uora_element;
    3387                 :            :                 if (elems->uora_element)
    3388                 :            :                         bss_conf->uora_ocw_range = elems->uora_element[0];
    3389                 :            : 
    3390                 :            :                 ieee80211_he_op_ie_to_bss_conf(&sdata->vif, elems->he_operation);
    3391                 :            :                 ieee80211_he_spr_ie_to_bss_conf(&sdata->vif, elems->he_spr);
    3392                 :            :                 /* TODO: OPEN: what happens if BSS color disable is set? */
    3393                 :            :         }
    3394                 :            : 
    3395                 :            :         if (cbss->transmitted_bss) {
    3396                 :            :                 bss_conf->nontransmitted = true;
    3397                 :            :                 ether_addr_copy(bss_conf->transmitter_bssid,
    3398                 :            :                                 cbss->transmitted_bss->bssid);
    3399                 :            :                 bss_conf->bssid_indicator = cbss->max_bssid_indicator;
    3400                 :            :                 bss_conf->bssid_index = cbss->bssid_index;
    3401                 :            :         }
    3402                 :            : 
    3403                 :            :         /*
    3404                 :            :          * Some APs, e.g. Netgear WNDR3700, report invalid HT operation data
    3405                 :            :          * in their association response, so ignore that data for our own
    3406                 :            :          * configuration. If it changed since the last beacon, we'll get the
    3407                 :            :          * next beacon and update then.
    3408                 :            :          */
    3409                 :            : 
    3410                 :            :         /*
    3411                 :            :          * If an operating mode notification IE is present, override the
    3412                 :            :          * NSS calculation (that would be done in rate_control_rate_init())
    3413                 :            :          * and use the # of streams from that element.
    3414                 :            :          */
    3415                 :            :         if (elems->opmode_notif &&
    3416                 :            :             !(*elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)) {
    3417                 :            :                 u8 nss;
    3418                 :            : 
    3419                 :            :                 nss = *elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK;
    3420                 :            :                 nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT;
    3421                 :            :                 nss += 1;
    3422                 :            :                 sta->sta.rx_nss = nss;
    3423                 :            :         }
    3424                 :            : 
    3425                 :            :         rate_control_rate_init(sta);
    3426                 :            : 
    3427                 :            :         if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) {
    3428                 :            :                 set_sta_flag(sta, WLAN_STA_MFP);
    3429                 :            :                 sta->sta.mfp = true;
    3430                 :            :         } else {
    3431                 :            :                 sta->sta.mfp = false;
    3432                 :            :         }
    3433                 :            : 
    3434                 :            :         sta->sta.wme = elems->wmm_param && local->hw.queues >= IEEE80211_NUM_ACS;
    3435                 :            : 
    3436                 :            :         err = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
    3437                 :            :         if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
    3438                 :            :                 err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
    3439                 :            :         if (err) {
    3440                 :            :                 sdata_info(sdata,
    3441                 :            :                            "failed to move station %pM to desired state\n",
    3442                 :            :                            sta->sta.addr);
    3443                 :            :                 WARN_ON(__sta_info_destroy(sta));
    3444                 :            :                 mutex_unlock(&sdata->local->sta_mtx);
    3445                 :            :                 ret = false;
    3446                 :            :                 goto out;
    3447                 :            :         }
    3448                 :            : 
    3449                 :            :         mutex_unlock(&sdata->local->sta_mtx);
    3450                 :            : 
    3451                 :            :         /*
    3452                 :            :          * Always handle WMM once after association regardless
    3453                 :            :          * of the first value the AP uses. Setting -1 here has
    3454                 :            :          * that effect because the AP values is an unsigned
    3455                 :            :          * 4-bit value.
    3456                 :            :          */
    3457                 :            :         ifmgd->wmm_last_param_set = -1;
    3458                 :            :         ifmgd->mu_edca_last_param_set = -1;
    3459                 :            : 
    3460                 :            :         if (ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
    3461                 :            :                 ieee80211_set_wmm_default(sdata, false, false);
    3462                 :            :         } else if (!ieee80211_sta_wmm_params(local, sdata, elems->wmm_param,
    3463                 :            :                                              elems->wmm_param_len,
    3464                 :            :                                              elems->mu_edca_param_set)) {
    3465                 :            :                 /* still enable QoS since we might have HT/VHT */
    3466                 :            :                 ieee80211_set_wmm_default(sdata, false, true);
    3467                 :            :                 /* set the disable-WMM flag in this case to disable
    3468                 :            :                  * tracking WMM parameter changes in the beacon if
    3469                 :            :                  * the parameters weren't actually valid. Doing so
    3470                 :            :                  * avoids changing parameters very strangely when
    3471                 :            :                  * the AP is going back and forth between valid and
    3472                 :            :                  * invalid parameters.
    3473                 :            :                  */
    3474                 :            :                 ifmgd->flags |= IEEE80211_STA_DISABLE_WMM;
    3475                 :            :         }
    3476                 :            :         changed |= BSS_CHANGED_QOS;
    3477                 :            : 
    3478                 :            :         if (elems->max_idle_period_ie) {
    3479                 :            :                 bss_conf->max_idle_period =
    3480                 :            :                         le16_to_cpu(elems->max_idle_period_ie->max_idle_period);
    3481                 :            :                 bss_conf->protected_keep_alive =
    3482                 :            :                         !!(elems->max_idle_period_ie->idle_options &
    3483                 :            :                            WLAN_IDLE_OPTIONS_PROTECTED_KEEP_ALIVE);
    3484                 :            :                 changed |= BSS_CHANGED_KEEP_ALIVE;
    3485                 :            :         } else {
    3486                 :            :                 bss_conf->max_idle_period = 0;
    3487                 :            :                 bss_conf->protected_keep_alive = false;
    3488                 :            :         }
    3489                 :            : 
    3490                 :            :         /* set AID and assoc capability,
    3491                 :            :          * ieee80211_set_associated() will tell the driver */
    3492                 :            :         bss_conf->aid = aid;
    3493                 :            :         bss_conf->assoc_capability = capab_info;
    3494                 :            :         ieee80211_set_associated(sdata, cbss, changed);
    3495                 :            : 
    3496                 :            :         /*
    3497                 :            :          * If we're using 4-addr mode, let the AP know that we're
    3498                 :            :          * doing so, so that it can create the STA VLAN on its side
    3499                 :            :          */
    3500                 :            :         if (ifmgd->use_4addr)
    3501                 :            :                 ieee80211_send_4addr_nullfunc(local, sdata);
    3502                 :            : 
    3503                 :            :         /*
    3504                 :            :          * Start timer to probe the connection to the AP now.
    3505                 :            :          * Also start the timer that will detect beacon loss.
    3506                 :            :          */
    3507                 :            :         ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt);
    3508                 :            :         ieee80211_sta_reset_beacon_monitor(sdata);
    3509                 :            : 
    3510                 :            :         ret = true;
    3511                 :            :  out:
    3512                 :            :         kfree(bss_ies);
    3513                 :            :         return ret;
    3514                 :            : }
    3515                 :            : 
    3516                 :          0 : static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
    3517                 :            :                                          struct ieee80211_mgmt *mgmt,
    3518                 :            :                                          size_t len)
    3519                 :            : {
    3520                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    3521                 :          0 :         struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
    3522                 :          0 :         u16 capab_info, status_code, aid;
    3523                 :          0 :         struct ieee802_11_elems elems;
    3524                 :          0 :         int ac, uapsd_queues = -1;
    3525                 :          0 :         u8 *pos;
    3526                 :          0 :         bool reassoc;
    3527                 :          0 :         struct cfg80211_bss *bss;
    3528                 :          0 :         struct ieee80211_event event = {
    3529                 :            :                 .type = MLME_EVENT,
    3530                 :            :                 .u.mlme.data = ASSOC_EVENT,
    3531                 :            :         };
    3532                 :            : 
    3533         [ #  # ]:          0 :         sdata_assert_lock(sdata);
    3534                 :            : 
    3535         [ #  # ]:          0 :         if (!assoc_data)
    3536                 :          0 :                 return;
    3537         [ #  # ]:          0 :         if (!ether_addr_equal(assoc_data->bss->bssid, mgmt->bssid))
    3538                 :            :                 return;
    3539                 :            : 
    3540                 :            :         /*
    3541                 :            :          * AssocResp and ReassocResp have identical structure, so process both
    3542                 :            :          * of them in this function.
    3543                 :            :          */
    3544                 :            : 
    3545         [ #  # ]:          0 :         if (len < 24 + 6)
    3546                 :            :                 return;
    3547                 :            : 
    3548         [ #  # ]:          0 :         reassoc = ieee80211_is_reassoc_resp(mgmt->frame_control);
    3549                 :          0 :         capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
    3550                 :          0 :         status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
    3551                 :          0 :         aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
    3552                 :            : 
    3553         [ #  # ]:          0 :         sdata_info(sdata,
    3554                 :            :                    "RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n",
    3555                 :            :                    reassoc ? "Rea" : "A", mgmt->sa,
    3556                 :            :                    capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
    3557                 :            : 
    3558   [ #  #  #  # ]:          0 :         if (assoc_data->fils_kek_len &&
    3559                 :          0 :             fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0)
    3560                 :            :                 return;
    3561                 :            : 
    3562                 :          0 :         pos = mgmt->u.assoc_resp.variable;
    3563                 :          0 :         ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
    3564                 :          0 :                                mgmt->bssid, assoc_data->bss->bssid);
    3565                 :            : 
    3566         [ #  # ]:          0 :         if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
    3567         [ #  # ]:          0 :             elems.timeout_int &&
    3568         [ #  # ]:          0 :             elems.timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) {
    3569                 :          0 :                 u32 tu, ms;
    3570                 :          0 :                 tu = le32_to_cpu(elems.timeout_int->value);
    3571                 :          0 :                 ms = tu * 1024 / 1000;
    3572                 :          0 :                 sdata_info(sdata,
    3573                 :            :                            "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n",
    3574                 :            :                            mgmt->sa, tu, ms);
    3575         [ #  # ]:          0 :                 assoc_data->timeout = jiffies + msecs_to_jiffies(ms);
    3576                 :          0 :                 assoc_data->timeout_started = true;
    3577         [ #  # ]:          0 :                 if (ms > IEEE80211_ASSOC_TIMEOUT)
    3578         [ #  # ]:          0 :                         run_again(sdata, assoc_data->timeout);
    3579                 :          0 :                 return;
    3580                 :            :         }
    3581                 :            : 
    3582                 :          0 :         bss = assoc_data->bss;
    3583                 :            : 
    3584         [ #  # ]:          0 :         if (status_code != WLAN_STATUS_SUCCESS) {
    3585                 :          0 :                 sdata_info(sdata, "%pM denied association (code=%d)\n",
    3586                 :            :                            mgmt->sa, status_code);
    3587                 :          0 :                 ieee80211_destroy_assoc_data(sdata, false, false);
    3588                 :          0 :                 event.u.mlme.status = MLME_DENIED;
    3589                 :          0 :                 event.u.mlme.reason = status_code;
    3590                 :          0 :                 drv_event_callback(sdata->local, sdata, &event);
    3591                 :            :         } else {
    3592         [ #  # ]:          0 :                 if (!ieee80211_assoc_success(sdata, bss, mgmt, len, &elems)) {
    3593                 :            :                         /* oops -- internal error -- send timeout for now */
    3594                 :          0 :                         ieee80211_destroy_assoc_data(sdata, false, false);
    3595                 :          0 :                         cfg80211_assoc_timeout(sdata->dev, bss);
    3596                 :          0 :                         return;
    3597                 :            :                 }
    3598                 :          0 :                 event.u.mlme.status = MLME_SUCCESS;
    3599                 :          0 :                 drv_event_callback(sdata->local, sdata, &event);
    3600                 :          0 :                 sdata_info(sdata, "associated\n");
    3601                 :            : 
    3602                 :            :                 /*
    3603                 :            :                  * destroy assoc_data afterwards, as otherwise an idle
    3604                 :            :                  * recalc after assoc_data is NULL but before associated
    3605                 :            :                  * is set can cause the interface to go idle
    3606                 :            :                  */
    3607                 :          0 :                 ieee80211_destroy_assoc_data(sdata, true, false);
    3608                 :            : 
    3609                 :            :                 /* get uapsd queues configuration */
    3610                 :          0 :                 uapsd_queues = 0;
    3611         [ #  # ]:          0 :                 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
    3612         [ #  # ]:          0 :                         if (sdata->tx_conf[ac].uapsd)
    3613                 :          0 :                                 uapsd_queues |= ieee80211_ac_to_qos_mask[ac];
    3614                 :            :         }
    3615                 :            : 
    3616                 :          0 :         cfg80211_rx_assoc_resp(sdata->dev, bss, (u8 *)mgmt, len, uapsd_queues,
    3617                 :          0 :                                ifmgd->assoc_req_ies, ifmgd->assoc_req_ies_len);
    3618                 :            : }
    3619                 :            : 
    3620                 :            : static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
    3621                 :            :                                   struct ieee80211_mgmt *mgmt, size_t len,
    3622                 :            :                                   struct ieee80211_rx_status *rx_status)
    3623                 :            : {
    3624                 :            :         struct ieee80211_local *local = sdata->local;
    3625                 :            :         struct ieee80211_bss *bss;
    3626                 :            :         struct ieee80211_channel *channel;
    3627                 :            : 
    3628                 :            :         sdata_assert_lock(sdata);
    3629                 :            : 
    3630                 :            :         channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
    3631                 :            :         if (!channel)
    3632                 :            :                 return;
    3633                 :            : 
    3634                 :            :         bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, channel);
    3635                 :            :         if (bss) {
    3636                 :            :                 sdata->vif.bss_conf.beacon_rate = bss->beacon_rate;
    3637                 :            :                 ieee80211_rx_bss_put(local, bss);
    3638                 :            :         }
    3639                 :            : }
    3640                 :            : 
    3641                 :            : 
    3642                 :          0 : static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
    3643                 :            :                                          struct sk_buff *skb)
    3644                 :            : {
    3645                 :          0 :         struct ieee80211_mgmt *mgmt = (void *)skb->data;
    3646                 :          0 :         struct ieee80211_if_managed *ifmgd;
    3647                 :          0 :         struct ieee80211_rx_status *rx_status = (void *) skb->cb;
    3648                 :          0 :         size_t baselen, len = skb->len;
    3649                 :            : 
    3650                 :          0 :         ifmgd = &sdata->u.mgd;
    3651                 :            : 
    3652         [ #  # ]:          0 :         sdata_assert_lock(sdata);
    3653                 :            : 
    3654         [ #  # ]:          0 :         if (!ether_addr_equal(mgmt->da, sdata->vif.addr))
    3655                 :            :                 return; /* ignore ProbeResp to foreign address */
    3656                 :            : 
    3657                 :          0 :         baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
    3658         [ #  # ]:          0 :         if (baselen > len)
    3659                 :            :                 return;
    3660                 :            : 
    3661                 :          0 :         ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
    3662                 :            : 
    3663   [ #  #  #  # ]:          0 :         if (ifmgd->associated &&
    3664                 :            :             ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
    3665                 :          0 :                 ieee80211_reset_ap_probe(sdata);
    3666                 :            : }
    3667                 :            : 
    3668                 :            : /*
    3669                 :            :  * This is the canonical list of information elements we care about,
    3670                 :            :  * the filter code also gives us all changes to the Microsoft OUI
    3671                 :            :  * (00:50:F2) vendor IE which is used for WMM which we need to track,
    3672                 :            :  * as well as the DTPC IE (part of the Cisco OUI) used for signaling
    3673                 :            :  * changes to requested client power.
    3674                 :            :  *
    3675                 :            :  * We implement beacon filtering in software since that means we can
    3676                 :            :  * avoid processing the frame here and in cfg80211, and userspace
    3677                 :            :  * will not be able to tell whether the hardware supports it or not.
    3678                 :            :  *
    3679                 :            :  * XXX: This list needs to be dynamic -- userspace needs to be able to
    3680                 :            :  *      add items it requires. It also needs to be able to tell us to
    3681                 :            :  *      look out for other vendor IEs.
    3682                 :            :  */
    3683                 :            : static const u64 care_about_ies =
    3684                 :            :         (1ULL << WLAN_EID_COUNTRY) |
    3685                 :            :         (1ULL << WLAN_EID_ERP_INFO) |
    3686                 :            :         (1ULL << WLAN_EID_CHANNEL_SWITCH) |
    3687                 :            :         (1ULL << WLAN_EID_PWR_CONSTRAINT) |
    3688                 :            :         (1ULL << WLAN_EID_HT_CAPABILITY) |
    3689                 :            :         (1ULL << WLAN_EID_HT_OPERATION) |
    3690                 :            :         (1ULL << WLAN_EID_EXT_CHANSWITCH_ANN);
    3691                 :            : 
    3692                 :            : static void ieee80211_handle_beacon_sig(struct ieee80211_sub_if_data *sdata,
    3693                 :            :                                         struct ieee80211_if_managed *ifmgd,
    3694                 :            :                                         struct ieee80211_bss_conf *bss_conf,
    3695                 :            :                                         struct ieee80211_local *local,
    3696                 :            :                                         struct ieee80211_rx_status *rx_status)
    3697                 :            : {
    3698                 :            :         /* Track average RSSI from the Beacon frames of the current AP */
    3699                 :            : 
    3700                 :            :         if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
    3701                 :            :                 ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
    3702                 :            :                 ewma_beacon_signal_init(&ifmgd->ave_beacon_signal);
    3703                 :            :                 ifmgd->last_cqm_event_signal = 0;
    3704                 :            :                 ifmgd->count_beacon_signal = 1;
    3705                 :            :                 ifmgd->last_ave_beacon_signal = 0;
    3706                 :            :         } else {
    3707                 :            :                 ifmgd->count_beacon_signal++;
    3708                 :            :         }
    3709                 :            : 
    3710                 :            :         ewma_beacon_signal_add(&ifmgd->ave_beacon_signal, -rx_status->signal);
    3711                 :            : 
    3712                 :            :         if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold &&
    3713                 :            :             ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
    3714                 :            :                 int sig = -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
    3715                 :            :                 int last_sig = ifmgd->last_ave_beacon_signal;
    3716                 :            :                 struct ieee80211_event event = {
    3717                 :            :                         .type = RSSI_EVENT,
    3718                 :            :                 };
    3719                 :            : 
    3720                 :            :                 /*
    3721                 :            :                  * if signal crosses either of the boundaries, invoke callback
    3722                 :            :                  * with appropriate parameters
    3723                 :            :                  */
    3724                 :            :                 if (sig > ifmgd->rssi_max_thold &&
    3725                 :            :                     (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) {
    3726                 :            :                         ifmgd->last_ave_beacon_signal = sig;
    3727                 :            :                         event.u.rssi.data = RSSI_EVENT_HIGH;
    3728                 :            :                         drv_event_callback(local, sdata, &event);
    3729                 :            :                 } else if (sig < ifmgd->rssi_min_thold &&
    3730                 :            :                            (last_sig >= ifmgd->rssi_max_thold ||
    3731                 :            :                            last_sig == 0)) {
    3732                 :            :                         ifmgd->last_ave_beacon_signal = sig;
    3733                 :            :                         event.u.rssi.data = RSSI_EVENT_LOW;
    3734                 :            :                         drv_event_callback(local, sdata, &event);
    3735                 :            :                 }
    3736                 :            :         }
    3737                 :            : 
    3738                 :            :         if (bss_conf->cqm_rssi_thold &&
    3739                 :            :             ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT &&
    3740                 :            :             !(sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) {
    3741                 :            :                 int sig = -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
    3742                 :            :                 int last_event = ifmgd->last_cqm_event_signal;
    3743                 :            :                 int thold = bss_conf->cqm_rssi_thold;
    3744                 :            :                 int hyst = bss_conf->cqm_rssi_hyst;
    3745                 :            : 
    3746                 :            :                 if (sig < thold &&
    3747                 :            :                     (last_event == 0 || sig < last_event - hyst)) {
    3748                 :            :                         ifmgd->last_cqm_event_signal = sig;
    3749                 :            :                         ieee80211_cqm_rssi_notify(
    3750                 :            :                                 &sdata->vif,
    3751                 :            :                                 NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
    3752                 :            :                                 sig, GFP_KERNEL);
    3753                 :            :                 } else if (sig > thold &&
    3754                 :            :                            (last_event == 0 || sig > last_event + hyst)) {
    3755                 :            :                         ifmgd->last_cqm_event_signal = sig;
    3756                 :            :                         ieee80211_cqm_rssi_notify(
    3757                 :            :                                 &sdata->vif,
    3758                 :            :                                 NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
    3759                 :            :                                 sig, GFP_KERNEL);
    3760                 :            :                 }
    3761                 :            :         }
    3762                 :            : 
    3763                 :            :         if (bss_conf->cqm_rssi_low &&
    3764                 :            :             ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
    3765                 :            :                 int sig = -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
    3766                 :            :                 int last_event = ifmgd->last_cqm_event_signal;
    3767                 :            :                 int low = bss_conf->cqm_rssi_low;
    3768                 :            :                 int high = bss_conf->cqm_rssi_high;
    3769                 :            : 
    3770                 :            :                 if (sig < low &&
    3771                 :            :                     (last_event == 0 || last_event >= low)) {
    3772                 :            :                         ifmgd->last_cqm_event_signal = sig;
    3773                 :            :                         ieee80211_cqm_rssi_notify(
    3774                 :            :                                 &sdata->vif,
    3775                 :            :                                 NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
    3776                 :            :                                 sig, GFP_KERNEL);
    3777                 :            :                 } else if (sig > high &&
    3778                 :            :                            (last_event == 0 || last_event <= high)) {
    3779                 :            :                         ifmgd->last_cqm_event_signal = sig;
    3780                 :            :                         ieee80211_cqm_rssi_notify(
    3781                 :            :                                 &sdata->vif,
    3782                 :            :                                 NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
    3783                 :            :                                 sig, GFP_KERNEL);
    3784                 :            :                 }
    3785                 :            :         }
    3786                 :            : }
    3787                 :            : 
    3788                 :          0 : static bool ieee80211_rx_our_beacon(const u8 *tx_bssid,
    3789                 :            :                                     struct cfg80211_bss *bss)
    3790                 :            : {
    3791         [ #  # ]:          0 :         if (ether_addr_equal(tx_bssid, bss->bssid))
    3792                 :            :                 return true;
    3793   [ #  #  #  # ]:          0 :         if (!bss->transmitted_bss)
    3794                 :            :                 return false;
    3795   [ #  #  #  # ]:          0 :         return ether_addr_equal(tx_bssid, bss->transmitted_bss->bssid);
    3796                 :            : }
    3797                 :            : 
    3798                 :          0 : static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
    3799                 :            :                                      struct ieee80211_mgmt *mgmt, size_t len,
    3800                 :            :                                      struct ieee80211_rx_status *rx_status)
    3801                 :            : {
    3802                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    3803                 :          0 :         struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
    3804                 :          0 :         size_t baselen;
    3805                 :          0 :         struct ieee802_11_elems elems;
    3806                 :          0 :         struct ieee80211_local *local = sdata->local;
    3807                 :          0 :         struct ieee80211_chanctx_conf *chanctx_conf;
    3808                 :          0 :         struct ieee80211_channel *chan;
    3809                 :          0 :         struct sta_info *sta;
    3810                 :          0 :         u32 changed = 0;
    3811                 :          0 :         bool erp_valid;
    3812                 :          0 :         u8 erp_value = 0;
    3813                 :          0 :         u32 ncrc;
    3814                 :          0 :         u8 *bssid;
    3815                 :          0 :         u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN];
    3816                 :            : 
    3817         [ #  # ]:          0 :         sdata_assert_lock(sdata);
    3818                 :            : 
    3819                 :            :         /* Process beacon from the current BSS */
    3820                 :          0 :         baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
    3821         [ #  # ]:          0 :         if (baselen > len)
    3822                 :          0 :                 return;
    3823                 :            : 
    3824                 :          0 :         rcu_read_lock();
    3825         [ #  # ]:          0 :         chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
    3826         [ #  # ]:          0 :         if (!chanctx_conf) {
    3827                 :          0 :                 rcu_read_unlock();
    3828                 :          0 :                 return;
    3829                 :            :         }
    3830                 :            : 
    3831         [ #  # ]:          0 :         if (rx_status->freq != chanctx_conf->def.chan->center_freq) {
    3832                 :          0 :                 rcu_read_unlock();
    3833                 :          0 :                 return;
    3834                 :            :         }
    3835                 :          0 :         chan = chanctx_conf->def.chan;
    3836                 :          0 :         rcu_read_unlock();
    3837                 :            : 
    3838   [ #  #  #  #  :          0 :         if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
                   #  # ]
    3839         [ #  # ]:          0 :             ieee80211_rx_our_beacon(mgmt->bssid, ifmgd->assoc_data->bss)) {
    3840                 :          0 :                 ieee802_11_parse_elems(mgmt->u.beacon.variable,
    3841                 :            :                                        len - baselen, false, &elems,
    3842                 :          0 :                                        mgmt->bssid,
    3843                 :          0 :                                        ifmgd->assoc_data->bss->bssid);
    3844                 :            : 
    3845                 :          0 :                 ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
    3846                 :            : 
    3847         [ #  # ]:          0 :                 if (elems.dtim_period)
    3848                 :          0 :                         ifmgd->dtim_period = elems.dtim_period;
    3849                 :          0 :                 ifmgd->have_beacon = true;
    3850                 :          0 :                 ifmgd->assoc_data->need_beacon = false;
    3851         [ #  # ]:          0 :                 if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) {
    3852                 :          0 :                         sdata->vif.bss_conf.sync_tsf =
    3853                 :          0 :                                 le64_to_cpu(mgmt->u.beacon.timestamp);
    3854                 :          0 :                         sdata->vif.bss_conf.sync_device_ts =
    3855                 :          0 :                                 rx_status->device_timestamp;
    3856                 :          0 :                         sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
    3857                 :            :                 }
    3858                 :            : 
    3859         [ #  # ]:          0 :                 if (elems.mbssid_config_ie)
    3860                 :          0 :                         bss_conf->profile_periodicity =
    3861                 :          0 :                                 elems.mbssid_config_ie->profile_periodicity;
    3862                 :            : 
    3863         [ #  # ]:          0 :                 if (elems.ext_capab_len >= 11 &&
    3864         [ #  # ]:          0 :                     (elems.ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
    3865                 :          0 :                         bss_conf->ema_ap = true;
    3866                 :            : 
    3867                 :            :                 /* continue assoc process */
    3868                 :          0 :                 ifmgd->assoc_data->timeout = jiffies;
    3869                 :          0 :                 ifmgd->assoc_data->timeout_started = true;
    3870         [ #  # ]:          0 :                 run_again(sdata, ifmgd->assoc_data->timeout);
    3871                 :          0 :                 return;
    3872                 :            :         }
    3873                 :            : 
    3874   [ #  #  #  # ]:          0 :         if (!ifmgd->associated ||
    3875                 :            :             !ieee80211_rx_our_beacon(mgmt->bssid,  ifmgd->associated))
    3876                 :            :                 return;
    3877                 :          0 :         bssid = ifmgd->associated->bssid;
    3878                 :            : 
    3879         [ #  # ]:          0 :         if (!(rx_status->flag & RX_FLAG_NO_SIGNAL_VAL))
    3880                 :          0 :                 ieee80211_handle_beacon_sig(sdata, ifmgd, bss_conf,
    3881                 :            :                                             local, rx_status);
    3882                 :            : 
    3883         [ #  # ]:          0 :         if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) {
    3884                 :          0 :                 mlme_dbg_ratelimited(sdata,
    3885                 :            :                                      "cancelling AP probe due to a received beacon\n");
    3886                 :          0 :                 ieee80211_reset_ap_probe(sdata);
    3887                 :            :         }
    3888                 :            : 
    3889                 :            :         /*
    3890                 :            :          * Push the beacon loss detection into the future since
    3891                 :            :          * we are processing a beacon from the AP just now.
    3892                 :            :          */
    3893                 :          0 :         ieee80211_sta_reset_beacon_monitor(sdata);
    3894                 :            : 
    3895                 :          0 :         ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
    3896                 :          0 :         ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
    3897                 :            :                                           len - baselen, false, &elems,
    3898                 :            :                                           care_about_ies, ncrc,
    3899                 :          0 :                                           mgmt->bssid, bssid);
    3900                 :            : 
    3901         [ #  # ]:          0 :         if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
    3902         [ #  # ]:          0 :             ieee80211_check_tim(elems.tim, elems.tim_len, ifmgd->aid)) {
    3903         [ #  # ]:          0 :                 if (local->hw.conf.dynamic_ps_timeout > 0) {
    3904         [ #  # ]:          0 :                         if (local->hw.conf.flags & IEEE80211_CONF_PS) {
    3905                 :          0 :                                 local->hw.conf.flags &= ~IEEE80211_CONF_PS;
    3906                 :          0 :                                 ieee80211_hw_config(local,
    3907                 :            :                                                     IEEE80211_CONF_CHANGE_PS);
    3908                 :            :                         }
    3909                 :          0 :                         ieee80211_send_nullfunc(local, sdata, false);
    3910   [ #  #  #  # ]:          0 :                 } else if (!local->pspolling && sdata->u.mgd.powersave) {
    3911                 :          0 :                         local->pspolling = true;
    3912                 :            : 
    3913                 :            :                         /*
    3914                 :            :                          * Here is assumed that the driver will be
    3915                 :            :                          * able to send ps-poll frame and receive a
    3916                 :            :                          * response even though power save mode is
    3917                 :            :                          * enabled, but some drivers might require
    3918                 :            :                          * to disable power save here. This needs
    3919                 :            :                          * to be investigated.
    3920                 :            :                          */
    3921                 :          0 :                         ieee80211_send_pspoll(local, sdata);
    3922                 :            :                 }
    3923                 :            :         }
    3924                 :            : 
    3925         [ #  # ]:          0 :         if (sdata->vif.p2p ||
    3926         [ #  # ]:          0 :             sdata->vif.driver_flags & IEEE80211_VIF_GET_NOA_UPDATE) {
    3927                 :          0 :                 struct ieee80211_p2p_noa_attr noa = {};
    3928                 :          0 :                 int ret;
    3929                 :            : 
    3930                 :          0 :                 ret = cfg80211_get_p2p_attr(mgmt->u.beacon.variable,
    3931                 :            :                                             len - baselen,
    3932                 :            :                                             IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
    3933                 :            :                                             (u8 *) &noa, sizeof(noa));
    3934         [ #  # ]:          0 :                 if (ret >= 2) {
    3935         [ #  # ]:          0 :                         if (sdata->u.mgd.p2p_noa_index != noa.index) {
    3936                 :            :                                 /* valid noa_attr and index changed */
    3937                 :          0 :                                 sdata->u.mgd.p2p_noa_index = noa.index;
    3938                 :          0 :                                 memcpy(&bss_conf->p2p_noa_attr, &noa, sizeof(noa));
    3939                 :          0 :                                 changed |= BSS_CHANGED_P2P_PS;
    3940                 :            :                                 /*
    3941                 :            :                                  * make sure we update all information, the CRC
    3942                 :            :                                  * mechanism doesn't look at P2P attributes.
    3943                 :            :                                  */
    3944                 :          0 :                                 ifmgd->beacon_crc_valid = false;
    3945                 :            :                         }
    3946         [ #  # ]:          0 :                 } else if (sdata->u.mgd.p2p_noa_index != -1) {
    3947                 :            :                         /* noa_attr not found and we had valid noa_attr before */
    3948                 :          0 :                         sdata->u.mgd.p2p_noa_index = -1;
    3949                 :          0 :                         memset(&bss_conf->p2p_noa_attr, 0, sizeof(bss_conf->p2p_noa_attr));
    3950                 :          0 :                         changed |= BSS_CHANGED_P2P_PS;
    3951                 :          0 :                         ifmgd->beacon_crc_valid = false;
    3952                 :            :                 }
    3953                 :            :         }
    3954                 :            : 
    3955         [ #  # ]:          0 :         if (ifmgd->csa_waiting_bcn)
    3956                 :          0 :                 ieee80211_chswitch_post_beacon(sdata);
    3957                 :            : 
    3958                 :            :         /*
    3959                 :            :          * Update beacon timing and dtim count on every beacon appearance. This
    3960                 :            :          * will allow the driver to use the most updated values. Do it before
    3961                 :            :          * comparing this one with last received beacon.
    3962                 :            :          * IMPORTANT: These parameters would possibly be out of sync by the time
    3963                 :            :          * the driver will use them. The synchronized view is currently
    3964                 :            :          * guaranteed only in certain callbacks.
    3965                 :            :          */
    3966         [ #  # ]:          0 :         if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) {
    3967                 :          0 :                 sdata->vif.bss_conf.sync_tsf =
    3968                 :          0 :                         le64_to_cpu(mgmt->u.beacon.timestamp);
    3969                 :          0 :                 sdata->vif.bss_conf.sync_device_ts =
    3970                 :          0 :                         rx_status->device_timestamp;
    3971                 :          0 :                 sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
    3972                 :            :         }
    3973                 :            : 
    3974   [ #  #  #  # ]:          0 :         if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
    3975                 :            :                 return;
    3976                 :          0 :         ifmgd->beacon_crc = ncrc;
    3977                 :          0 :         ifmgd->beacon_crc_valid = true;
    3978                 :            : 
    3979                 :          0 :         ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
    3980                 :            : 
    3981                 :          0 :         ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
    3982                 :            :                                          rx_status->device_timestamp,
    3983                 :            :                                          &elems, true);
    3984                 :            : 
    3985   [ #  #  #  # ]:          0 :         if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
    3986                 :          0 :             ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
    3987                 :          0 :                                      elems.wmm_param_len,
    3988                 :            :                                      elems.mu_edca_param_set))
    3989                 :          0 :                 changed |= BSS_CHANGED_QOS;
    3990                 :            : 
    3991                 :            :         /*
    3992                 :            :          * If we haven't had a beacon before, tell the driver about the
    3993                 :            :          * DTIM period (and beacon timing if desired) now.
    3994                 :            :          */
    3995         [ #  # ]:          0 :         if (!ifmgd->have_beacon) {
    3996                 :            :                 /* a few bogus AP send dtim_period = 0 or no TIM IE */
    3997                 :          0 :                 bss_conf->dtim_period = elems.dtim_period ?: 1;
    3998                 :            : 
    3999                 :          0 :                 changed |= BSS_CHANGED_BEACON_INFO;
    4000                 :          0 :                 ifmgd->have_beacon = true;
    4001                 :            : 
    4002                 :          0 :                 mutex_lock(&local->iflist_mtx);
    4003                 :          0 :                 ieee80211_recalc_ps(local);
    4004                 :          0 :                 mutex_unlock(&local->iflist_mtx);
    4005                 :            : 
    4006                 :          0 :                 ieee80211_recalc_ps_vif(sdata);
    4007                 :            :         }
    4008                 :            : 
    4009         [ #  # ]:          0 :         if (elems.erp_info) {
    4010                 :          0 :                 erp_valid = true;
    4011                 :          0 :                 erp_value = elems.erp_info[0];
    4012                 :            :         } else {
    4013                 :            :                 erp_valid = false;
    4014                 :            :         }
    4015                 :          0 :         changed |= ieee80211_handle_bss_capability(sdata,
    4016                 :          0 :                         le16_to_cpu(mgmt->u.beacon.capab_info),
    4017                 :            :                         erp_valid, erp_value);
    4018                 :            : 
    4019                 :          0 :         mutex_lock(&local->sta_mtx);
    4020                 :          0 :         sta = sta_info_get(sdata, bssid);
    4021                 :            : 
    4022         [ #  # ]:          0 :         changed |= ieee80211_recalc_twt_req(sdata, sta, &elems);
    4023                 :            : 
    4024         [ #  # ]:          0 :         if (ieee80211_config_bw(sdata, sta,
    4025                 :            :                                 elems.ht_cap_elem, elems.ht_operation,
    4026                 :            :                                 elems.vht_operation, elems.he_operation,
    4027                 :            :                                 bssid, &changed)) {
    4028                 :          0 :                 mutex_unlock(&local->sta_mtx);
    4029                 :          0 :                 sdata_info(sdata,
    4030                 :            :                            "failed to follow AP %pM bandwidth change, disconnect\n",
    4031                 :            :                            bssid);
    4032                 :          0 :                 ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
    4033                 :            :                                        WLAN_REASON_DEAUTH_LEAVING,
    4034                 :            :                                        true, deauth_buf);
    4035                 :          0 :                 ieee80211_report_disconnect(sdata, deauth_buf,
    4036                 :            :                                             sizeof(deauth_buf), true,
    4037                 :            :                                             WLAN_REASON_DEAUTH_LEAVING);
    4038                 :          0 :                 return;
    4039                 :            :         }
    4040                 :            : 
    4041   [ #  #  #  # ]:          0 :         if (sta && elems.opmode_notif)
    4042                 :          0 :                 ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif,
    4043                 :          0 :                                             rx_status->band);
    4044                 :          0 :         mutex_unlock(&local->sta_mtx);
    4045                 :            : 
    4046                 :          0 :         changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt,
    4047                 :            :                                                elems.country_elem,
    4048                 :          0 :                                                elems.country_elem_len,
    4049                 :            :                                                elems.pwr_constr_elem,
    4050                 :            :                                                elems.cisco_dtpc_elem);
    4051                 :            : 
    4052                 :          0 :         ieee80211_bss_info_change_notify(sdata, changed);
    4053                 :            : }
    4054                 :            : 
    4055                 :          0 : void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
    4056                 :            :                                   struct sk_buff *skb)
    4057                 :            : {
    4058                 :          0 :         struct ieee80211_rx_status *rx_status;
    4059                 :          0 :         struct ieee80211_mgmt *mgmt;
    4060                 :          0 :         u16 fc;
    4061                 :          0 :         struct ieee802_11_elems elems;
    4062                 :          0 :         int ies_len;
    4063                 :            : 
    4064                 :          0 :         rx_status = (struct ieee80211_rx_status *) skb->cb;
    4065                 :          0 :         mgmt = (struct ieee80211_mgmt *) skb->data;
    4066                 :          0 :         fc = le16_to_cpu(mgmt->frame_control);
    4067                 :            : 
    4068                 :          0 :         sdata_lock(sdata);
    4069                 :            : 
    4070   [ #  #  #  #  :          0 :         switch (fc & IEEE80211_FCTL_STYPE) {
             #  #  #  # ]
    4071                 :          0 :         case IEEE80211_STYPE_BEACON:
    4072                 :          0 :                 ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status);
    4073                 :          0 :                 break;
    4074                 :          0 :         case IEEE80211_STYPE_PROBE_RESP:
    4075                 :          0 :                 ieee80211_rx_mgmt_probe_resp(sdata, skb);
    4076                 :          0 :                 break;
    4077                 :          0 :         case IEEE80211_STYPE_AUTH:
    4078                 :          0 :                 ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len);
    4079                 :          0 :                 break;
    4080                 :          0 :         case IEEE80211_STYPE_DEAUTH:
    4081                 :          0 :                 ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len);
    4082                 :          0 :                 break;
    4083                 :          0 :         case IEEE80211_STYPE_DISASSOC:
    4084                 :          0 :                 ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
    4085                 :          0 :                 break;
    4086                 :          0 :         case IEEE80211_STYPE_ASSOC_RESP:
    4087                 :            :         case IEEE80211_STYPE_REASSOC_RESP:
    4088                 :          0 :                 ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len);
    4089                 :          0 :                 break;
    4090                 :          0 :         case IEEE80211_STYPE_ACTION:
    4091         [ #  # ]:          0 :                 if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) {
    4092                 :          0 :                         ies_len = skb->len -
    4093                 :            :                                   offsetof(struct ieee80211_mgmt,
    4094                 :            :                                            u.action.u.chan_switch.variable);
    4095                 :            : 
    4096         [ #  # ]:          0 :                         if (ies_len < 0)
    4097                 :            :                                 break;
    4098                 :            : 
    4099                 :            :                         /* CSA IE cannot be overridden, no need for BSSID */
    4100                 :          0 :                         ieee802_11_parse_elems(
    4101                 :          0 :                                 mgmt->u.action.u.chan_switch.variable,
    4102                 :          0 :                                 ies_len, true, &elems, mgmt->bssid, NULL);
    4103                 :            : 
    4104         [ #  # ]:          0 :                         if (elems.parse_error)
    4105                 :            :                                 break;
    4106                 :            : 
    4107                 :          0 :                         ieee80211_sta_process_chanswitch(sdata,
    4108                 :            :                                                  rx_status->mactime,
    4109                 :            :                                                  rx_status->device_timestamp,
    4110                 :            :                                                  &elems, false);
    4111         [ #  # ]:          0 :                 } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
    4112                 :          0 :                         ies_len = skb->len -
    4113                 :            :                                   offsetof(struct ieee80211_mgmt,
    4114                 :            :                                            u.action.u.ext_chan_switch.variable);
    4115                 :            : 
    4116         [ #  # ]:          0 :                         if (ies_len < 0)
    4117                 :            :                                 break;
    4118                 :            : 
    4119                 :            :                         /*
    4120                 :            :                          * extended CSA IE can't be overridden, no need for
    4121                 :            :                          * BSSID
    4122                 :            :                          */
    4123                 :          0 :                         ieee802_11_parse_elems(
    4124                 :          0 :                                 mgmt->u.action.u.ext_chan_switch.variable,
    4125                 :          0 :                                 ies_len, true, &elems, mgmt->bssid, NULL);
    4126                 :            : 
    4127         [ #  # ]:          0 :                         if (elems.parse_error)
    4128                 :            :                                 break;
    4129                 :            : 
    4130                 :            :                         /* for the handling code pretend this was also an IE */
    4131                 :          0 :                         elems.ext_chansw_ie =
    4132                 :          0 :                                 &mgmt->u.action.u.ext_chan_switch.data;
    4133                 :            : 
    4134                 :          0 :                         ieee80211_sta_process_chanswitch(sdata,
    4135                 :            :                                                  rx_status->mactime,
    4136                 :            :                                                  rx_status->device_timestamp,
    4137                 :            :                                                  &elems, false);
    4138                 :            :                 }
    4139                 :            :                 break;
    4140                 :            :         }
    4141                 :          0 :         sdata_unlock(sdata);
    4142                 :          0 : }
    4143                 :            : 
    4144                 :          0 : static void ieee80211_sta_timer(struct timer_list *t)
    4145                 :            : {
    4146                 :          0 :         struct ieee80211_sub_if_data *sdata =
    4147                 :          0 :                 from_timer(sdata, t, u.mgd.timer);
    4148                 :            : 
    4149                 :          0 :         ieee80211_queue_work(&sdata->local->hw, &sdata->work);
    4150                 :          0 : }
    4151                 :            : 
    4152                 :          0 : static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
    4153                 :            :                                           u8 *bssid, u8 reason, bool tx)
    4154                 :            : {
    4155                 :          0 :         u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
    4156                 :            : 
    4157                 :          0 :         ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason,
    4158                 :            :                                tx, frame_buf);
    4159                 :            : 
    4160                 :          0 :         ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true,
    4161                 :            :                                     reason);
    4162                 :          0 : }
    4163                 :            : 
    4164                 :          0 : static int ieee80211_auth(struct ieee80211_sub_if_data *sdata)
    4165                 :            : {
    4166                 :          0 :         struct ieee80211_local *local = sdata->local;
    4167                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    4168                 :          0 :         struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data;
    4169                 :          0 :         u32 tx_flags = 0;
    4170                 :          0 :         u16 trans = 1;
    4171                 :          0 :         u16 status = 0;
    4172                 :          0 :         u16 prepare_tx_duration = 0;
    4173                 :            : 
    4174         [ #  # ]:          0 :         sdata_assert_lock(sdata);
    4175                 :            : 
    4176   [ #  #  #  # ]:          0 :         if (WARN_ON_ONCE(!auth_data))
    4177                 :            :                 return -EINVAL;
    4178                 :            : 
    4179                 :          0 :         auth_data->tries++;
    4180                 :            : 
    4181         [ #  # ]:          0 :         if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) {
    4182                 :          0 :                 sdata_info(sdata, "authentication with %pM timed out\n",
    4183                 :            :                            auth_data->bss->bssid);
    4184                 :            : 
    4185                 :            :                 /*
    4186                 :            :                  * Most likely AP is not in the range so remove the
    4187                 :            :                  * bss struct for that AP.
    4188                 :            :                  */
    4189                 :          0 :                 cfg80211_unlink_bss(local->hw.wiphy, auth_data->bss);
    4190                 :            : 
    4191                 :          0 :                 return -ETIMEDOUT;
    4192                 :            :         }
    4193                 :            : 
    4194         [ #  # ]:          0 :         if (auth_data->algorithm == WLAN_AUTH_SAE)
    4195                 :          0 :                 prepare_tx_duration =
    4196                 :          0 :                         jiffies_to_msecs(IEEE80211_AUTH_TIMEOUT_SAE);
    4197                 :            : 
    4198                 :          0 :         drv_mgd_prepare_tx(local, sdata, prepare_tx_duration);
    4199                 :            : 
    4200                 :          0 :         sdata_info(sdata, "send auth to %pM (try %d/%d)\n",
    4201                 :            :                    auth_data->bss->bssid, auth_data->tries,
    4202                 :            :                    IEEE80211_AUTH_MAX_TRIES);
    4203                 :            : 
    4204                 :          0 :         auth_data->expected_transaction = 2;
    4205                 :            : 
    4206         [ #  # ]:          0 :         if (auth_data->algorithm == WLAN_AUTH_SAE) {
    4207                 :          0 :                 trans = auth_data->sae_trans;
    4208                 :          0 :                 status = auth_data->sae_status;
    4209                 :          0 :                 auth_data->expected_transaction = trans;
    4210                 :            :         }
    4211                 :            : 
    4212         [ #  # ]:          0 :         if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
    4213                 :          0 :                 tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
    4214                 :            :                            IEEE80211_TX_INTFL_MLME_CONN_TX;
    4215                 :            : 
    4216                 :          0 :         ieee80211_send_auth(sdata, trans, auth_data->algorithm, status,
    4217                 :          0 :                             auth_data->data, auth_data->data_len,
    4218                 :            :                             auth_data->bss->bssid,
    4219                 :          0 :                             auth_data->bss->bssid, NULL, 0, 0,
    4220                 :            :                             tx_flags);
    4221                 :            : 
    4222         [ #  # ]:          0 :         if (tx_flags == 0) {
    4223         [ #  # ]:          0 :                 if (auth_data->algorithm == WLAN_AUTH_SAE)
    4224                 :          0 :                         auth_data->timeout = jiffies +
    4225                 :            :                                 IEEE80211_AUTH_TIMEOUT_SAE;
    4226                 :            :                 else
    4227                 :          0 :                         auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
    4228                 :            :         } else {
    4229                 :          0 :                 auth_data->timeout =
    4230                 :          0 :                         round_jiffies_up(jiffies + IEEE80211_AUTH_TIMEOUT_LONG);
    4231                 :            :         }
    4232                 :            : 
    4233                 :          0 :         auth_data->timeout_started = true;
    4234         [ #  # ]:          0 :         run_again(sdata, auth_data->timeout);
    4235                 :            : 
    4236                 :            :         return 0;
    4237                 :            : }
    4238                 :            : 
    4239                 :          0 : static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
    4240                 :            : {
    4241                 :          0 :         struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data;
    4242                 :          0 :         struct ieee80211_local *local = sdata->local;
    4243                 :            : 
    4244         [ #  # ]:          0 :         sdata_assert_lock(sdata);
    4245                 :            : 
    4246                 :          0 :         assoc_data->tries++;
    4247         [ #  # ]:          0 :         if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) {
    4248                 :          0 :                 sdata_info(sdata, "association with %pM timed out\n",
    4249                 :            :                            assoc_data->bss->bssid);
    4250                 :            : 
    4251                 :            :                 /*
    4252                 :            :                  * Most likely AP is not in the range so remove the
    4253                 :            :                  * bss struct for that AP.
    4254                 :            :                  */
    4255                 :          0 :                 cfg80211_unlink_bss(local->hw.wiphy, assoc_data->bss);
    4256                 :            : 
    4257                 :          0 :                 return -ETIMEDOUT;
    4258                 :            :         }
    4259                 :            : 
    4260                 :          0 :         sdata_info(sdata, "associate with %pM (try %d/%d)\n",
    4261                 :            :                    assoc_data->bss->bssid, assoc_data->tries,
    4262                 :            :                    IEEE80211_ASSOC_MAX_TRIES);
    4263                 :          0 :         ieee80211_send_assoc(sdata);
    4264                 :            : 
    4265         [ #  # ]:          0 :         if (!ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
    4266                 :          0 :                 assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
    4267                 :          0 :                 assoc_data->timeout_started = true;
    4268         [ #  # ]:          0 :                 run_again(sdata, assoc_data->timeout);
    4269                 :            :         } else {
    4270                 :          0 :                 assoc_data->timeout =
    4271                 :          0 :                         round_jiffies_up(jiffies +
    4272                 :            :                                          IEEE80211_ASSOC_TIMEOUT_LONG);
    4273                 :          0 :                 assoc_data->timeout_started = true;
    4274         [ #  # ]:          0 :                 run_again(sdata, assoc_data->timeout);
    4275                 :            :         }
    4276                 :            : 
    4277                 :            :         return 0;
    4278                 :            : }
    4279                 :            : 
    4280                 :          0 : void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata,
    4281                 :            :                                   __le16 fc, bool acked)
    4282                 :            : {
    4283                 :          0 :         struct ieee80211_local *local = sdata->local;
    4284                 :            : 
    4285                 :          0 :         sdata->u.mgd.status_fc = fc;
    4286                 :          0 :         sdata->u.mgd.status_acked = acked;
    4287                 :          0 :         sdata->u.mgd.status_received = true;
    4288                 :            : 
    4289                 :          0 :         ieee80211_queue_work(&local->hw, &sdata->work);
    4290                 :          0 : }
    4291                 :            : 
    4292                 :          0 : void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
    4293                 :            : {
    4294                 :          0 :         struct ieee80211_local *local = sdata->local;
    4295                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    4296                 :            : 
    4297                 :          0 :         sdata_lock(sdata);
    4298                 :            : 
    4299         [ #  # ]:          0 :         if (ifmgd->status_received) {
    4300                 :          0 :                 __le16 fc = ifmgd->status_fc;
    4301                 :          0 :                 bool status_acked = ifmgd->status_acked;
    4302                 :            : 
    4303                 :          0 :                 ifmgd->status_received = false;
    4304   [ #  #  #  # ]:          0 :                 if (ifmgd->auth_data && ieee80211_is_auth(fc)) {
    4305         [ #  # ]:          0 :                         if (status_acked) {
    4306         [ #  # ]:          0 :                                 if (ifmgd->auth_data->algorithm ==
    4307                 :            :                                     WLAN_AUTH_SAE)
    4308                 :          0 :                                         ifmgd->auth_data->timeout =
    4309                 :          0 :                                                 jiffies +
    4310                 :            :                                                 IEEE80211_AUTH_TIMEOUT_SAE;
    4311                 :            :                                 else
    4312                 :          0 :                                         ifmgd->auth_data->timeout =
    4313                 :          0 :                                                 jiffies +
    4314                 :            :                                                 IEEE80211_AUTH_TIMEOUT_SHORT;
    4315         [ #  # ]:          0 :                                 run_again(sdata, ifmgd->auth_data->timeout);
    4316                 :            :                         } else {
    4317                 :          0 :                                 ifmgd->auth_data->timeout = jiffies - 1;
    4318                 :            :                         }
    4319                 :          0 :                         ifmgd->auth_data->timeout_started = true;
    4320   [ #  #  #  # ]:          0 :                 } else if (ifmgd->assoc_data &&
    4321         [ #  # ]:          0 :                            (ieee80211_is_assoc_req(fc) ||
    4322                 :            :                             ieee80211_is_reassoc_req(fc))) {
    4323         [ #  # ]:          0 :                         if (status_acked) {
    4324                 :          0 :                                 ifmgd->assoc_data->timeout =
    4325                 :          0 :                                         jiffies + IEEE80211_ASSOC_TIMEOUT_SHORT;
    4326         [ #  # ]:          0 :                                 run_again(sdata, ifmgd->assoc_data->timeout);
    4327                 :            :                         } else {
    4328                 :          0 :                                 ifmgd->assoc_data->timeout = jiffies - 1;
    4329                 :            :                         }
    4330                 :          0 :                         ifmgd->assoc_data->timeout_started = true;
    4331                 :            :                 }
    4332                 :            :         }
    4333                 :            : 
    4334   [ #  #  #  # ]:          0 :         if (ifmgd->auth_data && ifmgd->auth_data->timeout_started &&
    4335         [ #  # ]:          0 :             time_after(jiffies, ifmgd->auth_data->timeout)) {
    4336         [ #  # ]:          0 :                 if (ifmgd->auth_data->done) {
    4337                 :            :                         /*
    4338                 :            :                          * ok ... we waited for assoc but userspace didn't,
    4339                 :            :                          * so let's just kill the auth data
    4340                 :            :                          */
    4341                 :          0 :                         ieee80211_destroy_auth_data(sdata, false);
    4342         [ #  # ]:          0 :                 } else if (ieee80211_auth(sdata)) {
    4343                 :          0 :                         u8 bssid[ETH_ALEN];
    4344                 :          0 :                         struct ieee80211_event event = {
    4345                 :            :                                 .type = MLME_EVENT,
    4346                 :            :                                 .u.mlme.data = AUTH_EVENT,
    4347                 :            :                                 .u.mlme.status = MLME_TIMEOUT,
    4348                 :            :                         };
    4349                 :            : 
    4350                 :          0 :                         memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN);
    4351                 :            : 
    4352                 :          0 :                         ieee80211_destroy_auth_data(sdata, false);
    4353                 :            : 
    4354                 :          0 :                         cfg80211_auth_timeout(sdata->dev, bssid);
    4355                 :          0 :                         drv_event_callback(sdata->local, sdata, &event);
    4356                 :            :                 }
    4357   [ #  #  #  # ]:          0 :         } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started)
    4358         [ #  # ]:          0 :                 run_again(sdata, ifmgd->auth_data->timeout);
    4359                 :            : 
    4360   [ #  #  #  # ]:          0 :         if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started &&
    4361         [ #  # ]:          0 :             time_after(jiffies, ifmgd->assoc_data->timeout)) {
    4362   [ #  #  #  #  :          0 :                 if ((ifmgd->assoc_data->need_beacon && !ifmgd->have_beacon) ||
                   #  # ]
    4363                 :          0 :                     ieee80211_do_assoc(sdata)) {
    4364                 :          0 :                         struct cfg80211_bss *bss = ifmgd->assoc_data->bss;
    4365                 :          0 :                         struct ieee80211_event event = {
    4366                 :            :                                 .type = MLME_EVENT,
    4367                 :            :                                 .u.mlme.data = ASSOC_EVENT,
    4368                 :            :                                 .u.mlme.status = MLME_TIMEOUT,
    4369                 :            :                         };
    4370                 :            : 
    4371                 :          0 :                         ieee80211_destroy_assoc_data(sdata, false, false);
    4372                 :          0 :                         cfg80211_assoc_timeout(sdata->dev, bss);
    4373                 :          0 :                         drv_event_callback(sdata->local, sdata, &event);
    4374                 :            :                 }
    4375   [ #  #  #  # ]:          0 :         } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started)
    4376         [ #  # ]:          0 :                 run_again(sdata, ifmgd->assoc_data->timeout);
    4377                 :            : 
    4378         [ #  # ]:          0 :         if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL &&
    4379         [ #  # ]:          0 :             ifmgd->associated) {
    4380                 :          0 :                 u8 bssid[ETH_ALEN];
    4381                 :          0 :                 int max_tries;
    4382                 :            : 
    4383                 :          0 :                 memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
    4384                 :            : 
    4385         [ #  # ]:          0 :                 if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
    4386                 :          0 :                         max_tries = max_nullfunc_tries;
    4387                 :            :                 else
    4388                 :          0 :                         max_tries = max_probe_tries;
    4389                 :            : 
    4390                 :            :                 /* ACK received for nullfunc probing frame */
    4391         [ #  # ]:          0 :                 if (!ifmgd->probe_send_count)
    4392                 :          0 :                         ieee80211_reset_ap_probe(sdata);
    4393         [ #  # ]:          0 :                 else if (ifmgd->nullfunc_failed) {
    4394         [ #  # ]:          0 :                         if (ifmgd->probe_send_count < max_tries) {
    4395                 :          0 :                                 mlme_dbg(sdata,
    4396                 :            :                                          "No ack for nullfunc frame to AP %pM, try %d/%i\n",
    4397                 :            :                                          bssid, ifmgd->probe_send_count,
    4398                 :            :                                          max_tries);
    4399                 :          0 :                                 ieee80211_mgd_probe_ap_send(sdata);
    4400                 :            :                         } else {
    4401                 :          0 :                                 mlme_dbg(sdata,
    4402                 :            :                                          "No ack for nullfunc frame to AP %pM, disconnecting.\n",
    4403                 :            :                                          bssid);
    4404                 :          0 :                                 ieee80211_sta_connection_lost(sdata, bssid,
    4405                 :            :                                         WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
    4406                 :            :                                         false);
    4407                 :            :                         }
    4408         [ #  # ]:          0 :                 } else if (time_is_after_jiffies(ifmgd->probe_timeout))
    4409         [ #  # ]:          0 :                         run_again(sdata, ifmgd->probe_timeout);
    4410         [ #  # ]:          0 :                 else if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
    4411                 :          0 :                         mlme_dbg(sdata,
    4412                 :            :                                  "Failed to send nullfunc to AP %pM after %dms, disconnecting\n",
    4413                 :            :                                  bssid, probe_wait_ms);
    4414                 :          0 :                         ieee80211_sta_connection_lost(sdata, bssid,
    4415                 :            :                                 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, false);
    4416         [ #  # ]:          0 :                 } else if (ifmgd->probe_send_count < max_tries) {
    4417                 :          0 :                         mlme_dbg(sdata,
    4418                 :            :                                  "No probe response from AP %pM after %dms, try %d/%i\n",
    4419                 :            :                                  bssid, probe_wait_ms,
    4420                 :            :                                  ifmgd->probe_send_count, max_tries);
    4421                 :          0 :                         ieee80211_mgd_probe_ap_send(sdata);
    4422                 :            :                 } else {
    4423                 :            :                         /*
    4424                 :            :                          * We actually lost the connection ... or did we?
    4425                 :            :                          * Let's make sure!
    4426                 :            :                          */
    4427                 :          0 :                         mlme_dbg(sdata,
    4428                 :            :                                  "No probe response from AP %pM after %dms, disconnecting.\n",
    4429                 :            :                                  bssid, probe_wait_ms);
    4430                 :            : 
    4431                 :          0 :                         ieee80211_sta_connection_lost(sdata, bssid,
    4432                 :            :                                 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, false);
    4433                 :            :                 }
    4434                 :            :         }
    4435                 :            : 
    4436                 :          0 :         sdata_unlock(sdata);
    4437                 :          0 : }
    4438                 :            : 
    4439                 :          0 : static void ieee80211_sta_bcn_mon_timer(struct timer_list *t)
    4440                 :            : {
    4441                 :          0 :         struct ieee80211_sub_if_data *sdata =
    4442                 :          0 :                 from_timer(sdata, t, u.mgd.bcn_mon_timer);
    4443                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    4444                 :            : 
    4445   [ #  #  #  # ]:          0 :         if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
    4446                 :            :                 return;
    4447                 :            : 
    4448                 :          0 :         sdata->u.mgd.connection_loss = false;
    4449                 :          0 :         ieee80211_queue_work(&sdata->local->hw,
    4450                 :            :                              &sdata->u.mgd.beacon_connection_loss_work);
    4451                 :            : }
    4452                 :            : 
    4453                 :          0 : static void ieee80211_sta_conn_mon_timer(struct timer_list *t)
    4454                 :            : {
    4455                 :          0 :         struct ieee80211_sub_if_data *sdata =
    4456                 :          0 :                 from_timer(sdata, t, u.mgd.conn_mon_timer);
    4457                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    4458                 :          0 :         struct ieee80211_local *local = sdata->local;
    4459                 :            : 
    4460   [ #  #  #  # ]:          0 :         if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
    4461                 :            :                 return;
    4462                 :            : 
    4463                 :          0 :         ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);
    4464                 :            : }
    4465                 :            : 
    4466                 :          0 : static void ieee80211_sta_monitor_work(struct work_struct *work)
    4467                 :            : {
    4468                 :          0 :         struct ieee80211_sub_if_data *sdata =
    4469                 :          0 :                 container_of(work, struct ieee80211_sub_if_data,
    4470                 :            :                              u.mgd.monitor_work);
    4471                 :            : 
    4472                 :          0 :         ieee80211_mgd_probe_ap(sdata, false);
    4473                 :          0 : }
    4474                 :            : 
    4475                 :          0 : static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
    4476                 :            : {
    4477         [ #  # ]:          0 :         if (sdata->vif.type == NL80211_IFTYPE_STATION) {
    4478                 :          0 :                 __ieee80211_stop_poll(sdata);
    4479                 :            : 
    4480                 :            :                 /* let's probe the connection once */
    4481         [ #  # ]:          0 :                 if (!ieee80211_hw_check(&sdata->local->hw, CONNECTION_MONITOR))
    4482                 :          0 :                         ieee80211_queue_work(&sdata->local->hw,
    4483                 :            :                                              &sdata->u.mgd.monitor_work);
    4484                 :            :         }
    4485                 :          0 : }
    4486                 :            : 
    4487                 :            : #ifdef CONFIG_PM
    4488                 :          0 : void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata)
    4489                 :            : {
    4490                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    4491                 :          0 :         u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
    4492                 :            : 
    4493                 :          0 :         sdata_lock(sdata);
    4494                 :            : 
    4495   [ #  #  #  # ]:          0 :         if (ifmgd->auth_data || ifmgd->assoc_data) {
    4496         [ #  # ]:          0 :                 const u8 *bssid = ifmgd->auth_data ?
    4497                 :          0 :                                 ifmgd->auth_data->bss->bssid :
    4498                 :          0 :                                 ifmgd->assoc_data->bss->bssid;
    4499                 :            : 
    4500                 :            :                 /*
    4501                 :            :                  * If we are trying to authenticate / associate while suspending,
    4502                 :            :                  * cfg80211 won't know and won't actually abort those attempts,
    4503                 :            :                  * thus we need to do that ourselves.
    4504                 :            :                  */
    4505                 :          0 :                 ieee80211_send_deauth_disassoc(sdata, bssid, bssid,
    4506                 :            :                                                IEEE80211_STYPE_DEAUTH,
    4507                 :            :                                                WLAN_REASON_DEAUTH_LEAVING,
    4508                 :            :                                                false, frame_buf);
    4509         [ #  # ]:          0 :                 if (ifmgd->assoc_data)
    4510                 :          0 :                         ieee80211_destroy_assoc_data(sdata, false, true);
    4511         [ #  # ]:          0 :                 if (ifmgd->auth_data)
    4512                 :          0 :                         ieee80211_destroy_auth_data(sdata, false);
    4513                 :          0 :                 cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
    4514                 :            :                                       IEEE80211_DEAUTH_FRAME_LEN);
    4515                 :            :         }
    4516                 :            : 
    4517                 :            :         /* This is a bit of a hack - we should find a better and more generic
    4518                 :            :          * solution to this. Normally when suspending, cfg80211 will in fact
    4519                 :            :          * deauthenticate. However, it doesn't (and cannot) stop an ongoing
    4520                 :            :          * auth (not so important) or assoc (this is the problem) process.
    4521                 :            :          *
    4522                 :            :          * As a consequence, it can happen that we are in the process of both
    4523                 :            :          * associating and suspending, and receive an association response
    4524                 :            :          * after cfg80211 has checked if it needs to disconnect, but before
    4525                 :            :          * we actually set the flag to drop incoming frames. This will then
    4526                 :            :          * cause the workqueue flush to process the association response in
    4527                 :            :          * the suspend, resulting in a successful association just before it
    4528                 :            :          * tries to remove the interface from the driver, which now though
    4529                 :            :          * has a channel context assigned ... this results in issues.
    4530                 :            :          *
    4531                 :            :          * To work around this (for now) simply deauth here again if we're
    4532                 :            :          * now connected.
    4533                 :            :          */
    4534   [ #  #  #  # ]:          0 :         if (ifmgd->associated && !sdata->local->wowlan) {
    4535                 :          0 :                 u8 bssid[ETH_ALEN];
    4536                 :          0 :                 struct cfg80211_deauth_request req = {
    4537                 :            :                         .reason_code = WLAN_REASON_DEAUTH_LEAVING,
    4538                 :            :                         .bssid = bssid,
    4539                 :            :                 };
    4540                 :            : 
    4541                 :          0 :                 memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
    4542                 :          0 :                 ieee80211_mgd_deauth(sdata, &req);
    4543                 :            :         }
    4544                 :            : 
    4545                 :          0 :         sdata_unlock(sdata);
    4546                 :          0 : }
    4547                 :            : 
    4548                 :          0 : void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
    4549                 :            : {
    4550                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    4551                 :            : 
    4552                 :          0 :         sdata_lock(sdata);
    4553         [ #  # ]:          0 :         if (!ifmgd->associated) {
    4554                 :          0 :                 sdata_unlock(sdata);
    4555                 :          0 :                 return;
    4556                 :            :         }
    4557                 :            : 
    4558         [ #  # ]:          0 :         if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) {
    4559                 :          0 :                 sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME;
    4560                 :          0 :                 mlme_dbg(sdata, "driver requested disconnect after resume\n");
    4561                 :          0 :                 ieee80211_sta_connection_lost(sdata,
    4562                 :          0 :                                               ifmgd->associated->bssid,
    4563                 :            :                                               WLAN_REASON_UNSPECIFIED,
    4564                 :            :                                               true);
    4565                 :          0 :                 sdata_unlock(sdata);
    4566                 :          0 :                 return;
    4567                 :            :         }
    4568                 :          0 :         sdata_unlock(sdata);
    4569                 :            : }
    4570                 :            : #endif
    4571                 :            : 
    4572                 :            : /* interface setup */
    4573                 :          0 : void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
    4574                 :            : {
    4575                 :          0 :         struct ieee80211_if_managed *ifmgd;
    4576                 :            : 
    4577                 :          0 :         ifmgd = &sdata->u.mgd;
    4578                 :          0 :         INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work);
    4579                 :          0 :         INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
    4580                 :          0 :         INIT_WORK(&ifmgd->beacon_connection_loss_work,
    4581                 :            :                   ieee80211_beacon_connection_loss_work);
    4582                 :          0 :         INIT_WORK(&ifmgd->csa_connection_drop_work,
    4583                 :            :                   ieee80211_csa_connection_drop_work);
    4584                 :          0 :         INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work);
    4585                 :          0 :         INIT_DELAYED_WORK(&ifmgd->tdls_peer_del_work,
    4586                 :            :                           ieee80211_tdls_peer_del_work);
    4587                 :          0 :         timer_setup(&ifmgd->timer, ieee80211_sta_timer, 0);
    4588                 :          0 :         timer_setup(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, 0);
    4589                 :          0 :         timer_setup(&ifmgd->conn_mon_timer, ieee80211_sta_conn_mon_timer, 0);
    4590                 :          0 :         timer_setup(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, 0);
    4591                 :          0 :         INIT_DELAYED_WORK(&ifmgd->tx_tspec_wk,
    4592                 :            :                           ieee80211_sta_handle_tspec_ac_params_wk);
    4593                 :            : 
    4594                 :          0 :         ifmgd->flags = 0;
    4595                 :          0 :         ifmgd->powersave = sdata->wdev.ps;
    4596                 :          0 :         ifmgd->uapsd_queues = sdata->local->hw.uapsd_queues;
    4597                 :          0 :         ifmgd->uapsd_max_sp_len = sdata->local->hw.uapsd_max_sp_len;
    4598                 :          0 :         ifmgd->p2p_noa_index = -1;
    4599                 :            : 
    4600         [ #  # ]:          0 :         if (sdata->local->hw.wiphy->features & NL80211_FEATURE_DYNAMIC_SMPS)
    4601                 :          0 :                 ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC;
    4602                 :            :         else
    4603                 :          0 :                 ifmgd->req_smps = IEEE80211_SMPS_OFF;
    4604                 :            : 
    4605                 :            :         /* Setup TDLS data */
    4606                 :          0 :         spin_lock_init(&ifmgd->teardown_lock);
    4607                 :          0 :         ifmgd->teardown_skb = NULL;
    4608                 :          0 :         ifmgd->orig_teardown_skb = NULL;
    4609                 :          0 : }
    4610                 :            : 
    4611                 :            : /* scan finished notification */
    4612                 :          0 : void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
    4613                 :            : {
    4614                 :          0 :         struct ieee80211_sub_if_data *sdata;
    4615                 :            : 
    4616                 :            :         /* Restart STA timers */
    4617                 :          0 :         rcu_read_lock();
    4618         [ #  # ]:          0 :         list_for_each_entry_rcu(sdata, &local->interfaces, list) {
    4619         [ #  # ]:          0 :                 if (ieee80211_sdata_running(sdata))
    4620                 :          0 :                         ieee80211_restart_sta_timer(sdata);
    4621                 :            :         }
    4622                 :          0 :         rcu_read_unlock();
    4623                 :          0 : }
    4624                 :            : 
    4625                 :          0 : static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata,
    4626                 :            :                                      struct cfg80211_bss *cbss)
    4627                 :            : {
    4628                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    4629                 :          0 :         const u8 *ht_cap_ie, *vht_cap_ie;
    4630                 :          0 :         const struct ieee80211_ht_cap *ht_cap;
    4631                 :          0 :         const struct ieee80211_vht_cap *vht_cap;
    4632                 :          0 :         u8 chains = 1;
    4633                 :            : 
    4634         [ #  # ]:          0 :         if (ifmgd->flags & IEEE80211_STA_DISABLE_HT)
    4635                 :            :                 return chains;
    4636                 :            : 
    4637                 :          0 :         ht_cap_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY);
    4638   [ #  #  #  # ]:          0 :         if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap)) {
    4639                 :          0 :                 ht_cap = (void *)(ht_cap_ie + 2);
    4640                 :          0 :                 chains = ieee80211_mcs_to_chains(&ht_cap->mcs);
    4641                 :            :                 /*
    4642                 :            :                  * TODO: use "Tx Maximum Number Spatial Streams Supported" and
    4643                 :            :                  *       "Tx Unequal Modulation Supported" fields.
    4644                 :            :                  */
    4645                 :            :         }
    4646                 :            : 
    4647         [ #  # ]:          0 :         if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
    4648                 :            :                 return chains;
    4649                 :            : 
    4650                 :          0 :         vht_cap_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_VHT_CAPABILITY);
    4651   [ #  #  #  # ]:          0 :         if (vht_cap_ie && vht_cap_ie[1] >= sizeof(*vht_cap)) {
    4652                 :          0 :                 u8 nss;
    4653                 :          0 :                 u16 tx_mcs_map;
    4654                 :            : 
    4655                 :          0 :                 vht_cap = (void *)(vht_cap_ie + 2);
    4656                 :          0 :                 tx_mcs_map = le16_to_cpu(vht_cap->supp_mcs.tx_mcs_map);
    4657         [ #  # ]:          0 :                 for (nss = 8; nss > 0; nss--) {
    4658         [ #  # ]:          0 :                         if (((tx_mcs_map >> (2 * (nss - 1))) & 3) !=
    4659                 :            :                                         IEEE80211_VHT_MCS_NOT_SUPPORTED)
    4660                 :            :                                 break;
    4661                 :            :                 }
    4662                 :            :                 /* TODO: use "Tx Highest Supported Long GI Data Rate" field? */
    4663                 :          0 :                 chains = max(chains, nss);
    4664                 :            :         }
    4665                 :            : 
    4666                 :            :         return chains;
    4667                 :            : }
    4668                 :            : 
    4669                 :            : static bool
    4670                 :          0 : ieee80211_verify_sta_he_mcs_support(struct ieee80211_supported_band *sband,
    4671                 :            :                                     const struct ieee80211_he_operation *he_op)
    4672                 :            : {
    4673                 :          0 :         const struct ieee80211_sta_he_cap *sta_he_cap =
    4674                 :            :                 ieee80211_get_he_sta_cap(sband);
    4675                 :          0 :         u16 ap_min_req_set;
    4676                 :          0 :         int i;
    4677                 :            : 
    4678         [ #  # ]:          0 :         if (!sta_he_cap || !he_op)
    4679                 :            :                 return false;
    4680                 :            : 
    4681                 :          0 :         ap_min_req_set = le16_to_cpu(he_op->he_mcs_nss_set);
    4682                 :            : 
    4683                 :            :         /* Need to go over for 80MHz, 160MHz and for 80+80 */
    4684         [ #  # ]:          0 :         for (i = 0; i < 3; i++) {
    4685                 :          0 :                 const struct ieee80211_he_mcs_nss_supp *sta_mcs_nss_supp =
    4686                 :            :                         &sta_he_cap->he_mcs_nss_supp;
    4687                 :          0 :                 u16 sta_mcs_map_rx =
    4688                 :          0 :                         le16_to_cpu(((__le16 *)sta_mcs_nss_supp)[2 * i]);
    4689                 :          0 :                 u16 sta_mcs_map_tx =
    4690                 :          0 :                         le16_to_cpu(((__le16 *)sta_mcs_nss_supp)[2 * i + 1]);
    4691                 :          0 :                 u8 nss;
    4692                 :          0 :                 bool verified = true;
    4693                 :            : 
    4694                 :            :                 /*
    4695                 :            :                  * For each band there is a maximum of 8 spatial streams
    4696                 :            :                  * possible. Each of the sta_mcs_map_* is a 16-bit struct built
    4697                 :            :                  * of 2 bits per NSS (1-8), with the values defined in enum
    4698                 :            :                  * ieee80211_he_mcs_support. Need to make sure STA TX and RX
    4699                 :            :                  * capabilities aren't less than the AP's minimum requirements
    4700                 :            :                  * for this HE BSS per SS.
    4701                 :            :                  * It is enough to find one such band that meets the reqs.
    4702                 :            :                  */
    4703         [ #  # ]:          0 :                 for (nss = 8; nss > 0; nss--) {
    4704                 :          0 :                         u8 sta_rx_val = (sta_mcs_map_rx >> (2 * (nss - 1))) & 3;
    4705                 :          0 :                         u8 sta_tx_val = (sta_mcs_map_tx >> (2 * (nss - 1))) & 3;
    4706                 :          0 :                         u8 ap_val = (ap_min_req_set >> (2 * (nss - 1))) & 3;
    4707                 :            : 
    4708         [ #  # ]:          0 :                         if (ap_val == IEEE80211_HE_MCS_NOT_SUPPORTED)
    4709                 :          0 :                                 continue;
    4710                 :            : 
    4711                 :            :                         /*
    4712                 :            :                          * Make sure the HE AP doesn't require MCSs that aren't
    4713                 :            :                          * supported by the client
    4714                 :            :                          */
    4715                 :          0 :                         if (sta_rx_val == IEEE80211_HE_MCS_NOT_SUPPORTED ||
    4716         [ #  # ]:          0 :                             sta_tx_val == IEEE80211_HE_MCS_NOT_SUPPORTED ||
    4717         [ #  # ]:          0 :                             (ap_val > sta_rx_val) || (ap_val > sta_tx_val)) {
    4718                 :            :                                 verified = false;
    4719                 :            :                                 break;
    4720                 :            :                         }
    4721                 :            :                 }
    4722                 :            : 
    4723         [ #  # ]:          0 :                 if (verified)
    4724                 :            :                         return true;
    4725                 :            :         }
    4726                 :            : 
    4727                 :            :         /* If here, STA doesn't meet AP's HE min requirements */
    4728                 :            :         return false;
    4729                 :            : }
    4730                 :            : 
    4731                 :          0 : static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
    4732                 :            :                                   struct cfg80211_bss *cbss)
    4733                 :            : {
    4734                 :          0 :         struct ieee80211_local *local = sdata->local;
    4735                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    4736                 :          0 :         const struct ieee80211_ht_cap *ht_cap = NULL;
    4737                 :          0 :         const struct ieee80211_ht_operation *ht_oper = NULL;
    4738                 :          0 :         const struct ieee80211_vht_operation *vht_oper = NULL;
    4739                 :          0 :         const struct ieee80211_he_operation *he_oper = NULL;
    4740                 :          0 :         struct ieee80211_supported_band *sband;
    4741                 :          0 :         struct cfg80211_chan_def chandef;
    4742                 :          0 :         int ret;
    4743                 :          0 :         u32 i;
    4744                 :          0 :         bool have_80mhz;
    4745                 :            : 
    4746                 :          0 :         sband = local->hw.wiphy->bands[cbss->channel->band];
    4747                 :            : 
    4748                 :          0 :         ifmgd->flags &= ~(IEEE80211_STA_DISABLE_40MHZ |
    4749                 :            :                           IEEE80211_STA_DISABLE_80P80MHZ |
    4750                 :            :                           IEEE80211_STA_DISABLE_160MHZ);
    4751                 :            : 
    4752                 :          0 :         rcu_read_lock();
    4753                 :            : 
    4754         [ #  # ]:          0 :         if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
    4755         [ #  # ]:          0 :             sband->ht_cap.ht_supported) {
    4756                 :          0 :                 const u8 *ht_oper_ie, *ht_cap_ie;
    4757                 :            : 
    4758                 :          0 :                 ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION);
    4759   [ #  #  #  # ]:          0 :                 if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper))
    4760                 :          0 :                         ht_oper = (void *)(ht_oper_ie + 2);
    4761                 :            : 
    4762                 :          0 :                 ht_cap_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY);
    4763   [ #  #  #  # ]:          0 :                 if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap))
    4764                 :          0 :                         ht_cap = (void *)(ht_cap_ie + 2);
    4765                 :            : 
    4766         [ #  # ]:          0 :                 if (!ht_cap) {
    4767                 :          0 :                         ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
    4768                 :          0 :                         ht_oper = NULL;
    4769                 :            :                 }
    4770                 :            :         }
    4771                 :            : 
    4772         [ #  # ]:          0 :         if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
    4773         [ #  # ]:          0 :             sband->vht_cap.vht_supported) {
    4774                 :          0 :                 const u8 *vht_oper_ie, *vht_cap;
    4775                 :            : 
    4776                 :          0 :                 vht_oper_ie = ieee80211_bss_get_ie(cbss,
    4777                 :            :                                                    WLAN_EID_VHT_OPERATION);
    4778   [ #  #  #  # ]:          0 :                 if (vht_oper_ie && vht_oper_ie[1] >= sizeof(*vht_oper))
    4779                 :          0 :                         vht_oper = (void *)(vht_oper_ie + 2);
    4780         [ #  # ]:          0 :                 if (vht_oper && !ht_oper) {
    4781                 :          0 :                         vht_oper = NULL;
    4782                 :          0 :                         sdata_info(sdata,
    4783                 :            :                                    "AP advertised VHT without HT, disabling both\n");
    4784                 :          0 :                         ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
    4785                 :          0 :                         ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
    4786                 :            :                 }
    4787                 :            : 
    4788                 :          0 :                 vht_cap = ieee80211_bss_get_ie(cbss, WLAN_EID_VHT_CAPABILITY);
    4789   [ #  #  #  # ]:          0 :                 if (!vht_cap || vht_cap[1] < sizeof(struct ieee80211_vht_cap)) {
    4790                 :          0 :                         ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
    4791                 :          0 :                         vht_oper = NULL;
    4792                 :            :                 }
    4793                 :            :         }
    4794                 :            : 
    4795         [ #  # ]:          0 :         if (!ieee80211_get_he_sta_cap(sband))
    4796                 :          0 :                 ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
    4797                 :            : 
    4798         [ #  # ]:          0 :         if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) {
    4799                 :          0 :                 const struct cfg80211_bss_ies *ies;
    4800                 :          0 :                 const u8 *he_oper_ie;
    4801                 :            : 
    4802                 :          0 :                 ies = rcu_dereference(cbss->ies);
    4803                 :          0 :                 he_oper_ie = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_OPERATION,
    4804                 :          0 :                                                   ies->data, ies->len);
    4805   [ #  #  #  # ]:          0 :                 if (he_oper_ie &&
    4806         [ #  # ]:          0 :                     he_oper_ie[1] == ieee80211_he_oper_size(&he_oper_ie[3]))
    4807                 :            :                         he_oper = (void *)(he_oper_ie + 3);
    4808                 :            :                 else
    4809                 :            :                         he_oper = NULL;
    4810                 :            : 
    4811         [ #  # ]:          0 :                 if (!ieee80211_verify_sta_he_mcs_support(sband, he_oper))
    4812                 :          0 :                         ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
    4813                 :            :         }
    4814                 :            : 
    4815                 :            :         /* Allow VHT if at least one channel on the sband supports 80 MHz */
    4816                 :          0 :         have_80mhz = false;
    4817         [ #  # ]:          0 :         for (i = 0; i < sband->n_channels; i++) {
    4818         [ #  # ]:          0 :                 if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED |
    4819                 :            :                                                 IEEE80211_CHAN_NO_80MHZ))
    4820                 :          0 :                         continue;
    4821                 :            : 
    4822                 :            :                 have_80mhz = true;
    4823                 :            :                 break;
    4824                 :            :         }
    4825                 :            : 
    4826         [ #  # ]:          0 :         if (!have_80mhz)
    4827                 :          0 :                 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
    4828                 :            : 
    4829                 :          0 :         ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
    4830                 :            :                                                      cbss->channel,
    4831                 :            :                                                      ht_oper, vht_oper, he_oper,
    4832                 :            :                                                      &chandef, false);
    4833                 :            : 
    4834                 :          0 :         sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss),
    4835                 :            :                                       local->rx_chains);
    4836                 :            : 
    4837                 :          0 :         rcu_read_unlock();
    4838                 :            : 
    4839                 :            :         /* will change later if needed */
    4840                 :          0 :         sdata->smps_mode = IEEE80211_SMPS_OFF;
    4841                 :            : 
    4842                 :          0 :         mutex_lock(&local->mtx);
    4843                 :            :         /*
    4844                 :            :          * If this fails (possibly due to channel context sharing
    4845                 :            :          * on incompatible channels, e.g. 80+80 and 160 sharing the
    4846                 :            :          * same control channel) try to use a smaller bandwidth.
    4847                 :            :          */
    4848                 :          0 :         ret = ieee80211_vif_use_channel(sdata, &chandef,
    4849                 :            :                                         IEEE80211_CHANCTX_SHARED);
    4850                 :            : 
    4851                 :            :         /* don't downgrade for 5 and 10 MHz channels, though. */
    4852         [ #  # ]:          0 :         if (chandef.width == NL80211_CHAN_WIDTH_5 ||
    4853                 :            :             chandef.width == NL80211_CHAN_WIDTH_10)
    4854                 :          0 :                 goto out;
    4855                 :            : 
    4856   [ #  #  #  # ]:          0 :         while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) {
    4857                 :          0 :                 ifmgd->flags |= ieee80211_chandef_downgrade(&chandef);
    4858                 :          0 :                 ret = ieee80211_vif_use_channel(sdata, &chandef,
    4859                 :            :                                                 IEEE80211_CHANCTX_SHARED);
    4860                 :            :         }
    4861                 :          0 :  out:
    4862                 :          0 :         mutex_unlock(&local->mtx);
    4863                 :          0 :         return ret;
    4864                 :            : }
    4865                 :            : 
    4866                 :          0 : static bool ieee80211_get_dtim(const struct cfg80211_bss_ies *ies,
    4867                 :            :                                u8 *dtim_count, u8 *dtim_period)
    4868                 :            : {
    4869                 :          0 :         const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len);
    4870                 :          0 :         const u8 *idx_ie = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX, ies->data,
    4871                 :            :                                          ies->len);
    4872                 :          0 :         const struct ieee80211_tim_ie *tim = NULL;
    4873                 :          0 :         const struct ieee80211_bssid_index *idx;
    4874   [ #  #  #  # ]:          0 :         bool valid = tim_ie && tim_ie[1] >= 2;
    4875                 :            : 
    4876         [ #  # ]:          0 :         if (valid)
    4877                 :          0 :                 tim = (void *)(tim_ie + 2);
    4878                 :            : 
    4879         [ #  # ]:          0 :         if (dtim_count)
    4880         [ #  # ]:          0 :                 *dtim_count = valid ? tim->dtim_count : 0;
    4881                 :            : 
    4882         [ #  # ]:          0 :         if (dtim_period)
    4883         [ #  # ]:          0 :                 *dtim_period = valid ? tim->dtim_period : 0;
    4884                 :            : 
    4885                 :            :         /* Check if value is overridden by non-transmitted profile */
    4886   [ #  #  #  # ]:          0 :         if (!idx_ie || idx_ie[1] < 3)
    4887                 :            :                 return valid;
    4888                 :            : 
    4889                 :          0 :         idx = (void *)(idx_ie + 2);
    4890                 :            : 
    4891         [ #  # ]:          0 :         if (dtim_count)
    4892                 :          0 :                 *dtim_count = idx->dtim_count;
    4893                 :            : 
    4894         [ #  # ]:          0 :         if (dtim_period)
    4895                 :          0 :                 *dtim_period = idx->dtim_period;
    4896                 :            : 
    4897                 :            :         return true;
    4898                 :            : }
    4899                 :            : 
    4900                 :          0 : static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
    4901                 :            :                                      struct cfg80211_bss *cbss, bool assoc,
    4902                 :            :                                      bool override)
    4903                 :            : {
    4904                 :          0 :         struct ieee80211_local *local = sdata->local;
    4905                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    4906                 :          0 :         struct ieee80211_bss *bss = (void *)cbss->priv;
    4907                 :          0 :         struct sta_info *new_sta = NULL;
    4908                 :          0 :         struct ieee80211_supported_band *sband;
    4909                 :          0 :         bool have_sta = false;
    4910                 :          0 :         int err;
    4911                 :            : 
    4912                 :          0 :         sband = local->hw.wiphy->bands[cbss->channel->band];
    4913                 :            : 
    4914   [ #  #  #  #  :          0 :         if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data))
             #  #  #  # ]
    4915                 :            :                 return -EINVAL;
    4916                 :            : 
    4917                 :            :         /* If a reconfig is happening, bail out */
    4918         [ #  # ]:          0 :         if (local->in_reconfig)
    4919                 :            :                 return -EBUSY;
    4920                 :            : 
    4921         [ #  # ]:          0 :         if (assoc) {
    4922                 :          0 :                 rcu_read_lock();
    4923                 :          0 :                 have_sta = sta_info_get(sdata, cbss->bssid);
    4924                 :          0 :                 rcu_read_unlock();
    4925                 :            :         }
    4926                 :            : 
    4927         [ #  # ]:          0 :         if (!have_sta) {
    4928                 :          0 :                 new_sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL);
    4929         [ #  # ]:          0 :                 if (!new_sta)
    4930                 :            :                         return -ENOMEM;
    4931                 :            :         }
    4932                 :            : 
    4933                 :            :         /*
    4934                 :            :          * Set up the information for the new channel before setting the
    4935                 :            :          * new channel. We can't - completely race-free - change the basic
    4936                 :            :          * rates bitmap and the channel (sband) that it refers to, but if
    4937                 :            :          * we set it up before we at least avoid calling into the driver's
    4938                 :            :          * bss_info_changed() method with invalid information (since we do
    4939                 :            :          * call that from changing the channel - only for IDLE and perhaps
    4940                 :            :          * some others, but ...).
    4941                 :            :          *
    4942                 :            :          * So to avoid that, just set up all the new information before the
    4943                 :            :          * channel, but tell the driver to apply it only afterwards, since
    4944                 :            :          * it might need the new channel for that.
    4945                 :            :          */
    4946                 :          0 :         if (new_sta) {
    4947                 :          0 :                 u32 rates = 0, basic_rates = 0;
    4948                 :          0 :                 bool have_higher_than_11mbit;
    4949                 :          0 :                 int min_rate = INT_MAX, min_rate_index = -1;
    4950                 :          0 :                 const struct cfg80211_bss_ies *ies;
    4951                 :          0 :                 int shift = ieee80211_vif_get_shift(&sdata->vif);
    4952                 :            : 
    4953                 :          0 :                 ieee80211_get_rates(sband, bss->supp_rates,
    4954                 :          0 :                                     bss->supp_rates_len,
    4955                 :            :                                     &rates, &basic_rates,
    4956                 :            :                                     &have_higher_than_11mbit,
    4957                 :            :                                     &min_rate, &min_rate_index,
    4958                 :            :                                     shift);
    4959                 :            : 
    4960                 :            :                 /*
    4961                 :            :                  * This used to be a workaround for basic rates missing
    4962                 :            :                  * in the association response frame. Now that we no
    4963                 :            :                  * longer use the basic rates from there, it probably
    4964                 :            :                  * doesn't happen any more, but keep the workaround so
    4965                 :            :                  * in case some *other* APs are buggy in different ways
    4966                 :            :                  * we can connect -- with a warning.
    4967                 :            :                  */
    4968   [ #  #  #  # ]:          0 :                 if (!basic_rates && min_rate_index >= 0) {
    4969                 :          0 :                         sdata_info(sdata,
    4970                 :            :                                    "No basic rates, using min rate instead\n");
    4971                 :          0 :                         basic_rates = BIT(min_rate_index);
    4972                 :            :                 }
    4973                 :            : 
    4974         [ #  # ]:          0 :                 if (rates)
    4975                 :          0 :                         new_sta->sta.supp_rates[cbss->channel->band] = rates;
    4976                 :            :                 else
    4977                 :          0 :                         sdata_info(sdata,
    4978                 :            :                                    "No rates found, keeping mandatory only\n");
    4979                 :            : 
    4980                 :          0 :                 sdata->vif.bss_conf.basic_rates = basic_rates;
    4981                 :            : 
    4982                 :            :                 /* cf. IEEE 802.11 9.2.12 */
    4983   [ #  #  #  # ]:          0 :                 if (cbss->channel->band == NL80211_BAND_2GHZ &&
    4984                 :            :                     have_higher_than_11mbit)
    4985                 :          0 :                         sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
    4986                 :            :                 else
    4987                 :          0 :                         sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
    4988                 :            : 
    4989                 :          0 :                 memcpy(ifmgd->bssid, cbss->bssid, ETH_ALEN);
    4990                 :            : 
    4991                 :            :                 /* set timing information */
    4992                 :          0 :                 sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
    4993                 :          0 :                 rcu_read_lock();
    4994         [ #  # ]:          0 :                 ies = rcu_dereference(cbss->beacon_ies);
    4995         [ #  # ]:          0 :                 if (ies) {
    4996                 :          0 :                         sdata->vif.bss_conf.sync_tsf = ies->tsf;
    4997                 :          0 :                         sdata->vif.bss_conf.sync_device_ts =
    4998                 :          0 :                                 bss->device_ts_beacon;
    4999                 :            : 
    5000                 :          0 :                         ieee80211_get_dtim(ies,
    5001                 :            :                                            &sdata->vif.bss_conf.sync_dtim_count,
    5002                 :            :                                            NULL);
    5003         [ #  # ]:          0 :                 } else if (!ieee80211_hw_check(&sdata->local->hw,
    5004                 :            :                                                TIMING_BEACON_ONLY)) {
    5005                 :          0 :                         ies = rcu_dereference(cbss->proberesp_ies);
    5006                 :            :                         /* must be non-NULL since beacon IEs were NULL */
    5007                 :          0 :                         sdata->vif.bss_conf.sync_tsf = ies->tsf;
    5008                 :          0 :                         sdata->vif.bss_conf.sync_device_ts =
    5009                 :          0 :                                 bss->device_ts_presp;
    5010                 :          0 :                         sdata->vif.bss_conf.sync_dtim_count = 0;
    5011                 :            :                 } else {
    5012                 :          0 :                         sdata->vif.bss_conf.sync_tsf = 0;
    5013                 :          0 :                         sdata->vif.bss_conf.sync_device_ts = 0;
    5014                 :          0 :                         sdata->vif.bss_conf.sync_dtim_count = 0;
    5015                 :            :                 }
    5016                 :          0 :                 rcu_read_unlock();
    5017                 :            :         }
    5018                 :            : 
    5019         [ #  # ]:          0 :         if (new_sta || override) {
    5020                 :          0 :                 err = ieee80211_prep_channel(sdata, cbss);
    5021         [ #  # ]:          0 :                 if (err) {
    5022         [ #  # ]:          0 :                         if (new_sta)
    5023                 :          0 :                                 sta_info_free(local, new_sta);
    5024                 :          0 :                         return -EINVAL;
    5025                 :            :                 }
    5026                 :            :         }
    5027                 :            : 
    5028         [ #  # ]:          0 :         if (new_sta) {
    5029                 :            :                 /*
    5030                 :            :                  * tell driver about BSSID, basic rates and timing
    5031                 :            :                  * this was set up above, before setting the channel
    5032                 :            :                  */
    5033                 :          0 :                 ieee80211_bss_info_change_notify(sdata,
    5034                 :            :                         BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES |
    5035                 :            :                         BSS_CHANGED_BEACON_INT);
    5036                 :            : 
    5037         [ #  # ]:          0 :                 if (assoc)
    5038                 :          0 :                         sta_info_pre_move_state(new_sta, IEEE80211_STA_AUTH);
    5039                 :            : 
    5040                 :          0 :                 err = sta_info_insert(new_sta);
    5041                 :          0 :                 new_sta = NULL;
    5042         [ #  # ]:          0 :                 if (err) {
    5043                 :          0 :                         sdata_info(sdata,
    5044                 :            :                                    "failed to insert STA entry for the AP (error %d)\n",
    5045                 :            :                                    err);
    5046                 :          0 :                         return err;
    5047                 :            :                 }
    5048                 :            :         } else
    5049         [ #  # ]:          0 :                 WARN_ON_ONCE(!ether_addr_equal(ifmgd->bssid, cbss->bssid));
    5050                 :            : 
    5051                 :            :         /* Cancel scan to ensure that nothing interferes with connection */
    5052         [ #  # ]:          0 :         if (local->scanning)
    5053                 :          0 :                 ieee80211_scan_cancel(local);
    5054                 :            : 
    5055                 :            :         return 0;
    5056                 :            : }
    5057                 :            : 
    5058                 :            : /* config hooks */
    5059                 :          0 : int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
    5060                 :            :                        struct cfg80211_auth_request *req)
    5061                 :            : {
    5062                 :          0 :         struct ieee80211_local *local = sdata->local;
    5063                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    5064                 :          0 :         struct ieee80211_mgd_auth_data *auth_data;
    5065                 :          0 :         u16 auth_alg;
    5066                 :          0 :         int err;
    5067                 :          0 :         bool cont_auth;
    5068                 :            : 
    5069                 :            :         /* prepare auth data structure */
    5070                 :            : 
    5071         [ #  # ]:          0 :         switch (req->auth_type) {
    5072                 :            :         case NL80211_AUTHTYPE_OPEN_SYSTEM:
    5073                 :            :                 auth_alg = WLAN_AUTH_OPEN;
    5074                 :            :                 break;
    5075                 :            :         case NL80211_AUTHTYPE_SHARED_KEY:
    5076                 :            :                 if (fips_enabled)
    5077                 :            :                         return -EOPNOTSUPP;
    5078                 :            :                 auth_alg = WLAN_AUTH_SHARED_KEY;
    5079                 :            :                 break;
    5080                 :            :         case NL80211_AUTHTYPE_FT:
    5081                 :            :                 auth_alg = WLAN_AUTH_FT;
    5082                 :            :                 break;
    5083                 :            :         case NL80211_AUTHTYPE_NETWORK_EAP:
    5084                 :            :                 auth_alg = WLAN_AUTH_LEAP;
    5085                 :            :                 break;
    5086                 :            :         case NL80211_AUTHTYPE_SAE:
    5087                 :            :                 auth_alg = WLAN_AUTH_SAE;
    5088                 :            :                 break;
    5089                 :            :         case NL80211_AUTHTYPE_FILS_SK:
    5090                 :            :                 auth_alg = WLAN_AUTH_FILS_SK;
    5091                 :            :                 break;
    5092                 :            :         case NL80211_AUTHTYPE_FILS_SK_PFS:
    5093                 :            :                 auth_alg = WLAN_AUTH_FILS_SK_PFS;
    5094                 :            :                 break;
    5095                 :            :         case NL80211_AUTHTYPE_FILS_PK:
    5096                 :            :                 auth_alg = WLAN_AUTH_FILS_PK;
    5097                 :            :                 break;
    5098                 :            :         default:
    5099                 :            :                 return -EOPNOTSUPP;
    5100                 :            :         }
    5101                 :            : 
    5102         [ #  # ]:          0 :         if (ifmgd->assoc_data)
    5103                 :            :                 return -EBUSY;
    5104                 :            : 
    5105                 :          0 :         auth_data = kzalloc(sizeof(*auth_data) + req->auth_data_len +
    5106                 :          0 :                             req->ie_len, GFP_KERNEL);
    5107         [ #  # ]:          0 :         if (!auth_data)
    5108                 :            :                 return -ENOMEM;
    5109                 :            : 
    5110                 :          0 :         auth_data->bss = req->bss;
    5111                 :            : 
    5112         [ #  # ]:          0 :         if (req->auth_data_len >= 4) {
    5113         [ #  # ]:          0 :                 if (req->auth_type == NL80211_AUTHTYPE_SAE) {
    5114                 :          0 :                         __le16 *pos = (__le16 *) req->auth_data;
    5115                 :            : 
    5116                 :          0 :                         auth_data->sae_trans = le16_to_cpu(pos[0]);
    5117                 :          0 :                         auth_data->sae_status = le16_to_cpu(pos[1]);
    5118                 :            :                 }
    5119                 :          0 :                 memcpy(auth_data->data, req->auth_data + 4,
    5120                 :          0 :                        req->auth_data_len - 4);
    5121                 :          0 :                 auth_data->data_len += req->auth_data_len - 4;
    5122                 :            :         }
    5123                 :            : 
    5124                 :            :         /* Check if continuing authentication or trying to authenticate with the
    5125                 :            :          * same BSS that we were in the process of authenticating with and avoid
    5126                 :            :          * removal and re-addition of the STA entry in
    5127                 :            :          * ieee80211_prep_connection().
    5128                 :            :          */
    5129   [ #  #  #  # ]:          0 :         cont_auth = ifmgd->auth_data && req->bss == ifmgd->auth_data->bss;
    5130                 :            : 
    5131   [ #  #  #  # ]:          0 :         if (req->ie && req->ie_len) {
    5132                 :          0 :                 memcpy(&auth_data->data[auth_data->data_len],
    5133                 :            :                        req->ie, req->ie_len);
    5134                 :          0 :                 auth_data->data_len += req->ie_len;
    5135                 :            :         }
    5136                 :            : 
    5137   [ #  #  #  # ]:          0 :         if (req->key && req->key_len) {
    5138                 :          0 :                 auth_data->key_len = req->key_len;
    5139                 :          0 :                 auth_data->key_idx = req->key_idx;
    5140                 :          0 :                 memcpy(auth_data->key, req->key, req->key_len);
    5141                 :            :         }
    5142                 :            : 
    5143                 :          0 :         auth_data->algorithm = auth_alg;
    5144                 :            : 
    5145                 :            :         /* try to authenticate/probe */
    5146                 :            : 
    5147         [ #  # ]:          0 :         if (ifmgd->auth_data) {
    5148   [ #  #  #  # ]:          0 :                 if (cont_auth && req->auth_type == NL80211_AUTHTYPE_SAE) {
    5149                 :          0 :                         auth_data->peer_confirmed =
    5150                 :          0 :                                 ifmgd->auth_data->peer_confirmed;
    5151                 :            :                 }
    5152                 :          0 :                 ieee80211_destroy_auth_data(sdata, cont_auth);
    5153                 :            :         }
    5154                 :            : 
    5155                 :            :         /* prep auth_data so we don't go into idle on disassoc */
    5156                 :          0 :         ifmgd->auth_data = auth_data;
    5157                 :            : 
    5158                 :            :         /* If this is continuation of an ongoing SAE authentication exchange
    5159                 :            :          * (i.e., request to send SAE Confirm) and the peer has already
    5160                 :            :          * confirmed, mark authentication completed since we are about to send
    5161                 :            :          * out SAE Confirm.
    5162                 :            :          */
    5163   [ #  #  #  # ]:          0 :         if (cont_auth && req->auth_type == NL80211_AUTHTYPE_SAE &&
    5164   [ #  #  #  # ]:          0 :             auth_data->peer_confirmed && auth_data->sae_trans == 2)
    5165                 :          0 :                 ieee80211_mark_sta_auth(sdata, req->bss->bssid);
    5166                 :            : 
    5167         [ #  # ]:          0 :         if (ifmgd->associated) {
    5168                 :          0 :                 u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
    5169                 :            : 
    5170                 :          0 :                 sdata_info(sdata,
    5171                 :            :                            "disconnect from AP %pM for new auth to %pM\n",
    5172                 :            :                            ifmgd->associated->bssid, req->bss->bssid);
    5173                 :          0 :                 ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
    5174                 :            :                                        WLAN_REASON_UNSPECIFIED,
    5175                 :            :                                        false, frame_buf);
    5176                 :            : 
    5177                 :          0 :                 ieee80211_report_disconnect(sdata, frame_buf,
    5178                 :            :                                             sizeof(frame_buf), true,
    5179                 :            :                                             WLAN_REASON_UNSPECIFIED);
    5180                 :            :         }
    5181                 :            : 
    5182                 :          0 :         sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
    5183                 :            : 
    5184                 :          0 :         err = ieee80211_prep_connection(sdata, req->bss, cont_auth, false);
    5185         [ #  # ]:          0 :         if (err)
    5186                 :          0 :                 goto err_clear;
    5187                 :            : 
    5188                 :          0 :         err = ieee80211_auth(sdata);
    5189         [ #  # ]:          0 :         if (err) {
    5190                 :          0 :                 sta_info_destroy_addr(sdata, req->bss->bssid);
    5191                 :          0 :                 goto err_clear;
    5192                 :            :         }
    5193                 :            : 
    5194                 :            :         /* hold our own reference */
    5195                 :          0 :         cfg80211_ref_bss(local->hw.wiphy, auth_data->bss);
    5196                 :          0 :         return 0;
    5197                 :            : 
    5198                 :          0 :  err_clear:
    5199                 :          0 :         eth_zero_addr(ifmgd->bssid);
    5200                 :          0 :         ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
    5201                 :          0 :         ifmgd->auth_data = NULL;
    5202                 :          0 :         mutex_lock(&sdata->local->mtx);
    5203                 :          0 :         ieee80211_vif_release_channel(sdata);
    5204                 :          0 :         mutex_unlock(&sdata->local->mtx);
    5205                 :          0 :         kfree(auth_data);
    5206                 :          0 :         return err;
    5207                 :            : }
    5208                 :            : 
    5209                 :          0 : int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
    5210                 :            :                         struct cfg80211_assoc_request *req)
    5211                 :            : {
    5212                 :          0 :         struct ieee80211_local *local = sdata->local;
    5213                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    5214                 :          0 :         struct ieee80211_bss *bss = (void *)req->bss->priv;
    5215                 :          0 :         struct ieee80211_mgd_assoc_data *assoc_data;
    5216                 :          0 :         const struct cfg80211_bss_ies *beacon_ies;
    5217                 :          0 :         struct ieee80211_supported_band *sband;
    5218                 :          0 :         const u8 *ssidie, *ht_ie, *vht_ie;
    5219                 :          0 :         int i, err;
    5220                 :          0 :         bool override = false;
    5221                 :            : 
    5222                 :          0 :         assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL);
    5223         [ #  # ]:          0 :         if (!assoc_data)
    5224                 :            :                 return -ENOMEM;
    5225                 :            : 
    5226                 :          0 :         rcu_read_lock();
    5227                 :          0 :         ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
    5228   [ #  #  #  # ]:          0 :         if (!ssidie || ssidie[1] > sizeof(assoc_data->ssid)) {
    5229                 :          0 :                 rcu_read_unlock();
    5230                 :          0 :                 kfree(assoc_data);
    5231                 :          0 :                 return -EINVAL;
    5232                 :            :         }
    5233                 :          0 :         memcpy(assoc_data->ssid, ssidie + 2, ssidie[1]);
    5234                 :          0 :         assoc_data->ssid_len = ssidie[1];
    5235                 :          0 :         rcu_read_unlock();
    5236                 :            : 
    5237         [ #  # ]:          0 :         if (ifmgd->associated) {
    5238                 :          0 :                 u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
    5239                 :            : 
    5240                 :          0 :                 sdata_info(sdata,
    5241                 :            :                            "disconnect from AP %pM for new assoc to %pM\n",
    5242                 :            :                            ifmgd->associated->bssid, req->bss->bssid);
    5243                 :          0 :                 ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
    5244                 :            :                                        WLAN_REASON_UNSPECIFIED,
    5245                 :            :                                        false, frame_buf);
    5246                 :            : 
    5247                 :          0 :                 ieee80211_report_disconnect(sdata, frame_buf,
    5248                 :            :                                             sizeof(frame_buf), true,
    5249                 :            :                                             WLAN_REASON_UNSPECIFIED);
    5250                 :            :         }
    5251                 :            : 
    5252   [ #  #  #  # ]:          0 :         if (ifmgd->auth_data && !ifmgd->auth_data->done) {
    5253                 :          0 :                 err = -EBUSY;
    5254                 :          0 :                 goto err_free;
    5255                 :            :         }
    5256                 :            : 
    5257         [ #  # ]:          0 :         if (ifmgd->assoc_data) {
    5258                 :          0 :                 err = -EBUSY;
    5259                 :          0 :                 goto err_free;
    5260                 :            :         }
    5261                 :            : 
    5262         [ #  # ]:          0 :         if (ifmgd->auth_data) {
    5263                 :          0 :                 bool match;
    5264                 :            : 
    5265                 :            :                 /* keep sta info, bssid if matching */
    5266                 :          0 :                 match = ether_addr_equal(ifmgd->bssid, req->bss->bssid);
    5267                 :          0 :                 ieee80211_destroy_auth_data(sdata, match);
    5268                 :            :         }
    5269                 :            : 
    5270                 :            :         /* prepare assoc data */
    5271                 :            : 
    5272                 :          0 :         ifmgd->beacon_crc_valid = false;
    5273                 :            : 
    5274         [ #  # ]:          0 :         assoc_data->wmm = bss->wmm_used &&
    5275         [ #  # ]:          0 :                           (local->hw.queues >= IEEE80211_NUM_ACS);
    5276                 :            : 
    5277                 :            :         /*
    5278                 :            :          * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode.
    5279                 :            :          * We still associate in non-HT mode (11a/b/g) if any one of these
    5280                 :            :          * ciphers is configured as pairwise.
    5281                 :            :          * We can set this to true for non-11n hardware, that'll be checked
    5282                 :            :          * separately along with the peer capabilities.
    5283                 :            :          */
    5284         [ #  # ]:          0 :         for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) {
    5285                 :          0 :                 if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
    5286         [ #  # ]:          0 :                     req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
    5287                 :            :                     req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) {
    5288                 :          0 :                         ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
    5289                 :          0 :                         ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
    5290                 :          0 :                         ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
    5291                 :          0 :                         netdev_info(sdata->dev,
    5292                 :            :                                     "disabling HT/VHT/HE due to WEP/TKIP use\n");
    5293                 :            :                 }
    5294                 :            :         }
    5295                 :            : 
    5296                 :            :         /* Also disable HT if we don't support it or the AP doesn't use WMM */
    5297                 :          0 :         sband = local->hw.wiphy->bands[req->bss->channel->band];
    5298         [ #  # ]:          0 :         if (!sband->ht_cap.ht_supported ||
    5299   [ #  #  #  # ]:          0 :             local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used ||
    5300         [ #  # ]:          0 :             ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
    5301                 :          0 :                 ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
    5302         [ #  # ]:          0 :                 if (!bss->wmm_used &&
    5303         [ #  # ]:          0 :                     !(ifmgd->flags & IEEE80211_STA_DISABLE_WMM))
    5304                 :          0 :                         netdev_info(sdata->dev,
    5305                 :            :                                     "disabling HT as WMM/QoS is not supported by the AP\n");
    5306                 :            :         }
    5307                 :            : 
    5308                 :            :         /* disable VHT if we don't support it or the AP doesn't use WMM */
    5309         [ #  # ]:          0 :         if (!sband->vht_cap.vht_supported ||
    5310   [ #  #  #  # ]:          0 :             local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used ||
    5311         [ #  # ]:          0 :             ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
    5312                 :          0 :                 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
    5313         [ #  # ]:          0 :                 if (!bss->wmm_used &&
    5314         [ #  # ]:          0 :                     !(ifmgd->flags & IEEE80211_STA_DISABLE_WMM))
    5315                 :          0 :                         netdev_info(sdata->dev,
    5316                 :            :                                     "disabling VHT as WMM/QoS is not supported by the AP\n");
    5317                 :            :         }
    5318                 :            : 
    5319                 :          0 :         memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
    5320                 :          0 :         memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask,
    5321                 :            :                sizeof(ifmgd->ht_capa_mask));
    5322                 :            : 
    5323                 :          0 :         memcpy(&ifmgd->vht_capa, &req->vht_capa, sizeof(ifmgd->vht_capa));
    5324                 :          0 :         memcpy(&ifmgd->vht_capa_mask, &req->vht_capa_mask,
    5325                 :            :                sizeof(ifmgd->vht_capa_mask));
    5326                 :            : 
    5327   [ #  #  #  # ]:          0 :         if (req->ie && req->ie_len) {
    5328                 :          0 :                 memcpy(assoc_data->ie, req->ie, req->ie_len);
    5329                 :          0 :                 assoc_data->ie_len = req->ie_len;
    5330                 :            :         }
    5331                 :            : 
    5332         [ #  # ]:          0 :         if (req->fils_kek) {
    5333                 :            :                 /* should already be checked in cfg80211 - so warn */
    5334   [ #  #  #  # ]:          0 :                 if (WARN_ON(req->fils_kek_len > FILS_MAX_KEK_LEN)) {
    5335                 :          0 :                         err = -EINVAL;
    5336                 :          0 :                         goto err_free;
    5337                 :            :                 }
    5338                 :          0 :                 memcpy(assoc_data->fils_kek, req->fils_kek,
    5339                 :            :                        req->fils_kek_len);
    5340                 :          0 :                 assoc_data->fils_kek_len = req->fils_kek_len;
    5341                 :            :         }
    5342                 :            : 
    5343         [ #  # ]:          0 :         if (req->fils_nonces)
    5344                 :          0 :                 memcpy(assoc_data->fils_nonces, req->fils_nonces,
    5345                 :            :                        2 * FILS_NONCE_LEN);
    5346                 :            : 
    5347                 :          0 :         assoc_data->bss = req->bss;
    5348                 :            : 
    5349         [ #  # ]:          0 :         if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) {
    5350         [ #  # ]:          0 :                 if (ifmgd->powersave)
    5351                 :          0 :                         sdata->smps_mode = IEEE80211_SMPS_DYNAMIC;
    5352                 :            :                 else
    5353                 :          0 :                         sdata->smps_mode = IEEE80211_SMPS_OFF;
    5354                 :            :         } else
    5355                 :          0 :                 sdata->smps_mode = ifmgd->req_smps;
    5356                 :            : 
    5357                 :          0 :         assoc_data->capability = req->bss->capability;
    5358                 :          0 :         assoc_data->supp_rates = bss->supp_rates;
    5359                 :          0 :         assoc_data->supp_rates_len = bss->supp_rates_len;
    5360                 :            : 
    5361                 :          0 :         rcu_read_lock();
    5362                 :          0 :         ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
    5363   [ #  #  #  # ]:          0 :         if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation))
    5364                 :          0 :                 assoc_data->ap_ht_param =
    5365                 :          0 :                         ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param;
    5366                 :            :         else
    5367                 :          0 :                 ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
    5368                 :          0 :         vht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_VHT_CAPABILITY);
    5369   [ #  #  #  # ]:          0 :         if (vht_ie && vht_ie[1] >= sizeof(struct ieee80211_vht_cap))
    5370                 :          0 :                 memcpy(&assoc_data->ap_vht_cap, vht_ie + 2,
    5371                 :            :                        sizeof(struct ieee80211_vht_cap));
    5372                 :            :         else
    5373                 :          0 :                 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
    5374                 :          0 :         rcu_read_unlock();
    5375                 :            : 
    5376   [ #  #  #  #  :          0 :         if (WARN((sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_UAPSD) &&
             #  #  #  # ]
    5377                 :            :                  ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK),
    5378                 :            :              "U-APSD not supported with HW_PS_NULLFUNC_STACK\n"))
    5379                 :          0 :                 sdata->vif.driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;
    5380                 :            : 
    5381   [ #  #  #  # ]:          0 :         if (bss->wmm_used && bss->uapsd_supported &&
    5382         [ #  # ]:          0 :             (sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_UAPSD)) {
    5383                 :          0 :                 assoc_data->uapsd = true;
    5384                 :          0 :                 ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED;
    5385                 :            :         } else {
    5386                 :          0 :                 assoc_data->uapsd = false;
    5387                 :          0 :                 ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED;
    5388                 :            :         }
    5389                 :            : 
    5390         [ #  # ]:          0 :         if (req->prev_bssid)
    5391                 :          0 :                 memcpy(assoc_data->prev_bssid, req->prev_bssid, ETH_ALEN);
    5392                 :            : 
    5393         [ #  # ]:          0 :         if (req->use_mfp) {
    5394                 :          0 :                 ifmgd->mfp = IEEE80211_MFP_REQUIRED;
    5395                 :          0 :                 ifmgd->flags |= IEEE80211_STA_MFP_ENABLED;
    5396                 :            :         } else {
    5397                 :          0 :                 ifmgd->mfp = IEEE80211_MFP_DISABLED;
    5398                 :          0 :                 ifmgd->flags &= ~IEEE80211_STA_MFP_ENABLED;
    5399                 :            :         }
    5400                 :            : 
    5401         [ #  # ]:          0 :         if (req->flags & ASSOC_REQ_USE_RRM)
    5402                 :          0 :                 ifmgd->flags |= IEEE80211_STA_ENABLE_RRM;
    5403                 :            :         else
    5404                 :          0 :                 ifmgd->flags &= ~IEEE80211_STA_ENABLE_RRM;
    5405                 :            : 
    5406         [ #  # ]:          0 :         if (req->crypto.control_port)
    5407                 :          0 :                 ifmgd->flags |= IEEE80211_STA_CONTROL_PORT;
    5408                 :            :         else
    5409                 :          0 :                 ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT;
    5410                 :            : 
    5411                 :          0 :         sdata->control_port_protocol = req->crypto.control_port_ethertype;
    5412                 :          0 :         sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt;
    5413                 :          0 :         sdata->control_port_over_nl80211 =
    5414                 :          0 :                                         req->crypto.control_port_over_nl80211;
    5415                 :          0 :         sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto,
    5416                 :            :                                                         sdata->vif.type);
    5417                 :            : 
    5418                 :            :         /* kick off associate process */
    5419                 :            : 
    5420                 :          0 :         ifmgd->assoc_data = assoc_data;
    5421                 :          0 :         ifmgd->dtim_period = 0;
    5422                 :          0 :         ifmgd->have_beacon = false;
    5423                 :            : 
    5424                 :            :         /* override HT/VHT configuration only if the AP and we support it */
    5425         [ #  # ]:          0 :         if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
    5426                 :          0 :                 struct ieee80211_sta_ht_cap sta_ht_cap;
    5427                 :            : 
    5428                 :          0 :                 if (req->flags & ASSOC_REQ_DISABLE_HT)
    5429                 :            :                         override = true;
    5430                 :            : 
    5431                 :          0 :                 memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
    5432                 :          0 :                 ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
    5433                 :            : 
    5434                 :            :                 /* check for 40 MHz disable override */
    5435         [ #  # ]:          0 :                 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ) &&
    5436         [ #  # ]:          0 :                     sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
    5437         [ #  # ]:          0 :                     !(sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
    5438                 :          0 :                         override = true;
    5439                 :            : 
    5440         [ #  # ]:          0 :                 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
    5441         [ #  # ]:          0 :                     req->flags & ASSOC_REQ_DISABLE_VHT)
    5442                 :          0 :                         override = true;
    5443                 :            :         }
    5444                 :            : 
    5445         [ #  # ]:          0 :         if (req->flags & ASSOC_REQ_DISABLE_HT) {
    5446                 :          0 :                 ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
    5447                 :          0 :                 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
    5448                 :            :         }
    5449                 :            : 
    5450         [ #  # ]:          0 :         if (req->flags & ASSOC_REQ_DISABLE_VHT)
    5451                 :          0 :                 ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
    5452                 :            : 
    5453                 :          0 :         err = ieee80211_prep_connection(sdata, req->bss, true, override);
    5454         [ #  # ]:          0 :         if (err)
    5455                 :          0 :                 goto err_clear;
    5456                 :            : 
    5457                 :          0 :         rcu_read_lock();
    5458                 :          0 :         beacon_ies = rcu_dereference(req->bss->beacon_ies);
    5459                 :            : 
    5460   [ #  #  #  # ]:          0 :         if (ieee80211_hw_check(&sdata->local->hw, NEED_DTIM_BEFORE_ASSOC) &&
    5461                 :            :             !beacon_ies) {
    5462                 :            :                 /*
    5463                 :            :                  * Wait up to one beacon interval ...
    5464                 :            :                  * should this be more if we miss one?
    5465                 :            :                  */
    5466                 :          0 :                 sdata_info(sdata, "waiting for beacon from %pM\n",
    5467                 :            :                            ifmgd->bssid);
    5468         [ #  # ]:          0 :                 assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval);
    5469                 :          0 :                 assoc_data->timeout_started = true;
    5470                 :          0 :                 assoc_data->need_beacon = true;
    5471         [ #  # ]:          0 :         } else if (beacon_ies) {
    5472                 :          0 :                 const u8 *ie;
    5473                 :          0 :                 u8 dtim_count = 0;
    5474                 :            : 
    5475                 :          0 :                 ieee80211_get_dtim(beacon_ies, &dtim_count,
    5476                 :            :                                    &ifmgd->dtim_period);
    5477                 :            : 
    5478                 :          0 :                 ifmgd->have_beacon = true;
    5479                 :          0 :                 assoc_data->timeout = jiffies;
    5480                 :          0 :                 assoc_data->timeout_started = true;
    5481                 :            : 
    5482         [ #  # ]:          0 :                 if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) {
    5483                 :          0 :                         sdata->vif.bss_conf.sync_tsf = beacon_ies->tsf;
    5484                 :          0 :                         sdata->vif.bss_conf.sync_device_ts =
    5485                 :          0 :                                 bss->device_ts_beacon;
    5486                 :          0 :                         sdata->vif.bss_conf.sync_dtim_count = dtim_count;
    5487                 :            :                 }
    5488                 :            : 
    5489                 :          0 :                 ie = cfg80211_find_ext_ie(WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION,
    5490                 :          0 :                                           beacon_ies->data, beacon_ies->len);
    5491   [ #  #  #  # ]:          0 :                 if (ie && ie[1] >= 3)
    5492                 :          0 :                         sdata->vif.bss_conf.profile_periodicity = ie[4];
    5493                 :            : 
    5494                 :          0 :                 ie = cfg80211_find_ie(WLAN_EID_EXT_CAPABILITY,
    5495                 :            :                                       beacon_ies->data, beacon_ies->len);
    5496   [ #  #  #  # ]:          0 :                 if (ie && ie[1] >= 11 &&
    5497         [ #  # ]:          0 :                     (ie[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
    5498                 :          0 :                         sdata->vif.bss_conf.ema_ap = true;
    5499                 :            :         } else {
    5500                 :          0 :                 assoc_data->timeout = jiffies;
    5501                 :          0 :                 assoc_data->timeout_started = true;
    5502                 :            :         }
    5503                 :          0 :         rcu_read_unlock();
    5504                 :            : 
    5505         [ #  # ]:          0 :         run_again(sdata, assoc_data->timeout);
    5506                 :            : 
    5507         [ #  # ]:          0 :         if (bss->corrupt_data) {
    5508                 :          0 :                 char *corrupt_type = "data";
    5509         [ #  # ]:          0 :                 if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_BEACON) {
    5510         [ #  # ]:          0 :                         if (bss->corrupt_data &
    5511                 :            :                                         IEEE80211_BSS_CORRUPT_PROBE_RESP)
    5512                 :            :                                 corrupt_type = "beacon and probe response";
    5513                 :            :                         else
    5514                 :          0 :                                 corrupt_type = "beacon";
    5515         [ #  # ]:          0 :                 } else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP)
    5516                 :          0 :                         corrupt_type = "probe response";
    5517                 :          0 :                 sdata_info(sdata, "associating with AP with corrupt %s\n",
    5518                 :            :                            corrupt_type);
    5519                 :            :         }
    5520                 :            : 
    5521                 :            :         return 0;
    5522                 :            :  err_clear:
    5523                 :          0 :         eth_zero_addr(ifmgd->bssid);
    5524                 :          0 :         ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
    5525                 :          0 :         ifmgd->assoc_data = NULL;
    5526                 :          0 :  err_free:
    5527                 :          0 :         kfree(assoc_data);
    5528                 :          0 :         return err;
    5529                 :            : }
    5530                 :            : 
    5531                 :          0 : int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
    5532                 :            :                          struct cfg80211_deauth_request *req)
    5533                 :            : {
    5534                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    5535                 :          0 :         u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
    5536                 :          0 :         bool tx = !req->local_state_change;
    5537                 :            : 
    5538   [ #  #  #  # ]:          0 :         if (ifmgd->auth_data &&
    5539         [ #  # ]:          0 :             ether_addr_equal(ifmgd->auth_data->bss->bssid, req->bssid)) {
    5540         [ #  # ]:          0 :                 sdata_info(sdata,
    5541                 :            :                            "aborting authentication with %pM by local choice (Reason: %u=%s)\n",
    5542                 :            :                            req->bssid, req->reason_code,
    5543                 :            :                            ieee80211_get_reason_code_string(req->reason_code));
    5544                 :            : 
    5545                 :          0 :                 drv_mgd_prepare_tx(sdata->local, sdata, 0);
    5546                 :          0 :                 ieee80211_send_deauth_disassoc(sdata, req->bssid, req->bssid,
    5547                 :            :                                                IEEE80211_STYPE_DEAUTH,
    5548                 :          0 :                                                req->reason_code, tx,
    5549                 :            :                                                frame_buf);
    5550                 :          0 :                 ieee80211_destroy_auth_data(sdata, false);
    5551                 :          0 :                 ieee80211_report_disconnect(sdata, frame_buf,
    5552                 :            :                                             sizeof(frame_buf), true,
    5553                 :          0 :                                             req->reason_code);
    5554                 :            : 
    5555                 :          0 :                 return 0;
    5556                 :            :         }
    5557                 :            : 
    5558   [ #  #  #  # ]:          0 :         if (ifmgd->assoc_data &&
    5559         [ #  # ]:          0 :             ether_addr_equal(ifmgd->assoc_data->bss->bssid, req->bssid)) {
    5560         [ #  # ]:          0 :                 sdata_info(sdata,
    5561                 :            :                            "aborting association with %pM by local choice (Reason: %u=%s)\n",
    5562                 :            :                            req->bssid, req->reason_code,
    5563                 :            :                            ieee80211_get_reason_code_string(req->reason_code));
    5564                 :            : 
    5565                 :          0 :                 drv_mgd_prepare_tx(sdata->local, sdata, 0);
    5566                 :          0 :                 ieee80211_send_deauth_disassoc(sdata, req->bssid, req->bssid,
    5567                 :            :                                                IEEE80211_STYPE_DEAUTH,
    5568                 :          0 :                                                req->reason_code, tx,
    5569                 :            :                                                frame_buf);
    5570                 :          0 :                 ieee80211_destroy_assoc_data(sdata, false, true);
    5571                 :          0 :                 ieee80211_report_disconnect(sdata, frame_buf,
    5572                 :            :                                             sizeof(frame_buf), true,
    5573                 :          0 :                                             req->reason_code);
    5574                 :          0 :                 return 0;
    5575                 :            :         }
    5576                 :            : 
    5577   [ #  #  #  # ]:          0 :         if (ifmgd->associated &&
    5578         [ #  # ]:          0 :             ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
    5579         [ #  # ]:          0 :                 sdata_info(sdata,
    5580                 :            :                            "deauthenticating from %pM by local choice (Reason: %u=%s)\n",
    5581                 :            :                            req->bssid, req->reason_code,
    5582                 :            :                            ieee80211_get_reason_code_string(req->reason_code));
    5583                 :            : 
    5584                 :          0 :                 ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
    5585                 :          0 :                                        req->reason_code, tx, frame_buf);
    5586                 :          0 :                 ieee80211_report_disconnect(sdata, frame_buf,
    5587                 :            :                                             sizeof(frame_buf), true,
    5588                 :          0 :                                             req->reason_code);
    5589                 :          0 :                 return 0;
    5590                 :            :         }
    5591                 :            : 
    5592                 :            :         return -ENOTCONN;
    5593                 :            : }
    5594                 :            : 
    5595                 :          0 : int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
    5596                 :            :                            struct cfg80211_disassoc_request *req)
    5597                 :            : {
    5598                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    5599                 :          0 :         u8 bssid[ETH_ALEN];
    5600                 :          0 :         u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
    5601                 :            : 
    5602                 :            :         /*
    5603                 :            :          * cfg80211 should catch this ... but it's racy since
    5604                 :            :          * we can receive a disassoc frame, process it, hand it
    5605                 :            :          * to cfg80211 while that's in a locked section already
    5606                 :            :          * trying to tell us that the user wants to disconnect.
    5607                 :            :          */
    5608         [ #  # ]:          0 :         if (ifmgd->associated != req->bss)
    5609                 :            :                 return -ENOLINK;
    5610                 :            : 
    5611         [ #  # ]:          0 :         sdata_info(sdata,
    5612                 :            :                    "disassociating from %pM by local choice (Reason: %u=%s)\n",
    5613                 :            :                    req->bss->bssid, req->reason_code, ieee80211_get_reason_code_string(req->reason_code));
    5614                 :            : 
    5615                 :          0 :         memcpy(bssid, req->bss->bssid, ETH_ALEN);
    5616                 :          0 :         ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC,
    5617                 :          0 :                                req->reason_code, !req->local_state_change,
    5618                 :          0 :                                frame_buf);
    5619                 :            : 
    5620                 :          0 :         ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true,
    5621                 :          0 :                                     req->reason_code);
    5622                 :            : 
    5623                 :          0 :         return 0;
    5624                 :            : }
    5625                 :            : 
    5626                 :          0 : void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
    5627                 :            : {
    5628                 :          0 :         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
    5629                 :            : 
    5630                 :            :         /*
    5631                 :            :          * Make sure some work items will not run after this,
    5632                 :            :          * they will not do anything but might not have been
    5633                 :            :          * cancelled when disconnecting.
    5634                 :            :          */
    5635                 :          0 :         cancel_work_sync(&ifmgd->monitor_work);
    5636                 :          0 :         cancel_work_sync(&ifmgd->beacon_connection_loss_work);
    5637                 :          0 :         cancel_work_sync(&ifmgd->request_smps_work);
    5638                 :          0 :         cancel_work_sync(&ifmgd->csa_connection_drop_work);
    5639                 :          0 :         cancel_work_sync(&ifmgd->chswitch_work);
    5640                 :          0 :         cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work);
    5641                 :            : 
    5642                 :          0 :         sdata_lock(sdata);
    5643         [ #  # ]:          0 :         if (ifmgd->assoc_data) {
    5644                 :          0 :                 struct cfg80211_bss *bss = ifmgd->assoc_data->bss;
    5645                 :          0 :                 ieee80211_destroy_assoc_data(sdata, false, false);
    5646                 :          0 :                 cfg80211_assoc_timeout(sdata->dev, bss);
    5647                 :            :         }
    5648         [ #  # ]:          0 :         if (ifmgd->auth_data)
    5649                 :          0 :                 ieee80211_destroy_auth_data(sdata, false);
    5650                 :          0 :         spin_lock_bh(&ifmgd->teardown_lock);
    5651         [ #  # ]:          0 :         if (ifmgd->teardown_skb) {
    5652                 :          0 :                 kfree_skb(ifmgd->teardown_skb);
    5653                 :          0 :                 ifmgd->teardown_skb = NULL;
    5654                 :          0 :                 ifmgd->orig_teardown_skb = NULL;
    5655                 :            :         }
    5656                 :          0 :         kfree(ifmgd->assoc_req_ies);
    5657                 :          0 :         ifmgd->assoc_req_ies = NULL;
    5658                 :          0 :         ifmgd->assoc_req_ies_len = 0;
    5659                 :          0 :         spin_unlock_bh(&ifmgd->teardown_lock);
    5660                 :          0 :         del_timer_sync(&ifmgd->timer);
    5661                 :          0 :         sdata_unlock(sdata);
    5662                 :          0 : }
    5663                 :            : 
    5664                 :          0 : void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
    5665                 :            :                                enum nl80211_cqm_rssi_threshold_event rssi_event,
    5666                 :            :                                s32 rssi_level,
    5667                 :            :                                gfp_t gfp)
    5668                 :            : {
    5669                 :          0 :         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
    5670                 :            : 
    5671                 :          0 :         trace_api_cqm_rssi_notify(sdata, rssi_event, rssi_level);
    5672                 :            : 
    5673                 :          0 :         cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, rssi_level, gfp);
    5674                 :          0 : }
    5675                 :            : EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);
    5676                 :            : 
    5677                 :          0 : void ieee80211_cqm_beacon_loss_notify(struct ieee80211_vif *vif, gfp_t gfp)
    5678                 :            : {
    5679                 :          0 :         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
    5680                 :            : 
    5681                 :          0 :         trace_api_cqm_beacon_loss_notify(sdata->local, sdata);
    5682                 :            : 
    5683                 :          0 :         cfg80211_cqm_beacon_loss_notify(sdata->dev, gfp);
    5684                 :          0 : }
    5685                 :            : EXPORT_SYMBOL(ieee80211_cqm_beacon_loss_notify);

Generated by: LCOV version 1.14