blob: 7fa9ba197c260c671053967e49583aa86e28a9f9 [file] [log] [blame]
Johannes Bergc2d15602007-07-27 15:43:23 +02001/*
2 * Copyright 2002-2005, Instant802 Networks, Inc.
3 * Copyright 2005-2006, Devicescape Software, Inc.
4 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
5 * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
Johannes Bergd98ad832014-09-03 15:24:57 +03006 * Copyright 2013-2014 Intel Mobile Communications GmbH
Johannes Bergda6a4352017-04-26 12:14:59 +02007 * Copyright (C) 2015-2017 Intel Deutschland GmbH
Haim Dreyfusse552af02018-03-28 13:24:10 +03008 * Copyright (C) 2018 Intel Corporation
Johannes Bergc2d15602007-07-27 15:43:23 +02009 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * utilities for mac80211
15 */
16
17#include <net/mac80211.h>
18#include <linux/netdevice.h>
Paul Gortmakerbc3b2d72011-07-15 11:47:34 -040019#include <linux/export.h>
Johannes Bergc2d15602007-07-27 15:43:23 +020020#include <linux/types.h>
21#include <linux/slab.h>
22#include <linux/skbuff.h>
23#include <linux/etherdevice.h>
24#include <linux/if_arp.h>
Johannes Bergc2d15602007-07-27 15:43:23 +020025#include <linux/bitmap.h>
Johannes Bergdd769862011-11-18 16:54:50 +010026#include <linux/crc32.h>
Eric W. Biederman881d9662007-09-17 11:56:21 -070027#include <net/net_namespace.h>
Johannes Bergc2d15602007-07-27 15:43:23 +020028#include <net/cfg80211.h>
Johannes Bergdabeb342007-11-09 01:57:29 +010029#include <net/rtnetlink.h>
Johannes Bergc2d15602007-07-27 15:43:23 +020030
31#include "ieee80211_i.h"
Johannes Berg24487982009-04-23 18:52:52 +020032#include "driver-ops.h"
Johannes Berg2c8dccc2008-04-08 15:14:40 -040033#include "rate.h"
Luis Carlos Coboee385852008-02-23 15:17:11 +010034#include "mesh.h"
Johannes Bergc2d15602007-07-27 15:43:23 +020035#include "wme.h"
Johannes Bergf2753dd2009-04-14 10:09:24 +020036#include "led.h"
Johannes Bergfffd0932009-07-08 14:22:54 +020037#include "wep.h"
Johannes Bergc2d15602007-07-27 15:43:23 +020038
39/* privid for wiphys to determine whether they belong to us or not */
Johannes Berg8a47cea2014-01-20 23:55:44 +010040const void *const mac80211_wiphy_privid = &mac80211_wiphy_privid;
Johannes Bergc2d15602007-07-27 15:43:23 +020041
Luis R. Rodriguez9a953712009-01-22 15:05:53 -080042struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy)
43{
44 struct ieee80211_local *local;
45 BUG_ON(!wiphy);
46
47 local = wiphy_priv(wiphy);
48 return &local->hw;
49}
50EXPORT_SYMBOL(wiphy_to_ieee80211_hw);
Johannes Bergc2d15602007-07-27 15:43:23 +020051
Johannes Berg5cf121c2008-02-25 16:27:43 +010052void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
Johannes Bergc2d15602007-07-27 15:43:23 +020053{
Johannes Berg252b86c2011-11-16 15:28:55 +010054 struct sk_buff *skb;
Johannes Berg2de8e0d2009-03-23 17:28:35 +010055 struct ieee80211_hdr *hdr;
Johannes Bergc2d15602007-07-27 15:43:23 +020056
Johannes Berg252b86c2011-11-16 15:28:55 +010057 skb_queue_walk(&tx->skbs, skb) {
Johannes Berg2de8e0d2009-03-23 17:28:35 +010058 hdr = (struct ieee80211_hdr *) skb->data;
59 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
Johannes Berg252b86c2011-11-16 15:28:55 +010060 }
Johannes Bergc2d15602007-07-27 15:43:23 +020061}
62
Johannes Berg57fbcce2016-04-12 15:56:15 +020063int ieee80211_frame_duration(enum nl80211_band band, size_t len,
Simon Wunderlich438b61b2013-07-08 16:55:51 +020064 int rate, int erp, int short_preamble,
65 int shift)
Johannes Bergc2d15602007-07-27 15:43:23 +020066{
67 int dur;
68
69 /* calculate duration (in microseconds, rounded up to next higher
70 * integer if it includes a fractional microsecond) to send frame of
71 * len bytes (does not include FCS) at the given rate. Duration will
72 * also include SIFS.
73 *
74 * rate is in 100 kbps, so divident is multiplied by 10 in the
75 * DIV_ROUND_UP() operations.
Simon Wunderlich438b61b2013-07-08 16:55:51 +020076 *
77 * shift may be 2 for 5 MHz channels or 1 for 10 MHz channels, and
78 * is assumed to be 0 otherwise.
Johannes Bergc2d15602007-07-27 15:43:23 +020079 */
80
Johannes Berg57fbcce2016-04-12 15:56:15 +020081 if (band == NL80211_BAND_5GHZ || erp) {
Johannes Bergc2d15602007-07-27 15:43:23 +020082 /*
83 * OFDM:
84 *
85 * N_DBPS = DATARATE x 4
86 * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS)
87 * (16 = SIGNAL time, 6 = tail bits)
88 * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext
89 *
90 * T_SYM = 4 usec
Simon Wunderlich438b61b2013-07-08 16:55:51 +020091 * 802.11a - 18.5.2: aSIFSTime = 16 usec
Johannes Bergc2d15602007-07-27 15:43:23 +020092 * 802.11g - 19.8.4: aSIFSTime = 10 usec +
93 * signal ext = 6 usec
94 */
Johannes Bergc2d15602007-07-27 15:43:23 +020095 dur = 16; /* SIFS + signal ext */
Simon Wunderlich438b61b2013-07-08 16:55:51 +020096 dur += 16; /* IEEE 802.11-2012 18.3.2.4: T_PREAMBLE = 16 usec */
97 dur += 4; /* IEEE 802.11-2012 18.3.2.4: T_SIGNAL = 4 usec */
Simon Wunderlich438b61b2013-07-08 16:55:51 +020098
99 /* IEEE 802.11-2012 18.3.2.4: all values above are:
100 * * times 4 for 5 MHz
101 * * times 2 for 10 MHz
102 */
103 dur *= 1 << shift;
Simon Wunderlich2103dec2013-07-08 16:55:53 +0200104
105 /* rates should already consider the channel bandwidth,
106 * don't apply divisor again.
107 */
108 dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
109 4 * rate); /* T_SYM x N_SYM */
Johannes Bergc2d15602007-07-27 15:43:23 +0200110 } else {
111 /*
112 * 802.11b or 802.11g with 802.11b compatibility:
113 * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime +
114 * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0.
115 *
116 * 802.11 (DS): 15.3.3, 802.11b: 18.3.4
117 * aSIFSTime = 10 usec
118 * aPreambleLength = 144 usec or 72 usec with short preamble
119 * aPLCPHeaderLength = 48 usec or 24 usec with short preamble
120 */
121 dur = 10; /* aSIFSTime = 10 usec */
122 dur += short_preamble ? (72 + 24) : (144 + 48);
123
124 dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate);
125 }
126
127 return dur;
128}
129
130/* Exported duration function for driver use */
Johannes Berg32bfd352007-12-19 01:31:26 +0100131__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
132 struct ieee80211_vif *vif,
Johannes Berg57fbcce2016-04-12 15:56:15 +0200133 enum nl80211_band band,
Johannes Berg8318d782008-01-24 19:38:38 +0100134 size_t frame_len,
135 struct ieee80211_rate *rate)
Johannes Bergc2d15602007-07-27 15:43:23 +0200136{
Johannes Berg25d834e2008-09-12 22:52:47 +0200137 struct ieee80211_sub_if_data *sdata;
Johannes Bergc2d15602007-07-27 15:43:23 +0200138 u16 dur;
Simon Wunderlich438b61b2013-07-08 16:55:51 +0200139 int erp, shift = 0;
Johannes Berg25d834e2008-09-12 22:52:47 +0200140 bool short_preamble = false;
Johannes Bergc2d15602007-07-27 15:43:23 +0200141
Johannes Berg8318d782008-01-24 19:38:38 +0100142 erp = 0;
Johannes Berg25d834e2008-09-12 22:52:47 +0200143 if (vif) {
144 sdata = vif_to_sdata(vif);
Johannes Bergbda39332008-10-11 01:51:51 +0200145 short_preamble = sdata->vif.bss_conf.use_short_preamble;
Johannes Berg25d834e2008-09-12 22:52:47 +0200146 if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
147 erp = rate->flags & IEEE80211_RATE_ERP_G;
Simon Wunderlich438b61b2013-07-08 16:55:51 +0200148 shift = ieee80211_vif_get_shift(vif);
Johannes Berg25d834e2008-09-12 22:52:47 +0200149 }
Johannes Berg8318d782008-01-24 19:38:38 +0100150
Michal Kazior4ee73f32012-04-11 08:47:56 +0200151 dur = ieee80211_frame_duration(band, frame_len, rate->bitrate, erp,
Simon Wunderlich438b61b2013-07-08 16:55:51 +0200152 short_preamble, shift);
Johannes Bergc2d15602007-07-27 15:43:23 +0200153
154 return cpu_to_le16(dur);
155}
156EXPORT_SYMBOL(ieee80211_generic_frame_duration);
157
Johannes Berg32bfd352007-12-19 01:31:26 +0100158__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
159 struct ieee80211_vif *vif, size_t frame_len,
Johannes Berge039fa42008-05-15 12:55:29 +0200160 const struct ieee80211_tx_info *frame_txctl)
Johannes Bergc2d15602007-07-27 15:43:23 +0200161{
162 struct ieee80211_local *local = hw_to_local(hw);
163 struct ieee80211_rate *rate;
Johannes Berg25d834e2008-09-12 22:52:47 +0200164 struct ieee80211_sub_if_data *sdata;
Johannes Berg471b3ef2007-12-28 14:32:58 +0100165 bool short_preamble;
Simon Wunderlich2103dec2013-07-08 16:55:53 +0200166 int erp, shift = 0, bitrate;
Johannes Bergc2d15602007-07-27 15:43:23 +0200167 u16 dur;
Johannes Berg2e92e6f2008-05-15 12:55:27 +0200168 struct ieee80211_supported_band *sband;
169
Michal Kazior4ee73f32012-04-11 08:47:56 +0200170 sband = local->hw.wiphy->bands[frame_txctl->band];
Johannes Bergc2d15602007-07-27 15:43:23 +0200171
Johannes Berg25d834e2008-09-12 22:52:47 +0200172 short_preamble = false;
Daniel Drake7e9ed182007-07-27 15:43:24 +0200173
Johannes Berge039fa42008-05-15 12:55:29 +0200174 rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
Johannes Berg8318d782008-01-24 19:38:38 +0100175
176 erp = 0;
Johannes Berg25d834e2008-09-12 22:52:47 +0200177 if (vif) {
178 sdata = vif_to_sdata(vif);
Johannes Bergbda39332008-10-11 01:51:51 +0200179 short_preamble = sdata->vif.bss_conf.use_short_preamble;
Johannes Berg25d834e2008-09-12 22:52:47 +0200180 if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
181 erp = rate->flags & IEEE80211_RATE_ERP_G;
Simon Wunderlich438b61b2013-07-08 16:55:51 +0200182 shift = ieee80211_vif_get_shift(vif);
Johannes Berg25d834e2008-09-12 22:52:47 +0200183 }
Johannes Bergc2d15602007-07-27 15:43:23 +0200184
Simon Wunderlich2103dec2013-07-08 16:55:53 +0200185 bitrate = DIV_ROUND_UP(rate->bitrate, 1 << shift);
186
Johannes Bergc2d15602007-07-27 15:43:23 +0200187 /* CTS duration */
Simon Wunderlich2103dec2013-07-08 16:55:53 +0200188 dur = ieee80211_frame_duration(sband->band, 10, bitrate,
Simon Wunderlich438b61b2013-07-08 16:55:51 +0200189 erp, short_preamble, shift);
Johannes Bergc2d15602007-07-27 15:43:23 +0200190 /* Data frame duration */
Simon Wunderlich2103dec2013-07-08 16:55:53 +0200191 dur += ieee80211_frame_duration(sband->band, frame_len, bitrate,
Simon Wunderlich438b61b2013-07-08 16:55:51 +0200192 erp, short_preamble, shift);
Johannes Bergc2d15602007-07-27 15:43:23 +0200193 /* ACK duration */
Simon Wunderlich2103dec2013-07-08 16:55:53 +0200194 dur += ieee80211_frame_duration(sband->band, 10, bitrate,
Simon Wunderlich438b61b2013-07-08 16:55:51 +0200195 erp, short_preamble, shift);
Johannes Bergc2d15602007-07-27 15:43:23 +0200196
197 return cpu_to_le16(dur);
198}
199EXPORT_SYMBOL(ieee80211_rts_duration);
200
Johannes Berg32bfd352007-12-19 01:31:26 +0100201__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
202 struct ieee80211_vif *vif,
Johannes Bergc2d15602007-07-27 15:43:23 +0200203 size_t frame_len,
Johannes Berge039fa42008-05-15 12:55:29 +0200204 const struct ieee80211_tx_info *frame_txctl)
Johannes Bergc2d15602007-07-27 15:43:23 +0200205{
206 struct ieee80211_local *local = hw_to_local(hw);
207 struct ieee80211_rate *rate;
Johannes Berg25d834e2008-09-12 22:52:47 +0200208 struct ieee80211_sub_if_data *sdata;
Johannes Berg471b3ef2007-12-28 14:32:58 +0100209 bool short_preamble;
Simon Wunderlich2103dec2013-07-08 16:55:53 +0200210 int erp, shift = 0, bitrate;
Johannes Bergc2d15602007-07-27 15:43:23 +0200211 u16 dur;
Johannes Berg2e92e6f2008-05-15 12:55:27 +0200212 struct ieee80211_supported_band *sband;
213
Michal Kazior4ee73f32012-04-11 08:47:56 +0200214 sband = local->hw.wiphy->bands[frame_txctl->band];
Johannes Bergc2d15602007-07-27 15:43:23 +0200215
Johannes Berg25d834e2008-09-12 22:52:47 +0200216 short_preamble = false;
Daniel Drake7e9ed182007-07-27 15:43:24 +0200217
Johannes Berge039fa42008-05-15 12:55:29 +0200218 rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
Johannes Berg8318d782008-01-24 19:38:38 +0100219 erp = 0;
Johannes Berg25d834e2008-09-12 22:52:47 +0200220 if (vif) {
221 sdata = vif_to_sdata(vif);
Johannes Bergbda39332008-10-11 01:51:51 +0200222 short_preamble = sdata->vif.bss_conf.use_short_preamble;
Johannes Berg25d834e2008-09-12 22:52:47 +0200223 if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
224 erp = rate->flags & IEEE80211_RATE_ERP_G;
Simon Wunderlich438b61b2013-07-08 16:55:51 +0200225 shift = ieee80211_vif_get_shift(vif);
Johannes Berg25d834e2008-09-12 22:52:47 +0200226 }
Johannes Bergc2d15602007-07-27 15:43:23 +0200227
Simon Wunderlich2103dec2013-07-08 16:55:53 +0200228 bitrate = DIV_ROUND_UP(rate->bitrate, 1 << shift);
229
Johannes Bergc2d15602007-07-27 15:43:23 +0200230 /* Data frame duration */
Simon Wunderlich2103dec2013-07-08 16:55:53 +0200231 dur = ieee80211_frame_duration(sband->band, frame_len, bitrate,
Simon Wunderlich438b61b2013-07-08 16:55:51 +0200232 erp, short_preamble, shift);
Johannes Berge039fa42008-05-15 12:55:29 +0200233 if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) {
Johannes Bergc2d15602007-07-27 15:43:23 +0200234 /* ACK duration */
Simon Wunderlich2103dec2013-07-08 16:55:53 +0200235 dur += ieee80211_frame_duration(sband->band, 10, bitrate,
Simon Wunderlich438b61b2013-07-08 16:55:51 +0200236 erp, short_preamble, shift);
Johannes Bergc2d15602007-07-27 15:43:23 +0200237 }
238
Johannes Bergc2d15602007-07-27 15:43:23 +0200239 return cpu_to_le16(dur);
240}
241EXPORT_SYMBOL(ieee80211_ctstoself_duration);
242
Manikanta Pubbisetty21a5d4c2018-07-11 00:12:53 +0530243static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
244{
245 struct ieee80211_local *local = sdata->local;
246 struct ieee80211_vif *vif = &sdata->vif;
247 struct fq *fq = &local->fq;
248 struct ps_data *ps = NULL;
249 struct txq_info *txqi;
250 struct sta_info *sta;
251 int i;
252
253 spin_lock_bh(&fq->lock);
254
255 if (sdata->vif.type == NL80211_IFTYPE_AP)
256 ps = &sdata->bss->ps;
257
258 sdata->vif.txqs_stopped[ac] = false;
259
260 list_for_each_entry_rcu(sta, &local->sta_list, list) {
261 if (sdata != sta->sdata)
262 continue;
263
264 for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
265 struct ieee80211_txq *txq = sta->sta.txq[i];
266
Erik Stromdahla5ae3262018-09-14 18:00:34 +0200267 if (!txq)
268 continue;
269
Manikanta Pubbisetty21a5d4c2018-07-11 00:12:53 +0530270 txqi = to_txq_info(txq);
271
272 if (ac != txq->ac)
273 continue;
274
275 if (!test_and_clear_bit(IEEE80211_TXQ_STOP_NETIF_TX,
276 &txqi->flags))
277 continue;
278
279 spin_unlock_bh(&fq->lock);
280 drv_wake_tx_queue(local, txqi);
281 spin_lock_bh(&fq->lock);
282 }
283 }
284
285 if (!vif->txq)
286 goto out;
287
288 txqi = to_txq_info(vif->txq);
289
290 if (!test_and_clear_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags) ||
291 (ps && atomic_read(&ps->num_sta_ps)) || ac != vif->txq->ac)
292 goto out;
293
294 spin_unlock_bh(&fq->lock);
295
296 drv_wake_tx_queue(local, txqi);
297 return;
298out:
299 spin_unlock_bh(&fq->lock);
300}
301
Emmanuel Grumbachf6c7f032018-12-03 21:15:49 +0200302static void
303__releases(&local->queue_stop_reason_lock)
304__acquires(&local->queue_stop_reason_lock)
305_ieee80211_wake_txqs(struct ieee80211_local *local, unsigned long *flags)
Manikanta Pubbisetty21a5d4c2018-07-11 00:12:53 +0530306{
Manikanta Pubbisetty21a5d4c2018-07-11 00:12:53 +0530307 struct ieee80211_sub_if_data *sdata;
308 int n_acs = IEEE80211_NUM_ACS;
Manikanta Pubbisetty21a5d4c2018-07-11 00:12:53 +0530309 int i;
310
311 rcu_read_lock();
Manikanta Pubbisetty21a5d4c2018-07-11 00:12:53 +0530312
313 if (local->hw.queues < IEEE80211_NUM_ACS)
314 n_acs = 1;
315
316 for (i = 0; i < local->hw.queues; i++) {
317 if (local->queue_stop_reasons[i])
318 continue;
319
Emmanuel Grumbachf6c7f032018-12-03 21:15:49 +0200320 spin_unlock_irqrestore(&local->queue_stop_reason_lock, *flags);
Manikanta Pubbisetty21a5d4c2018-07-11 00:12:53 +0530321 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
322 int ac;
323
324 for (ac = 0; ac < n_acs; ac++) {
325 int ac_queue = sdata->vif.hw_queue[ac];
326
327 if (ac_queue == i ||
328 sdata->vif.cab_queue == i)
329 __ieee80211_wake_txqs(sdata, ac);
330 }
331 }
Emmanuel Grumbachf6c7f032018-12-03 21:15:49 +0200332 spin_lock_irqsave(&local->queue_stop_reason_lock, *flags);
Manikanta Pubbisetty21a5d4c2018-07-11 00:12:53 +0530333 }
334
Manikanta Pubbisetty21a5d4c2018-07-11 00:12:53 +0530335 rcu_read_unlock();
336}
337
Emmanuel Grumbachf6c7f032018-12-03 21:15:49 +0200338void ieee80211_wake_txqs(unsigned long data)
339{
340 struct ieee80211_local *local = (struct ieee80211_local *)data;
341 unsigned long flags;
342
343 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
344 _ieee80211_wake_txqs(local, &flags);
345 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
346}
347
Johannes Berg3a25a8c2012-04-03 16:28:50 +0200348void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
349{
350 struct ieee80211_sub_if_data *sdata;
Johannes Berga6f38ac2012-07-04 12:49:59 +0200351 int n_acs = IEEE80211_NUM_ACS;
352
Michal Kazior80a83cf2016-05-19 10:37:48 +0200353 if (local->ops->wake_tx_queue)
354 return;
355
Johannes Berga6f38ac2012-07-04 12:49:59 +0200356 if (local->hw.queues < IEEE80211_NUM_ACS)
357 n_acs = 1;
Johannes Berg3a25a8c2012-04-03 16:28:50 +0200358
359 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
360 int ac;
361
Johannes Bergf142c6b2012-06-18 20:07:15 +0200362 if (!sdata->dev)
363 continue;
364
Johannes Berg3a25a8c2012-04-03 16:28:50 +0200365 if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE &&
366 local->queue_stop_reasons[sdata->vif.cab_queue] != 0)
367 continue;
368
Johannes Berga6f38ac2012-07-04 12:49:59 +0200369 for (ac = 0; ac < n_acs; ac++) {
Johannes Berg3a25a8c2012-04-03 16:28:50 +0200370 int ac_queue = sdata->vif.hw_queue[ac];
371
372 if (ac_queue == queue ||
373 (sdata->vif.cab_queue == queue &&
374 local->queue_stop_reasons[ac_queue] == 0 &&
375 skb_queue_empty(&local->pending[ac_queue])))
376 netif_wake_subqueue(sdata->dev, ac);
377 }
378 }
379}
380
Kalle Valoce7c9112008-12-18 23:35:20 +0200381static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
Luciano Coelhocca07b02014-06-13 16:30:05 +0300382 enum queue_stop_reason reason,
Emmanuel Grumbachf6c7f032018-12-03 21:15:49 +0200383 bool refcounted,
384 unsigned long *flags)
Johannes Bergc2d15602007-07-27 15:43:23 +0200385{
386 struct ieee80211_local *local = hw_to_local(hw);
387
Johannes Bergb5878a22010-04-07 16:48:40 +0200388 trace_wake_queue(local, queue, reason);
389
Johannes Berge4e72fb2009-03-23 17:28:42 +0100390 if (WARN_ON(queue >= hw->queues))
391 return;
Kalle Valoce7c9112008-12-18 23:35:20 +0200392
Johannes Bergada15122012-03-28 11:04:27 +0200393 if (!test_bit(reason, &local->queue_stop_reasons[queue]))
394 return;
395
Johannes Berg856142c2015-11-24 15:29:53 +0100396 if (!refcounted) {
Luciano Coelhocca07b02014-06-13 16:30:05 +0300397 local->q_stop_reasons[queue][reason] = 0;
Johannes Berg856142c2015-11-24 15:29:53 +0100398 } else {
Luciano Coelhocca07b02014-06-13 16:30:05 +0300399 local->q_stop_reasons[queue][reason]--;
Johannes Berg856142c2015-11-24 15:29:53 +0100400 if (WARN_ON(local->q_stop_reasons[queue][reason] < 0))
401 local->q_stop_reasons[queue][reason] = 0;
402 }
Luciano Coelhocca07b02014-06-13 16:30:05 +0300403
404 if (local->q_stop_reasons[queue][reason] == 0)
405 __clear_bit(reason, &local->queue_stop_reasons[queue]);
Johannes Berg96f5e662009-02-12 00:51:53 +0100406
407 if (local->queue_stop_reasons[queue] != 0)
408 /* someone still has this queue stopped */
409 return;
410
Johannes Berg7236fe22010-03-22 13:42:43 -0700411 if (skb_queue_empty(&local->pending[queue])) {
412 rcu_read_lock();
Johannes Berg3a25a8c2012-04-03 16:28:50 +0200413 ieee80211_propagate_queue_wake(local, queue);
Johannes Berg7236fe22010-03-22 13:42:43 -0700414 rcu_read_unlock();
415 } else
Johannes Berg3b8d81e02009-06-17 17:43:56 +0200416 tasklet_schedule(&local->tx_pending_tasklet);
Manikanta Pubbisetty21a5d4c2018-07-11 00:12:53 +0530417
Emmanuel Grumbachf6c7f032018-12-03 21:15:49 +0200418 /*
419 * Calling _ieee80211_wake_txqs here can be a problem because it may
420 * release queue_stop_reason_lock which has been taken by
421 * __ieee80211_wake_queue's caller. It is certainly not very nice to
422 * release someone's lock, but it is fine because all the callers of
423 * __ieee80211_wake_queue call it right before releasing the lock.
424 */
425 if (local->ops->wake_tx_queue) {
426 if (reason == IEEE80211_QUEUE_STOP_REASON_DRIVER)
427 tasklet_schedule(&local->wake_txqs_tasklet);
428 else
429 _ieee80211_wake_txqs(local, flags);
430 }
Johannes Bergc2d15602007-07-27 15:43:23 +0200431}
Kalle Valoce7c9112008-12-18 23:35:20 +0200432
Johannes Berg96f5e662009-02-12 00:51:53 +0100433void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
Luciano Coelhocca07b02014-06-13 16:30:05 +0300434 enum queue_stop_reason reason,
435 bool refcounted)
Kalle Valoce7c9112008-12-18 23:35:20 +0200436{
437 struct ieee80211_local *local = hw_to_local(hw);
438 unsigned long flags;
439
440 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
Emmanuel Grumbachf6c7f032018-12-03 21:15:49 +0200441 __ieee80211_wake_queue(hw, queue, reason, refcounted, &flags);
Kalle Valoce7c9112008-12-18 23:35:20 +0200442 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
443}
444
445void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
446{
447 ieee80211_wake_queue_by_reason(hw, queue,
Luciano Coelhocca07b02014-06-13 16:30:05 +0300448 IEEE80211_QUEUE_STOP_REASON_DRIVER,
449 false);
Kalle Valoce7c9112008-12-18 23:35:20 +0200450}
Johannes Bergc2d15602007-07-27 15:43:23 +0200451EXPORT_SYMBOL(ieee80211_wake_queue);
452
Kalle Valoce7c9112008-12-18 23:35:20 +0200453static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
Luciano Coelhocca07b02014-06-13 16:30:05 +0300454 enum queue_stop_reason reason,
455 bool refcounted)
Johannes Bergc2d15602007-07-27 15:43:23 +0200456{
457 struct ieee80211_local *local = hw_to_local(hw);
Johannes Bergcf0277e2010-01-05 18:00:58 +0100458 struct ieee80211_sub_if_data *sdata;
Johannes Berga6f38ac2012-07-04 12:49:59 +0200459 int n_acs = IEEE80211_NUM_ACS;
Johannes Bergc2d15602007-07-27 15:43:23 +0200460
Johannes Bergb5878a22010-04-07 16:48:40 +0200461 trace_stop_queue(local, queue, reason);
462
Johannes Berge4e72fb2009-03-23 17:28:42 +0100463 if (WARN_ON(queue >= hw->queues))
464 return;
Johannes Berg96f5e662009-02-12 00:51:53 +0100465
Luciano Coelhocca07b02014-06-13 16:30:05 +0300466 if (!refcounted)
467 local->q_stop_reasons[queue][reason] = 1;
468 else
469 local->q_stop_reasons[queue][reason]++;
Johannes Bergada15122012-03-28 11:04:27 +0200470
Luciano Coelhocca07b02014-06-13 16:30:05 +0300471 if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue]))
472 return;
Johannes Bergcf0277e2010-01-05 18:00:58 +0100473
Johannes Berga6f38ac2012-07-04 12:49:59 +0200474 if (local->hw.queues < IEEE80211_NUM_ACS)
475 n_acs = 1;
476
Johannes Bergcf0277e2010-01-05 18:00:58 +0100477 rcu_read_lock();
Johannes Berg3a25a8c2012-04-03 16:28:50 +0200478 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
479 int ac;
480
Johannes Bergf142c6b2012-06-18 20:07:15 +0200481 if (!sdata->dev)
482 continue;
483
Johannes Berga6f38ac2012-07-04 12:49:59 +0200484 for (ac = 0; ac < n_acs; ac++) {
Johannes Berg3a25a8c2012-04-03 16:28:50 +0200485 if (sdata->vif.hw_queue[ac] == queue ||
Manikanta Pubbisetty21a5d4c2018-07-11 00:12:53 +0530486 sdata->vif.cab_queue == queue) {
487 if (!local->ops->wake_tx_queue) {
488 netif_stop_subqueue(sdata->dev, ac);
489 continue;
490 }
491 spin_lock(&local->fq.lock);
492 sdata->vif.txqs_stopped[ac] = true;
493 spin_unlock(&local->fq.lock);
494 }
Johannes Berg3a25a8c2012-04-03 16:28:50 +0200495 }
496 }
Johannes Bergcf0277e2010-01-05 18:00:58 +0100497 rcu_read_unlock();
Johannes Bergc2d15602007-07-27 15:43:23 +0200498}
Kalle Valoce7c9112008-12-18 23:35:20 +0200499
Johannes Berg96f5e662009-02-12 00:51:53 +0100500void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
Luciano Coelhocca07b02014-06-13 16:30:05 +0300501 enum queue_stop_reason reason,
502 bool refcounted)
Kalle Valoce7c9112008-12-18 23:35:20 +0200503{
504 struct ieee80211_local *local = hw_to_local(hw);
505 unsigned long flags;
506
507 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
Luciano Coelhocca07b02014-06-13 16:30:05 +0300508 __ieee80211_stop_queue(hw, queue, reason, refcounted);
Kalle Valoce7c9112008-12-18 23:35:20 +0200509 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
510}
511
512void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
513{
514 ieee80211_stop_queue_by_reason(hw, queue,
Luciano Coelhocca07b02014-06-13 16:30:05 +0300515 IEEE80211_QUEUE_STOP_REASON_DRIVER,
516 false);
Kalle Valoce7c9112008-12-18 23:35:20 +0200517}
Johannes Bergc2d15602007-07-27 15:43:23 +0200518EXPORT_SYMBOL(ieee80211_stop_queue);
519
Johannes Berg8f77f382009-06-07 21:58:37 +0200520void ieee80211_add_pending_skb(struct ieee80211_local *local,
521 struct sk_buff *skb)
522{
523 struct ieee80211_hw *hw = &local->hw;
524 unsigned long flags;
Johannes Berga7bc3762009-07-27 10:33:31 +0200525 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
Johannes Berg3a25a8c2012-04-03 16:28:50 +0200526 int queue = info->hw_queue;
Johannes Berga7bc3762009-07-27 10:33:31 +0200527
528 if (WARN_ON(!info->control.vif)) {
Felix Fietkaud4fa14c2012-10-10 22:40:23 +0200529 ieee80211_free_txskb(&local->hw, skb);
Johannes Berga7bc3762009-07-27 10:33:31 +0200530 return;
531 }
Johannes Berg8f77f382009-06-07 21:58:37 +0200532
533 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
Luciano Coelhocca07b02014-06-13 16:30:05 +0300534 __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
535 false);
Johannes Berg3b8d81e02009-06-17 17:43:56 +0200536 __skb_queue_tail(&local->pending[queue], skb);
Luciano Coelhocca07b02014-06-13 16:30:05 +0300537 __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
Emmanuel Grumbachf6c7f032018-12-03 21:15:49 +0200538 false, &flags);
Johannes Berg8f77f382009-06-07 21:58:37 +0200539 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
540}
541
Johannes Berge3685e02014-02-20 11:19:58 +0100542void ieee80211_add_pending_skbs(struct ieee80211_local *local,
543 struct sk_buff_head *skbs)
Johannes Berg8f77f382009-06-07 21:58:37 +0200544{
545 struct ieee80211_hw *hw = &local->hw;
546 struct sk_buff *skb;
547 unsigned long flags;
Johannes Bergb0b97a82011-09-29 16:04:30 +0200548 int queue, i;
Johannes Berg8f77f382009-06-07 21:58:37 +0200549
550 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
Johannes Berg8f77f382009-06-07 21:58:37 +0200551 while ((skb = skb_dequeue(skbs))) {
Johannes Berga7bc3762009-07-27 10:33:31 +0200552 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
553
554 if (WARN_ON(!info->control.vif)) {
Felix Fietkaud4fa14c2012-10-10 22:40:23 +0200555 ieee80211_free_txskb(&local->hw, skb);
Johannes Berga7bc3762009-07-27 10:33:31 +0200556 continue;
557 }
558
Johannes Berg3a25a8c2012-04-03 16:28:50 +0200559 queue = info->hw_queue;
Johannes Berg4644ae82012-03-28 11:04:28 +0200560
561 __ieee80211_stop_queue(hw, queue,
Luciano Coelhocca07b02014-06-13 16:30:05 +0300562 IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
563 false);
Johannes Berg4644ae82012-03-28 11:04:28 +0200564
Johannes Berg3b8d81e02009-06-17 17:43:56 +0200565 __skb_queue_tail(&local->pending[queue], skb);
Johannes Berg8f77f382009-06-07 21:58:37 +0200566 }
567
Johannes Berg3b8d81e02009-06-17 17:43:56 +0200568 for (i = 0; i < hw->queues; i++)
Johannes Berg8f77f382009-06-07 21:58:37 +0200569 __ieee80211_wake_queue(hw, i,
Luciano Coelhocca07b02014-06-13 16:30:05 +0300570 IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
Emmanuel Grumbachf6c7f032018-12-03 21:15:49 +0200571 false, &flags);
Johannes Berg8f77f382009-06-07 21:58:37 +0200572 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
Johannes Berg8f77f382009-06-07 21:58:37 +0200573}
574
Kalle Valoce7c9112008-12-18 23:35:20 +0200575void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
Johannes Berg445ea4e2013-02-13 12:25:28 +0100576 unsigned long queues,
Luciano Coelhocca07b02014-06-13 16:30:05 +0300577 enum queue_stop_reason reason,
578 bool refcounted)
Johannes Bergc2d15602007-07-27 15:43:23 +0200579{
Kalle Valoce7c9112008-12-18 23:35:20 +0200580 struct ieee80211_local *local = hw_to_local(hw);
581 unsigned long flags;
Johannes Bergc2d15602007-07-27 15:43:23 +0200582 int i;
583
Kalle Valoce7c9112008-12-18 23:35:20 +0200584 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
585
Johannes Berg445ea4e2013-02-13 12:25:28 +0100586 for_each_set_bit(i, &queues, hw->queues)
Luciano Coelhocca07b02014-06-13 16:30:05 +0300587 __ieee80211_stop_queue(hw, i, reason, refcounted);
Kalle Valoce7c9112008-12-18 23:35:20 +0200588
589 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
590}
591
592void ieee80211_stop_queues(struct ieee80211_hw *hw)
593{
Johannes Berg445ea4e2013-02-13 12:25:28 +0100594 ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
Luciano Coelhocca07b02014-06-13 16:30:05 +0300595 IEEE80211_QUEUE_STOP_REASON_DRIVER,
596 false);
Johannes Bergc2d15602007-07-27 15:43:23 +0200597}
598EXPORT_SYMBOL(ieee80211_stop_queues);
599
Tomas Winkler92ab8532008-07-24 21:02:04 +0300600int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
601{
602 struct ieee80211_local *local = hw_to_local(hw);
Johannes Berg3b8d81e02009-06-17 17:43:56 +0200603 unsigned long flags;
604 int ret;
Johannes Berg96f5e662009-02-12 00:51:53 +0100605
Johannes Berge4e72fb2009-03-23 17:28:42 +0100606 if (WARN_ON(queue >= hw->queues))
607 return true;
Johannes Berg96f5e662009-02-12 00:51:53 +0100608
Johannes Berg3b8d81e02009-06-17 17:43:56 +0200609 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
Thomas Pedersen2419ea12013-04-10 15:41:40 -0700610 ret = test_bit(IEEE80211_QUEUE_STOP_REASON_DRIVER,
611 &local->queue_stop_reasons[queue]);
Johannes Berg3b8d81e02009-06-17 17:43:56 +0200612 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
613 return ret;
Tomas Winkler92ab8532008-07-24 21:02:04 +0300614}
615EXPORT_SYMBOL(ieee80211_queue_stopped);
616
Kalle Valoce7c9112008-12-18 23:35:20 +0200617void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
Johannes Berg445ea4e2013-02-13 12:25:28 +0100618 unsigned long queues,
Luciano Coelhocca07b02014-06-13 16:30:05 +0300619 enum queue_stop_reason reason,
620 bool refcounted)
Johannes Bergc2d15602007-07-27 15:43:23 +0200621{
Kalle Valoce7c9112008-12-18 23:35:20 +0200622 struct ieee80211_local *local = hw_to_local(hw);
623 unsigned long flags;
Johannes Bergc2d15602007-07-27 15:43:23 +0200624 int i;
625
Kalle Valoce7c9112008-12-18 23:35:20 +0200626 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
627
Johannes Berg445ea4e2013-02-13 12:25:28 +0100628 for_each_set_bit(i, &queues, hw->queues)
Emmanuel Grumbachf6c7f032018-12-03 21:15:49 +0200629 __ieee80211_wake_queue(hw, i, reason, refcounted, &flags);
Kalle Valoce7c9112008-12-18 23:35:20 +0200630
631 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
632}
633
634void ieee80211_wake_queues(struct ieee80211_hw *hw)
635{
Johannes Berg445ea4e2013-02-13 12:25:28 +0100636 ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
Luciano Coelhocca07b02014-06-13 16:30:05 +0300637 IEEE80211_QUEUE_STOP_REASON_DRIVER,
638 false);
Johannes Bergc2d15602007-07-27 15:43:23 +0200639}
640EXPORT_SYMBOL(ieee80211_wake_queues);
Johannes Bergdabeb342007-11-09 01:57:29 +0100641
Luciano Coelho26da23b2014-06-13 16:30:06 +0300642static unsigned int
643ieee80211_get_vif_queues(struct ieee80211_local *local,
644 struct ieee80211_sub_if_data *sdata)
Johannes Berg39ecc012013-02-13 12:11:00 +0100645{
Luciano Coelho26da23b2014-06-13 16:30:06 +0300646 unsigned int queues;
Johannes Berg39ecc012013-02-13 12:11:00 +0100647
Johannes Berg30686bf2015-06-02 21:39:54 +0200648 if (sdata && ieee80211_hw_check(&local->hw, QUEUE_CONTROL)) {
Johannes Berg39ecc012013-02-13 12:11:00 +0100649 int ac;
650
651 queues = 0;
652
653 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
654 queues |= BIT(sdata->vif.hw_queue[ac]);
655 if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE)
656 queues |= BIT(sdata->vif.cab_queue);
657 } else {
658 /* all queues */
659 queues = BIT(local->hw.queues) - 1;
660 }
661
Luciano Coelho26da23b2014-06-13 16:30:06 +0300662 return queues;
663}
664
Liad Kaufman4f9610d2014-11-09 18:50:21 +0200665void __ieee80211_flush_queues(struct ieee80211_local *local,
666 struct ieee80211_sub_if_data *sdata,
Emmanuel Grumbach3b24f4c2015-01-07 15:42:39 +0200667 unsigned int queues, bool drop)
Luciano Coelho26da23b2014-06-13 16:30:06 +0300668{
Luciano Coelho26da23b2014-06-13 16:30:06 +0300669 if (!local->ops->flush)
670 return;
671
Liad Kaufman4f9610d2014-11-09 18:50:21 +0200672 /*
673 * If no queue was set, or if the HW doesn't support
674 * IEEE80211_HW_QUEUE_CONTROL - flush all queues
675 */
Johannes Berg30686bf2015-06-02 21:39:54 +0200676 if (!queues || !ieee80211_hw_check(&local->hw, QUEUE_CONTROL))
Liad Kaufman4f9610d2014-11-09 18:50:21 +0200677 queues = ieee80211_get_vif_queues(local, sdata);
Luciano Coelho26da23b2014-06-13 16:30:06 +0300678
Luciano Coelho59f48fe2014-06-13 16:30:04 +0300679 ieee80211_stop_queues_by_reason(&local->hw, queues,
Luciano Coelhocca07b02014-06-13 16:30:05 +0300680 IEEE80211_QUEUE_STOP_REASON_FLUSH,
681 false);
Johannes Berg445ea4e2013-02-13 12:25:28 +0100682
Emmanuel Grumbach3b24f4c2015-01-07 15:42:39 +0200683 drv_flush(local, sdata, queues, drop);
Johannes Berg445ea4e2013-02-13 12:25:28 +0100684
Luciano Coelho59f48fe2014-06-13 16:30:04 +0300685 ieee80211_wake_queues_by_reason(&local->hw, queues,
Luciano Coelhocca07b02014-06-13 16:30:05 +0300686 IEEE80211_QUEUE_STOP_REASON_FLUSH,
687 false);
Johannes Berg39ecc012013-02-13 12:11:00 +0100688}
689
Liad Kaufman4f9610d2014-11-09 18:50:21 +0200690void ieee80211_flush_queues(struct ieee80211_local *local,
Emmanuel Grumbach3b24f4c2015-01-07 15:42:39 +0200691 struct ieee80211_sub_if_data *sdata, bool drop)
Liad Kaufman4f9610d2014-11-09 18:50:21 +0200692{
Emmanuel Grumbach3b24f4c2015-01-07 15:42:39 +0200693 __ieee80211_flush_queues(local, sdata, 0, drop);
Liad Kaufman4f9610d2014-11-09 18:50:21 +0200694}
695
Luciano Coelho26da23b2014-06-13 16:30:06 +0300696void ieee80211_stop_vif_queues(struct ieee80211_local *local,
697 struct ieee80211_sub_if_data *sdata,
698 enum queue_stop_reason reason)
699{
700 ieee80211_stop_queues_by_reason(&local->hw,
701 ieee80211_get_vif_queues(local, sdata),
702 reason, true);
703}
704
705void ieee80211_wake_vif_queues(struct ieee80211_local *local,
706 struct ieee80211_sub_if_data *sdata,
707 enum queue_stop_reason reason)
708{
709 ieee80211_wake_queues_by_reason(&local->hw,
710 ieee80211_get_vif_queues(local, sdata),
711 reason, true);
712}
713
Arik Nemtsov3384d752015-03-01 09:10:15 +0200714static void __iterate_interfaces(struct ieee80211_local *local,
715 u32 iter_flags,
716 void (*iterator)(void *data, u8 *mac,
717 struct ieee80211_vif *vif),
718 void *data)
Johannes Bergdabeb342007-11-09 01:57:29 +0100719{
Johannes Bergdabeb342007-11-09 01:57:29 +0100720 struct ieee80211_sub_if_data *sdata;
Arik Nemtsov3384d752015-03-01 09:10:15 +0200721 bool active_only = iter_flags & IEEE80211_IFACE_ITER_ACTIVE;
Johannes Bergdabeb342007-11-09 01:57:29 +0100722
Johannes Berge38bad42007-11-28 10:55:32 +0100723 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
Johannes Berg51fb61e2007-12-19 01:31:27 +0100724 switch (sdata->vif.type) {
Johannes Berg05c914f2008-09-11 00:01:58 +0200725 case NL80211_IFTYPE_MONITOR:
Aviya Erenfeldd8212182016-08-29 23:25:15 +0300726 if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
Felix Fietkau31eba5b2013-05-28 13:01:53 +0200727 continue;
728 break;
Johannes Berg05c914f2008-09-11 00:01:58 +0200729 case NL80211_IFTYPE_AP_VLAN:
Johannes Bergdabeb342007-11-09 01:57:29 +0100730 continue;
Johannes Berg2ca27bc2010-09-16 14:58:23 +0200731 default:
Johannes Bergdabeb342007-11-09 01:57:29 +0100732 break;
733 }
Johannes Berg8b2c9822012-11-06 20:23:30 +0100734 if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
Arik Nemtsov3384d752015-03-01 09:10:15 +0200735 active_only && !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
Johannes Berg8b2c9822012-11-06 20:23:30 +0100736 continue;
Arik Nemtsov3384d752015-03-01 09:10:15 +0200737 if (ieee80211_sdata_running(sdata) || !active_only)
Johannes Berg47846c92009-11-25 17:46:19 +0100738 iterator(data, sdata->vif.addr,
Johannes Berg32bfd352007-12-19 01:31:26 +0100739 &sdata->vif);
Johannes Bergdabeb342007-11-09 01:57:29 +0100740 }
Johannes Berge38bad42007-11-28 10:55:32 +0100741
Johannes Bergc7c71062013-08-21 22:07:20 +0200742 sdata = rcu_dereference_check(local->monitor_sdata,
743 lockdep_is_held(&local->iflist_mtx) ||
744 lockdep_rtnl_is_held());
Johannes Berg8b2c9822012-11-06 20:23:30 +0100745 if (sdata &&
Arik Nemtsov3384d752015-03-01 09:10:15 +0200746 (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || !active_only ||
Johannes Berg8b2c9822012-11-06 20:23:30 +0100747 sdata->flags & IEEE80211_SDATA_IN_DRIVER))
Johannes Berg685fb722012-07-11 16:38:09 +0200748 iterator(data, sdata->vif.addr, &sdata->vif);
Johannes Bergc7c71062013-08-21 22:07:20 +0200749}
Johannes Berg685fb722012-07-11 16:38:09 +0200750
Arik Nemtsov3384d752015-03-01 09:10:15 +0200751void ieee80211_iterate_interfaces(
Johannes Bergc7c71062013-08-21 22:07:20 +0200752 struct ieee80211_hw *hw, u32 iter_flags,
753 void (*iterator)(void *data, u8 *mac,
754 struct ieee80211_vif *vif),
755 void *data)
756{
757 struct ieee80211_local *local = hw_to_local(hw);
758
759 mutex_lock(&local->iflist_mtx);
Arik Nemtsov3384d752015-03-01 09:10:15 +0200760 __iterate_interfaces(local, iter_flags, iterator, data);
Johannes Bergc7c71062013-08-21 22:07:20 +0200761 mutex_unlock(&local->iflist_mtx);
762}
Arik Nemtsov3384d752015-03-01 09:10:15 +0200763EXPORT_SYMBOL_GPL(ieee80211_iterate_interfaces);
Johannes Bergc7c71062013-08-21 22:07:20 +0200764
765void ieee80211_iterate_active_interfaces_atomic(
766 struct ieee80211_hw *hw, u32 iter_flags,
767 void (*iterator)(void *data, u8 *mac,
768 struct ieee80211_vif *vif),
769 void *data)
770{
771 struct ieee80211_local *local = hw_to_local(hw);
772
773 rcu_read_lock();
Arik Nemtsov3384d752015-03-01 09:10:15 +0200774 __iterate_interfaces(local, iter_flags | IEEE80211_IFACE_ITER_ACTIVE,
775 iterator, data);
Johannes Berge38bad42007-11-28 10:55:32 +0100776 rcu_read_unlock();
Johannes Bergdabeb342007-11-09 01:57:29 +0100777}
Ivo van Doorn2f561fe2008-05-10 13:40:49 +0200778EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
Johannes Berg37ffc8d2008-09-08 16:40:36 +0200779
Johannes Bergc7c71062013-08-21 22:07:20 +0200780void ieee80211_iterate_active_interfaces_rtnl(
781 struct ieee80211_hw *hw, u32 iter_flags,
782 void (*iterator)(void *data, u8 *mac,
783 struct ieee80211_vif *vif),
784 void *data)
785{
786 struct ieee80211_local *local = hw_to_local(hw);
787
788 ASSERT_RTNL();
789
Arik Nemtsov3384d752015-03-01 09:10:15 +0200790 __iterate_interfaces(local, iter_flags | IEEE80211_IFACE_ITER_ACTIVE,
791 iterator, data);
Johannes Bergc7c71062013-08-21 22:07:20 +0200792}
793EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl);
794
Arik Nemtsov0fc1e042014-10-22 12:30:59 +0300795static void __iterate_stations(struct ieee80211_local *local,
796 void (*iterator)(void *data,
797 struct ieee80211_sta *sta),
798 void *data)
799{
800 struct sta_info *sta;
801
802 list_for_each_entry_rcu(sta, &local->sta_list, list) {
803 if (!sta->uploaded)
804 continue;
805
806 iterator(data, &sta->sta);
807 }
808}
809
810void ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw,
811 void (*iterator)(void *data,
812 struct ieee80211_sta *sta),
813 void *data)
814{
815 struct ieee80211_local *local = hw_to_local(hw);
816
817 rcu_read_lock();
818 __iterate_stations(local, iterator, data);
819 rcu_read_unlock();
820}
821EXPORT_SYMBOL_GPL(ieee80211_iterate_stations_atomic);
822
Johannes Bergad7e7182013-11-13 13:37:47 +0100823struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev)
824{
825 struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
826
827 if (!ieee80211_sdata_running(sdata) ||
828 !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
829 return NULL;
830 return &sdata->vif;
831}
832EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif);
833
Emmanuel Grumbachdc5a1ad2015-03-12 08:53:24 +0200834struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif)
835{
Johannes Berg6513e982015-06-10 20:18:55 +0300836 struct ieee80211_sub_if_data *sdata;
837
838 if (!vif)
839 return NULL;
840
841 sdata = vif_to_sdata(vif);
Emmanuel Grumbachdc5a1ad2015-03-12 08:53:24 +0200842
843 if (!ieee80211_sdata_running(sdata) ||
844 !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
845 return NULL;
846
847 return &sdata->wdev;
848}
849EXPORT_SYMBOL_GPL(ieee80211_vif_to_wdev);
850
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -0400851/*
852 * Nothing should have been stuffed into the workqueue during
Emmanuel Grumbach4afaff12015-01-22 23:32:46 +0200853 * the suspend->resume cycle. Since we can't check each caller
854 * of this function if we are already quiescing / suspended,
855 * check here and don't WARN since this can actually happen when
856 * the rx path (for example) is racing against __ieee80211_suspend
857 * and suspending / quiescing was set after the rx path checked
858 * them.
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -0400859 */
860static bool ieee80211_can_queue_work(struct ieee80211_local *local)
861{
Emmanuel Grumbach4afaff12015-01-22 23:32:46 +0200862 if (local->quiescing || (local->suspended && !local->resuming)) {
863 pr_warn("queueing ieee80211 work while going to suspend\n");
Johannes Bergceb99fe2009-11-19 14:29:39 +0100864 return false;
Emmanuel Grumbach4afaff12015-01-22 23:32:46 +0200865 }
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -0400866
867 return true;
868}
869
870void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work)
871{
872 struct ieee80211_local *local = hw_to_local(hw);
873
874 if (!ieee80211_can_queue_work(local))
875 return;
876
877 queue_work(local->workqueue, work);
878}
879EXPORT_SYMBOL(ieee80211_queue_work);
880
881void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
882 struct delayed_work *dwork,
883 unsigned long delay)
884{
885 struct ieee80211_local *local = hw_to_local(hw);
886
887 if (!ieee80211_can_queue_work(local))
888 return;
889
890 queue_delayed_work(local->workqueue, dwork, delay);
891}
892EXPORT_SYMBOL(ieee80211_queue_delayed_work);
893
Johannes Berg35d865a2013-05-28 10:54:03 +0200894u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
Johannes Bergdd769862011-11-18 16:54:50 +0100895 struct ieee802_11_elems *elems,
896 u64 filter, u32 crc)
897{
Johannes Bergc17e28d2019-02-07 22:18:19 +0100898 struct element *elem;
Johannes Bergdd769862011-11-18 16:54:50 +0100899 bool calc_crc = filter != 0;
Paul Stewartfcff4f12012-02-23 17:59:53 -0800900 DECLARE_BITMAP(seen_elems, 256);
Johannes Bergb2e506b2013-03-26 14:54:16 +0100901 const u8 *ie;
Johannes Bergdd769862011-11-18 16:54:50 +0100902
Paul Stewartfcff4f12012-02-23 17:59:53 -0800903 bitmap_zero(seen_elems, 256);
Johannes Bergdd769862011-11-18 16:54:50 +0100904 memset(elems, 0, sizeof(*elems));
905 elems->ie_start = start;
906 elems->total_len = len;
907
Johannes Bergc17e28d2019-02-07 22:18:19 +0100908 for_each_element(elem, start, len) {
Paul Stewartfcff4f12012-02-23 17:59:53 -0800909 bool elem_parse_failed;
Johannes Bergc17e28d2019-02-07 22:18:19 +0100910 u8 id = elem->id;
911 u8 elen = elem->datalen;
912 const u8 *pos = elem->data;
Paul Stewartfcff4f12012-02-23 17:59:53 -0800913
Johannes Berg9690fb12012-10-24 14:19:53 +0200914 switch (id) {
915 case WLAN_EID_SSID:
916 case WLAN_EID_SUPP_RATES:
917 case WLAN_EID_FH_PARAMS:
918 case WLAN_EID_DS_PARAMS:
919 case WLAN_EID_CF_PARAMS:
920 case WLAN_EID_TIM:
921 case WLAN_EID_IBSS_PARAMS:
922 case WLAN_EID_CHALLENGE:
923 case WLAN_EID_RSN:
924 case WLAN_EID_ERP_INFO:
925 case WLAN_EID_EXT_SUPP_RATES:
926 case WLAN_EID_HT_CAPABILITY:
927 case WLAN_EID_HT_OPERATION:
928 case WLAN_EID_VHT_CAPABILITY:
929 case WLAN_EID_VHT_OPERATION:
930 case WLAN_EID_MESH_ID:
931 case WLAN_EID_MESH_CONFIG:
932 case WLAN_EID_PEER_MGMT:
933 case WLAN_EID_PREQ:
934 case WLAN_EID_PREP:
935 case WLAN_EID_PERR:
936 case WLAN_EID_RANN:
937 case WLAN_EID_CHANNEL_SWITCH:
938 case WLAN_EID_EXT_CHANSWITCH_ANN:
939 case WLAN_EID_COUNTRY:
940 case WLAN_EID_PWR_CONSTRAINT:
941 case WLAN_EID_TIMEOUT_INTERVAL:
Johannes Berg85220d72013-03-25 18:29:27 +0100942 case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
Johannes Bergb2e506b2013-03-26 14:54:16 +0100943 case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
Chun-Yeow Yeoh8f2535b2013-10-14 19:08:27 -0700944 case WLAN_EID_CHAN_SWITCH_PARAM:
Arik Nemtsov9041c1f2014-11-09 18:50:15 +0200945 case WLAN_EID_EXT_CAPABILITY:
Arik Nemtsov538375842014-11-09 18:50:18 +0200946 case WLAN_EID_CHAN_SWITCH_TIMING:
947 case WLAN_EID_LINK_ID:
Avraham Sterne38a0172017-04-26 10:58:47 +0300948 case WLAN_EID_BSS_MAX_IDLE_PERIOD:
Johannes Bergb2e506b2013-03-26 14:54:16 +0100949 /*
950 * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible
951 * that if the content gets bigger it might be needed more than once
952 */
Johannes Berg9690fb12012-10-24 14:19:53 +0200953 if (test_bit(id, seen_elems)) {
954 elems->parse_error = true;
Johannes Berg9690fb12012-10-24 14:19:53 +0200955 continue;
956 }
957 break;
Paul Stewartfcff4f12012-02-23 17:59:53 -0800958 }
Johannes Bergdd769862011-11-18 16:54:50 +0100959
960 if (calc_crc && id < 64 && (filter & (1ULL << id)))
961 crc = crc32_be(crc, pos - 2, elen + 2);
962
Paul Stewartfcff4f12012-02-23 17:59:53 -0800963 elem_parse_failed = false;
964
Johannes Bergdd769862011-11-18 16:54:50 +0100965 switch (id) {
Arik Nemtsov538375842014-11-09 18:50:18 +0200966 case WLAN_EID_LINK_ID:
967 if (elen + 2 != sizeof(struct ieee80211_tdls_lnkie)) {
968 elem_parse_failed = true;
969 break;
970 }
971 elems->lnk_id = (void *)(pos - 2);
972 break;
973 case WLAN_EID_CHAN_SWITCH_TIMING:
974 if (elen != sizeof(struct ieee80211_ch_switch_timing)) {
975 elem_parse_failed = true;
976 break;
977 }
978 elems->ch_sw_timing = (void *)pos;
979 break;
Arik Nemtsov9041c1f2014-11-09 18:50:15 +0200980 case WLAN_EID_EXT_CAPABILITY:
981 elems->ext_capab = pos;
982 elems->ext_capab_len = elen;
983 break;
Johannes Bergdd769862011-11-18 16:54:50 +0100984 case WLAN_EID_SSID:
985 elems->ssid = pos;
986 elems->ssid_len = elen;
987 break;
988 case WLAN_EID_SUPP_RATES:
989 elems->supp_rates = pos;
990 elems->supp_rates_len = elen;
991 break;
Johannes Bergdd769862011-11-18 16:54:50 +0100992 case WLAN_EID_DS_PARAMS:
Johannes Berg1cd8e882013-03-27 14:30:12 +0100993 if (elen >= 1)
994 elems->ds_params = pos;
995 else
996 elem_parse_failed = true;
Johannes Bergdd769862011-11-18 16:54:50 +0100997 break;
Johannes Bergdd769862011-11-18 16:54:50 +0100998 case WLAN_EID_TIM:
999 if (elen >= sizeof(struct ieee80211_tim_ie)) {
1000 elems->tim = (void *)pos;
1001 elems->tim_len = elen;
Paul Stewartfcff4f12012-02-23 17:59:53 -08001002 } else
1003 elem_parse_failed = true;
Johannes Bergdd769862011-11-18 16:54:50 +01001004 break;
Johannes Bergdd769862011-11-18 16:54:50 +01001005 case WLAN_EID_CHALLENGE:
1006 elems->challenge = pos;
1007 elems->challenge_len = elen;
1008 break;
1009 case WLAN_EID_VENDOR_SPECIFIC:
1010 if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
1011 pos[2] == 0xf2) {
1012 /* Microsoft OUI (00:50:F2) */
1013
1014 if (calc_crc)
1015 crc = crc32_be(crc, pos - 2, elen + 2);
1016
Johannes Berg441a33b2013-02-12 16:27:04 +01001017 if (elen >= 5 && pos[3] == 2) {
Johannes Bergdd769862011-11-18 16:54:50 +01001018 /* OUI Type 2 - WMM IE */
1019 if (pos[4] == 0) {
1020 elems->wmm_info = pos;
1021 elems->wmm_info_len = elen;
1022 } else if (pos[4] == 1) {
1023 elems->wmm_param = pos;
1024 elems->wmm_param_len = elen;
1025 }
1026 }
1027 }
1028 break;
1029 case WLAN_EID_RSN:
1030 elems->rsn = pos;
1031 elems->rsn_len = elen;
1032 break;
1033 case WLAN_EID_ERP_INFO:
Johannes Berg1946bed2013-03-27 14:31:53 +01001034 if (elen >= 1)
1035 elems->erp_info = pos;
1036 else
1037 elem_parse_failed = true;
Johannes Bergdd769862011-11-18 16:54:50 +01001038 break;
1039 case WLAN_EID_EXT_SUPP_RATES:
1040 elems->ext_supp_rates = pos;
1041 elems->ext_supp_rates_len = elen;
1042 break;
1043 case WLAN_EID_HT_CAPABILITY:
1044 if (elen >= sizeof(struct ieee80211_ht_cap))
1045 elems->ht_cap_elem = (void *)pos;
Paul Stewartfcff4f12012-02-23 17:59:53 -08001046 else
1047 elem_parse_failed = true;
Johannes Bergdd769862011-11-18 16:54:50 +01001048 break;
Johannes Berg074d46d2012-03-15 19:45:16 +01001049 case WLAN_EID_HT_OPERATION:
1050 if (elen >= sizeof(struct ieee80211_ht_operation))
1051 elems->ht_operation = (void *)pos;
Paul Stewartfcff4f12012-02-23 17:59:53 -08001052 else
1053 elem_parse_failed = true;
Johannes Bergdd769862011-11-18 16:54:50 +01001054 break;
Mahesh Palivela818255e2012-10-10 11:33:04 +00001055 case WLAN_EID_VHT_CAPABILITY:
1056 if (elen >= sizeof(struct ieee80211_vht_cap))
1057 elems->vht_cap_elem = (void *)pos;
1058 else
1059 elem_parse_failed = true;
1060 break;
1061 case WLAN_EID_VHT_OPERATION:
1062 if (elen >= sizeof(struct ieee80211_vht_operation))
1063 elems->vht_operation = (void *)pos;
1064 else
1065 elem_parse_failed = true;
1066 break;
Johannes Bergbee7f5862013-02-07 22:24:55 +01001067 case WLAN_EID_OPMODE_NOTIF:
1068 if (elen > 0)
1069 elems->opmode_notif = pos;
1070 else
1071 elem_parse_failed = true;
1072 break;
Johannes Bergdd769862011-11-18 16:54:50 +01001073 case WLAN_EID_MESH_ID:
1074 elems->mesh_id = pos;
1075 elems->mesh_id_len = elen;
1076 break;
1077 case WLAN_EID_MESH_CONFIG:
1078 if (elen >= sizeof(struct ieee80211_meshconf_ie))
1079 elems->mesh_config = (void *)pos;
Paul Stewartfcff4f12012-02-23 17:59:53 -08001080 else
1081 elem_parse_failed = true;
Johannes Bergdd769862011-11-18 16:54:50 +01001082 break;
1083 case WLAN_EID_PEER_MGMT:
1084 elems->peering = pos;
1085 elems->peering_len = elen;
1086 break;
Marco Porsch3f52b7e2013-01-30 18:14:08 +01001087 case WLAN_EID_MESH_AWAKE_WINDOW:
1088 if (elen >= 2)
1089 elems->awake_window = (void *)pos;
1090 break;
Johannes Bergdd769862011-11-18 16:54:50 +01001091 case WLAN_EID_PREQ:
1092 elems->preq = pos;
1093 elems->preq_len = elen;
1094 break;
1095 case WLAN_EID_PREP:
1096 elems->prep = pos;
1097 elems->prep_len = elen;
1098 break;
1099 case WLAN_EID_PERR:
1100 elems->perr = pos;
1101 elems->perr_len = elen;
1102 break;
1103 case WLAN_EID_RANN:
1104 if (elen >= sizeof(struct ieee80211_rann_ie))
1105 elems->rann = (void *)pos;
Paul Stewartfcff4f12012-02-23 17:59:53 -08001106 else
1107 elem_parse_failed = true;
Johannes Bergdd769862011-11-18 16:54:50 +01001108 break;
1109 case WLAN_EID_CHANNEL_SWITCH:
Johannes Berg5bc14202012-08-01 16:13:02 +02001110 if (elen != sizeof(struct ieee80211_channel_sw_ie)) {
1111 elem_parse_failed = true;
1112 break;
1113 }
1114 elems->ch_switch_ie = (void *)pos;
Johannes Bergdd769862011-11-18 16:54:50 +01001115 break;
Johannes Bergb4f286a12013-03-26 14:13:58 +01001116 case WLAN_EID_EXT_CHANSWITCH_ANN:
1117 if (elen != sizeof(struct ieee80211_ext_chansw_ie)) {
1118 elem_parse_failed = true;
1119 break;
1120 }
1121 elems->ext_chansw_ie = (void *)pos;
1122 break;
Johannes Berg85220d72013-03-25 18:29:27 +01001123 case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
1124 if (elen != sizeof(struct ieee80211_sec_chan_offs_ie)) {
1125 elem_parse_failed = true;
1126 break;
1127 }
1128 elems->sec_chan_offs = (void *)pos;
1129 break;
Chun-Yeow Yeoh8f2535b2013-10-14 19:08:27 -07001130 case WLAN_EID_CHAN_SWITCH_PARAM:
1131 if (elen !=
1132 sizeof(*elems->mesh_chansw_params_ie)) {
1133 elem_parse_failed = true;
1134 break;
1135 }
1136 elems->mesh_chansw_params_ie = (void *)pos;
1137 break;
Johannes Bergb2e506b2013-03-26 14:54:16 +01001138 case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
1139 if (!action ||
1140 elen != sizeof(*elems->wide_bw_chansw_ie)) {
1141 elem_parse_failed = true;
1142 break;
1143 }
1144 elems->wide_bw_chansw_ie = (void *)pos;
1145 break;
1146 case WLAN_EID_CHANNEL_SWITCH_WRAPPER:
1147 if (action) {
1148 elem_parse_failed = true;
1149 break;
1150 }
1151 /*
1152 * This is a bit tricky, but as we only care about
1153 * the wide bandwidth channel switch element, so
1154 * just parse it out manually.
1155 */
1156 ie = cfg80211_find_ie(WLAN_EID_WIDE_BW_CHANNEL_SWITCH,
1157 pos, elen);
1158 if (ie) {
1159 if (ie[1] == sizeof(*elems->wide_bw_chansw_ie))
1160 elems->wide_bw_chansw_ie =
1161 (void *)(ie + 2);
1162 else
1163 elem_parse_failed = true;
1164 }
1165 break;
Johannes Bergdd769862011-11-18 16:54:50 +01001166 case WLAN_EID_COUNTRY:
1167 elems->country_elem = pos;
1168 elems->country_elem_len = elen;
1169 break;
1170 case WLAN_EID_PWR_CONSTRAINT:
Johannes Berg761a48d2012-09-05 13:07:00 +02001171 if (elen != 1) {
1172 elem_parse_failed = true;
1173 break;
1174 }
Johannes Bergdd769862011-11-18 16:54:50 +01001175 elems->pwr_constr_elem = pos;
Johannes Bergdd769862011-11-18 16:54:50 +01001176 break;
Steinar H. Gundersonc8d65912014-09-03 06:48:37 -07001177 case WLAN_EID_CISCO_VENDOR_SPECIFIC:
1178 /* Lots of different options exist, but we only care
1179 * about the Dynamic Transmit Power Control element.
1180 * First check for the Cisco OUI, then for the DTPC
1181 * tag (0x00).
1182 */
1183 if (elen < 4) {
1184 elem_parse_failed = true;
1185 break;
1186 }
1187
1188 if (pos[0] != 0x00 || pos[1] != 0x40 ||
1189 pos[2] != 0x96 || pos[3] != 0x00)
1190 break;
1191
1192 if (elen != 6) {
1193 elem_parse_failed = true;
1194 break;
1195 }
1196
1197 if (calc_crc)
1198 crc = crc32_be(crc, pos - 2, elen + 2);
1199
1200 elems->cisco_dtpc_elem = pos;
1201 break;
Johannes Bergdd769862011-11-18 16:54:50 +01001202 case WLAN_EID_TIMEOUT_INTERVAL:
Johannes Berg79ba1d82013-03-27 14:38:07 +01001203 if (elen >= sizeof(struct ieee80211_timeout_interval_ie))
1204 elems->timeout_int = (void *)pos;
1205 else
1206 elem_parse_failed = true;
Johannes Bergdd769862011-11-18 16:54:50 +01001207 break;
Avraham Sterne38a0172017-04-26 10:58:47 +03001208 case WLAN_EID_BSS_MAX_IDLE_PERIOD:
1209 if (elen >= sizeof(*elems->max_idle_period_ie))
1210 elems->max_idle_period_ie = (void *)pos;
1211 break;
Luca Coelho41cbb0f2018-06-09 09:14:44 +03001212 case WLAN_EID_EXTENSION:
1213 if (pos[0] == WLAN_EID_EXT_HE_MU_EDCA &&
1214 elen >= (sizeof(*elems->mu_edca_param_set) + 1)) {
1215 elems->mu_edca_param_set = (void *)&pos[1];
Shaul Triebitz2e249fc2018-12-15 11:03:15 +02001216 if (calc_crc)
1217 crc = crc32_be(crc, pos - 2, elen + 2);
Luca Coelho41cbb0f2018-06-09 09:14:44 +03001218 } else if (pos[0] == WLAN_EID_EXT_HE_CAPABILITY) {
1219 elems->he_cap = (void *)&pos[1];
1220 elems->he_cap_len = elen - 1;
1221 } else if (pos[0] == WLAN_EID_EXT_HE_OPERATION &&
1222 elen >= sizeof(*elems->he_operation) &&
1223 elen >= ieee80211_he_oper_size(&pos[1])) {
1224 elems->he_operation = (void *)&pos[1];
1225 } else if (pos[0] == WLAN_EID_EXT_UORA && elen >= 1) {
1226 elems->uora_element = (void *)&pos[1];
1227 }
1228 break;
Johannes Bergdd769862011-11-18 16:54:50 +01001229 default:
1230 break;
1231 }
1232
Paul Stewartfcff4f12012-02-23 17:59:53 -08001233 if (elem_parse_failed)
1234 elems->parse_error = true;
1235 else
Johannes Berg5df45692012-10-24 14:22:37 +02001236 __set_bit(id, seen_elems);
Johannes Bergdd769862011-11-18 16:54:50 +01001237 }
1238
Johannes Bergc17e28d2019-02-07 22:18:19 +01001239 if (!for_each_element_completed(elem, start, len))
Paul Stewartfcff4f12012-02-23 17:59:53 -08001240 elems->parse_error = true;
1241
Johannes Bergdd769862011-11-18 16:54:50 +01001242 return crc;
1243}
1244
Haim Dreyfusse552af02018-03-28 13:24:10 +03001245void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
1246 struct ieee80211_tx_queue_params
1247 *qparam, int ac)
1248{
1249 struct ieee80211_chanctx_conf *chanctx_conf;
1250 const struct ieee80211_reg_rule *rrule;
Stanislaw Gruszka38cb87e2018-08-22 13:52:21 +02001251 const struct ieee80211_wmm_ac *wmm_ac;
Haim Dreyfusse552af02018-03-28 13:24:10 +03001252 u16 center_freq = 0;
1253
1254 if (sdata->vif.type != NL80211_IFTYPE_AP &&
1255 sdata->vif.type != NL80211_IFTYPE_STATION)
1256 return;
1257
1258 rcu_read_lock();
1259 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
1260 if (chanctx_conf)
1261 center_freq = chanctx_conf->def.chan->center_freq;
1262
1263 if (!center_freq) {
1264 rcu_read_unlock();
1265 return;
1266 }
1267
1268 rrule = freq_reg_info(sdata->wdev.wiphy, MHZ_TO_KHZ(center_freq));
1269
Stanislaw Gruszka38cb87e2018-08-22 13:52:21 +02001270 if (IS_ERR_OR_NULL(rrule) || !rrule->has_wmm) {
Haim Dreyfusse552af02018-03-28 13:24:10 +03001271 rcu_read_unlock();
1272 return;
1273 }
1274
1275 if (sdata->vif.type == NL80211_IFTYPE_AP)
Stanislaw Gruszka38cb87e2018-08-22 13:52:21 +02001276 wmm_ac = &rrule->wmm_rule.ap[ac];
Haim Dreyfusse552af02018-03-28 13:24:10 +03001277 else
Stanislaw Gruszka38cb87e2018-08-22 13:52:21 +02001278 wmm_ac = &rrule->wmm_rule.client[ac];
Haim Dreyfusse552af02018-03-28 13:24:10 +03001279 qparam->cw_min = max_t(u16, qparam->cw_min, wmm_ac->cw_min);
1280 qparam->cw_max = max_t(u16, qparam->cw_max, wmm_ac->cw_max);
1281 qparam->aifs = max_t(u8, qparam->aifs, wmm_ac->aifsn);
Dreyfuss, Haimabd76d22018-08-31 11:31:04 +03001282 qparam->txop = min_t(u16, qparam->txop, wmm_ac->cot / 32);
Haim Dreyfusse552af02018-03-28 13:24:10 +03001283 rcu_read_unlock();
1284}
1285
Johannes Berg3abead52012-03-02 15:56:59 +01001286void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
Johannes Bergcec66282015-10-22 17:46:04 +02001287 bool bss_notify, bool enable_qos)
Johannes Berg5825fe102008-09-09 12:56:01 +02001288{
1289 struct ieee80211_local *local = sdata->local;
1290 struct ieee80211_tx_queue_params qparam;
Johannes Berg55de9082012-07-26 17:24:39 +02001291 struct ieee80211_chanctx_conf *chanctx_conf;
Johannes Berg54bcbc62012-03-28 11:04:25 +02001292 int ac;
Johannes Bergcec66282015-10-22 17:46:04 +02001293 bool use_11b;
Rostislav Lisovy239281f2014-11-03 10:33:19 +01001294 bool is_ocb; /* Use another EDCA parameters if dot11OCBActivated=true */
Johannes Bergaa837e12009-05-07 16:16:24 +02001295 int aCWmin, aCWmax;
Johannes Berg5825fe102008-09-09 12:56:01 +02001296
1297 if (!local->ops->conf_tx)
1298 return;
1299
Johannes Berg54bcbc62012-03-28 11:04:25 +02001300 if (local->hw.queues < IEEE80211_NUM_ACS)
1301 return;
1302
Johannes Berg5825fe102008-09-09 12:56:01 +02001303 memset(&qparam, 0, sizeof(qparam));
1304
Johannes Berg55de9082012-07-26 17:24:39 +02001305 rcu_read_lock();
1306 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
1307 use_11b = (chanctx_conf &&
Johannes Berg57fbcce2016-04-12 15:56:15 +02001308 chanctx_conf->def.chan->band == NL80211_BAND_2GHZ) &&
Johannes Bergaa837e12009-05-07 16:16:24 +02001309 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
Johannes Berg55de9082012-07-26 17:24:39 +02001310 rcu_read_unlock();
Johannes Berg5825fe102008-09-09 12:56:01 +02001311
Rostislav Lisovy239281f2014-11-03 10:33:19 +01001312 is_ocb = (sdata->vif.type == NL80211_IFTYPE_OCB);
1313
Fred Zhou1f4ffde2013-09-09 23:03:41 +08001314 /* Set defaults according to 802.11-2007 Table 7-37 */
1315 aCWmax = 1023;
1316 if (use_11b)
1317 aCWmin = 31;
1318 else
1319 aCWmin = 15;
Johannes Berg5825fe102008-09-09 12:56:01 +02001320
Fred Zhou1f4ffde2013-09-09 23:03:41 +08001321 /* Confiure old 802.11b/g medium access rules. */
1322 qparam.cw_max = aCWmax;
1323 qparam.cw_min = aCWmin;
1324 qparam.txop = 0;
1325 qparam.aifs = 2;
1326
1327 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
1328 /* Update if QoS is enabled. */
Stanislaw Gruszkaa8ce85442012-05-30 10:56:46 +02001329 if (enable_qos) {
1330 switch (ac) {
1331 case IEEE80211_AC_BK:
1332 qparam.cw_max = aCWmax;
1333 qparam.cw_min = aCWmin;
1334 qparam.txop = 0;
Rostislav Lisovy239281f2014-11-03 10:33:19 +01001335 if (is_ocb)
1336 qparam.aifs = 9;
1337 else
1338 qparam.aifs = 7;
Stanislaw Gruszkaa8ce85442012-05-30 10:56:46 +02001339 break;
1340 /* never happens but let's not leave undefined */
1341 default:
1342 case IEEE80211_AC_BE:
1343 qparam.cw_max = aCWmax;
1344 qparam.cw_min = aCWmin;
1345 qparam.txop = 0;
Rostislav Lisovy239281f2014-11-03 10:33:19 +01001346 if (is_ocb)
1347 qparam.aifs = 6;
1348 else
1349 qparam.aifs = 3;
Stanislaw Gruszkaa8ce85442012-05-30 10:56:46 +02001350 break;
1351 case IEEE80211_AC_VI:
1352 qparam.cw_max = aCWmin;
1353 qparam.cw_min = (aCWmin + 1) / 2 - 1;
Rostislav Lisovy239281f2014-11-03 10:33:19 +01001354 if (is_ocb)
1355 qparam.txop = 0;
1356 else if (use_11b)
Stanislaw Gruszkaa8ce85442012-05-30 10:56:46 +02001357 qparam.txop = 6016/32;
1358 else
1359 qparam.txop = 3008/32;
Rostislav Lisovy239281f2014-11-03 10:33:19 +01001360
1361 if (is_ocb)
1362 qparam.aifs = 3;
1363 else
1364 qparam.aifs = 2;
Stanislaw Gruszkaa8ce85442012-05-30 10:56:46 +02001365 break;
1366 case IEEE80211_AC_VO:
1367 qparam.cw_max = (aCWmin + 1) / 2 - 1;
1368 qparam.cw_min = (aCWmin + 1) / 4 - 1;
Rostislav Lisovy239281f2014-11-03 10:33:19 +01001369 if (is_ocb)
1370 qparam.txop = 0;
1371 else if (use_11b)
Stanislaw Gruszkaa8ce85442012-05-30 10:56:46 +02001372 qparam.txop = 3264/32;
1373 else
1374 qparam.txop = 1504/32;
1375 qparam.aifs = 2;
1376 break;
1377 }
Johannes Bergaa837e12009-05-07 16:16:24 +02001378 }
Haim Dreyfusse552af02018-03-28 13:24:10 +03001379 ieee80211_regulatory_limit_wmm_params(sdata, &qparam, ac);
Johannes Berg5825fe102008-09-09 12:56:01 +02001380
Kalle Valoab133152010-01-12 10:42:31 +02001381 qparam.uapsd = false;
1382
Johannes Berg54bcbc62012-03-28 11:04:25 +02001383 sdata->tx_conf[ac] = qparam;
1384 drv_conf_tx(local, sdata, ac, &qparam);
Johannes Bergaa837e12009-05-07 16:16:24 +02001385 }
Stanislaw Gruszkae1b3ec12010-03-29 12:18:34 +02001386
Johannes Bergf142c6b2012-06-18 20:07:15 +02001387 if (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
Ayala Beker708d50e2016-09-20 17:31:14 +03001388 sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
1389 sdata->vif.type != NL80211_IFTYPE_NAN) {
Stanislaw Gruszkaa8ce85442012-05-30 10:56:46 +02001390 sdata->vif.bss_conf.qos = enable_qos;
Johannes Berg3abead52012-03-02 15:56:59 +01001391 if (bss_notify)
1392 ieee80211_bss_info_change_notify(sdata,
1393 BSS_CHANGED_QOS);
Sujithd9734972010-07-23 10:47:11 +05301394 }
Johannes Berg5825fe102008-09-09 12:56:01 +02001395}
Johannes Berge50db652008-09-09 15:07:09 +02001396
Johannes Berg46900292009-02-15 12:44:28 +01001397void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
Jouni Malinen700e8ea2012-09-30 19:29:37 +03001398 u16 transaction, u16 auth_alg, u16 status,
Johannes Berg4a3cb702013-02-12 16:43:19 +01001399 const u8 *extra, size_t extra_len, const u8 *da,
Johannes Berg1672c0e32013-01-29 15:02:27 +01001400 const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx,
1401 u32 tx_flags)
Johannes Berg46900292009-02-15 12:44:28 +01001402{
1403 struct ieee80211_local *local = sdata->local;
1404 struct sk_buff *skb;
1405 struct ieee80211_mgmt *mgmt;
Johannes Bergfffd0932009-07-08 14:22:54 +02001406 int err;
Johannes Berg46900292009-02-15 12:44:28 +01001407
Fred Zhou15e230a2013-09-24 10:33:01 +08001408 /* 24 + 6 = header + auth_algo + auth_transaction + status_code */
Max Stepanov744462a2014-06-10 20:00:08 +03001409 skb = dev_alloc_skb(local->hw.extra_tx_headroom + IEEE80211_WEP_IV_LEN +
1410 24 + 6 + extra_len + IEEE80211_WEP_ICV_LEN);
Joe Perchesd15b8452011-08-29 14:17:31 -07001411 if (!skb)
Johannes Berg46900292009-02-15 12:44:28 +01001412 return;
Joe Perchesd15b8452011-08-29 14:17:31 -07001413
Max Stepanov744462a2014-06-10 20:00:08 +03001414 skb_reserve(skb, local->hw.extra_tx_headroom + IEEE80211_WEP_IV_LEN);
Johannes Berg46900292009-02-15 12:44:28 +01001415
Johannes Bergb080db52017-06-16 14:29:19 +02001416 mgmt = skb_put_zero(skb, 24 + 6);
Johannes Berg46900292009-02-15 12:44:28 +01001417 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
1418 IEEE80211_STYPE_AUTH);
Antonio Quartulliefa6a092012-01-09 19:43:06 +01001419 memcpy(mgmt->da, da, ETH_ALEN);
Johannes Berg47846c92009-11-25 17:46:19 +01001420 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
Johannes Berg46900292009-02-15 12:44:28 +01001421 memcpy(mgmt->bssid, bssid, ETH_ALEN);
1422 mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg);
1423 mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
Jouni Malinen700e8ea2012-09-30 19:29:37 +03001424 mgmt->u.auth.status_code = cpu_to_le16(status);
Johannes Berg46900292009-02-15 12:44:28 +01001425 if (extra)
Johannes Berg59ae1d12017-06-16 14:29:20 +02001426 skb_put_data(skb, extra, extra_len);
Johannes Berg46900292009-02-15 12:44:28 +01001427
Johannes Bergfffd0932009-07-08 14:22:54 +02001428 if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
1429 mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
1430 err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx);
1431 WARN_ON(err);
1432 }
1433
Johannes Berg1672c0e32013-01-29 15:02:27 +01001434 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
1435 tx_flags;
Johannes Berg62ae67b2009-11-18 18:42:05 +01001436 ieee80211_tx_skb(sdata, skb);
Johannes Berg46900292009-02-15 12:44:28 +01001437}
1438
Antonio Quartulli6ae16772012-09-07 13:28:52 +02001439void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
1440 const u8 *bssid, u16 stype, u16 reason,
1441 bool send_frame, u8 *frame_buf)
1442{
1443 struct ieee80211_local *local = sdata->local;
1444 struct sk_buff *skb;
1445 struct ieee80211_mgmt *mgmt = (void *)frame_buf;
1446
1447 /* build frame */
1448 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
1449 mgmt->duration = 0; /* initialize only */
1450 mgmt->seq_ctrl = 0; /* initialize only */
1451 memcpy(mgmt->da, bssid, ETH_ALEN);
1452 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
1453 memcpy(mgmt->bssid, bssid, ETH_ALEN);
1454 /* u.deauth.reason_code == u.disassoc.reason_code */
1455 mgmt->u.deauth.reason_code = cpu_to_le16(reason);
1456
1457 if (send_frame) {
1458 skb = dev_alloc_skb(local->hw.extra_tx_headroom +
1459 IEEE80211_DEAUTH_FRAME_LEN);
1460 if (!skb)
1461 return;
1462
1463 skb_reserve(skb, local->hw.extra_tx_headroom);
1464
1465 /* copy in frame */
Johannes Berg59ae1d12017-06-16 14:29:20 +02001466 skb_put_data(skb, mgmt, IEEE80211_DEAUTH_FRAME_LEN);
Antonio Quartulli6ae16772012-09-07 13:28:52 +02001467
1468 if (sdata->vif.type != NL80211_IFTYPE_STATION ||
1469 !(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED))
1470 IEEE80211_SKB_CB(skb)->flags |=
1471 IEEE80211_TX_INTFL_DONT_ENCRYPT;
1472
1473 ieee80211_tx_skb(sdata, skb);
1474 }
1475}
1476
David Spinadelc56ef672014-02-05 15:21:13 +02001477static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
1478 u8 *buffer, size_t buffer_len,
1479 const u8 *ie, size_t ie_len,
Johannes Berg57fbcce2016-04-12 15:56:15 +02001480 enum nl80211_band band,
David Spinadelc56ef672014-02-05 15:21:13 +02001481 u32 rate_mask,
1482 struct cfg80211_chan_def *chandef,
Johannes Berg00387f32018-05-28 15:47:38 +02001483 size_t *offset, u32 flags)
Johannes Bergde95a54b2009-04-01 11:58:36 +02001484{
1485 struct ieee80211_supported_band *sband;
Luca Coelho41cbb0f2018-06-09 09:14:44 +03001486 const struct ieee80211_sta_he_cap *he_cap;
Johannes Bergc604b9f2012-11-29 12:45:18 +01001487 u8 *pos = buffer, *end = buffer + buffer_len;
David Spinadelc56ef672014-02-05 15:21:13 +02001488 size_t noffset;
Johannes Berg8e664fb2009-12-23 13:15:38 +01001489 int supp_rates_len, i;
Jouni Malinen8dcb2002010-08-28 19:36:10 +03001490 u8 rates[32];
1491 int num_rates;
1492 int ext_rates_len;
Simon Wunderlich2103dec2013-07-08 16:55:53 +02001493 int shift;
1494 u32 rate_flags;
Johannes Berg40a11ca2014-11-24 15:49:44 +01001495 bool have_80mhz = false;
Johannes Bergde95a54b2009-04-01 11:58:36 +02001496
David Spinadelc56ef672014-02-05 15:21:13 +02001497 *offset = 0;
1498
Johannes Berg4d36ec52009-10-27 20:59:55 +01001499 sband = local->hw.wiphy->bands[band];
Arik Nemtsovd811b3d2012-07-09 19:57:28 +03001500 if (WARN_ON_ONCE(!sband))
1501 return 0;
Johannes Bergde95a54b2009-04-01 11:58:36 +02001502
Simon Wunderlich2103dec2013-07-08 16:55:53 +02001503 rate_flags = ieee80211_chandef_rate_flags(chandef);
1504 shift = ieee80211_chandef_get_shift(chandef);
1505
Jouni Malinen8dcb2002010-08-28 19:36:10 +03001506 num_rates = 0;
1507 for (i = 0; i < sband->n_bitrates; i++) {
1508 if ((BIT(i) & rate_mask) == 0)
1509 continue; /* skip rate */
Simon Wunderlich2103dec2013-07-08 16:55:53 +02001510 if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
1511 continue;
1512
1513 rates[num_rates++] =
1514 (u8) DIV_ROUND_UP(sband->bitrates[i].bitrate,
1515 (1 << shift) * 5);
Jouni Malinen8dcb2002010-08-28 19:36:10 +03001516 }
1517
1518 supp_rates_len = min_t(int, num_rates, 8);
Johannes Berg8e664fb2009-12-23 13:15:38 +01001519
Johannes Bergc604b9f2012-11-29 12:45:18 +01001520 if (end - pos < 2 + supp_rates_len)
1521 goto out_err;
Johannes Bergde95a54b2009-04-01 11:58:36 +02001522 *pos++ = WLAN_EID_SUPP_RATES;
Johannes Berg8e664fb2009-12-23 13:15:38 +01001523 *pos++ = supp_rates_len;
Jouni Malinen8dcb2002010-08-28 19:36:10 +03001524 memcpy(pos, rates, supp_rates_len);
1525 pos += supp_rates_len;
Johannes Bergde95a54b2009-04-01 11:58:36 +02001526
Johannes Berg8e664fb2009-12-23 13:15:38 +01001527 /* insert "request information" if in custom IEs */
1528 if (ie && ie_len) {
1529 static const u8 before_extrates[] = {
1530 WLAN_EID_SSID,
1531 WLAN_EID_SUPP_RATES,
1532 WLAN_EID_REQUEST,
1533 };
1534 noffset = ieee80211_ie_split(ie, ie_len,
1535 before_extrates,
1536 ARRAY_SIZE(before_extrates),
David Spinadelc56ef672014-02-05 15:21:13 +02001537 *offset);
1538 if (end - pos < noffset - *offset)
Johannes Bergc604b9f2012-11-29 12:45:18 +01001539 goto out_err;
David Spinadelc56ef672014-02-05 15:21:13 +02001540 memcpy(pos, ie + *offset, noffset - *offset);
1541 pos += noffset - *offset;
1542 *offset = noffset;
Johannes Berg8e664fb2009-12-23 13:15:38 +01001543 }
Johannes Bergde95a54b2009-04-01 11:58:36 +02001544
Jouni Malinen8dcb2002010-08-28 19:36:10 +03001545 ext_rates_len = num_rates - supp_rates_len;
1546 if (ext_rates_len > 0) {
Johannes Bergc604b9f2012-11-29 12:45:18 +01001547 if (end - pos < 2 + ext_rates_len)
1548 goto out_err;
Johannes Berg8e664fb2009-12-23 13:15:38 +01001549 *pos++ = WLAN_EID_EXT_SUPP_RATES;
Jouni Malinen8dcb2002010-08-28 19:36:10 +03001550 *pos++ = ext_rates_len;
1551 memcpy(pos, rates + supp_rates_len, ext_rates_len);
1552 pos += ext_rates_len;
Johannes Berg8e664fb2009-12-23 13:15:38 +01001553 }
1554
Johannes Berg57fbcce2016-04-12 15:56:15 +02001555 if (chandef->chan && sband->band == NL80211_BAND_2GHZ) {
Johannes Bergc604b9f2012-11-29 12:45:18 +01001556 if (end - pos < 3)
1557 goto out_err;
Jouni Malinen651b5222010-08-28 19:37:51 +03001558 *pos++ = WLAN_EID_DS_PARAMS;
1559 *pos++ = 1;
Simon Wunderlich2103dec2013-07-08 16:55:53 +02001560 *pos++ = ieee80211_frequency_to_channel(
1561 chandef->chan->center_freq);
Jouni Malinen651b5222010-08-28 19:37:51 +03001562 }
1563
Johannes Bergb9771d42018-05-28 15:47:41 +02001564 if (flags & IEEE80211_PROBE_FLAG_MIN_CONTENT)
1565 goto done;
1566
Johannes Berg8e664fb2009-12-23 13:15:38 +01001567 /* insert custom IEs that go before HT */
1568 if (ie && ie_len) {
1569 static const u8 before_ht[] = {
Johannes Berga7f26d82017-08-05 11:44:32 +03001570 /*
1571 * no need to list the ones split off already
1572 * (or generated here)
1573 */
Johannes Berg8e664fb2009-12-23 13:15:38 +01001574 WLAN_EID_DS_PARAMS,
1575 WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
1576 };
1577 noffset = ieee80211_ie_split(ie, ie_len,
1578 before_ht, ARRAY_SIZE(before_ht),
David Spinadelc56ef672014-02-05 15:21:13 +02001579 *offset);
1580 if (end - pos < noffset - *offset)
Johannes Bergc604b9f2012-11-29 12:45:18 +01001581 goto out_err;
David Spinadelc56ef672014-02-05 15:21:13 +02001582 memcpy(pos, ie + *offset, noffset - *offset);
1583 pos += noffset - *offset;
1584 *offset = noffset;
Johannes Bergde95a54b2009-04-01 11:58:36 +02001585 }
1586
Johannes Bergc604b9f2012-11-29 12:45:18 +01001587 if (sband->ht_cap.ht_supported) {
1588 if (end - pos < 2 + sizeof(struct ieee80211_ht_cap))
1589 goto out_err;
Ben Greearef96a8422011-11-18 11:32:00 -08001590 pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
1591 sband->ht_cap.cap);
Johannes Bergc604b9f2012-11-29 12:45:18 +01001592 }
Johannes Berg5ef2d412009-03-31 12:12:07 +02001593
Johannes Berg4d952302014-02-04 09:48:34 +01001594 /* insert custom IEs that go before VHT */
Johannes Berg8e664fb2009-12-23 13:15:38 +01001595 if (ie && ie_len) {
Johannes Berg4d952302014-02-04 09:48:34 +01001596 static const u8 before_vht[] = {
Johannes Berga7f26d82017-08-05 11:44:32 +03001597 /*
1598 * no need to list the ones split off already
1599 * (or generated here)
1600 */
Johannes Berg4d952302014-02-04 09:48:34 +01001601 WLAN_EID_BSS_COEX_2040,
1602 WLAN_EID_EXT_CAPABILITY,
1603 WLAN_EID_SSID_LIST,
1604 WLAN_EID_CHANNEL_USAGE,
1605 WLAN_EID_INTERWORKING,
Liad Kaufmanb44eebe2017-08-05 11:44:29 +03001606 WLAN_EID_MESH_ID,
Johannes Berga7f26d82017-08-05 11:44:32 +03001607 /* 60 GHz (Multi-band, DMG, MMS) can't happen */
Johannes Berg4d952302014-02-04 09:48:34 +01001608 };
1609 noffset = ieee80211_ie_split(ie, ie_len,
1610 before_vht, ARRAY_SIZE(before_vht),
David Spinadelc56ef672014-02-05 15:21:13 +02001611 *offset);
1612 if (end - pos < noffset - *offset)
Johannes Bergc604b9f2012-11-29 12:45:18 +01001613 goto out_err;
David Spinadelc56ef672014-02-05 15:21:13 +02001614 memcpy(pos, ie + *offset, noffset - *offset);
1615 pos += noffset - *offset;
1616 *offset = noffset;
Johannes Bergde95a54b2009-04-01 11:58:36 +02001617 }
1618
Johannes Berg40a11ca2014-11-24 15:49:44 +01001619 /* Check if any channel in this sband supports at least 80 MHz */
1620 for (i = 0; i < sband->n_channels; i++) {
Arik Nemtsovfa44b982015-01-01 13:43:17 +02001621 if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED |
1622 IEEE80211_CHAN_NO_80MHZ))
1623 continue;
1624
1625 have_80mhz = true;
1626 break;
Johannes Berg40a11ca2014-11-24 15:49:44 +01001627 }
1628
1629 if (sband->vht_cap.vht_supported && have_80mhz) {
Johannes Bergc604b9f2012-11-29 12:45:18 +01001630 if (end - pos < 2 + sizeof(struct ieee80211_vht_cap))
1631 goto out_err;
Mahesh Palivelaba0afa22012-07-02 11:25:12 +00001632 pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap,
1633 sband->vht_cap.cap);
Johannes Bergc604b9f2012-11-29 12:45:18 +01001634 }
Mahesh Palivelaba0afa22012-07-02 11:25:12 +00001635
Luca Coelho41cbb0f2018-06-09 09:14:44 +03001636 /* insert custom IEs that go before HE */
1637 if (ie && ie_len) {
1638 static const u8 before_he[] = {
1639 /*
1640 * no need to list the ones split off before VHT
1641 * or generated here
1642 */
1643 WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_REQ_PARAMS,
1644 WLAN_EID_AP_CSN,
1645 /* TODO: add 11ah/11aj/11ak elements */
1646 };
1647 noffset = ieee80211_ie_split(ie, ie_len,
1648 before_he, ARRAY_SIZE(before_he),
1649 *offset);
1650 if (end - pos < noffset - *offset)
1651 goto out_err;
1652 memcpy(pos, ie + *offset, noffset - *offset);
1653 pos += noffset - *offset;
1654 *offset = noffset;
1655 }
1656
1657 he_cap = ieee80211_get_he_sta_cap(sband);
1658 if (he_cap) {
1659 pos = ieee80211_ie_build_he_cap(pos, he_cap, end);
1660 if (!pos)
1661 goto out_err;
1662 }
1663
1664 /*
1665 * If adding more here, adjust code in main.c
1666 * that calculates local->scan_ies_len.
1667 */
1668
Johannes Bergde95a54b2009-04-01 11:58:36 +02001669 return pos - buffer;
Johannes Bergc604b9f2012-11-29 12:45:18 +01001670 out_err:
1671 WARN_ONCE(1, "not enough space for preq IEs\n");
Johannes Bergb9771d42018-05-28 15:47:41 +02001672 done:
Johannes Bergc604b9f2012-11-29 12:45:18 +01001673 return pos - buffer;
Johannes Bergde95a54b2009-04-01 11:58:36 +02001674}
1675
David Spinadelc56ef672014-02-05 15:21:13 +02001676int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1677 size_t buffer_len,
1678 struct ieee80211_scan_ies *ie_desc,
1679 const u8 *ie, size_t ie_len,
1680 u8 bands_used, u32 *rate_masks,
Johannes Berg00387f32018-05-28 15:47:38 +02001681 struct cfg80211_chan_def *chandef,
1682 u32 flags)
David Spinadelc56ef672014-02-05 15:21:13 +02001683{
1684 size_t pos = 0, old_pos = 0, custom_ie_offset = 0;
1685 int i;
1686
1687 memset(ie_desc, 0, sizeof(*ie_desc));
1688
Johannes Berg57fbcce2016-04-12 15:56:15 +02001689 for (i = 0; i < NUM_NL80211_BANDS; i++) {
David Spinadelc56ef672014-02-05 15:21:13 +02001690 if (bands_used & BIT(i)) {
1691 pos += ieee80211_build_preq_ies_band(local,
1692 buffer + pos,
1693 buffer_len - pos,
1694 ie, ie_len, i,
1695 rate_masks[i],
1696 chandef,
Johannes Berg00387f32018-05-28 15:47:38 +02001697 &custom_ie_offset,
1698 flags);
David Spinadelc56ef672014-02-05 15:21:13 +02001699 ie_desc->ies[i] = buffer + old_pos;
1700 ie_desc->len[i] = pos - old_pos;
1701 old_pos = pos;
1702 }
1703 }
1704
1705 /* add any remaining custom IEs */
1706 if (ie && ie_len) {
1707 if (WARN_ONCE(buffer_len - pos < ie_len - custom_ie_offset,
1708 "not enough space for preq custom IEs\n"))
1709 return pos;
1710 memcpy(buffer + pos, ie + custom_ie_offset,
1711 ie_len - custom_ie_offset);
1712 ie_desc->common_ies = buffer + pos;
1713 ie_desc->common_ie_len = ie_len - custom_ie_offset;
1714 pos += ie_len - custom_ie_offset;
1715 }
1716
1717 return pos;
1718};
1719
Juuso Oikarinena619a4c2010-11-11 08:50:18 +02001720struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
Johannes Berga344d672014-06-12 22:24:31 +02001721 const u8 *src, const u8 *dst,
1722 u32 ratemask,
Johannes Berg6b778632012-07-23 14:53:27 +02001723 struct ieee80211_channel *chan,
Juuso Oikarinena619a4c2010-11-11 08:50:18 +02001724 const u8 *ssid, size_t ssid_len,
Paul Stewarta806c552011-06-23 09:00:11 -08001725 const u8 *ie, size_t ie_len,
Johannes Berg00387f32018-05-28 15:47:38 +02001726 u32 flags)
Johannes Berg46900292009-02-15 12:44:28 +01001727{
1728 struct ieee80211_local *local = sdata->local;
Simon Wunderlich2103dec2013-07-08 16:55:53 +02001729 struct cfg80211_chan_def chandef;
Johannes Berg46900292009-02-15 12:44:28 +01001730 struct sk_buff *skb;
1731 struct ieee80211_mgmt *mgmt;
Johannes Bergb9a9ada2012-11-29 13:00:10 +01001732 int ies_len;
Johannes Berg57fbcce2016-04-12 15:56:15 +02001733 u32 rate_masks[NUM_NL80211_BANDS] = {};
David Spinadelc56ef672014-02-05 15:21:13 +02001734 struct ieee80211_scan_ies dummy_ie_desc;
Johannes Berg46900292009-02-15 12:44:28 +01001735
Paul Stewarta806c552011-06-23 09:00:11 -08001736 /*
1737 * Do not send DS Channel parameter for directed probe requests
1738 * in order to maximize the chance that we get a response. Some
1739 * badly-behaved APs don't respond when this parameter is included.
1740 */
Simon Wunderlich2103dec2013-07-08 16:55:53 +02001741 chandef.width = sdata->vif.bss_conf.chandef.width;
Johannes Berg00387f32018-05-28 15:47:38 +02001742 if (flags & IEEE80211_PROBE_FLAG_DIRECTED)
Simon Wunderlich2103dec2013-07-08 16:55:53 +02001743 chandef.chan = NULL;
Paul Stewarta806c552011-06-23 09:00:11 -08001744 else
Simon Wunderlich2103dec2013-07-08 16:55:53 +02001745 chandef.chan = chan;
Jouni Malinen651b5222010-08-28 19:37:51 +03001746
Johannes Berga344d672014-06-12 22:24:31 +02001747 skb = ieee80211_probereq_get(&local->hw, src, ssid, ssid_len,
1748 100 + ie_len);
Johannes Berg5b2bbf72011-11-08 13:04:41 +01001749 if (!skb)
Johannes Bergb9a9ada2012-11-29 13:00:10 +01001750 return NULL;
1751
David Spinadelc56ef672014-02-05 15:21:13 +02001752 rate_masks[chan->band] = ratemask;
Johannes Bergb9a9ada2012-11-29 13:00:10 +01001753 ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb),
David Spinadelc56ef672014-02-05 15:21:13 +02001754 skb_tailroom(skb), &dummy_ie_desc,
1755 ie, ie_len, BIT(chan->band),
Johannes Berg00387f32018-05-28 15:47:38 +02001756 rate_masks, &chandef, flags);
Johannes Bergb9a9ada2012-11-29 13:00:10 +01001757 skb_put(skb, ies_len);
Kalle Valo7c12ce82010-01-05 20:16:44 +02001758
Johannes Berg46900292009-02-15 12:44:28 +01001759 if (dst) {
Kalle Valo7c12ce82010-01-05 20:16:44 +02001760 mgmt = (struct ieee80211_mgmt *) skb->data;
Johannes Berg46900292009-02-15 12:44:28 +01001761 memcpy(mgmt->da, dst, ETH_ALEN);
1762 memcpy(mgmt->bssid, dst, ETH_ALEN);
Johannes Berg46900292009-02-15 12:44:28 +01001763 }
Johannes Berg46900292009-02-15 12:44:28 +01001764
Johannes Berg62ae67b2009-11-18 18:42:05 +01001765 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
Johannes Berg5b2bbf72011-11-08 13:04:41 +01001766
Juuso Oikarinena619a4c2010-11-11 08:50:18 +02001767 return skb;
1768}
1769
Simon Wunderlich2103dec2013-07-08 16:55:53 +02001770u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata,
Johannes Berg46900292009-02-15 12:44:28 +01001771 struct ieee802_11_elems *elems,
Johannes Berg57fbcce2016-04-12 15:56:15 +02001772 enum nl80211_band band, u32 *basic_rates)
Johannes Berg46900292009-02-15 12:44:28 +01001773{
1774 struct ieee80211_supported_band *sband;
Johannes Berg46900292009-02-15 12:44:28 +01001775 size_t num_rates;
Simon Wunderlich2103dec2013-07-08 16:55:53 +02001776 u32 supp_rates, rate_flags;
1777 int i, j, shift;
Mohammed Shafi Shajakhan21a8e9d2017-04-27 12:45:38 +05301778
Simon Wunderlich2103dec2013-07-08 16:55:53 +02001779 sband = sdata->local->hw.wiphy->bands[band];
Mohammed Shafi Shajakhan21a8e9d2017-04-27 12:45:38 +05301780 if (WARN_ON(!sband))
1781 return 1;
Simon Wunderlich2103dec2013-07-08 16:55:53 +02001782
1783 rate_flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef);
1784 shift = ieee80211_vif_get_shift(&sdata->vif);
Johannes Berg46900292009-02-15 12:44:28 +01001785
Johannes Berg46900292009-02-15 12:44:28 +01001786 num_rates = sband->n_bitrates;
1787 supp_rates = 0;
1788 for (i = 0; i < elems->supp_rates_len +
1789 elems->ext_supp_rates_len; i++) {
1790 u8 rate = 0;
1791 int own_rate;
Ashok Nagarajan9ebb61a2012-04-02 21:21:21 -07001792 bool is_basic;
Johannes Berg46900292009-02-15 12:44:28 +01001793 if (i < elems->supp_rates_len)
1794 rate = elems->supp_rates[i];
1795 else if (elems->ext_supp_rates)
1796 rate = elems->ext_supp_rates
1797 [i - elems->supp_rates_len];
1798 own_rate = 5 * (rate & 0x7f);
Ashok Nagarajan9ebb61a2012-04-02 21:21:21 -07001799 is_basic = !!(rate & 0x80);
1800
1801 if (is_basic && (rate & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
1802 continue;
1803
1804 for (j = 0; j < num_rates; j++) {
Simon Wunderlich2103dec2013-07-08 16:55:53 +02001805 int brate;
1806 if ((rate_flags & sband->bitrates[j].flags)
1807 != rate_flags)
1808 continue;
1809
1810 brate = DIV_ROUND_UP(sband->bitrates[j].bitrate,
1811 1 << shift);
1812
1813 if (brate == own_rate) {
Johannes Berg46900292009-02-15 12:44:28 +01001814 supp_rates |= BIT(j);
Ashok Nagarajan9ebb61a2012-04-02 21:21:21 -07001815 if (basic_rates && is_basic)
1816 *basic_rates |= BIT(j);
1817 }
1818 }
Johannes Berg46900292009-02-15 12:44:28 +01001819 }
1820 return supp_rates;
1821}
Johannes Bergf2753dd2009-04-14 10:09:24 +02001822
Johannes Berg84f6a012009-08-20 20:02:20 +02001823void ieee80211_stop_device(struct ieee80211_local *local)
1824{
1825 ieee80211_led_radio(local, false);
Johannes Berg67408c82010-11-30 08:59:23 +01001826 ieee80211_mod_tpt_led_trig(local, 0, IEEE80211_TPT_LEDTRIG_FL_RADIO);
Johannes Berg84f6a012009-08-20 20:02:20 +02001827
1828 cancel_work_sync(&local->reconfig_filter);
Johannes Berg84f6a012009-08-20 20:02:20 +02001829
1830 flush_workqueue(local->workqueue);
Lennert Buytenhek678f4152010-01-10 14:07:53 +01001831 drv_stop(local);
Johannes Berg84f6a012009-08-20 20:02:20 +02001832}
1833
Johannes Berg74430f92015-12-08 16:04:38 +02001834static void ieee80211_flush_completed_scan(struct ieee80211_local *local,
1835 bool aborted)
1836{
1837 /* It's possible that we don't handle the scan completion in
1838 * time during suspend, so if it's still marked as completed
1839 * here, queue the work and flush it to clean things up.
1840 * Instead of calling the worker function directly here, we
1841 * really queue it to avoid potential races with other flows
1842 * scheduling the same work.
1843 */
1844 if (test_bit(SCAN_COMPLETED, &local->scanning)) {
1845 /* If coming from reconfiguration failure, abort the scan so
1846 * we don't attempt to continue a partial HW scan - which is
1847 * possible otherwise if (e.g.) the 2.4 GHz portion was the
1848 * completed scan, and a 5 GHz portion is still pending.
1849 */
1850 if (aborted)
1851 set_bit(SCAN_ABORTED, &local->scanning);
1852 ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0);
1853 flush_delayed_work(&local->scan_work);
1854 }
1855}
1856
Johannes Bergf6837ba82014-04-30 14:19:04 +02001857static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
1858{
1859 struct ieee80211_sub_if_data *sdata;
1860 struct ieee80211_chanctx *ctx;
1861
1862 /*
1863 * We get here if during resume the device can't be restarted properly.
1864 * We might also get here if this happens during HW reset, which is a
1865 * slightly different situation and we need to drop all connections in
1866 * the latter case.
1867 *
1868 * Ask cfg80211 to turn off all interfaces, this will result in more
1869 * warnings but at least we'll then get into a clean stopped state.
1870 */
1871
1872 local->resuming = false;
1873 local->suspended = false;
Eliad Peller7584f882015-06-10 20:19:37 +03001874 local->in_reconfig = false;
Johannes Bergf6837ba82014-04-30 14:19:04 +02001875
Johannes Berg74430f92015-12-08 16:04:38 +02001876 ieee80211_flush_completed_scan(local, true);
1877
Johannes Bergf6837ba82014-04-30 14:19:04 +02001878 /* scheduled scan clearly can't be running any more, but tell
1879 * cfg80211 and clear local state
1880 */
1881 ieee80211_sched_scan_end(local);
1882
1883 list_for_each_entry(sdata, &local->interfaces, list)
1884 sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
1885
1886 /* Mark channel contexts as not being in the driver any more to avoid
1887 * removing them from the driver during the shutdown process...
1888 */
1889 mutex_lock(&local->chanctx_mtx);
1890 list_for_each_entry(ctx, &local->chanctx_list, list)
1891 ctx->driver_present = false;
1892 mutex_unlock(&local->chanctx_mtx);
1893
1894 cfg80211_shutdown_all_interfaces(local->hw.wiphy);
1895}
1896
Stanislaw Gruszka153a5fc42013-02-28 10:55:30 +01001897static void ieee80211_assign_chanctx(struct ieee80211_local *local,
1898 struct ieee80211_sub_if_data *sdata)
1899{
1900 struct ieee80211_chanctx_conf *conf;
1901 struct ieee80211_chanctx *ctx;
1902
1903 if (!local->use_chanctx)
1904 return;
1905
1906 mutex_lock(&local->chanctx_mtx);
1907 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
1908 lockdep_is_held(&local->chanctx_mtx));
1909 if (conf) {
1910 ctx = container_of(conf, struct ieee80211_chanctx, conf);
1911 drv_assign_vif_chanctx(local, sdata, ctx);
1912 }
1913 mutex_unlock(&local->chanctx_mtx);
1914}
1915
Johannes Berg1ea2c862015-12-08 16:04:39 +02001916static void ieee80211_reconfig_stations(struct ieee80211_sub_if_data *sdata)
1917{
1918 struct ieee80211_local *local = sdata->local;
1919 struct sta_info *sta;
1920
1921 /* add STAs back */
1922 mutex_lock(&local->sta_mtx);
1923 list_for_each_entry(sta, &local->sta_list, list) {
1924 enum ieee80211_sta_state state;
1925
1926 if (!sta->uploaded || sta->sdata != sdata)
1927 continue;
1928
1929 for (state = IEEE80211_STA_NOTEXIST;
1930 state < sta->sta_state; state++)
1931 WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
1932 state + 1));
1933 }
1934 mutex_unlock(&local->sta_mtx);
1935}
1936
Ayala Beker167e33f2016-09-20 17:31:20 +03001937static int ieee80211_reconfig_nan(struct ieee80211_sub_if_data *sdata)
1938{
1939 struct cfg80211_nan_func *func, **funcs;
1940 int res, id, i = 0;
1941
1942 res = drv_start_nan(sdata->local, sdata,
1943 &sdata->u.nan.conf);
1944 if (WARN_ON(res))
1945 return res;
1946
Kees Cook6396bb22018-06-12 14:03:40 -07001947 funcs = kcalloc(sdata->local->hw.max_nan_de_entries + 1,
1948 sizeof(*funcs),
1949 GFP_KERNEL);
Ayala Beker167e33f2016-09-20 17:31:20 +03001950 if (!funcs)
1951 return -ENOMEM;
1952
1953 /* Add all the functions:
1954 * This is a little bit ugly. We need to call a potentially sleeping
1955 * callback for each NAN function, so we can't hold the spinlock.
1956 */
1957 spin_lock_bh(&sdata->u.nan.func_lock);
1958
1959 idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, id)
1960 funcs[i++] = func;
1961
1962 spin_unlock_bh(&sdata->u.nan.func_lock);
1963
1964 for (i = 0; funcs[i]; i++) {
1965 res = drv_add_nan_func(sdata->local, sdata, funcs[i]);
1966 if (WARN_ON(res))
1967 ieee80211_nan_func_terminated(&sdata->vif,
1968 funcs[i]->instance_id,
1969 NL80211_NAN_FUNC_TERM_REASON_ERROR,
1970 GFP_KERNEL);
1971 }
1972
1973 kfree(funcs);
1974
1975 return 0;
1976}
1977
Johannes Bergf2753dd2009-04-14 10:09:24 +02001978int ieee80211_reconfig(struct ieee80211_local *local)
1979{
1980 struct ieee80211_hw *hw = &local->hw;
1981 struct ieee80211_sub_if_data *sdata;
Johannes Berg55de9082012-07-26 17:24:39 +02001982 struct ieee80211_chanctx *ctx;
Johannes Bergf2753dd2009-04-14 10:09:24 +02001983 struct sta_info *sta;
Eliad Peller2683d652011-07-14 20:29:42 +03001984 int res, i;
Johannes Bergd8881302013-01-10 23:55:33 +01001985 bool reconfig_due_to_wowlan = false;
David Spinadeld43c6b62013-12-08 21:48:57 +02001986 struct ieee80211_sub_if_data *sched_scan_sdata;
Johannes Berg6ea0a692014-11-19 11:55:49 +01001987 struct cfg80211_sched_scan_request *sched_scan_req;
David Spinadeld43c6b62013-12-08 21:48:57 +02001988 bool sched_scan_stopped = false;
Eliad Pellerb0485e92015-07-08 15:41:47 +03001989 bool suspended = local->suspended;
Johannes Bergd8881302013-01-10 23:55:33 +01001990
Eliad Peller0f8b8242014-12-14 11:05:53 +02001991 /* nothing to do if HW shouldn't run */
1992 if (!local->open_count)
1993 goto wake_up;
1994
Johannes Berg8f21b0a2013-01-11 00:28:01 +01001995#ifdef CONFIG_PM
Eliad Pellerb0485e92015-07-08 15:41:47 +03001996 if (suspended)
Johannes Bergceb99fe2009-11-19 14:29:39 +01001997 local->resuming = true;
Johannes Bergf2753dd2009-04-14 10:09:24 +02001998
Johannes Bergeecc4802011-05-04 15:37:29 +02001999 if (local->wowlan) {
Eliad Pellerb0485e92015-07-08 15:41:47 +03002000 /*
2001 * In the wowlan case, both mac80211 and the device
2002 * are functional when the resume op is called, so
2003 * clear local->suspended so the device could operate
2004 * normally (e.g. pass rx frames).
2005 */
2006 local->suspended = false;
Johannes Bergeecc4802011-05-04 15:37:29 +02002007 res = drv_resume(local);
Johannes Berg27b3eb92013-08-07 20:11:55 +02002008 local->wowlan = false;
Johannes Bergeecc4802011-05-04 15:37:29 +02002009 if (res < 0) {
2010 local->resuming = false;
2011 return res;
2012 }
2013 if (res == 0)
2014 goto wake_up;
2015 WARN_ON(res > 1);
2016 /*
2017 * res is 1, which means the driver requested
2018 * to go through a regular reset on wakeup.
Eliad Pellerb0485e92015-07-08 15:41:47 +03002019 * restore local->suspended in this case.
Johannes Bergeecc4802011-05-04 15:37:29 +02002020 */
Johannes Bergd8881302013-01-10 23:55:33 +01002021 reconfig_due_to_wowlan = true;
Eliad Pellerb0485e92015-07-08 15:41:47 +03002022 local->suspended = true;
Johannes Bergeecc4802011-05-04 15:37:29 +02002023 }
2024#endif
Johannes Berg94f9b972011-07-14 16:48:54 +02002025
2026 /*
Eliad Peller43d6df02015-10-25 10:59:35 +02002027 * In case of hw_restart during suspend (without wowlan),
2028 * cancel restart work, as we are reconfiguring the device
2029 * anyway.
2030 * Note that restart_work is scheduled on a frozen workqueue,
2031 * so we can't deadlock in this case.
2032 */
2033 if (suspended && local->in_reconfig && !reconfig_due_to_wowlan)
2034 cancel_work_sync(&local->restart_work);
2035
Eliad Peller968a76c2015-10-25 10:59:36 +02002036 local->started = false;
2037
Eliad Peller43d6df02015-10-25 10:59:35 +02002038 /*
Johannes Berg94f9b972011-07-14 16:48:54 +02002039 * Upon resume hardware can sometimes be goofy due to
2040 * various platform / driver / bus issues, so restarting
2041 * the device may at times not work immediately. Propagate
2042 * the error.
2043 */
2044 res = drv_start(local);
2045 if (res) {
Eliad Pellerb0485e92015-07-08 15:41:47 +03002046 if (suspended)
Johannes Bergf6837ba82014-04-30 14:19:04 +02002047 WARN(1, "Hardware became unavailable upon resume. This could be a software issue prior to suspend or a hardware issue.\n");
2048 else
2049 WARN(1, "Hardware became unavailable during restart.\n");
2050 ieee80211_handle_reconfig_failure(local);
Johannes Berg94f9b972011-07-14 16:48:54 +02002051 return res;
Johannes Bergf2753dd2009-04-14 10:09:24 +02002052 }
2053
Yogesh Ashok Powar7f2819752011-12-30 16:34:25 +05302054 /* setup fragmentation threshold */
2055 drv_set_frag_threshold(local, hw->wiphy->frag_threshold);
2056
2057 /* setup RTS threshold */
2058 drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
2059
2060 /* reset coverage class */
2061 drv_set_coverage_class(local, hw->wiphy->coverage_class);
2062
Johannes Berg94f9b972011-07-14 16:48:54 +02002063 ieee80211_led_radio(local, true);
2064 ieee80211_mod_tpt_led_trig(local,
2065 IEEE80211_TPT_LEDTRIG_FL_RADIO, 0);
2066
Johannes Bergf2753dd2009-04-14 10:09:24 +02002067 /* add interfaces */
Johannes Berg4b6f1dd2012-04-03 14:35:57 +02002068 sdata = rtnl_dereference(local->monitor_sdata);
2069 if (sdata) {
Johannes Berg3c3e21e2013-03-27 23:20:27 +01002070 /* in HW restart it exists already */
2071 WARN_ON(local->resuming);
Johannes Berg4b6f1dd2012-04-03 14:35:57 +02002072 res = drv_add_interface(local, sdata);
2073 if (WARN_ON(res)) {
Monam Agarwal0c2bef462014-03-24 00:51:43 +05302074 RCU_INIT_POINTER(local->monitor_sdata, NULL);
Johannes Berg4b6f1dd2012-04-03 14:35:57 +02002075 synchronize_net();
2076 kfree(sdata);
2077 }
2078 }
2079
Johannes Bergf2753dd2009-04-14 10:09:24 +02002080 list_for_each_entry(sdata, &local->interfaces, list) {
2081 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
2082 sdata->vif.type != NL80211_IFTYPE_MONITOR &&
Luciano Coelhoc8fff3d2015-03-01 09:10:04 +02002083 ieee80211_sdata_running(sdata)) {
Johannes Berg7b7eab62011-11-03 14:41:13 +01002084 res = drv_add_interface(local, sdata);
Luciano Coelhoc8fff3d2015-03-01 09:10:04 +02002085 if (WARN_ON(res))
2086 break;
2087 }
2088 }
2089
2090 /* If adding any of the interfaces failed above, roll back and
2091 * report failure.
2092 */
2093 if (res) {
2094 list_for_each_entry_continue_reverse(sdata, &local->interfaces,
2095 list)
2096 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
2097 sdata->vif.type != NL80211_IFTYPE_MONITOR &&
2098 ieee80211_sdata_running(sdata))
2099 drv_remove_interface(local, sdata);
2100 ieee80211_handle_reconfig_failure(local);
2101 return res;
Johannes Bergf2753dd2009-04-14 10:09:24 +02002102 }
2103
Johannes Berg55de9082012-07-26 17:24:39 +02002104 /* add channel contexts */
Arend van Sprielf0dea9c2012-11-19 12:01:05 +01002105 if (local->use_chanctx) {
2106 mutex_lock(&local->chanctx_mtx);
2107 list_for_each_entry(ctx, &local->chanctx_list, list)
Michal Kazior5bcae312014-06-25 12:35:06 +02002108 if (ctx->replace_state !=
2109 IEEE80211_CHANCTX_REPLACES_OTHER)
2110 WARN_ON(drv_add_chanctx(local, ctx));
Arend van Sprielf0dea9c2012-11-19 12:01:05 +01002111 mutex_unlock(&local->chanctx_mtx);
Johannes Berg55de9082012-07-26 17:24:39 +02002112
Zhao, Gang7df180f2014-04-26 09:43:40 +08002113 sdata = rtnl_dereference(local->monitor_sdata);
2114 if (sdata && ieee80211_sdata_running(sdata))
2115 ieee80211_assign_chanctx(local, sdata);
2116 }
Johannes Bergfe5f2552012-11-19 22:19:08 +01002117
Johannes Bergf2753dd2009-04-14 10:09:24 +02002118 /* reconfigure hardware */
2119 ieee80211_hw_config(local, ~0);
2120
Johannes Bergf2753dd2009-04-14 10:09:24 +02002121 ieee80211_configure_filter(local);
Johannes Bergf2753dd2009-04-14 10:09:24 +02002122
2123 /* Finally also reconfigure all the BSS information */
2124 list_for_each_entry(sdata, &local->interfaces, list) {
Johannes Bergac8dd502010-05-05 09:44:02 +02002125 u32 changed;
2126
Johannes Berg9607e6b662009-12-23 13:15:31 +01002127 if (!ieee80211_sdata_running(sdata))
Johannes Bergf2753dd2009-04-14 10:09:24 +02002128 continue;
Johannes Bergac8dd502010-05-05 09:44:02 +02002129
Johannes Berg1ea2c862015-12-08 16:04:39 +02002130 ieee80211_assign_chanctx(local, sdata);
2131
2132 switch (sdata->vif.type) {
2133 case NL80211_IFTYPE_AP_VLAN:
2134 case NL80211_IFTYPE_MONITOR:
2135 break;
2136 default:
2137 ieee80211_reconfig_stations(sdata);
2138 /* fall through */
2139 case NL80211_IFTYPE_AP: /* AP stations are handled later */
2140 for (i = 0; i < IEEE80211_NUM_ACS; i++)
2141 drv_conf_tx(local, sdata, i,
2142 &sdata->tx_conf[i]);
2143 break;
2144 }
2145
Johannes Bergac8dd502010-05-05 09:44:02 +02002146 /* common change flags for all interface types */
2147 changed = BSS_CHANGED_ERP_CTS_PROT |
2148 BSS_CHANGED_ERP_PREAMBLE |
2149 BSS_CHANGED_ERP_SLOT |
2150 BSS_CHANGED_HT |
2151 BSS_CHANGED_BASIC_RATES |
2152 BSS_CHANGED_BEACON_INT |
2153 BSS_CHANGED_BSSID |
Johannes Berg4ced3f72010-07-19 16:39:04 +02002154 BSS_CHANGED_CQM |
Eliad Peller55de47f2011-11-01 15:16:55 +02002155 BSS_CHANGED_QOS |
Johannes Berg1ea6f9c2012-10-24 10:59:25 +02002156 BSS_CHANGED_IDLE |
Pradeep Kumar Chitrapudcbe73c2018-03-22 12:18:03 -07002157 BSS_CHANGED_TXPOWER |
2158 BSS_CHANGED_MCAST_RATE;
Johannes Bergac8dd502010-05-05 09:44:02 +02002159
Sara Sharonb5a33d52016-02-16 12:48:18 +02002160 if (sdata->vif.mu_mimo_owner)
Sara Sharon23a1f8d2015-12-08 16:04:31 +02002161 changed |= BSS_CHANGED_MU_GROUPS;
2162
Johannes Bergf2753dd2009-04-14 10:09:24 +02002163 switch (sdata->vif.type) {
2164 case NL80211_IFTYPE_STATION:
Eliad Peller0d392e92011-12-12 14:10:49 +02002165 changed |= BSS_CHANGED_ASSOC |
Eliad Pellerab095872012-07-27 12:33:22 +03002166 BSS_CHANGED_ARP_FILTER |
2167 BSS_CHANGED_PS;
Emmanuel Grumbachc65dd142012-12-12 10:12:24 +02002168
Alexander Bondar989c6502013-05-16 17:34:17 +03002169 /* Re-send beacon info report to the driver */
2170 if (sdata->u.mgd.have_beacon)
2171 changed |= BSS_CHANGED_BEACON_INFO;
Emmanuel Grumbachc65dd142012-12-12 10:12:24 +02002172
Avraham Sterne38a0172017-04-26 10:58:47 +03002173 if (sdata->vif.bss_conf.max_idle_period ||
2174 sdata->vif.bss_conf.protected_keep_alive)
2175 changed |= BSS_CHANGED_KEEP_ALIVE;
2176
Johannes Berg8d61ffa2013-05-10 12:32:47 +02002177 sdata_lock(sdata);
Johannes Bergac8dd502010-05-05 09:44:02 +02002178 ieee80211_bss_info_change_notify(sdata, changed);
Johannes Berg8d61ffa2013-05-10 12:32:47 +02002179 sdata_unlock(sdata);
Johannes Bergac8dd502010-05-05 09:44:02 +02002180 break;
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +01002181 case NL80211_IFTYPE_OCB:
Rostislav Lisovy239281f2014-11-03 10:33:19 +01002182 changed |= BSS_CHANGED_OCB;
2183 ieee80211_bss_info_change_notify(sdata, changed);
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +01002184 break;
Johannes Bergf2753dd2009-04-14 10:09:24 +02002185 case NL80211_IFTYPE_ADHOC:
Johannes Bergac8dd502010-05-05 09:44:02 +02002186 changed |= BSS_CHANGED_IBSS;
2187 /* fall through */
Johannes Bergf2753dd2009-04-14 10:09:24 +02002188 case NL80211_IFTYPE_AP:
Johannes Berg339afbf2012-11-14 15:21:17 +01002189 changed |= BSS_CHANGED_SSID | BSS_CHANGED_P2P_PS;
Arik Nemtsove7979ac2011-11-22 19:33:18 +02002190
Pradeep Kumar Chitrapubc847972018-10-03 20:19:20 -07002191 if (sdata->vif.bss_conf.ftm_responder == 1 &&
2192 wiphy_ext_feature_isset(sdata->local->hw.wiphy,
2193 NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER))
2194 changed |= BSS_CHANGED_FTM_RESPONDER;
2195
Johannes Berg10416382012-10-19 15:44:42 +02002196 if (sdata->vif.type == NL80211_IFTYPE_AP) {
Arik Nemtsove7979ac2011-11-22 19:33:18 +02002197 changed |= BSS_CHANGED_AP_PROBE_RESP;
2198
Johannes Berg10416382012-10-19 15:44:42 +02002199 if (rcu_access_pointer(sdata->u.ap.beacon))
2200 drv_start_ap(local, sdata);
2201 }
2202
Arik Nemtsov78274932011-09-04 11:11:32 +03002203 /* fall through */
Johannes Bergf2753dd2009-04-14 10:09:24 +02002204 case NL80211_IFTYPE_MESH_POINT:
Johannes Berg8da34932012-12-14 14:17:26 +01002205 if (sdata->vif.bss_conf.enable_beacon) {
2206 changed |= BSS_CHANGED_BEACON |
2207 BSS_CHANGED_BEACON_ENABLED;
2208 ieee80211_bss_info_change_notify(sdata, changed);
2209 }
Johannes Bergf2753dd2009-04-14 10:09:24 +02002210 break;
Ayala Beker167e33f2016-09-20 17:31:20 +03002211 case NL80211_IFTYPE_NAN:
2212 res = ieee80211_reconfig_nan(sdata);
2213 if (res < 0) {
2214 ieee80211_handle_reconfig_failure(local);
2215 return res;
2216 }
2217 break;
Johannes Bergf2753dd2009-04-14 10:09:24 +02002218 case NL80211_IFTYPE_WDS:
Johannes Bergf2753dd2009-04-14 10:09:24 +02002219 case NL80211_IFTYPE_AP_VLAN:
2220 case NL80211_IFTYPE_MONITOR:
Johannes Berg98104fde2012-06-16 00:19:54 +02002221 case NL80211_IFTYPE_P2P_DEVICE:
Zhao, Gangb2057862014-04-26 09:43:41 +08002222 /* nothing to do */
Johannes Bergf142c6b2012-06-18 20:07:15 +02002223 break;
Johannes Bergf2753dd2009-04-14 10:09:24 +02002224 case NL80211_IFTYPE_UNSPECIFIED:
Johannes Berg2e161f782010-08-12 15:38:38 +02002225 case NUM_NL80211_IFTYPES:
Johannes Berg2ca27bc2010-09-16 14:58:23 +02002226 case NL80211_IFTYPE_P2P_CLIENT:
2227 case NL80211_IFTYPE_P2P_GO:
Johannes Bergf2753dd2009-04-14 10:09:24 +02002228 WARN_ON(1);
2229 break;
2230 }
2231 }
2232
Johannes Berg4a733ef2015-10-14 18:02:43 +02002233 ieee80211_recalc_ps(local);
Eyal Shapira8e1b23b2011-11-09 12:29:06 +02002234
Johannes Berg2a419052010-06-10 10:21:29 +02002235 /*
Eliad Peller6e1b1b22012-01-26 13:36:05 +02002236 * The sta might be in psm against the ap (e.g. because
2237 * this was the state before a hw restart), so we
2238 * explicitly send a null packet in order to make sure
2239 * it'll sync against the ap (and get out of psm).
2240 */
2241 if (!(local->hw.conf.flags & IEEE80211_CONF_PS)) {
2242 list_for_each_entry(sdata, &local->interfaces, list) {
2243 if (sdata->vif.type != NL80211_IFTYPE_STATION)
2244 continue;
Johannes Berg20f544e2012-11-08 14:06:28 +01002245 if (!sdata->u.mgd.associated)
2246 continue;
Eliad Peller6e1b1b22012-01-26 13:36:05 +02002247
Johannes Berg076cdcb2015-09-24 16:14:55 +02002248 ieee80211_send_nullfunc(local, sdata, false);
Eliad Peller6e1b1b22012-01-26 13:36:05 +02002249 }
2250 }
2251
Arik Nemtsov2e8d3972012-06-03 23:31:56 +03002252 /* APs are now beaconing, add back stations */
2253 mutex_lock(&local->sta_mtx);
2254 list_for_each_entry(sta, &local->sta_list, list) {
2255 enum ieee80211_sta_state state;
2256
2257 if (!sta->uploaded)
2258 continue;
2259
mpubbise@codeaurora.org19103a42018-07-02 15:40:14 +05302260 if (sta->sdata->vif.type != NL80211_IFTYPE_AP &&
2261 sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
Arik Nemtsov2e8d3972012-06-03 23:31:56 +03002262 continue;
2263
2264 for (state = IEEE80211_STA_NOTEXIST;
2265 state < sta->sta_state; state++)
2266 WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
2267 state + 1));
2268 }
2269 mutex_unlock(&local->sta_mtx);
2270
Eyal Shapira7b21aea2012-05-29 02:00:22 -07002271 /* add back keys */
2272 list_for_each_entry(sdata, &local->interfaces, list)
Michal Kaziorf9dca802015-05-13 09:16:48 +00002273 ieee80211_reset_crypto_tx_tailroom(sdata);
2274
2275 list_for_each_entry(sdata, &local->interfaces, list)
Eyal Shapira7b21aea2012-05-29 02:00:22 -07002276 if (ieee80211_sdata_running(sdata))
2277 ieee80211_enable_keys(sdata);
2278
Eliad Peller0d440ea2015-10-25 10:59:33 +02002279 /* Reconfigure sched scan if it was interrupted by FW restart */
2280 mutex_lock(&local->mtx);
2281 sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
2282 lockdep_is_held(&local->mtx));
2283 sched_scan_req = rcu_dereference_protected(local->sched_scan_req,
2284 lockdep_is_held(&local->mtx));
2285 if (sched_scan_sdata && sched_scan_req)
2286 /*
2287 * Sched scan stopped, but we don't want to report it. Instead,
2288 * we're trying to reschedule. However, if more than one scan
2289 * plan was set, we cannot reschedule since we don't know which
2290 * scan plan was currently running (and some scan plans may have
2291 * already finished).
2292 */
2293 if (sched_scan_req->n_scan_plans > 1 ||
2294 __ieee80211_request_sched_scan_start(sched_scan_sdata,
Eliad Pellerb9f628f2015-12-16 15:45:45 +02002295 sched_scan_req)) {
2296 RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
2297 RCU_INIT_POINTER(local->sched_scan_req, NULL);
Eliad Peller0d440ea2015-10-25 10:59:33 +02002298 sched_scan_stopped = true;
Eliad Pellerb9f628f2015-12-16 15:45:45 +02002299 }
Eliad Peller0d440ea2015-10-25 10:59:33 +02002300 mutex_unlock(&local->mtx);
2301
2302 if (sched_scan_stopped)
Arend Van Sprielb34939b2017-04-28 13:40:28 +01002303 cfg80211_sched_scan_stopped_rtnl(local->hw.wiphy, 0);
Eliad Peller0d440ea2015-10-25 10:59:33 +02002304
Eliad Pellerc6209482012-07-02 15:08:25 +03002305 wake_up:
Arik Nemtsov04800ad2012-06-06 11:25:02 +03002306
Johannes Berg3c3e21e2013-03-27 23:20:27 +01002307 if (local->monitors == local->open_count && local->monitors > 0)
2308 ieee80211_add_virtual_monitor(local);
2309
Eliad Peller6e1b1b22012-01-26 13:36:05 +02002310 /*
Johannes Berg2a419052010-06-10 10:21:29 +02002311 * Clear the WLAN_STA_BLOCK_BA flag so new aggregation
2312 * sessions can be established after a resume.
2313 *
2314 * Also tear down aggregation sessions since reconfiguring
2315 * them in a hardware restart scenario is not easily done
2316 * right now, and the hardware will have lost information
2317 * about the sessions, but we and the AP still think they
2318 * are active. This is really a workaround though.
2319 */
Johannes Berg30686bf2015-06-02 21:39:54 +02002320 if (ieee80211_hw_check(hw, AMPDU_AGGREGATION)) {
Johannes Berg2a419052010-06-10 10:21:29 +02002321 mutex_lock(&local->sta_mtx);
2322
2323 list_for_each_entry(sta, &local->sta_list, list) {
Eliad Peller27392712015-09-21 15:50:26 +03002324 if (!local->resuming)
2325 ieee80211_sta_tear_down_BA_sessions(
2326 sta, AGG_STOP_LOCAL_REQUEST);
Johannes Bergc2c98fd2011-09-29 16:04:36 +02002327 clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
Wey-Yi Guy74e2bd12010-02-03 09:28:55 -08002328 }
Johannes Berg2a419052010-06-10 10:21:29 +02002329
2330 mutex_unlock(&local->sta_mtx);
Wey-Yi Guy74e2bd12010-02-03 09:28:55 -08002331 }
Wey-Yi Guy74e2bd12010-02-03 09:28:55 -08002332
Sara Sharon23163802017-10-29 11:51:08 +02002333 if (local->in_reconfig) {
2334 local->in_reconfig = false;
2335 barrier();
2336
2337 /* Restart deferred ROCs */
2338 mutex_lock(&local->mtx);
2339 ieee80211_start_next_roc(local);
2340 mutex_unlock(&local->mtx);
2341 }
2342
Johannes Berg445ea4e2013-02-13 12:25:28 +01002343 ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
Luciano Coelhocca07b02014-06-13 16:30:05 +03002344 IEEE80211_QUEUE_STOP_REASON_SUSPEND,
2345 false);
Johannes Bergf2753dd2009-04-14 10:09:24 +02002346
Johannes Berg5bb644a2009-05-17 11:40:42 +02002347 /*
2348 * If this is for hw restart things are still running.
2349 * We may want to change that later, however.
2350 */
Eliad Pellerb0485e92015-07-08 15:41:47 +03002351 if (local->open_count && (!suspended || reconfig_due_to_wowlan))
Eliad Pellercf2c92d2014-11-04 11:43:54 +02002352 drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_RESTART);
Johannes Berg8f21b0a2013-01-11 00:28:01 +01002353
Eliad Pellerb0485e92015-07-08 15:41:47 +03002354 if (!suspended)
Johannes Berg5bb644a2009-05-17 11:40:42 +02002355 return 0;
2356
2357#ifdef CONFIG_PM
Johannes Bergceb99fe2009-11-19 14:29:39 +01002358 /* first set suspended false, then resuming */
Johannes Berg5bb644a2009-05-17 11:40:42 +02002359 local->suspended = false;
Johannes Bergceb99fe2009-11-19 14:29:39 +01002360 mb();
2361 local->resuming = false;
Johannes Berg5bb644a2009-05-17 11:40:42 +02002362
Johannes Berg74430f92015-12-08 16:04:38 +02002363 ieee80211_flush_completed_scan(local, false);
Luciano Coelho9120d94e2015-01-24 10:30:02 +02002364
Eliad Peller0f8b8242014-12-14 11:05:53 +02002365 if (local->open_count && !reconfig_due_to_wowlan)
Eliad Pellercf2c92d2014-11-04 11:43:54 +02002366 drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND);
2367
Johannes Bergb8360ab2013-04-29 14:57:44 +02002368 list_for_each_entry(sdata, &local->interfaces, list) {
2369 if (!ieee80211_sdata_running(sdata))
2370 continue;
2371 if (sdata->vif.type == NL80211_IFTYPE_STATION)
2372 ieee80211_sta_restart(sdata);
2373 }
2374
Johannes Berg26d59532011-04-01 13:52:48 +02002375 mod_timer(&local->sta_cleanup, jiffies + 1);
Johannes Berg5bb644a2009-05-17 11:40:42 +02002376#else
2377 WARN_ON(1);
2378#endif
David Spinadeld43c6b62013-12-08 21:48:57 +02002379
Johannes Bergf2753dd2009-04-14 10:09:24 +02002380 return 0;
2381}
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002382
Johannes Berg95acac62011-07-12 12:30:59 +02002383void ieee80211_resume_disconnect(struct ieee80211_vif *vif)
2384{
2385 struct ieee80211_sub_if_data *sdata;
2386 struct ieee80211_local *local;
2387 struct ieee80211_key *key;
2388
2389 if (WARN_ON(!vif))
2390 return;
2391
2392 sdata = vif_to_sdata(vif);
2393 local = sdata->local;
2394
2395 if (WARN_ON(!local->resuming))
2396 return;
2397
2398 if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
2399 return;
2400
2401 sdata->flags |= IEEE80211_SDATA_DISCONNECT_RESUME;
2402
2403 mutex_lock(&local->key_mtx);
2404 list_for_each_entry(key, &sdata->key_list, list)
2405 key->flags |= KEY_FLAG_TAINTED;
2406 mutex_unlock(&local->key_mtx);
2407}
2408EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect);
2409
Johannes Berg04ecd252012-09-11 14:34:12 +02002410void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata)
Johannes Berg0f782312009-12-01 13:37:02 +01002411{
Johannes Berg04ecd252012-09-11 14:34:12 +02002412 struct ieee80211_local *local = sdata->local;
2413 struct ieee80211_chanctx_conf *chanctx_conf;
2414 struct ieee80211_chanctx *chanctx;
Johannes Berg0f782312009-12-01 13:37:02 +01002415
Johannes Berg04ecd252012-09-11 14:34:12 +02002416 mutex_lock(&local->chanctx_mtx);
Johannes Berg0f782312009-12-01 13:37:02 +01002417
Johannes Berg04ecd252012-09-11 14:34:12 +02002418 chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
2419 lockdep_is_held(&local->chanctx_mtx));
Johannes Berg0f782312009-12-01 13:37:02 +01002420
Andrei Otcheretianskic189a682015-10-25 10:59:40 +02002421 /*
2422 * This function can be called from a work, thus it may be possible
2423 * that the chanctx_conf is removed (due to a disconnection, for
2424 * example).
2425 * So nothing should be done in such case.
2426 */
2427 if (!chanctx_conf)
Johannes Berg5d8e4232012-09-11 10:17:11 +02002428 goto unlock;
Johannes Berg0f782312009-12-01 13:37:02 +01002429
Johannes Berg04ecd252012-09-11 14:34:12 +02002430 chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
2431 ieee80211_recalc_smps_chanctx(local, chanctx);
Johannes Berg5d8e4232012-09-11 10:17:11 +02002432 unlock:
Johannes Berg04ecd252012-09-11 14:34:12 +02002433 mutex_unlock(&local->chanctx_mtx);
Johannes Berg0f782312009-12-01 13:37:02 +01002434}
Johannes Berg8e664fb2009-12-23 13:15:38 +01002435
Eliad Peller21f659b2013-11-11 20:14:01 +02002436void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata)
2437{
2438 struct ieee80211_local *local = sdata->local;
2439 struct ieee80211_chanctx_conf *chanctx_conf;
2440 struct ieee80211_chanctx *chanctx;
2441
2442 mutex_lock(&local->chanctx_mtx);
2443
2444 chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
2445 lockdep_is_held(&local->chanctx_mtx));
2446
2447 if (WARN_ON_ONCE(!chanctx_conf))
2448 goto unlock;
2449
2450 chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
2451 ieee80211_recalc_chanctx_min_def(local, chanctx);
2452 unlock:
2453 mutex_unlock(&local->chanctx_mtx);
2454}
2455
Johannes Berg8e664fb2009-12-23 13:15:38 +01002456size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)
2457{
2458 size_t pos = offset;
2459
2460 while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC)
2461 pos += 2 + ies[pos + 1];
2462
2463 return pos;
2464}
Meenakshi Venkataraman615f7b92011-07-08 08:46:22 -07002465
2466static void _ieee80211_enable_rssi_reports(struct ieee80211_sub_if_data *sdata,
2467 int rssi_min_thold,
2468 int rssi_max_thold)
2469{
2470 trace_api_enable_rssi_reports(sdata, rssi_min_thold, rssi_max_thold);
2471
2472 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
2473 return;
2474
2475 /*
2476 * Scale up threshold values before storing it, as the RSSI averaging
2477 * algorithm uses a scaled up value as well. Change this scaling
2478 * factor if the RSSI averaging algorithm changes.
2479 */
2480 sdata->u.mgd.rssi_min_thold = rssi_min_thold*16;
2481 sdata->u.mgd.rssi_max_thold = rssi_max_thold*16;
2482}
2483
2484void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
2485 int rssi_min_thold,
2486 int rssi_max_thold)
2487{
2488 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
2489
2490 WARN_ON(rssi_min_thold == rssi_max_thold ||
2491 rssi_min_thold > rssi_max_thold);
2492
2493 _ieee80211_enable_rssi_reports(sdata, rssi_min_thold,
2494 rssi_max_thold);
2495}
2496EXPORT_SYMBOL(ieee80211_enable_rssi_reports);
2497
2498void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
2499{
2500 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
2501
2502 _ieee80211_enable_rssi_reports(sdata, 0, 0);
2503}
2504EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
Arik Nemtsov768db342011-09-28 14:12:51 +03002505
Ben Greearef96a8422011-11-18 11:32:00 -08002506u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
Alexander Simon42e7aa72011-10-26 14:47:26 -07002507 u16 cap)
2508{
2509 __le16 tmp;
2510
2511 *pos++ = WLAN_EID_HT_CAPABILITY;
2512 *pos++ = sizeof(struct ieee80211_ht_cap);
2513 memset(pos, 0, sizeof(struct ieee80211_ht_cap));
2514
2515 /* capability flags */
2516 tmp = cpu_to_le16(cap);
2517 memcpy(pos, &tmp, sizeof(u16));
2518 pos += sizeof(u16);
2519
2520 /* AMPDU parameters */
Ben Greearef96a8422011-11-18 11:32:00 -08002521 *pos++ = ht_cap->ampdu_factor |
2522 (ht_cap->ampdu_density <<
Alexander Simon42e7aa72011-10-26 14:47:26 -07002523 IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
2524
2525 /* MCS set */
Ben Greearef96a8422011-11-18 11:32:00 -08002526 memcpy(pos, &ht_cap->mcs, sizeof(ht_cap->mcs));
2527 pos += sizeof(ht_cap->mcs);
Alexander Simon42e7aa72011-10-26 14:47:26 -07002528
2529 /* extended capabilities */
2530 pos += sizeof(__le16);
2531
2532 /* BF capabilities */
2533 pos += sizeof(__le32);
2534
2535 /* antenna selection */
2536 pos += sizeof(u8);
2537
2538 return pos;
2539}
2540
Mahesh Palivelaba0afa22012-07-02 11:25:12 +00002541u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
Johannes Bergcc3983d2012-12-07 12:45:06 +01002542 u32 cap)
Mahesh Palivelaba0afa22012-07-02 11:25:12 +00002543{
2544 __le32 tmp;
2545
2546 *pos++ = WLAN_EID_VHT_CAPABILITY;
Mahesh Palivelad4950282012-10-10 11:25:40 +00002547 *pos++ = sizeof(struct ieee80211_vht_cap);
2548 memset(pos, 0, sizeof(struct ieee80211_vht_cap));
Mahesh Palivelaba0afa22012-07-02 11:25:12 +00002549
2550 /* capability flags */
2551 tmp = cpu_to_le32(cap);
2552 memcpy(pos, &tmp, sizeof(u32));
2553 pos += sizeof(u32);
2554
2555 /* VHT MCS set */
2556 memcpy(pos, &vht_cap->vht_mcs, sizeof(vht_cap->vht_mcs));
2557 pos += sizeof(vht_cap->vht_mcs);
2558
2559 return pos;
2560}
2561
Luca Coelho41cbb0f2018-06-09 09:14:44 +03002562u8 *ieee80211_ie_build_he_cap(u8 *pos,
2563 const struct ieee80211_sta_he_cap *he_cap,
2564 u8 *end)
2565{
2566 u8 n;
2567 u8 ie_len;
2568 u8 *orig_pos = pos;
2569
2570 /* Make sure we have place for the IE */
2571 /*
2572 * TODO: the 1 added is because this temporarily is under the EXTENSION
2573 * IE. Get rid of it when it moves.
2574 */
2575 if (!he_cap)
2576 return orig_pos;
2577
2578 n = ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem);
2579 ie_len = 2 + 1 +
2580 sizeof(he_cap->he_cap_elem) + n +
2581 ieee80211_he_ppe_size(he_cap->ppe_thres[0],
2582 he_cap->he_cap_elem.phy_cap_info);
2583
2584 if ((end - pos) < ie_len)
2585 return orig_pos;
2586
2587 *pos++ = WLAN_EID_EXTENSION;
2588 pos++; /* We'll set the size later below */
2589 *pos++ = WLAN_EID_EXT_HE_CAPABILITY;
2590
2591 /* Fixed data */
2592 memcpy(pos, &he_cap->he_cap_elem, sizeof(he_cap->he_cap_elem));
2593 pos += sizeof(he_cap->he_cap_elem);
2594
2595 memcpy(pos, &he_cap->he_mcs_nss_supp, n);
2596 pos += n;
2597
2598 /* Check if PPE Threshold should be present */
2599 if ((he_cap->he_cap_elem.phy_cap_info[6] &
2600 IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) == 0)
2601 goto end;
2602
2603 /*
2604 * Calculate how many PPET16/PPET8 pairs are to come. Algorithm:
2605 * (NSS_M1 + 1) x (num of 1 bits in RU_INDEX_BITMASK)
2606 */
2607 n = hweight8(he_cap->ppe_thres[0] &
2608 IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK);
2609 n *= (1 + ((he_cap->ppe_thres[0] & IEEE80211_PPE_THRES_NSS_MASK) >>
2610 IEEE80211_PPE_THRES_NSS_POS));
2611
2612 /*
2613 * Each pair is 6 bits, and we need to add the 7 "header" bits to the
2614 * total size.
2615 */
2616 n = (n * IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2) + 7;
2617 n = DIV_ROUND_UP(n, 8);
2618
2619 /* Copy PPE Thresholds */
2620 memcpy(pos, &he_cap->ppe_thres, n);
2621 pos += n;
2622
2623end:
2624 orig_pos[1] = (pos - orig_pos) - 2;
2625 return pos;
2626}
2627
Johannes Berg074d46d2012-03-15 19:45:16 +01002628u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
Johannes Berg4bf88532012-11-09 11:39:59 +01002629 const struct cfg80211_chan_def *chandef,
Arik Nemtsov57f255f2015-10-25 10:59:34 +02002630 u16 prot_mode, bool rifs_mode)
Alexander Simon42e7aa72011-10-26 14:47:26 -07002631{
Johannes Berg074d46d2012-03-15 19:45:16 +01002632 struct ieee80211_ht_operation *ht_oper;
Alexander Simon42e7aa72011-10-26 14:47:26 -07002633 /* Build HT Information */
Johannes Berg074d46d2012-03-15 19:45:16 +01002634 *pos++ = WLAN_EID_HT_OPERATION;
2635 *pos++ = sizeof(struct ieee80211_ht_operation);
2636 ht_oper = (struct ieee80211_ht_operation *)pos;
Johannes Berg4bf88532012-11-09 11:39:59 +01002637 ht_oper->primary_chan = ieee80211_frequency_to_channel(
2638 chandef->chan->center_freq);
2639 switch (chandef->width) {
2640 case NL80211_CHAN_WIDTH_160:
2641 case NL80211_CHAN_WIDTH_80P80:
2642 case NL80211_CHAN_WIDTH_80:
2643 case NL80211_CHAN_WIDTH_40:
2644 if (chandef->center_freq1 > chandef->chan->center_freq)
2645 ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
2646 else
2647 ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
Alexander Simon42e7aa72011-10-26 14:47:26 -07002648 break;
Alexander Simon42e7aa72011-10-26 14:47:26 -07002649 default:
Johannes Berg074d46d2012-03-15 19:45:16 +01002650 ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
Alexander Simon42e7aa72011-10-26 14:47:26 -07002651 break;
2652 }
Thomas Pedersenaee286c2012-04-18 19:24:14 -07002653 if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
Johannes Berg4bf88532012-11-09 11:39:59 +01002654 chandef->width != NL80211_CHAN_WIDTH_20_NOHT &&
2655 chandef->width != NL80211_CHAN_WIDTH_20)
Johannes Berg074d46d2012-03-15 19:45:16 +01002656 ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
Simon Wunderlichff3cc5f2011-11-30 16:56:33 +01002657
Arik Nemtsov57f255f2015-10-25 10:59:34 +02002658 if (rifs_mode)
2659 ht_oper->ht_param |= IEEE80211_HT_PARAM_RIFS_MODE;
2660
Ashok Nagarajan431e3152012-04-30 14:20:29 -07002661 ht_oper->operation_mode = cpu_to_le16(prot_mode);
Johannes Berg074d46d2012-03-15 19:45:16 +01002662 ht_oper->stbc_param = 0x0000;
Alexander Simon42e7aa72011-10-26 14:47:26 -07002663
2664 /* It seems that Basic MCS set and Supported MCS set
2665 are identical for the first 10 bytes */
Johannes Berg074d46d2012-03-15 19:45:16 +01002666 memset(&ht_oper->basic_set, 0, 16);
2667 memcpy(&ht_oper->basic_set, &ht_cap->mcs, 10);
Alexander Simon42e7aa72011-10-26 14:47:26 -07002668
Johannes Berg074d46d2012-03-15 19:45:16 +01002669 return pos + sizeof(struct ieee80211_ht_operation);
Alexander Simon42e7aa72011-10-26 14:47:26 -07002670}
2671
Simon Wunderlich75d627d2017-05-23 17:00:42 +02002672void ieee80211_ie_build_wide_bw_cs(u8 *pos,
2673 const struct cfg80211_chan_def *chandef)
2674{
2675 *pos++ = WLAN_EID_WIDE_BW_CHANNEL_SWITCH; /* EID */
2676 *pos++ = 3; /* IE length */
2677 /* New channel width */
2678 switch (chandef->width) {
2679 case NL80211_CHAN_WIDTH_80:
2680 *pos++ = IEEE80211_VHT_CHANWIDTH_80MHZ;
2681 break;
2682 case NL80211_CHAN_WIDTH_160:
2683 *pos++ = IEEE80211_VHT_CHANWIDTH_160MHZ;
2684 break;
2685 case NL80211_CHAN_WIDTH_80P80:
2686 *pos++ = IEEE80211_VHT_CHANWIDTH_80P80MHZ;
2687 break;
2688 default:
2689 *pos++ = IEEE80211_VHT_CHANWIDTH_USE_HT;
2690 }
2691
2692 /* new center frequency segment 0 */
2693 *pos++ = ieee80211_frequency_to_channel(chandef->center_freq1);
2694 /* new center frequency segment 1 */
2695 if (chandef->center_freq2)
2696 *pos++ = ieee80211_frequency_to_channel(chandef->center_freq2);
2697 else
2698 *pos++ = 0;
2699}
2700
Arik Nemtsovfb28ec02015-03-01 09:10:02 +02002701u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
2702 const struct cfg80211_chan_def *chandef)
2703{
2704 struct ieee80211_vht_operation *vht_oper;
2705
2706 *pos++ = WLAN_EID_VHT_OPERATION;
2707 *pos++ = sizeof(struct ieee80211_vht_operation);
2708 vht_oper = (struct ieee80211_vht_operation *)pos;
Johannes Berg2fb51c32017-02-15 15:02:06 +01002709 vht_oper->center_freq_seg0_idx = ieee80211_frequency_to_channel(
Arik Nemtsovfb28ec02015-03-01 09:10:02 +02002710 chandef->center_freq1);
2711 if (chandef->center_freq2)
Johannes Berg2fb51c32017-02-15 15:02:06 +01002712 vht_oper->center_freq_seg1_idx =
Arik Nemtsovfb28ec02015-03-01 09:10:02 +02002713 ieee80211_frequency_to_channel(chandef->center_freq2);
Chun-Yeow Yeohf020ae42015-09-04 10:58:05 +08002714 else
Johannes Berg2fb51c32017-02-15 15:02:06 +01002715 vht_oper->center_freq_seg1_idx = 0x00;
Arik Nemtsovfb28ec02015-03-01 09:10:02 +02002716
2717 switch (chandef->width) {
2718 case NL80211_CHAN_WIDTH_160:
Jouni Malinen23665aa2016-02-01 11:40:55 +02002719 /*
2720 * Convert 160 MHz channel width to new style as interop
2721 * workaround.
2722 */
2723 vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
Johannes Berg2fb51c32017-02-15 15:02:06 +01002724 vht_oper->center_freq_seg1_idx = vht_oper->center_freq_seg0_idx;
Jouni Malinen23665aa2016-02-01 11:40:55 +02002725 if (chandef->chan->center_freq < chandef->center_freq1)
Johannes Berg2fb51c32017-02-15 15:02:06 +01002726 vht_oper->center_freq_seg0_idx -= 8;
Jouni Malinen23665aa2016-02-01 11:40:55 +02002727 else
Johannes Berg2fb51c32017-02-15 15:02:06 +01002728 vht_oper->center_freq_seg0_idx += 8;
Arik Nemtsovfb28ec02015-03-01 09:10:02 +02002729 break;
2730 case NL80211_CHAN_WIDTH_80P80:
Jouni Malinen23665aa2016-02-01 11:40:55 +02002731 /*
2732 * Convert 80+80 MHz channel width to new style as interop
2733 * workaround.
2734 */
2735 vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
Arik Nemtsovfb28ec02015-03-01 09:10:02 +02002736 break;
2737 case NL80211_CHAN_WIDTH_80:
2738 vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
2739 break;
2740 default:
2741 vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT;
2742 break;
2743 }
2744
2745 /* don't require special VHT peer rates */
2746 vht_oper->basic_mcs_set = cpu_to_le16(0xffff);
2747
2748 return pos + sizeof(struct ieee80211_vht_operation);
2749}
2750
Johannes Berg8ac3c7042015-12-18 15:08:34 +01002751bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
2752 struct cfg80211_chan_def *chandef)
Alexander Simon42e7aa72011-10-26 14:47:26 -07002753{
2754 enum nl80211_channel_type channel_type;
2755
Johannes Berg8ac3c7042015-12-18 15:08:34 +01002756 if (!ht_oper)
2757 return false;
Alexander Simon42e7aa72011-10-26 14:47:26 -07002758
Johannes Berg074d46d2012-03-15 19:45:16 +01002759 switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
Alexander Simon42e7aa72011-10-26 14:47:26 -07002760 case IEEE80211_HT_PARAM_CHA_SEC_NONE:
2761 channel_type = NL80211_CHAN_HT20;
2762 break;
2763 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
2764 channel_type = NL80211_CHAN_HT40PLUS;
2765 break;
2766 case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
2767 channel_type = NL80211_CHAN_HT40MINUS;
2768 break;
2769 default:
2770 channel_type = NL80211_CHAN_NO_HT;
Johannes Berg8ac3c7042015-12-18 15:08:34 +01002771 return false;
Alexander Simon42e7aa72011-10-26 14:47:26 -07002772 }
2773
Johannes Berg8ac3c7042015-12-18 15:08:34 +01002774 cfg80211_chandef_create(chandef, chandef->chan, channel_type);
2775 return true;
Alexander Simon42e7aa72011-10-26 14:47:26 -07002776}
2777
Johannes Berg7eb26df2018-08-31 11:31:18 +03002778bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw,
2779 const struct ieee80211_vht_operation *oper,
2780 const struct ieee80211_ht_operation *htop,
Johannes Berg8ac3c7042015-12-18 15:08:34 +01002781 struct cfg80211_chan_def *chandef)
Janusz.Dziedzic@tieto.comabcff6e2015-03-20 06:37:01 +01002782{
Johannes Berg8ac3c7042015-12-18 15:08:34 +01002783 struct cfg80211_chan_def new = *chandef;
Johannes Berg7eb26df2018-08-31 11:31:18 +03002784 int cf0, cf1;
2785 int ccfs0, ccfs1, ccfs2;
2786 int ccf0, ccf1;
Janusz.Dziedzic@tieto.comabcff6e2015-03-20 06:37:01 +01002787
Johannes Berg7eb26df2018-08-31 11:31:18 +03002788 if (!oper || !htop)
Johannes Berg8ac3c7042015-12-18 15:08:34 +01002789 return false;
2790
Johannes Berg7eb26df2018-08-31 11:31:18 +03002791 ccfs0 = oper->center_freq_seg0_idx;
2792 ccfs1 = oper->center_freq_seg1_idx;
2793 ccfs2 = (le16_to_cpu(htop->operation_mode) &
2794 IEEE80211_HT_OP_MODE_CCFS2_MASK)
2795 >> IEEE80211_HT_OP_MODE_CCFS2_SHIFT;
2796
2797 /* when parsing (and we know how to) CCFS1 and CCFS2 are equivalent */
2798 ccf0 = ccfs0;
2799 ccf1 = ccfs1;
2800 if (!ccfs1 && ieee80211_hw_check(hw, SUPPORTS_VHT_EXT_NSS_BW))
2801 ccf1 = ccfs2;
2802
2803 cf0 = ieee80211_channel_to_frequency(ccf0, chandef->chan->band);
2804 cf1 = ieee80211_channel_to_frequency(ccf1, chandef->chan->band);
Janusz.Dziedzic@tieto.comabcff6e2015-03-20 06:37:01 +01002805
2806 switch (oper->chan_width) {
2807 case IEEE80211_VHT_CHANWIDTH_USE_HT:
Johannes Berg7eb26df2018-08-31 11:31:18 +03002808 /* just use HT information directly */
Janusz.Dziedzic@tieto.comabcff6e2015-03-20 06:37:01 +01002809 break;
2810 case IEEE80211_VHT_CHANWIDTH_80MHZ:
Johannes Berg8ac3c7042015-12-18 15:08:34 +01002811 new.width = NL80211_CHAN_WIDTH_80;
Johannes Berg7eb26df2018-08-31 11:31:18 +03002812 new.center_freq1 = cf0;
Jouni Malinen23665aa2016-02-01 11:40:55 +02002813 /* If needed, adjust based on the newer interop workaround. */
Johannes Berg7eb26df2018-08-31 11:31:18 +03002814 if (ccf1) {
Jouni Malinen23665aa2016-02-01 11:40:55 +02002815 unsigned int diff;
2816
Johannes Berg7eb26df2018-08-31 11:31:18 +03002817 diff = abs(ccf1 - ccf0);
Jouni Malinen23665aa2016-02-01 11:40:55 +02002818 if (diff == 8) {
2819 new.width = NL80211_CHAN_WIDTH_160;
Johannes Berg7eb26df2018-08-31 11:31:18 +03002820 new.center_freq1 = cf1;
Jouni Malinen23665aa2016-02-01 11:40:55 +02002821 } else if (diff > 8) {
2822 new.width = NL80211_CHAN_WIDTH_80P80;
Johannes Berg7eb26df2018-08-31 11:31:18 +03002823 new.center_freq2 = cf1;
Jouni Malinen23665aa2016-02-01 11:40:55 +02002824 }
2825 }
Janusz.Dziedzic@tieto.comabcff6e2015-03-20 06:37:01 +01002826 break;
2827 case IEEE80211_VHT_CHANWIDTH_160MHZ:
Johannes Berg7eb26df2018-08-31 11:31:18 +03002828 /* deprecated encoding */
Johannes Berg8ac3c7042015-12-18 15:08:34 +01002829 new.width = NL80211_CHAN_WIDTH_160;
Johannes Berg7eb26df2018-08-31 11:31:18 +03002830 new.center_freq1 = cf0;
Janusz.Dziedzic@tieto.comabcff6e2015-03-20 06:37:01 +01002831 break;
2832 case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
Johannes Berg7eb26df2018-08-31 11:31:18 +03002833 /* deprecated encoding */
Johannes Berg8ac3c7042015-12-18 15:08:34 +01002834 new.width = NL80211_CHAN_WIDTH_80P80;
Johannes Berg7eb26df2018-08-31 11:31:18 +03002835 new.center_freq1 = cf0;
2836 new.center_freq2 = cf1;
Janusz.Dziedzic@tieto.comabcff6e2015-03-20 06:37:01 +01002837 break;
2838 default:
Johannes Berg8ac3c7042015-12-18 15:08:34 +01002839 return false;
Janusz.Dziedzic@tieto.comabcff6e2015-03-20 06:37:01 +01002840 }
2841
Johannes Berg8ac3c7042015-12-18 15:08:34 +01002842 if (!cfg80211_chandef_valid(&new))
2843 return false;
2844
2845 *chandef = new;
2846 return true;
Janusz.Dziedzic@tieto.comabcff6e2015-03-20 06:37:01 +01002847}
2848
Simon Wunderlich2103dec2013-07-08 16:55:53 +02002849int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
2850 const struct ieee80211_supported_band *sband,
2851 const u8 *srates, int srates_len, u32 *rates)
2852{
2853 u32 rate_flags = ieee80211_chandef_rate_flags(chandef);
2854 int shift = ieee80211_chandef_get_shift(chandef);
2855 struct ieee80211_rate *br;
2856 int brate, rate, i, j, count = 0;
2857
2858 *rates = 0;
2859
2860 for (i = 0; i < srates_len; i++) {
2861 rate = srates[i] & 0x7f;
2862
2863 for (j = 0; j < sband->n_bitrates; j++) {
2864 br = &sband->bitrates[j];
2865 if ((rate_flags & br->flags) != rate_flags)
2866 continue;
2867
2868 brate = DIV_ROUND_UP(br->bitrate, (1 << shift) * 5);
2869 if (brate == rate) {
2870 *rates |= BIT(j);
2871 count++;
2872 break;
2873 }
2874 }
2875 }
2876 return count;
2877}
2878
Johannes Bergfc8a7322012-06-28 10:33:25 +02002879int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
Johannes Berg6b778632012-07-23 14:53:27 +02002880 struct sk_buff *skb, bool need_basic,
Johannes Berg57fbcce2016-04-12 15:56:15 +02002881 enum nl80211_band band)
Arik Nemtsov768db342011-09-28 14:12:51 +03002882{
Arik Nemtsov768db342011-09-28 14:12:51 +03002883 struct ieee80211_local *local = sdata->local;
2884 struct ieee80211_supported_band *sband;
Simon Wunderlich2103dec2013-07-08 16:55:53 +02002885 int rate, shift;
Arik Nemtsov768db342011-09-28 14:12:51 +03002886 u8 i, rates, *pos;
Johannes Bergfc8a7322012-06-28 10:33:25 +02002887 u32 basic_rates = sdata->vif.bss_conf.basic_rates;
Simon Wunderlich2103dec2013-07-08 16:55:53 +02002888 u32 rate_flags;
Arik Nemtsov768db342011-09-28 14:12:51 +03002889
Simon Wunderlich2103dec2013-07-08 16:55:53 +02002890 shift = ieee80211_vif_get_shift(&sdata->vif);
2891 rate_flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef);
Johannes Berg6b778632012-07-23 14:53:27 +02002892 sband = local->hw.wiphy->bands[band];
Simon Wunderlich2103dec2013-07-08 16:55:53 +02002893 rates = 0;
2894 for (i = 0; i < sband->n_bitrates; i++) {
2895 if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
2896 continue;
2897 rates++;
2898 }
Arik Nemtsov768db342011-09-28 14:12:51 +03002899 if (rates > 8)
2900 rates = 8;
2901
2902 if (skb_tailroom(skb) < rates + 2)
2903 return -ENOMEM;
2904
2905 pos = skb_put(skb, rates + 2);
2906 *pos++ = WLAN_EID_SUPP_RATES;
2907 *pos++ = rates;
2908 for (i = 0; i < rates; i++) {
Ashok Nagarajan657c3e02012-04-02 21:21:20 -07002909 u8 basic = 0;
Simon Wunderlich2103dec2013-07-08 16:55:53 +02002910 if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
2911 continue;
2912
Ashok Nagarajan657c3e02012-04-02 21:21:20 -07002913 if (need_basic && basic_rates & BIT(i))
2914 basic = 0x80;
Simon Wunderlich2103dec2013-07-08 16:55:53 +02002915 rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
2916 5 * (1 << shift));
2917 *pos++ = basic | (u8) rate;
Arik Nemtsov768db342011-09-28 14:12:51 +03002918 }
2919
2920 return 0;
2921}
2922
Johannes Bergfc8a7322012-06-28 10:33:25 +02002923int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
Johannes Berg6b778632012-07-23 14:53:27 +02002924 struct sk_buff *skb, bool need_basic,
Johannes Berg57fbcce2016-04-12 15:56:15 +02002925 enum nl80211_band band)
Arik Nemtsov768db342011-09-28 14:12:51 +03002926{
Arik Nemtsov768db342011-09-28 14:12:51 +03002927 struct ieee80211_local *local = sdata->local;
2928 struct ieee80211_supported_band *sband;
Chun-Yeow Yeohcc63ec72013-09-07 23:40:44 -07002929 int rate, shift;
Arik Nemtsov768db342011-09-28 14:12:51 +03002930 u8 i, exrates, *pos;
Johannes Bergfc8a7322012-06-28 10:33:25 +02002931 u32 basic_rates = sdata->vif.bss_conf.basic_rates;
Simon Wunderlich2103dec2013-07-08 16:55:53 +02002932 u32 rate_flags;
2933
2934 rate_flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef);
2935 shift = ieee80211_vif_get_shift(&sdata->vif);
Arik Nemtsov768db342011-09-28 14:12:51 +03002936
Johannes Berg6b778632012-07-23 14:53:27 +02002937 sband = local->hw.wiphy->bands[band];
Simon Wunderlich2103dec2013-07-08 16:55:53 +02002938 exrates = 0;
2939 for (i = 0; i < sband->n_bitrates; i++) {
2940 if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
2941 continue;
2942 exrates++;
2943 }
2944
Arik Nemtsov768db342011-09-28 14:12:51 +03002945 if (exrates > 8)
2946 exrates -= 8;
2947 else
2948 exrates = 0;
2949
2950 if (skb_tailroom(skb) < exrates + 2)
2951 return -ENOMEM;
2952
2953 if (exrates) {
2954 pos = skb_put(skb, exrates + 2);
2955 *pos++ = WLAN_EID_EXT_SUPP_RATES;
2956 *pos++ = exrates;
2957 for (i = 8; i < sband->n_bitrates; i++) {
Ashok Nagarajan657c3e02012-04-02 21:21:20 -07002958 u8 basic = 0;
Simon Wunderlich2103dec2013-07-08 16:55:53 +02002959 if ((rate_flags & sband->bitrates[i].flags)
2960 != rate_flags)
2961 continue;
Ashok Nagarajan657c3e02012-04-02 21:21:20 -07002962 if (need_basic && basic_rates & BIT(i))
2963 basic = 0x80;
Simon Wunderlich2103dec2013-07-08 16:55:53 +02002964 rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
2965 5 * (1 << shift));
2966 *pos++ = basic | (u8) rate;
Arik Nemtsov768db342011-09-28 14:12:51 +03002967 }
2968 }
2969 return 0;
2970}
Wey-Yi Guy1dae27f2012-04-13 12:02:57 -07002971
2972int ieee80211_ave_rssi(struct ieee80211_vif *vif)
2973{
2974 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
2975 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2976
Wey-Yi Guybe6bcab2012-04-23 09:30:32 -07002977 if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION)) {
2978 /* non-managed type inferfaces */
2979 return 0;
2980 }
Johannes Berg338c17a2015-08-28 10:52:54 +02002981 return -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
Wey-Yi Guy1dae27f2012-04-13 12:02:57 -07002982}
Wey-Yi Guy0d8a0a12012-04-20 11:57:00 -07002983EXPORT_SYMBOL_GPL(ieee80211_ave_rssi);
Johannes Berg04ecd252012-09-11 14:34:12 +02002984
2985u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs)
2986{
2987 if (!mcs)
2988 return 1;
2989
2990 /* TODO: consider rx_highest */
2991
2992 if (mcs->rx_mask[3])
2993 return 4;
2994 if (mcs->rx_mask[2])
2995 return 3;
2996 if (mcs->rx_mask[1])
2997 return 2;
2998 return 1;
2999}
Thomas Pedersenf4bda332012-11-13 10:46:27 -08003000
3001/**
3002 * ieee80211_calculate_rx_timestamp - calculate timestamp in frame
3003 * @local: mac80211 hw info struct
3004 * @status: RX status
3005 * @mpdu_len: total MPDU length (including FCS)
3006 * @mpdu_offset: offset into MPDU to calculate timestamp at
3007 *
3008 * This function calculates the RX timestamp at the given MPDU offset, taking
3009 * into account what the RX timestamp was. An offset of 0 will just normalize
3010 * the timestamp to TSF at beginning of MPDU reception.
3011 */
3012u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
3013 struct ieee80211_rx_status *status,
3014 unsigned int mpdu_len,
3015 unsigned int mpdu_offset)
3016{
3017 u64 ts = status->mactime;
3018 struct rate_info ri;
3019 u16 rate;
3020
3021 if (WARN_ON(!ieee80211_have_rx_timestamp(status)))
3022 return 0;
3023
3024 memset(&ri, 0, sizeof(ri));
3025
Johannes Berg35f49622018-04-20 13:49:21 +03003026 ri.bw = status->bw;
3027
Thomas Pedersenf4bda332012-11-13 10:46:27 -08003028 /* Fill cfg80211 rate info */
Johannes Bergda6a4352017-04-26 12:14:59 +02003029 switch (status->encoding) {
3030 case RX_ENC_HT:
Thomas Pedersenf4bda332012-11-13 10:46:27 -08003031 ri.mcs = status->rate_idx;
3032 ri.flags |= RATE_INFO_FLAGS_MCS;
Johannes Berg7fdd69c2017-04-26 11:13:00 +02003033 if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
Thomas Pedersenf4bda332012-11-13 10:46:27 -08003034 ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
Johannes Bergda6a4352017-04-26 12:14:59 +02003035 break;
3036 case RX_ENC_VHT:
Johannes Berg56146182012-11-09 15:07:02 +01003037 ri.flags |= RATE_INFO_FLAGS_VHT_MCS;
3038 ri.mcs = status->rate_idx;
Johannes Berg8613c942017-04-26 13:51:41 +02003039 ri.nss = status->nss;
Johannes Berg7fdd69c2017-04-26 11:13:00 +02003040 if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
Johannes Berg56146182012-11-09 15:07:02 +01003041 ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
Johannes Bergda6a4352017-04-26 12:14:59 +02003042 break;
3043 default:
3044 WARN_ON(1);
3045 /* fall through */
3046 case RX_ENC_LEGACY: {
Thomas Pedersenf4bda332012-11-13 10:46:27 -08003047 struct ieee80211_supported_band *sband;
Simon Wunderlich2103dec2013-07-08 16:55:53 +02003048 int shift = 0;
3049 int bitrate;
3050
Johannes Bergda6a4352017-04-26 12:14:59 +02003051 switch (status->bw) {
3052 case RATE_INFO_BW_10:
Simon Wunderlich2103dec2013-07-08 16:55:53 +02003053 shift = 1;
Johannes Bergda6a4352017-04-26 12:14:59 +02003054 break;
3055 case RATE_INFO_BW_5:
Simon Wunderlich2103dec2013-07-08 16:55:53 +02003056 shift = 2;
Johannes Bergda6a4352017-04-26 12:14:59 +02003057 break;
Johannes Bergb51f3be2015-01-15 16:14:02 +01003058 }
Thomas Pedersenf4bda332012-11-13 10:46:27 -08003059
3060 sband = local->hw.wiphy->bands[status->band];
Simon Wunderlich2103dec2013-07-08 16:55:53 +02003061 bitrate = sband->bitrates[status->rate_idx].bitrate;
3062 ri.legacy = DIV_ROUND_UP(bitrate, (1 << shift));
Johannes Bergf4a0f0c2016-01-25 15:46:34 +02003063
3064 if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
3065 /* TODO: handle HT/VHT preambles */
Johannes Berg57fbcce2016-04-12 15:56:15 +02003066 if (status->band == NL80211_BAND_5GHZ) {
Johannes Bergf4a0f0c2016-01-25 15:46:34 +02003067 ts += 20 << shift;
3068 mpdu_offset += 2;
Johannes Berg7fdd69c2017-04-26 11:13:00 +02003069 } else if (status->enc_flags & RX_ENC_FLAG_SHORTPRE) {
Johannes Bergf4a0f0c2016-01-25 15:46:34 +02003070 ts += 96;
3071 } else {
3072 ts += 192;
3073 }
3074 }
Johannes Bergda6a4352017-04-26 12:14:59 +02003075 break;
3076 }
Thomas Pedersenf4bda332012-11-13 10:46:27 -08003077 }
3078
3079 rate = cfg80211_calculate_bitrate(&ri);
Johannes Bergd86aa4f2013-10-11 15:47:06 +02003080 if (WARN_ONCE(!rate,
Sara Sharonf980ebc2016-02-24 11:49:45 +02003081 "Invalid bitrate: flags=0x%llx, idx=%d, vht_nss=%d\n",
3082 (unsigned long long)status->flag, status->rate_idx,
Johannes Berg8613c942017-04-26 13:51:41 +02003083 status->nss))
Johannes Bergd86aa4f2013-10-11 15:47:06 +02003084 return 0;
Thomas Pedersenf4bda332012-11-13 10:46:27 -08003085
3086 /* rewind from end of MPDU */
3087 if (status->flag & RX_FLAG_MACTIME_END)
3088 ts -= mpdu_len * 8 * 10 / rate;
3089
3090 ts += mpdu_offset * 8 * 10 / rate;
3091
3092 return ts;
3093}
Simon Wunderlich164eb022013-02-08 18:16:20 +01003094
3095void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
3096{
3097 struct ieee80211_sub_if_data *sdata;
Janusz Dziedzicd2859df2013-11-06 13:55:51 +01003098 struct cfg80211_chan_def chandef;
Simon Wunderlich164eb022013-02-08 18:16:20 +01003099
Johannes Berg4a199062017-04-26 10:58:53 +03003100 /* for interface list, to avoid linking iflist_mtx and chanctx_mtx */
3101 ASSERT_RTNL();
3102
Johannes Berg34a37402013-12-18 09:43:33 +01003103 mutex_lock(&local->mtx);
Simon Wunderlich164eb022013-02-08 18:16:20 +01003104 list_for_each_entry(sdata, &local->interfaces, list) {
Johannes Berg34a37402013-12-18 09:43:33 +01003105 /* it might be waiting for the local->mtx, but then
3106 * by the time it gets it, sdata->wdev.cac_started
3107 * will no longer be true
3108 */
3109 cancel_delayed_work(&sdata->dfs_cac_timer_work);
Simon Wunderlich164eb022013-02-08 18:16:20 +01003110
3111 if (sdata->wdev.cac_started) {
Janusz Dziedzicd2859df2013-11-06 13:55:51 +01003112 chandef = sdata->vif.bss_conf.chandef;
Simon Wunderlich164eb022013-02-08 18:16:20 +01003113 ieee80211_vif_release_channel(sdata);
3114 cfg80211_cac_event(sdata->dev,
Janusz Dziedzicd2859df2013-11-06 13:55:51 +01003115 &chandef,
Simon Wunderlich164eb022013-02-08 18:16:20 +01003116 NL80211_RADAR_CAC_ABORTED,
3117 GFP_KERNEL);
3118 }
3119 }
Johannes Berg34a37402013-12-18 09:43:33 +01003120 mutex_unlock(&local->mtx);
Simon Wunderlich164eb022013-02-08 18:16:20 +01003121}
3122
3123void ieee80211_dfs_radar_detected_work(struct work_struct *work)
3124{
3125 struct ieee80211_local *local =
3126 container_of(work, struct ieee80211_local, radar_detected_work);
Janusz Dziedzic84a3d1c2013-11-05 14:48:46 +01003127 struct cfg80211_chan_def chandef = local->hw.conf.chandef;
Michal Kazior486cf4c2014-10-10 12:43:23 +02003128 struct ieee80211_chanctx *ctx;
3129 int num_chanctx = 0;
3130
3131 mutex_lock(&local->chanctx_mtx);
3132 list_for_each_entry(ctx, &local->chanctx_list, list) {
3133 if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER)
3134 continue;
3135
3136 num_chanctx++;
3137 chandef = ctx->conf.def;
3138 }
3139 mutex_unlock(&local->chanctx_mtx);
Simon Wunderlich164eb022013-02-08 18:16:20 +01003140
Johannes Berg4a199062017-04-26 10:58:53 +03003141 rtnl_lock();
Simon Wunderlich164eb022013-02-08 18:16:20 +01003142 ieee80211_dfs_cac_cancel(local);
Johannes Berg4a199062017-04-26 10:58:53 +03003143 rtnl_unlock();
Simon Wunderlich164eb022013-02-08 18:16:20 +01003144
Michal Kazior486cf4c2014-10-10 12:43:23 +02003145 if (num_chanctx > 1)
3146 /* XXX: multi-channel is not supported yet */
Simon Wunderlich164eb022013-02-08 18:16:20 +01003147 WARN_ON(1);
Janusz Dziedzic84a3d1c2013-11-05 14:48:46 +01003148 else
Simon Wunderlich164eb022013-02-08 18:16:20 +01003149 cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL);
Simon Wunderlich164eb022013-02-08 18:16:20 +01003150}
3151
3152void ieee80211_radar_detected(struct ieee80211_hw *hw)
3153{
3154 struct ieee80211_local *local = hw_to_local(hw);
3155
3156 trace_api_radar_detected(local);
3157
Johannes Berg4a199062017-04-26 10:58:53 +03003158 schedule_work(&local->radar_detected_work);
Simon Wunderlich164eb022013-02-08 18:16:20 +01003159}
3160EXPORT_SYMBOL(ieee80211_radar_detected);
Simon Wunderliche6b7cde2013-08-28 13:41:29 +02003161
3162u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
3163{
3164 u32 ret;
3165 int tmp;
3166
3167 switch (c->width) {
3168 case NL80211_CHAN_WIDTH_20:
3169 c->width = NL80211_CHAN_WIDTH_20_NOHT;
3170 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
3171 break;
3172 case NL80211_CHAN_WIDTH_40:
3173 c->width = NL80211_CHAN_WIDTH_20;
3174 c->center_freq1 = c->chan->center_freq;
3175 ret = IEEE80211_STA_DISABLE_40MHZ |
3176 IEEE80211_STA_DISABLE_VHT;
3177 break;
3178 case NL80211_CHAN_WIDTH_80:
3179 tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
3180 /* n_P40 */
3181 tmp /= 2;
3182 /* freq_P40 */
3183 c->center_freq1 = c->center_freq1 - 20 + 40 * tmp;
3184 c->width = NL80211_CHAN_WIDTH_40;
3185 ret = IEEE80211_STA_DISABLE_VHT;
3186 break;
3187 case NL80211_CHAN_WIDTH_80P80:
3188 c->center_freq2 = 0;
3189 c->width = NL80211_CHAN_WIDTH_80;
3190 ret = IEEE80211_STA_DISABLE_80P80MHZ |
3191 IEEE80211_STA_DISABLE_160MHZ;
3192 break;
3193 case NL80211_CHAN_WIDTH_160:
3194 /* n_P20 */
3195 tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
3196 /* n_P80 */
3197 tmp /= 4;
3198 c->center_freq1 = c->center_freq1 - 40 + 80 * tmp;
3199 c->width = NL80211_CHAN_WIDTH_80;
3200 ret = IEEE80211_STA_DISABLE_80P80MHZ |
3201 IEEE80211_STA_DISABLE_160MHZ;
3202 break;
3203 default:
3204 case NL80211_CHAN_WIDTH_20_NOHT:
3205 WARN_ON_ONCE(1);
3206 c->width = NL80211_CHAN_WIDTH_20_NOHT;
3207 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
3208 break;
3209 case NL80211_CHAN_WIDTH_5:
3210 case NL80211_CHAN_WIDTH_10:
3211 WARN_ON_ONCE(1);
3212 /* keep c->width */
3213 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
3214 break;
3215 }
3216
3217 WARN_ON_ONCE(!cfg80211_chandef_valid(c));
3218
3219 return ret;
3220}
Emmanuel Grumbach687da132013-10-01 16:45:43 +03003221
3222/*
3223 * Returns true if smps_mode_new is strictly more restrictive than
3224 * smps_mode_old.
3225 */
3226bool ieee80211_smps_is_restrictive(enum ieee80211_smps_mode smps_mode_old,
3227 enum ieee80211_smps_mode smps_mode_new)
3228{
3229 if (WARN_ON_ONCE(smps_mode_old == IEEE80211_SMPS_AUTOMATIC ||
3230 smps_mode_new == IEEE80211_SMPS_AUTOMATIC))
3231 return false;
3232
3233 switch (smps_mode_old) {
3234 case IEEE80211_SMPS_STATIC:
3235 return false;
3236 case IEEE80211_SMPS_DYNAMIC:
3237 return smps_mode_new == IEEE80211_SMPS_STATIC;
3238 case IEEE80211_SMPS_OFF:
3239 return smps_mode_new != IEEE80211_SMPS_OFF;
3240 default:
3241 WARN_ON(1);
3242 }
3243
3244 return false;
3245}
Chun-Yeow Yeohc6da6742013-10-14 19:08:28 -07003246
3247int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
3248 struct cfg80211_csa_settings *csa_settings)
3249{
3250 struct sk_buff *skb;
3251 struct ieee80211_mgmt *mgmt;
3252 struct ieee80211_local *local = sdata->local;
3253 int freq;
Johannes Berg4c121fd62017-09-08 11:54:46 +02003254 int hdr_len = offsetofend(struct ieee80211_mgmt,
3255 u.action.u.chan_switch);
Chun-Yeow Yeohc6da6742013-10-14 19:08:28 -07003256 u8 *pos;
3257
3258 if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
3259 sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
3260 return -EOPNOTSUPP;
3261
3262 skb = dev_alloc_skb(local->tx_headroom + hdr_len +
3263 5 + /* channel switch announcement element */
3264 3 + /* secondary channel offset element */
Simon Wunderlich75d627d2017-05-23 17:00:42 +02003265 5 + /* wide bandwidth channel switch announcement */
Chun-Yeow Yeohc6da6742013-10-14 19:08:28 -07003266 8); /* mesh channel switch parameters element */
3267 if (!skb)
3268 return -ENOMEM;
3269
3270 skb_reserve(skb, local->tx_headroom);
Johannes Bergb080db52017-06-16 14:29:19 +02003271 mgmt = skb_put_zero(skb, hdr_len);
Chun-Yeow Yeohc6da6742013-10-14 19:08:28 -07003272 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3273 IEEE80211_STYPE_ACTION);
3274
3275 eth_broadcast_addr(mgmt->da);
3276 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
3277 if (ieee80211_vif_is_mesh(&sdata->vif)) {
3278 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
3279 } else {
3280 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
3281 memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
3282 }
3283 mgmt->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
3284 mgmt->u.action.u.chan_switch.action_code = WLAN_ACTION_SPCT_CHL_SWITCH;
3285 pos = skb_put(skb, 5);
3286 *pos++ = WLAN_EID_CHANNEL_SWITCH; /* EID */
3287 *pos++ = 3; /* IE length */
3288 *pos++ = csa_settings->block_tx ? 1 : 0; /* CSA mode */
3289 freq = csa_settings->chandef.chan->center_freq;
3290 *pos++ = ieee80211_frequency_to_channel(freq); /* channel */
3291 *pos++ = csa_settings->count; /* count */
3292
3293 if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_40) {
3294 enum nl80211_channel_type ch_type;
3295
3296 skb_put(skb, 3);
3297 *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */
3298 *pos++ = 1; /* IE length */
3299 ch_type = cfg80211_get_chandef_type(&csa_settings->chandef);
3300 if (ch_type == NL80211_CHAN_HT40PLUS)
3301 *pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
3302 else
3303 *pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
3304 }
3305
3306 if (ieee80211_vif_is_mesh(&sdata->vif)) {
3307 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
Chun-Yeow Yeohc6da6742013-10-14 19:08:28 -07003308
3309 skb_put(skb, 8);
3310 *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; /* EID */
3311 *pos++ = 6; /* IE length */
3312 *pos++ = sdata->u.mesh.mshcfg.dot11MeshTTL; /* Mesh TTL */
3313 *pos = 0x00; /* Mesh Flag: Tx Restrict, Initiator, Reason */
3314 *pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
3315 *pos++ |= csa_settings->block_tx ?
3316 WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
3317 put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */
3318 pos += 2;
Chun-Yeow Yeohca91dc92013-11-12 10:31:48 +08003319 put_unaligned_le16(ifmsh->pre_value, pos);/* Precedence Value */
Chun-Yeow Yeohc6da6742013-10-14 19:08:28 -07003320 pos += 2;
Chun-Yeow Yeohc6da6742013-10-14 19:08:28 -07003321 }
3322
Simon Wunderlich75d627d2017-05-23 17:00:42 +02003323 if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_80 ||
3324 csa_settings->chandef.width == NL80211_CHAN_WIDTH_80P80 ||
3325 csa_settings->chandef.width == NL80211_CHAN_WIDTH_160) {
3326 skb_put(skb, 5);
3327 ieee80211_ie_build_wide_bw_cs(pos, &csa_settings->chandef);
3328 }
3329
Chun-Yeow Yeohc6da6742013-10-14 19:08:28 -07003330 ieee80211_tx_skb(sdata, skb);
3331 return 0;
3332}
Max Stepanov2475b1cc2013-03-24 14:23:27 +02003333
3334bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs)
3335{
3336 return !(cs == NULL || cs->cipher == 0 ||
3337 cs->hdr_len < cs->pn_len + cs->pn_off ||
3338 cs->hdr_len <= cs->key_idx_off ||
3339 cs->key_idx_shift > 7 ||
3340 cs->key_idx_mask == 0);
3341}
3342
3343bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n)
3344{
3345 int i;
3346
3347 /* Ensure we have enough iftype bitmap space for all iftype values */
3348 WARN_ON((NUM_NL80211_IFTYPES / 8 + 1) > sizeof(cs[0].iftype));
3349
3350 for (i = 0; i < n; i++)
3351 if (!ieee80211_cs_valid(&cs[i]))
3352 return false;
3353
3354 return true;
3355}
3356
3357const struct ieee80211_cipher_scheme *
3358ieee80211_cs_get(struct ieee80211_local *local, u32 cipher,
3359 enum nl80211_iftype iftype)
3360{
3361 const struct ieee80211_cipher_scheme *l = local->hw.cipher_schemes;
3362 int n = local->hw.n_cipher_schemes;
3363 int i;
3364 const struct ieee80211_cipher_scheme *cs = NULL;
3365
3366 for (i = 0; i < n; i++) {
3367 if (l[i].cipher == cipher) {
3368 cs = &l[i];
3369 break;
3370 }
3371 }
3372
3373 if (!cs || !(cs->iftype & BIT(iftype)))
3374 return NULL;
3375
3376 return cs;
3377}
3378
3379int ieee80211_cs_headroom(struct ieee80211_local *local,
3380 struct cfg80211_crypto_settings *crypto,
3381 enum nl80211_iftype iftype)
3382{
3383 const struct ieee80211_cipher_scheme *cs;
3384 int headroom = IEEE80211_ENCRYPT_HEADROOM;
3385 int i;
3386
3387 for (i = 0; i < crypto->n_ciphers_pairwise; i++) {
3388 cs = ieee80211_cs_get(local, crypto->ciphers_pairwise[i],
3389 iftype);
3390
3391 if (cs && headroom < cs->hdr_len)
3392 headroom = cs->hdr_len;
3393 }
3394
3395 cs = ieee80211_cs_get(local, crypto->cipher_group, iftype);
3396 if (cs && headroom < cs->hdr_len)
3397 headroom = cs->hdr_len;
3398
3399 return headroom;
3400}
Felix Fietkaua7022e62013-12-16 21:49:14 +01003401
3402static bool
3403ieee80211_extend_noa_desc(struct ieee80211_noa_data *data, u32 tsf, int i)
3404{
3405 s32 end = data->desc[i].start + data->desc[i].duration - (tsf + 1);
3406 int skip;
3407
3408 if (end > 0)
3409 return false;
3410
Janusz.Dziedzic@tieto.com519ee692015-10-27 08:35:11 +01003411 /* One shot NOA */
3412 if (data->count[i] == 1)
3413 return false;
3414
3415 if (data->desc[i].interval == 0)
3416 return false;
3417
Felix Fietkaua7022e62013-12-16 21:49:14 +01003418 /* End time is in the past, check for repetitions */
3419 skip = DIV_ROUND_UP(-end, data->desc[i].interval);
3420 if (data->count[i] < 255) {
3421 if (data->count[i] <= skip) {
3422 data->count[i] = 0;
3423 return false;
3424 }
3425
3426 data->count[i] -= skip;
3427 }
3428
3429 data->desc[i].start += skip * data->desc[i].interval;
3430
3431 return true;
3432}
3433
3434static bool
3435ieee80211_extend_absent_time(struct ieee80211_noa_data *data, u32 tsf,
3436 s32 *offset)
3437{
3438 bool ret = false;
3439 int i;
3440
3441 for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) {
3442 s32 cur;
3443
3444 if (!data->count[i])
3445 continue;
3446
3447 if (ieee80211_extend_noa_desc(data, tsf + *offset, i))
3448 ret = true;
3449
3450 cur = data->desc[i].start - tsf;
3451 if (cur > *offset)
3452 continue;
3453
3454 cur = data->desc[i].start + data->desc[i].duration - tsf;
3455 if (cur > *offset)
3456 *offset = cur;
3457 }
3458
3459 return ret;
3460}
3461
3462static u32
3463ieee80211_get_noa_absent_time(struct ieee80211_noa_data *data, u32 tsf)
3464{
3465 s32 offset = 0;
3466 int tries = 0;
3467 /*
3468 * arbitrary limit, used to avoid infinite loops when combined NoA
3469 * descriptors cover the full time period.
3470 */
3471 int max_tries = 5;
3472
3473 ieee80211_extend_absent_time(data, tsf, &offset);
3474 do {
3475 if (!ieee80211_extend_absent_time(data, tsf, &offset))
3476 break;
3477
3478 tries++;
3479 } while (tries < max_tries);
3480
3481 return offset;
3482}
3483
3484void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf)
3485{
3486 u32 next_offset = BIT(31) - 1;
3487 int i;
3488
3489 data->absent = 0;
3490 data->has_next_tsf = false;
3491 for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) {
3492 s32 start;
3493
3494 if (!data->count[i])
3495 continue;
3496
3497 ieee80211_extend_noa_desc(data, tsf, i);
3498 start = data->desc[i].start - tsf;
3499 if (start <= 0)
3500 data->absent |= BIT(i);
3501
3502 if (next_offset > start)
3503 next_offset = start;
3504
3505 data->has_next_tsf = true;
3506 }
3507
3508 if (data->absent)
3509 next_offset = ieee80211_get_noa_absent_time(data, tsf);
3510
3511 data->next_tsf = tsf + next_offset;
3512}
3513EXPORT_SYMBOL(ieee80211_update_p2p_noa);
3514
3515int ieee80211_parse_p2p_noa(const struct ieee80211_p2p_noa_attr *attr,
3516 struct ieee80211_noa_data *data, u32 tsf)
3517{
3518 int ret = 0;
3519 int i;
3520
3521 memset(data, 0, sizeof(*data));
3522
3523 for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) {
3524 const struct ieee80211_p2p_noa_desc *desc = &attr->desc[i];
3525
3526 if (!desc->count || !desc->duration)
3527 continue;
3528
3529 data->count[i] = desc->count;
3530 data->desc[i].start = le32_to_cpu(desc->start_time);
3531 data->desc[i].duration = le32_to_cpu(desc->duration);
3532 data->desc[i].interval = le32_to_cpu(desc->interval);
3533
3534 if (data->count[i] > 1 &&
3535 data->desc[i].interval < data->desc[i].duration)
3536 continue;
3537
3538 ieee80211_extend_noa_desc(data, tsf, i);
3539 ret++;
3540 }
3541
3542 if (ret)
3543 ieee80211_update_p2p_noa(data, tsf);
3544
3545 return ret;
3546}
3547EXPORT_SYMBOL(ieee80211_parse_p2p_noa);
Thomas Pedersen057d5f42013-12-19 10:25:15 -08003548
3549void ieee80211_recalc_dtim(struct ieee80211_local *local,
3550 struct ieee80211_sub_if_data *sdata)
3551{
3552 u64 tsf = drv_get_tsf(local, sdata);
3553 u64 dtim_count = 0;
3554 u16 beacon_int = sdata->vif.bss_conf.beacon_int * 1024;
3555 u8 dtim_period = sdata->vif.bss_conf.dtim_period;
3556 struct ps_data *ps;
3557 u8 bcns_from_dtim;
3558
3559 if (tsf == -1ULL || !beacon_int || !dtim_period)
3560 return;
3561
3562 if (sdata->vif.type == NL80211_IFTYPE_AP ||
3563 sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
3564 if (!sdata->bss)
3565 return;
3566
3567 ps = &sdata->bss->ps;
3568 } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
3569 ps = &sdata->u.mesh.ps;
3570 } else {
3571 return;
3572 }
3573
3574 /*
3575 * actually finds last dtim_count, mac80211 will update in
3576 * __beacon_add_tim().
3577 * dtim_count = dtim_period - (tsf / bcn_int) % dtim_period
3578 */
3579 do_div(tsf, beacon_int);
3580 bcns_from_dtim = do_div(tsf, dtim_period);
3581 /* just had a DTIM */
3582 if (!bcns_from_dtim)
3583 dtim_count = 0;
3584 else
3585 dtim_count = dtim_period - bcns_from_dtim;
3586
3587 ps->dtim_count = dtim_count;
3588}
Luciano Coelho73de86a2014-02-13 11:31:59 +02003589
Michal Kazior71e61952014-06-25 12:35:07 +02003590static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local,
3591 struct ieee80211_chanctx *ctx)
3592{
3593 struct ieee80211_sub_if_data *sdata;
3594 u8 radar_detect = 0;
3595
3596 lockdep_assert_held(&local->chanctx_mtx);
3597
3598 if (WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED))
3599 return 0;
3600
3601 list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list)
3602 if (sdata->reserved_radar_required)
3603 radar_detect |= BIT(sdata->reserved_chandef.width);
3604
3605 /*
3606 * An in-place reservation context should not have any assigned vifs
3607 * until it replaces the other context.
3608 */
3609 WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER &&
3610 !list_empty(&ctx->assigned_vifs));
3611
3612 list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list)
3613 if (sdata->radar_required)
3614 radar_detect |= BIT(sdata->vif.bss_conf.chandef.width);
3615
3616 return radar_detect;
3617}
3618
Luciano Coelho73de86a2014-02-13 11:31:59 +02003619int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
3620 const struct cfg80211_chan_def *chandef,
3621 enum ieee80211_chanctx_mode chanmode,
3622 u8 radar_detect)
3623{
3624 struct ieee80211_local *local = sdata->local;
3625 struct ieee80211_sub_if_data *sdata_iter;
3626 enum nl80211_iftype iftype = sdata->wdev.iftype;
Luciano Coelho73de86a2014-02-13 11:31:59 +02003627 struct ieee80211_chanctx *ctx;
Luciano Coelho73de86a2014-02-13 11:31:59 +02003628 int total = 1;
Purushottam Kushwahae2273002016-10-12 18:25:35 +05303629 struct iface_combination_params params = {
3630 .radar_detect = radar_detect,
3631 };
Luciano Coelho73de86a2014-02-13 11:31:59 +02003632
3633 lockdep_assert_held(&local->chanctx_mtx);
3634
3635 if (WARN_ON(hweight32(radar_detect) > 1))
3636 return -EINVAL;
3637
Luciano Coelhob6a55012014-02-27 11:07:21 +02003638 if (WARN_ON(chandef && chanmode == IEEE80211_CHANCTX_SHARED &&
3639 !chandef->chan))
Luciano Coelho73de86a2014-02-13 11:31:59 +02003640 return -EINVAL;
3641
3642 if (WARN_ON(iftype >= NUM_NL80211_IFTYPES))
3643 return -EINVAL;
3644
Johannes Bergac668af2016-10-21 14:25:14 +02003645 if (sdata->vif.type == NL80211_IFTYPE_AP ||
3646 sdata->vif.type == NL80211_IFTYPE_MESH_POINT) {
3647 /*
3648 * always passing this is harmless, since it'll be the
3649 * same value that cfg80211 finds if it finds the same
3650 * interface ... and that's always allowed
3651 */
3652 params.new_beacon_int = sdata->vif.bss_conf.beacon_int;
3653 }
3654
Luciano Coelho73de86a2014-02-13 11:31:59 +02003655 /* Always allow software iftypes */
3656 if (local->hw.wiphy->software_iftypes & BIT(iftype)) {
3657 if (radar_detect)
3658 return -EINVAL;
3659 return 0;
3660 }
3661
Purushottam Kushwahae2273002016-10-12 18:25:35 +05303662 if (chandef)
3663 params.num_different_channels = 1;
Luciano Coelho73de86a2014-02-13 11:31:59 +02003664
3665 if (iftype != NL80211_IFTYPE_UNSPECIFIED)
Purushottam Kushwahae2273002016-10-12 18:25:35 +05303666 params.iftype_num[iftype] = 1;
Luciano Coelho73de86a2014-02-13 11:31:59 +02003667
3668 list_for_each_entry(ctx, &local->chanctx_list, list) {
Michal Kazior5bcae312014-06-25 12:35:06 +02003669 if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
3670 continue;
Purushottam Kushwahae2273002016-10-12 18:25:35 +05303671 params.radar_detect |=
3672 ieee80211_chanctx_radar_detect(local, ctx);
Luciano Coelho73de86a2014-02-13 11:31:59 +02003673 if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
Purushottam Kushwahae2273002016-10-12 18:25:35 +05303674 params.num_different_channels++;
Luciano Coelho73de86a2014-02-13 11:31:59 +02003675 continue;
3676 }
Luciano Coelhob6a55012014-02-27 11:07:21 +02003677 if (chandef && chanmode == IEEE80211_CHANCTX_SHARED &&
Luciano Coelho73de86a2014-02-13 11:31:59 +02003678 cfg80211_chandef_compatible(chandef,
3679 &ctx->conf.def))
3680 continue;
Purushottam Kushwahae2273002016-10-12 18:25:35 +05303681 params.num_different_channels++;
Luciano Coelho73de86a2014-02-13 11:31:59 +02003682 }
3683
3684 list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) {
3685 struct wireless_dev *wdev_iter;
3686
3687 wdev_iter = &sdata_iter->wdev;
3688
3689 if (sdata_iter == sdata ||
Andrei Otcheretianski0f611d22015-03-12 08:53:30 +02003690 !ieee80211_sdata_running(sdata_iter) ||
Luciano Coelho73de86a2014-02-13 11:31:59 +02003691 local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
3692 continue;
3693
Purushottam Kushwahae2273002016-10-12 18:25:35 +05303694 params.iftype_num[wdev_iter->iftype]++;
Luciano Coelho73de86a2014-02-13 11:31:59 +02003695 total++;
3696 }
3697
Purushottam Kushwahae2273002016-10-12 18:25:35 +05303698 if (total == 1 && !params.radar_detect)
Luciano Coelho73de86a2014-02-13 11:31:59 +02003699 return 0;
3700
Purushottam Kushwahae2273002016-10-12 18:25:35 +05303701 return cfg80211_check_combinations(local->hw.wiphy, &params);
Luciano Coelho73de86a2014-02-13 11:31:59 +02003702}
Michal Kazior6fa001b2014-04-09 15:29:23 +02003703
3704static void
3705ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c,
3706 void *data)
3707{
3708 u32 *max_num_different_channels = data;
3709
3710 *max_num_different_channels = max(*max_num_different_channels,
3711 c->num_different_channels);
3712}
3713
3714int ieee80211_max_num_channels(struct ieee80211_local *local)
3715{
3716 struct ieee80211_sub_if_data *sdata;
Michal Kazior6fa001b2014-04-09 15:29:23 +02003717 struct ieee80211_chanctx *ctx;
Michal Kazior6fa001b2014-04-09 15:29:23 +02003718 u32 max_num_different_channels = 1;
3719 int err;
Purushottam Kushwahae2273002016-10-12 18:25:35 +05303720 struct iface_combination_params params = {0};
Michal Kazior6fa001b2014-04-09 15:29:23 +02003721
3722 lockdep_assert_held(&local->chanctx_mtx);
3723
3724 list_for_each_entry(ctx, &local->chanctx_list, list) {
Michal Kazior5bcae312014-06-25 12:35:06 +02003725 if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
3726 continue;
3727
Purushottam Kushwahae2273002016-10-12 18:25:35 +05303728 params.num_different_channels++;
Michal Kazior6fa001b2014-04-09 15:29:23 +02003729
Purushottam Kushwahae2273002016-10-12 18:25:35 +05303730 params.radar_detect |=
3731 ieee80211_chanctx_radar_detect(local, ctx);
Michal Kazior6fa001b2014-04-09 15:29:23 +02003732 }
3733
3734 list_for_each_entry_rcu(sdata, &local->interfaces, list)
Purushottam Kushwahae2273002016-10-12 18:25:35 +05303735 params.iftype_num[sdata->wdev.iftype]++;
Michal Kazior6fa001b2014-04-09 15:29:23 +02003736
Purushottam Kushwahae2273002016-10-12 18:25:35 +05303737 err = cfg80211_iter_combinations(local->hw.wiphy, &params,
3738 ieee80211_iter_max_chans,
Michal Kazior6fa001b2014-04-09 15:29:23 +02003739 &max_num_different_channels);
3740 if (err < 0)
3741 return err;
3742
3743 return max_num_different_channels;
3744}
Arik Nemtsov40b861a2014-07-17 17:14:23 +03003745
3746u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo)
3747{
3748 *buf++ = WLAN_EID_VENDOR_SPECIFIC;
3749 *buf++ = 7; /* len */
3750 *buf++ = 0x00; /* Microsoft OUI 00:50:F2 */
3751 *buf++ = 0x50;
3752 *buf++ = 0xf2;
3753 *buf++ = 2; /* WME */
3754 *buf++ = 0; /* WME info */
3755 *buf++ = 1; /* WME ver */
3756 *buf++ = qosinfo; /* U-APSD no in use */
3757
3758 return buf;
3759}
Felix Fietkauba8c3d62015-03-27 21:30:37 +01003760
Michal Kaziorf2ac7e302016-01-27 15:26:12 +01003761void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
3762 unsigned long *frame_cnt,
3763 unsigned long *byte_cnt)
3764{
3765 struct txq_info *txqi = to_txq_info(txq);
Toke Høiland-Jørgensenbb42f2d2016-09-22 19:04:20 +02003766 u32 frag_cnt = 0, frag_bytes = 0;
3767 struct sk_buff *skb;
3768
3769 skb_queue_walk(&txqi->frags, skb) {
3770 frag_cnt++;
3771 frag_bytes += skb->len;
3772 }
Michal Kaziorf2ac7e302016-01-27 15:26:12 +01003773
3774 if (frame_cnt)
Toke Høiland-Jørgensenbb42f2d2016-09-22 19:04:20 +02003775 *frame_cnt = txqi->tin.backlog_packets + frag_cnt;
Michal Kaziorf2ac7e302016-01-27 15:26:12 +01003776
3777 if (byte_cnt)
Toke Høiland-Jørgensenbb42f2d2016-09-22 19:04:20 +02003778 *byte_cnt = txqi->tin.backlog_bytes + frag_bytes;
Michal Kaziorf2ac7e302016-01-27 15:26:12 +01003779}
3780EXPORT_SYMBOL(ieee80211_txq_get_depth);
Emmanuel Grumbachf438ceb2016-10-18 23:12:12 +03003781
3782const u8 ieee80211_ac_to_qos_mask[IEEE80211_NUM_ACS] = {
3783 IEEE80211_WMM_IE_STA_QOSINFO_AC_VO,
3784 IEEE80211_WMM_IE_STA_QOSINFO_AC_VI,
3785 IEEE80211_WMM_IE_STA_QOSINFO_AC_BE,
3786 IEEE80211_WMM_IE_STA_QOSINFO_AC_BK
3787};