xref: /openbmc/linux/net/mac80211/util.c (revision 8d61ffa5)
1c2d1560aSJohannes Berg /*
2c2d1560aSJohannes Berg  * Copyright 2002-2005, Instant802 Networks, Inc.
3c2d1560aSJohannes Berg  * Copyright 2005-2006, Devicescape Software, Inc.
4c2d1560aSJohannes Berg  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
5c2d1560aSJohannes Berg  * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
6c2d1560aSJohannes Berg  *
7c2d1560aSJohannes Berg  * This program is free software; you can redistribute it and/or modify
8c2d1560aSJohannes Berg  * it under the terms of the GNU General Public License version 2 as
9c2d1560aSJohannes Berg  * published by the Free Software Foundation.
10c2d1560aSJohannes Berg  *
11c2d1560aSJohannes Berg  * utilities for mac80211
12c2d1560aSJohannes Berg  */
13c2d1560aSJohannes Berg 
14c2d1560aSJohannes Berg #include <net/mac80211.h>
15c2d1560aSJohannes Berg #include <linux/netdevice.h>
16bc3b2d7fSPaul Gortmaker #include <linux/export.h>
17c2d1560aSJohannes Berg #include <linux/types.h>
18c2d1560aSJohannes Berg #include <linux/slab.h>
19c2d1560aSJohannes Berg #include <linux/skbuff.h>
20c2d1560aSJohannes Berg #include <linux/etherdevice.h>
21c2d1560aSJohannes Berg #include <linux/if_arp.h>
22c2d1560aSJohannes Berg #include <linux/bitmap.h>
23dd76986bSJohannes Berg #include <linux/crc32.h>
24881d966bSEric W. Biederman #include <net/net_namespace.h>
25c2d1560aSJohannes Berg #include <net/cfg80211.h>
26dabeb344SJohannes Berg #include <net/rtnetlink.h>
27c2d1560aSJohannes Berg 
28c2d1560aSJohannes Berg #include "ieee80211_i.h"
2924487981SJohannes Berg #include "driver-ops.h"
302c8dccc7SJohannes Berg #include "rate.h"
31ee385855SLuis Carlos Cobo #include "mesh.h"
32c2d1560aSJohannes Berg #include "wme.h"
33f2753ddbSJohannes Berg #include "led.h"
34fffd0934SJohannes Berg #include "wep.h"
35c2d1560aSJohannes Berg 
36c2d1560aSJohannes Berg /* privid for wiphys to determine whether they belong to us or not */
37c2d1560aSJohannes Berg void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
38c2d1560aSJohannes Berg 
399a95371aSLuis R. Rodriguez struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy)
409a95371aSLuis R. Rodriguez {
419a95371aSLuis R. Rodriguez 	struct ieee80211_local *local;
429a95371aSLuis R. Rodriguez 	BUG_ON(!wiphy);
439a95371aSLuis R. Rodriguez 
449a95371aSLuis R. Rodriguez 	local = wiphy_priv(wiphy);
459a95371aSLuis R. Rodriguez 	return &local->hw;
469a95371aSLuis R. Rodriguez }
479a95371aSLuis R. Rodriguez EXPORT_SYMBOL(wiphy_to_ieee80211_hw);
48c2d1560aSJohannes Berg 
4971364716SRon Rindjunsky u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
5005c914feSJohannes Berg 			enum nl80211_iftype type)
51c2d1560aSJohannes Berg {
52a494bb1cSHarvey Harrison 	__le16 fc = hdr->frame_control;
53c2d1560aSJohannes Berg 
5498f0b0a3SRon Rindjunsky 	 /* drop ACK/CTS frames and incorrect hdr len (ctrl) */
5598f0b0a3SRon Rindjunsky 	if (len < 16)
56c2d1560aSJohannes Berg 		return NULL;
57c2d1560aSJohannes Berg 
58a494bb1cSHarvey Harrison 	if (ieee80211_is_data(fc)) {
5998f0b0a3SRon Rindjunsky 		if (len < 24) /* drop incorrect hdr len (data) */
6098f0b0a3SRon Rindjunsky 			return NULL;
61a494bb1cSHarvey Harrison 
62a494bb1cSHarvey Harrison 		if (ieee80211_has_a4(fc))
63c2d1560aSJohannes Berg 			return NULL;
64a494bb1cSHarvey Harrison 		if (ieee80211_has_tods(fc))
65a494bb1cSHarvey Harrison 			return hdr->addr1;
66a494bb1cSHarvey Harrison 		if (ieee80211_has_fromds(fc))
67c2d1560aSJohannes Berg 			return hdr->addr2;
68a494bb1cSHarvey Harrison 
69c2d1560aSJohannes Berg 		return hdr->addr3;
70c2d1560aSJohannes Berg 	}
71a494bb1cSHarvey Harrison 
72a494bb1cSHarvey Harrison 	if (ieee80211_is_mgmt(fc)) {
7398f0b0a3SRon Rindjunsky 		if (len < 24) /* drop incorrect hdr len (mgmt) */
7498f0b0a3SRon Rindjunsky 			return NULL;
75c2d1560aSJohannes Berg 		return hdr->addr3;
76a494bb1cSHarvey Harrison 	}
77a494bb1cSHarvey Harrison 
78a494bb1cSHarvey Harrison 	if (ieee80211_is_ctl(fc)) {
79a494bb1cSHarvey Harrison 		if(ieee80211_is_pspoll(fc))
80c2d1560aSJohannes Berg 			return hdr->addr1;
81a494bb1cSHarvey Harrison 
82a494bb1cSHarvey Harrison 		if (ieee80211_is_back_req(fc)) {
8371364716SRon Rindjunsky 			switch (type) {
8405c914feSJohannes Berg 			case NL80211_IFTYPE_STATION:
8571364716SRon Rindjunsky 				return hdr->addr2;
8605c914feSJohannes Berg 			case NL80211_IFTYPE_AP:
8705c914feSJohannes Berg 			case NL80211_IFTYPE_AP_VLAN:
8871364716SRon Rindjunsky 				return hdr->addr1;
8971364716SRon Rindjunsky 			default:
90a494bb1cSHarvey Harrison 				break; /* fall through to the return */
9171364716SRon Rindjunsky 			}
9271364716SRon Rindjunsky 		}
93c2d1560aSJohannes Berg 	}
94c2d1560aSJohannes Berg 
95c2d1560aSJohannes Berg 	return NULL;
96c2d1560aSJohannes Berg }
97c2d1560aSJohannes Berg 
985cf121c3SJohannes Berg void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
99c2d1560aSJohannes Berg {
100252b86c4SJohannes Berg 	struct sk_buff *skb;
1012de8e0d9SJohannes Berg 	struct ieee80211_hdr *hdr;
102c2d1560aSJohannes Berg 
103252b86c4SJohannes Berg 	skb_queue_walk(&tx->skbs, skb) {
1042de8e0d9SJohannes Berg 		hdr = (struct ieee80211_hdr *) skb->data;
105c2d1560aSJohannes Berg 		hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
106252b86c4SJohannes Berg 	}
107c2d1560aSJohannes Berg }
108c2d1560aSJohannes Berg 
1094ee73f33SMichal Kazior int ieee80211_frame_duration(enum ieee80211_band band, size_t len,
110c2d1560aSJohannes Berg 			     int rate, int erp, int short_preamble)
111c2d1560aSJohannes Berg {
112c2d1560aSJohannes Berg 	int dur;
113c2d1560aSJohannes Berg 
114c2d1560aSJohannes Berg 	/* calculate duration (in microseconds, rounded up to next higher
115c2d1560aSJohannes Berg 	 * integer if it includes a fractional microsecond) to send frame of
116c2d1560aSJohannes Berg 	 * len bytes (does not include FCS) at the given rate. Duration will
117c2d1560aSJohannes Berg 	 * also include SIFS.
118c2d1560aSJohannes Berg 	 *
119c2d1560aSJohannes Berg 	 * rate is in 100 kbps, so divident is multiplied by 10 in the
120c2d1560aSJohannes Berg 	 * DIV_ROUND_UP() operations.
121c2d1560aSJohannes Berg 	 */
122c2d1560aSJohannes Berg 
1234ee73f33SMichal Kazior 	if (band == IEEE80211_BAND_5GHZ || erp) {
124c2d1560aSJohannes Berg 		/*
125c2d1560aSJohannes Berg 		 * OFDM:
126c2d1560aSJohannes Berg 		 *
127c2d1560aSJohannes Berg 		 * N_DBPS = DATARATE x 4
128c2d1560aSJohannes Berg 		 * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS)
129c2d1560aSJohannes Berg 		 *	(16 = SIGNAL time, 6 = tail bits)
130c2d1560aSJohannes Berg 		 * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext
131c2d1560aSJohannes Berg 		 *
132c2d1560aSJohannes Berg 		 * T_SYM = 4 usec
133c2d1560aSJohannes Berg 		 * 802.11a - 17.5.2: aSIFSTime = 16 usec
134c2d1560aSJohannes Berg 		 * 802.11g - 19.8.4: aSIFSTime = 10 usec +
135c2d1560aSJohannes Berg 		 *	signal ext = 6 usec
136c2d1560aSJohannes Berg 		 */
137c2d1560aSJohannes Berg 		dur = 16; /* SIFS + signal ext */
138c2d1560aSJohannes Berg 		dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */
139c2d1560aSJohannes Berg 		dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */
140c2d1560aSJohannes Berg 		dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
141c2d1560aSJohannes Berg 					4 * rate); /* T_SYM x N_SYM */
142c2d1560aSJohannes Berg 	} else {
143c2d1560aSJohannes Berg 		/*
144c2d1560aSJohannes Berg 		 * 802.11b or 802.11g with 802.11b compatibility:
145c2d1560aSJohannes Berg 		 * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime +
146c2d1560aSJohannes Berg 		 * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0.
147c2d1560aSJohannes Berg 		 *
148c2d1560aSJohannes Berg 		 * 802.11 (DS): 15.3.3, 802.11b: 18.3.4
149c2d1560aSJohannes Berg 		 * aSIFSTime = 10 usec
150c2d1560aSJohannes Berg 		 * aPreambleLength = 144 usec or 72 usec with short preamble
151c2d1560aSJohannes Berg 		 * aPLCPHeaderLength = 48 usec or 24 usec with short preamble
152c2d1560aSJohannes Berg 		 */
153c2d1560aSJohannes Berg 		dur = 10; /* aSIFSTime = 10 usec */
154c2d1560aSJohannes Berg 		dur += short_preamble ? (72 + 24) : (144 + 48);
155c2d1560aSJohannes Berg 
156c2d1560aSJohannes Berg 		dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate);
157c2d1560aSJohannes Berg 	}
158c2d1560aSJohannes Berg 
159c2d1560aSJohannes Berg 	return dur;
160c2d1560aSJohannes Berg }
161c2d1560aSJohannes Berg 
162c2d1560aSJohannes Berg /* Exported duration function for driver use */
16332bfd35dSJohannes Berg __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
16432bfd35dSJohannes Berg 					struct ieee80211_vif *vif,
1654ee73f33SMichal Kazior 					enum ieee80211_band band,
1668318d78aSJohannes Berg 					size_t frame_len,
1678318d78aSJohannes Berg 					struct ieee80211_rate *rate)
168c2d1560aSJohannes Berg {
16925d834e1SJohannes Berg 	struct ieee80211_sub_if_data *sdata;
170c2d1560aSJohannes Berg 	u16 dur;
171c2d1560aSJohannes Berg 	int erp;
17225d834e1SJohannes Berg 	bool short_preamble = false;
173c2d1560aSJohannes Berg 
1748318d78aSJohannes Berg 	erp = 0;
17525d834e1SJohannes Berg 	if (vif) {
17625d834e1SJohannes Berg 		sdata = vif_to_sdata(vif);
177bda3933aSJohannes Berg 		short_preamble = sdata->vif.bss_conf.use_short_preamble;
1788318d78aSJohannes Berg 		if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
1798318d78aSJohannes Berg 			erp = rate->flags & IEEE80211_RATE_ERP_G;
18025d834e1SJohannes Berg 	}
1818318d78aSJohannes Berg 
1824ee73f33SMichal Kazior 	dur = ieee80211_frame_duration(band, frame_len, rate->bitrate, erp,
18325d834e1SJohannes Berg 				       short_preamble);
184c2d1560aSJohannes Berg 
185c2d1560aSJohannes Berg 	return cpu_to_le16(dur);
186c2d1560aSJohannes Berg }
187c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_generic_frame_duration);
188c2d1560aSJohannes Berg 
18932bfd35dSJohannes Berg __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
19032bfd35dSJohannes Berg 			      struct ieee80211_vif *vif, size_t frame_len,
191e039fa4aSJohannes Berg 			      const struct ieee80211_tx_info *frame_txctl)
192c2d1560aSJohannes Berg {
193c2d1560aSJohannes Berg 	struct ieee80211_local *local = hw_to_local(hw);
194c2d1560aSJohannes Berg 	struct ieee80211_rate *rate;
19525d834e1SJohannes Berg 	struct ieee80211_sub_if_data *sdata;
196471b3efdSJohannes Berg 	bool short_preamble;
197c2d1560aSJohannes Berg 	int erp;
198c2d1560aSJohannes Berg 	u16 dur;
1992e92e6f2SJohannes Berg 	struct ieee80211_supported_band *sband;
2002e92e6f2SJohannes Berg 
2014ee73f33SMichal Kazior 	sband = local->hw.wiphy->bands[frame_txctl->band];
202c2d1560aSJohannes Berg 
20325d834e1SJohannes Berg 	short_preamble = false;
2047e9ed188SDaniel Drake 
205e039fa4aSJohannes Berg 	rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
2068318d78aSJohannes Berg 
2078318d78aSJohannes Berg 	erp = 0;
20825d834e1SJohannes Berg 	if (vif) {
20925d834e1SJohannes Berg 		sdata = vif_to_sdata(vif);
210bda3933aSJohannes Berg 		short_preamble = sdata->vif.bss_conf.use_short_preamble;
2118318d78aSJohannes Berg 		if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
2128318d78aSJohannes Berg 			erp = rate->flags & IEEE80211_RATE_ERP_G;
21325d834e1SJohannes Berg 	}
214c2d1560aSJohannes Berg 
215c2d1560aSJohannes Berg 	/* CTS duration */
2164ee73f33SMichal Kazior 	dur = ieee80211_frame_duration(sband->band, 10, rate->bitrate,
217c2d1560aSJohannes Berg 				       erp, short_preamble);
218c2d1560aSJohannes Berg 	/* Data frame duration */
2194ee73f33SMichal Kazior 	dur += ieee80211_frame_duration(sband->band, frame_len, rate->bitrate,
220c2d1560aSJohannes Berg 					erp, short_preamble);
221c2d1560aSJohannes Berg 	/* ACK duration */
2224ee73f33SMichal Kazior 	dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate,
223c2d1560aSJohannes Berg 					erp, short_preamble);
224c2d1560aSJohannes Berg 
225c2d1560aSJohannes Berg 	return cpu_to_le16(dur);
226c2d1560aSJohannes Berg }
227c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_rts_duration);
228c2d1560aSJohannes Berg 
22932bfd35dSJohannes Berg __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
23032bfd35dSJohannes Berg 				    struct ieee80211_vif *vif,
231c2d1560aSJohannes Berg 				    size_t frame_len,
232e039fa4aSJohannes Berg 				    const struct ieee80211_tx_info *frame_txctl)
233c2d1560aSJohannes Berg {
234c2d1560aSJohannes Berg 	struct ieee80211_local *local = hw_to_local(hw);
235c2d1560aSJohannes Berg 	struct ieee80211_rate *rate;
23625d834e1SJohannes Berg 	struct ieee80211_sub_if_data *sdata;
237471b3efdSJohannes Berg 	bool short_preamble;
238c2d1560aSJohannes Berg 	int erp;
239c2d1560aSJohannes Berg 	u16 dur;
2402e92e6f2SJohannes Berg 	struct ieee80211_supported_band *sband;
2412e92e6f2SJohannes Berg 
2424ee73f33SMichal Kazior 	sband = local->hw.wiphy->bands[frame_txctl->band];
243c2d1560aSJohannes Berg 
24425d834e1SJohannes Berg 	short_preamble = false;
2457e9ed188SDaniel Drake 
246e039fa4aSJohannes Berg 	rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
2478318d78aSJohannes Berg 	erp = 0;
24825d834e1SJohannes Berg 	if (vif) {
24925d834e1SJohannes Berg 		sdata = vif_to_sdata(vif);
250bda3933aSJohannes Berg 		short_preamble = sdata->vif.bss_conf.use_short_preamble;
2518318d78aSJohannes Berg 		if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
2528318d78aSJohannes Berg 			erp = rate->flags & IEEE80211_RATE_ERP_G;
25325d834e1SJohannes Berg 	}
254c2d1560aSJohannes Berg 
255c2d1560aSJohannes Berg 	/* Data frame duration */
2564ee73f33SMichal Kazior 	dur = ieee80211_frame_duration(sband->band, frame_len, rate->bitrate,
257c2d1560aSJohannes Berg 				       erp, short_preamble);
258e039fa4aSJohannes Berg 	if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) {
259c2d1560aSJohannes Berg 		/* ACK duration */
2604ee73f33SMichal Kazior 		dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate,
261c2d1560aSJohannes Berg 						erp, short_preamble);
262c2d1560aSJohannes Berg 	}
263c2d1560aSJohannes Berg 
264c2d1560aSJohannes Berg 	return cpu_to_le16(dur);
265c2d1560aSJohannes Berg }
266c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_ctstoself_duration);
267c2d1560aSJohannes Berg 
2683a25a8c8SJohannes Berg void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
2693a25a8c8SJohannes Berg {
2703a25a8c8SJohannes Berg 	struct ieee80211_sub_if_data *sdata;
271a6f38ac3SJohannes Berg 	int n_acs = IEEE80211_NUM_ACS;
272a6f38ac3SJohannes Berg 
273a6f38ac3SJohannes Berg 	if (local->hw.queues < IEEE80211_NUM_ACS)
274a6f38ac3SJohannes Berg 		n_acs = 1;
2753a25a8c8SJohannes Berg 
2763a25a8c8SJohannes Berg 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
2773a25a8c8SJohannes Berg 		int ac;
2783a25a8c8SJohannes Berg 
279f142c6b9SJohannes Berg 		if (!sdata->dev)
280f142c6b9SJohannes Berg 			continue;
281f142c6b9SJohannes Berg 
2823a25a8c8SJohannes Berg 		if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
2833a25a8c8SJohannes Berg 			continue;
2843a25a8c8SJohannes Berg 
2853a25a8c8SJohannes Berg 		if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE &&
2863a25a8c8SJohannes Berg 		    local->queue_stop_reasons[sdata->vif.cab_queue] != 0)
2873a25a8c8SJohannes Berg 			continue;
2883a25a8c8SJohannes Berg 
289a6f38ac3SJohannes Berg 		for (ac = 0; ac < n_acs; ac++) {
2903a25a8c8SJohannes Berg 			int ac_queue = sdata->vif.hw_queue[ac];
2913a25a8c8SJohannes Berg 
2923a25a8c8SJohannes Berg 			if (ac_queue == queue ||
2933a25a8c8SJohannes Berg 			    (sdata->vif.cab_queue == queue &&
2943a25a8c8SJohannes Berg 			     local->queue_stop_reasons[ac_queue] == 0 &&
2953a25a8c8SJohannes Berg 			     skb_queue_empty(&local->pending[ac_queue])))
2963a25a8c8SJohannes Berg 				netif_wake_subqueue(sdata->dev, ac);
2973a25a8c8SJohannes Berg 		}
2983a25a8c8SJohannes Berg 	}
2993a25a8c8SJohannes Berg }
3003a25a8c8SJohannes Berg 
301ce7c9111SKalle Valo static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
302ce7c9111SKalle Valo 				   enum queue_stop_reason reason)
303c2d1560aSJohannes Berg {
304c2d1560aSJohannes Berg 	struct ieee80211_local *local = hw_to_local(hw);
305c2d1560aSJohannes Berg 
306b5878a2dSJohannes Berg 	trace_wake_queue(local, queue, reason);
307b5878a2dSJohannes Berg 
308e4e72fb4SJohannes Berg 	if (WARN_ON(queue >= hw->queues))
30996f5e66eSJohannes Berg 		return;
31096f5e66eSJohannes Berg 
311ada15125SJohannes Berg 	if (!test_bit(reason, &local->queue_stop_reasons[queue]))
312ada15125SJohannes Berg 		return;
313ada15125SJohannes Berg 
314ce7c9111SKalle Valo 	__clear_bit(reason, &local->queue_stop_reasons[queue]);
315ce7c9111SKalle Valo 
316ce7c9111SKalle Valo 	if (local->queue_stop_reasons[queue] != 0)
317ce7c9111SKalle Valo 		/* someone still has this queue stopped */
318ce7c9111SKalle Valo 		return;
319ce7c9111SKalle Valo 
3207236fe29SJohannes Berg 	if (skb_queue_empty(&local->pending[queue])) {
321cf0277e7SJohannes Berg 		rcu_read_lock();
3223a25a8c8SJohannes Berg 		ieee80211_propagate_queue_wake(local, queue);
323cf0277e7SJohannes Berg 		rcu_read_unlock();
3247236fe29SJohannes Berg 	} else
3257236fe29SJohannes Berg 		tasklet_schedule(&local->tx_pending_tasklet);
326c2d1560aSJohannes Berg }
327ce7c9111SKalle Valo 
32896f5e66eSJohannes Berg void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
329ce7c9111SKalle Valo 				    enum queue_stop_reason reason)
330ce7c9111SKalle Valo {
331ce7c9111SKalle Valo 	struct ieee80211_local *local = hw_to_local(hw);
332ce7c9111SKalle Valo 	unsigned long flags;
333ce7c9111SKalle Valo 
334ce7c9111SKalle Valo 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
335ce7c9111SKalle Valo 	__ieee80211_wake_queue(hw, queue, reason);
336ce7c9111SKalle Valo 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
337ce7c9111SKalle Valo }
338ce7c9111SKalle Valo 
339ce7c9111SKalle Valo void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
340ce7c9111SKalle Valo {
341ce7c9111SKalle Valo 	ieee80211_wake_queue_by_reason(hw, queue,
342ce7c9111SKalle Valo 				       IEEE80211_QUEUE_STOP_REASON_DRIVER);
343ce7c9111SKalle Valo }
344c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queue);
345c2d1560aSJohannes Berg 
346ce7c9111SKalle Valo static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
347ce7c9111SKalle Valo 				   enum queue_stop_reason reason)
348c2d1560aSJohannes Berg {
349c2d1560aSJohannes Berg 	struct ieee80211_local *local = hw_to_local(hw);
350cf0277e7SJohannes Berg 	struct ieee80211_sub_if_data *sdata;
351a6f38ac3SJohannes Berg 	int n_acs = IEEE80211_NUM_ACS;
352c2d1560aSJohannes Berg 
353b5878a2dSJohannes Berg 	trace_stop_queue(local, queue, reason);
354b5878a2dSJohannes Berg 
355e4e72fb4SJohannes Berg 	if (WARN_ON(queue >= hw->queues))
35696f5e66eSJohannes Berg 		return;
35796f5e66eSJohannes Berg 
358ada15125SJohannes Berg 	if (test_bit(reason, &local->queue_stop_reasons[queue]))
359ada15125SJohannes Berg 		return;
360ada15125SJohannes Berg 
3612a577d98SJohannes Berg 	__set_bit(reason, &local->queue_stop_reasons[queue]);
362cf0277e7SJohannes Berg 
363a6f38ac3SJohannes Berg 	if (local->hw.queues < IEEE80211_NUM_ACS)
364a6f38ac3SJohannes Berg 		n_acs = 1;
365a6f38ac3SJohannes Berg 
366cf0277e7SJohannes Berg 	rcu_read_lock();
3673a25a8c8SJohannes Berg 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
3683a25a8c8SJohannes Berg 		int ac;
3693a25a8c8SJohannes Berg 
370f142c6b9SJohannes Berg 		if (!sdata->dev)
371f142c6b9SJohannes Berg 			continue;
372f142c6b9SJohannes Berg 
373a6f38ac3SJohannes Berg 		for (ac = 0; ac < n_acs; ac++) {
3743a25a8c8SJohannes Berg 			if (sdata->vif.hw_queue[ac] == queue ||
3753a25a8c8SJohannes Berg 			    sdata->vif.cab_queue == queue)
3763a25a8c8SJohannes Berg 				netif_stop_subqueue(sdata->dev, ac);
3773a25a8c8SJohannes Berg 		}
3783a25a8c8SJohannes Berg 	}
379cf0277e7SJohannes Berg 	rcu_read_unlock();
380c2d1560aSJohannes Berg }
381ce7c9111SKalle Valo 
38296f5e66eSJohannes Berg void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
383ce7c9111SKalle Valo 				    enum queue_stop_reason reason)
384ce7c9111SKalle Valo {
385ce7c9111SKalle Valo 	struct ieee80211_local *local = hw_to_local(hw);
386ce7c9111SKalle Valo 	unsigned long flags;
387ce7c9111SKalle Valo 
388ce7c9111SKalle Valo 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
389ce7c9111SKalle Valo 	__ieee80211_stop_queue(hw, queue, reason);
390ce7c9111SKalle Valo 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
391ce7c9111SKalle Valo }
392ce7c9111SKalle Valo 
393ce7c9111SKalle Valo void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
394ce7c9111SKalle Valo {
395ce7c9111SKalle Valo 	ieee80211_stop_queue_by_reason(hw, queue,
396ce7c9111SKalle Valo 				       IEEE80211_QUEUE_STOP_REASON_DRIVER);
397ce7c9111SKalle Valo }
398c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queue);
399c2d1560aSJohannes Berg 
4008f77f384SJohannes Berg void ieee80211_add_pending_skb(struct ieee80211_local *local,
4018f77f384SJohannes Berg 			       struct sk_buff *skb)
4028f77f384SJohannes Berg {
4038f77f384SJohannes Berg 	struct ieee80211_hw *hw = &local->hw;
4048f77f384SJohannes Berg 	unsigned long flags;
405a7bc376cSJohannes Berg 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
4063a25a8c8SJohannes Berg 	int queue = info->hw_queue;
407a7bc376cSJohannes Berg 
408a7bc376cSJohannes Berg 	if (WARN_ON(!info->control.vif)) {
409d4fa14cdSFelix Fietkau 		ieee80211_free_txskb(&local->hw, skb);
410a7bc376cSJohannes Berg 		return;
411a7bc376cSJohannes Berg 	}
4128f77f384SJohannes Berg 
4138f77f384SJohannes Berg 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
4148f77f384SJohannes Berg 	__ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
4153b8d81e0SJohannes Berg 	__skb_queue_tail(&local->pending[queue], skb);
4168f77f384SJohannes Berg 	__ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
4178f77f384SJohannes Berg 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
4188f77f384SJohannes Berg }
4198f77f384SJohannes Berg 
420b0b97a8aSJohannes Berg void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
42150a9432dSJohannes Berg 				   struct sk_buff_head *skbs,
42250a9432dSJohannes Berg 				   void (*fn)(void *data), void *data)
4238f77f384SJohannes Berg {
4248f77f384SJohannes Berg 	struct ieee80211_hw *hw = &local->hw;
4258f77f384SJohannes Berg 	struct sk_buff *skb;
4268f77f384SJohannes Berg 	unsigned long flags;
427b0b97a8aSJohannes Berg 	int queue, i;
4288f77f384SJohannes Berg 
4298f77f384SJohannes Berg 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
4308f77f384SJohannes Berg 	while ((skb = skb_dequeue(skbs))) {
431a7bc376cSJohannes Berg 		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
432a7bc376cSJohannes Berg 
433a7bc376cSJohannes Berg 		if (WARN_ON(!info->control.vif)) {
434d4fa14cdSFelix Fietkau 			ieee80211_free_txskb(&local->hw, skb);
435a7bc376cSJohannes Berg 			continue;
436a7bc376cSJohannes Berg 		}
437a7bc376cSJohannes Berg 
4383a25a8c8SJohannes Berg 		queue = info->hw_queue;
4394644ae89SJohannes Berg 
4404644ae89SJohannes Berg 		__ieee80211_stop_queue(hw, queue,
4414644ae89SJohannes Berg 				IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
4424644ae89SJohannes Berg 
4433b8d81e0SJohannes Berg 		__skb_queue_tail(&local->pending[queue], skb);
4448f77f384SJohannes Berg 	}
4458f77f384SJohannes Berg 
44650a9432dSJohannes Berg 	if (fn)
44750a9432dSJohannes Berg 		fn(data);
44850a9432dSJohannes Berg 
4493b8d81e0SJohannes Berg 	for (i = 0; i < hw->queues; i++)
4508f77f384SJohannes Berg 		__ieee80211_wake_queue(hw, i,
4518f77f384SJohannes Berg 			IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
4528f77f384SJohannes Berg 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
4538f77f384SJohannes Berg }
4548f77f384SJohannes Berg 
455ce7c9111SKalle Valo void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
456445ea4e8SJohannes Berg 				     unsigned long queues,
457ce7c9111SKalle Valo 				     enum queue_stop_reason reason)
458c2d1560aSJohannes Berg {
459ce7c9111SKalle Valo 	struct ieee80211_local *local = hw_to_local(hw);
460ce7c9111SKalle Valo 	unsigned long flags;
461c2d1560aSJohannes Berg 	int i;
462c2d1560aSJohannes Berg 
463ce7c9111SKalle Valo 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
464ce7c9111SKalle Valo 
465445ea4e8SJohannes Berg 	for_each_set_bit(i, &queues, hw->queues)
466ce7c9111SKalle Valo 		__ieee80211_stop_queue(hw, i, reason);
467ce7c9111SKalle Valo 
468ce7c9111SKalle Valo 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
469ce7c9111SKalle Valo }
470ce7c9111SKalle Valo 
471ce7c9111SKalle Valo void ieee80211_stop_queues(struct ieee80211_hw *hw)
472ce7c9111SKalle Valo {
473445ea4e8SJohannes Berg 	ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
474ce7c9111SKalle Valo 					IEEE80211_QUEUE_STOP_REASON_DRIVER);
475c2d1560aSJohannes Berg }
476c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queues);
477c2d1560aSJohannes Berg 
47892ab8535STomas Winkler int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
47992ab8535STomas Winkler {
48092ab8535STomas Winkler 	struct ieee80211_local *local = hw_to_local(hw);
4813b8d81e0SJohannes Berg 	unsigned long flags;
4823b8d81e0SJohannes Berg 	int ret;
48396f5e66eSJohannes Berg 
484e4e72fb4SJohannes Berg 	if (WARN_ON(queue >= hw->queues))
48596f5e66eSJohannes Berg 		return true;
48696f5e66eSJohannes Berg 
4873b8d81e0SJohannes Berg 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
4882419ea14SThomas Pedersen 	ret = test_bit(IEEE80211_QUEUE_STOP_REASON_DRIVER,
4892419ea14SThomas Pedersen 		       &local->queue_stop_reasons[queue]);
4903b8d81e0SJohannes Berg 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
4913b8d81e0SJohannes Berg 	return ret;
49292ab8535STomas Winkler }
49392ab8535STomas Winkler EXPORT_SYMBOL(ieee80211_queue_stopped);
49492ab8535STomas Winkler 
495ce7c9111SKalle Valo void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
496445ea4e8SJohannes Berg 				     unsigned long queues,
497ce7c9111SKalle Valo 				     enum queue_stop_reason reason)
498c2d1560aSJohannes Berg {
499ce7c9111SKalle Valo 	struct ieee80211_local *local = hw_to_local(hw);
500ce7c9111SKalle Valo 	unsigned long flags;
501c2d1560aSJohannes Berg 	int i;
502c2d1560aSJohannes Berg 
503ce7c9111SKalle Valo 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
504ce7c9111SKalle Valo 
505445ea4e8SJohannes Berg 	for_each_set_bit(i, &queues, hw->queues)
506ce7c9111SKalle Valo 		__ieee80211_wake_queue(hw, i, reason);
507ce7c9111SKalle Valo 
508ce7c9111SKalle Valo 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
509ce7c9111SKalle Valo }
510ce7c9111SKalle Valo 
511ce7c9111SKalle Valo void ieee80211_wake_queues(struct ieee80211_hw *hw)
512ce7c9111SKalle Valo {
513445ea4e8SJohannes Berg 	ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
514445ea4e8SJohannes Berg 					IEEE80211_QUEUE_STOP_REASON_DRIVER);
515c2d1560aSJohannes Berg }
516c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queues);
517dabeb344SJohannes Berg 
51839ecc01dSJohannes Berg void ieee80211_flush_queues(struct ieee80211_local *local,
51939ecc01dSJohannes Berg 			    struct ieee80211_sub_if_data *sdata)
52039ecc01dSJohannes Berg {
52139ecc01dSJohannes Berg 	u32 queues;
52239ecc01dSJohannes Berg 
52339ecc01dSJohannes Berg 	if (!local->ops->flush)
52439ecc01dSJohannes Berg 		return;
52539ecc01dSJohannes Berg 
52639ecc01dSJohannes Berg 	if (sdata && local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) {
52739ecc01dSJohannes Berg 		int ac;
52839ecc01dSJohannes Berg 
52939ecc01dSJohannes Berg 		queues = 0;
53039ecc01dSJohannes Berg 
53139ecc01dSJohannes Berg 		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
53239ecc01dSJohannes Berg 			queues |= BIT(sdata->vif.hw_queue[ac]);
53339ecc01dSJohannes Berg 		if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE)
53439ecc01dSJohannes Berg 			queues |= BIT(sdata->vif.cab_queue);
53539ecc01dSJohannes Berg 	} else {
53639ecc01dSJohannes Berg 		/* all queues */
53739ecc01dSJohannes Berg 		queues = BIT(local->hw.queues) - 1;
53839ecc01dSJohannes Berg 	}
53939ecc01dSJohannes Berg 
540445ea4e8SJohannes Berg 	ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
541445ea4e8SJohannes Berg 					IEEE80211_QUEUE_STOP_REASON_FLUSH);
542445ea4e8SJohannes Berg 
54339ecc01dSJohannes Berg 	drv_flush(local, queues, false);
544445ea4e8SJohannes Berg 
545445ea4e8SJohannes Berg 	ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
546445ea4e8SJohannes Berg 					IEEE80211_QUEUE_STOP_REASON_FLUSH);
54739ecc01dSJohannes Berg }
54839ecc01dSJohannes Berg 
54932bfd35dSJohannes Berg void ieee80211_iterate_active_interfaces(
5508b2c9824SJohannes Berg 	struct ieee80211_hw *hw, u32 iter_flags,
551dabeb344SJohannes Berg 	void (*iterator)(void *data, u8 *mac,
55232bfd35dSJohannes Berg 			 struct ieee80211_vif *vif),
553dabeb344SJohannes Berg 	void *data)
554dabeb344SJohannes Berg {
555dabeb344SJohannes Berg 	struct ieee80211_local *local = hw_to_local(hw);
556dabeb344SJohannes Berg 	struct ieee80211_sub_if_data *sdata;
557dabeb344SJohannes Berg 
558c771c9d8SJohannes Berg 	mutex_lock(&local->iflist_mtx);
5592f561febSIvo van Doorn 
5602f561febSIvo van Doorn 	list_for_each_entry(sdata, &local->interfaces, list) {
5612f561febSIvo van Doorn 		switch (sdata->vif.type) {
56205c914feSJohannes Berg 		case NL80211_IFTYPE_MONITOR:
56305c914feSJohannes Berg 		case NL80211_IFTYPE_AP_VLAN:
5642f561febSIvo van Doorn 			continue;
5652ca27bcfSJohannes Berg 		default:
5662f561febSIvo van Doorn 			break;
5672f561febSIvo van Doorn 		}
5688b2c9824SJohannes Berg 		if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
5698b2c9824SJohannes Berg 		    !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
5708b2c9824SJohannes Berg 			continue;
5719607e6b6SJohannes Berg 		if (ieee80211_sdata_running(sdata))
57247846c9bSJohannes Berg 			iterator(data, sdata->vif.addr,
5732f561febSIvo van Doorn 				 &sdata->vif);
5742f561febSIvo van Doorn 	}
5752f561febSIvo van Doorn 
576685fb72bSJohannes Berg 	sdata = rcu_dereference_protected(local->monitor_sdata,
577685fb72bSJohannes Berg 					  lockdep_is_held(&local->iflist_mtx));
5788b2c9824SJohannes Berg 	if (sdata &&
5798b2c9824SJohannes Berg 	    (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
5808b2c9824SJohannes Berg 	     sdata->flags & IEEE80211_SDATA_IN_DRIVER))
581685fb72bSJohannes Berg 		iterator(data, sdata->vif.addr, &sdata->vif);
582685fb72bSJohannes Berg 
583c771c9d8SJohannes Berg 	mutex_unlock(&local->iflist_mtx);
5842f561febSIvo van Doorn }
5852f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
5862f561febSIvo van Doorn 
5872f561febSIvo van Doorn void ieee80211_iterate_active_interfaces_atomic(
5888b2c9824SJohannes Berg 	struct ieee80211_hw *hw, u32 iter_flags,
5892f561febSIvo van Doorn 	void (*iterator)(void *data, u8 *mac,
5902f561febSIvo van Doorn 			 struct ieee80211_vif *vif),
5912f561febSIvo van Doorn 	void *data)
5922f561febSIvo van Doorn {
5932f561febSIvo van Doorn 	struct ieee80211_local *local = hw_to_local(hw);
5942f561febSIvo van Doorn 	struct ieee80211_sub_if_data *sdata;
5952f561febSIvo van Doorn 
596e38bad47SJohannes Berg 	rcu_read_lock();
597dabeb344SJohannes Berg 
598e38bad47SJohannes Berg 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
59951fb61e7SJohannes Berg 		switch (sdata->vif.type) {
60005c914feSJohannes Berg 		case NL80211_IFTYPE_MONITOR:
60105c914feSJohannes Berg 		case NL80211_IFTYPE_AP_VLAN:
602dabeb344SJohannes Berg 			continue;
6032ca27bcfSJohannes Berg 		default:
604dabeb344SJohannes Berg 			break;
605dabeb344SJohannes Berg 		}
6068b2c9824SJohannes Berg 		if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
6078b2c9824SJohannes Berg 		    !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
6088b2c9824SJohannes Berg 			continue;
6099607e6b6SJohannes Berg 		if (ieee80211_sdata_running(sdata))
61047846c9bSJohannes Berg 			iterator(data, sdata->vif.addr,
61132bfd35dSJohannes Berg 				 &sdata->vif);
612dabeb344SJohannes Berg 	}
613e38bad47SJohannes Berg 
614685fb72bSJohannes Berg 	sdata = rcu_dereference(local->monitor_sdata);
6158b2c9824SJohannes Berg 	if (sdata &&
6168b2c9824SJohannes Berg 	    (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
6178b2c9824SJohannes Berg 	     sdata->flags & IEEE80211_SDATA_IN_DRIVER))
618685fb72bSJohannes Berg 		iterator(data, sdata->vif.addr, &sdata->vif);
619685fb72bSJohannes Berg 
620e38bad47SJohannes Berg 	rcu_read_unlock();
621dabeb344SJohannes Berg }
6222f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
62337ffc8daSJohannes Berg 
62442935ecaSLuis R. Rodriguez /*
62542935ecaSLuis R. Rodriguez  * Nothing should have been stuffed into the workqueue during
62642935ecaSLuis R. Rodriguez  * the suspend->resume cycle. If this WARN is seen then there
62742935ecaSLuis R. Rodriguez  * is a bug with either the driver suspend or something in
62842935ecaSLuis R. Rodriguez  * mac80211 stuffing into the workqueue which we haven't yet
62942935ecaSLuis R. Rodriguez  * cleared during mac80211's suspend cycle.
63042935ecaSLuis R. Rodriguez  */
63142935ecaSLuis R. Rodriguez static bool ieee80211_can_queue_work(struct ieee80211_local *local)
63242935ecaSLuis R. Rodriguez {
633ceb99fe0SJohannes Berg 	if (WARN(local->suspended && !local->resuming,
634ceb99fe0SJohannes Berg 		 "queueing ieee80211 work while going to suspend\n"))
63542935ecaSLuis R. Rodriguez 		return false;
63642935ecaSLuis R. Rodriguez 
63742935ecaSLuis R. Rodriguez 	return true;
63842935ecaSLuis R. Rodriguez }
63942935ecaSLuis R. Rodriguez 
64042935ecaSLuis R. Rodriguez void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work)
64142935ecaSLuis R. Rodriguez {
64242935ecaSLuis R. Rodriguez 	struct ieee80211_local *local = hw_to_local(hw);
64342935ecaSLuis R. Rodriguez 
64442935ecaSLuis R. Rodriguez 	if (!ieee80211_can_queue_work(local))
64542935ecaSLuis R. Rodriguez 		return;
64642935ecaSLuis R. Rodriguez 
64742935ecaSLuis R. Rodriguez 	queue_work(local->workqueue, work);
64842935ecaSLuis R. Rodriguez }
64942935ecaSLuis R. Rodriguez EXPORT_SYMBOL(ieee80211_queue_work);
65042935ecaSLuis R. Rodriguez 
65142935ecaSLuis R. Rodriguez void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
65242935ecaSLuis R. Rodriguez 				  struct delayed_work *dwork,
65342935ecaSLuis R. Rodriguez 				  unsigned long delay)
65442935ecaSLuis R. Rodriguez {
65542935ecaSLuis R. Rodriguez 	struct ieee80211_local *local = hw_to_local(hw);
65642935ecaSLuis R. Rodriguez 
65742935ecaSLuis R. Rodriguez 	if (!ieee80211_can_queue_work(local))
65842935ecaSLuis R. Rodriguez 		return;
65942935ecaSLuis R. Rodriguez 
66042935ecaSLuis R. Rodriguez 	queue_delayed_work(local->workqueue, dwork, delay);
66142935ecaSLuis R. Rodriguez }
66242935ecaSLuis R. Rodriguez EXPORT_SYMBOL(ieee80211_queue_delayed_work);
66342935ecaSLuis R. Rodriguez 
664b2e506bfSJohannes Berg u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, bool action,
665dd76986bSJohannes Berg 			       struct ieee802_11_elems *elems,
666dd76986bSJohannes Berg 			       u64 filter, u32 crc)
667dd76986bSJohannes Berg {
668dd76986bSJohannes Berg 	size_t left = len;
669dd76986bSJohannes Berg 	u8 *pos = start;
670dd76986bSJohannes Berg 	bool calc_crc = filter != 0;
671fcff4f10SPaul Stewart 	DECLARE_BITMAP(seen_elems, 256);
672b2e506bfSJohannes Berg 	const u8 *ie;
673dd76986bSJohannes Berg 
674fcff4f10SPaul Stewart 	bitmap_zero(seen_elems, 256);
675dd76986bSJohannes Berg 	memset(elems, 0, sizeof(*elems));
676dd76986bSJohannes Berg 	elems->ie_start = start;
677dd76986bSJohannes Berg 	elems->total_len = len;
678dd76986bSJohannes Berg 
679dd76986bSJohannes Berg 	while (left >= 2) {
680dd76986bSJohannes Berg 		u8 id, elen;
681fcff4f10SPaul Stewart 		bool elem_parse_failed;
682dd76986bSJohannes Berg 
683dd76986bSJohannes Berg 		id = *pos++;
684dd76986bSJohannes Berg 		elen = *pos++;
685dd76986bSJohannes Berg 		left -= 2;
686dd76986bSJohannes Berg 
687fcff4f10SPaul Stewart 		if (elen > left) {
688fcff4f10SPaul Stewart 			elems->parse_error = true;
689dd76986bSJohannes Berg 			break;
690fcff4f10SPaul Stewart 		}
691fcff4f10SPaul Stewart 
6929690fb16SJohannes Berg 		switch (id) {
6939690fb16SJohannes Berg 		case WLAN_EID_SSID:
6949690fb16SJohannes Berg 		case WLAN_EID_SUPP_RATES:
6959690fb16SJohannes Berg 		case WLAN_EID_FH_PARAMS:
6969690fb16SJohannes Berg 		case WLAN_EID_DS_PARAMS:
6979690fb16SJohannes Berg 		case WLAN_EID_CF_PARAMS:
6989690fb16SJohannes Berg 		case WLAN_EID_TIM:
6999690fb16SJohannes Berg 		case WLAN_EID_IBSS_PARAMS:
7009690fb16SJohannes Berg 		case WLAN_EID_CHALLENGE:
7019690fb16SJohannes Berg 		case WLAN_EID_RSN:
7029690fb16SJohannes Berg 		case WLAN_EID_ERP_INFO:
7039690fb16SJohannes Berg 		case WLAN_EID_EXT_SUPP_RATES:
7049690fb16SJohannes Berg 		case WLAN_EID_HT_CAPABILITY:
7059690fb16SJohannes Berg 		case WLAN_EID_HT_OPERATION:
7069690fb16SJohannes Berg 		case WLAN_EID_VHT_CAPABILITY:
7079690fb16SJohannes Berg 		case WLAN_EID_VHT_OPERATION:
7089690fb16SJohannes Berg 		case WLAN_EID_MESH_ID:
7099690fb16SJohannes Berg 		case WLAN_EID_MESH_CONFIG:
7109690fb16SJohannes Berg 		case WLAN_EID_PEER_MGMT:
7119690fb16SJohannes Berg 		case WLAN_EID_PREQ:
7129690fb16SJohannes Berg 		case WLAN_EID_PREP:
7139690fb16SJohannes Berg 		case WLAN_EID_PERR:
7149690fb16SJohannes Berg 		case WLAN_EID_RANN:
7159690fb16SJohannes Berg 		case WLAN_EID_CHANNEL_SWITCH:
7169690fb16SJohannes Berg 		case WLAN_EID_EXT_CHANSWITCH_ANN:
7179690fb16SJohannes Berg 		case WLAN_EID_COUNTRY:
7189690fb16SJohannes Berg 		case WLAN_EID_PWR_CONSTRAINT:
7199690fb16SJohannes Berg 		case WLAN_EID_TIMEOUT_INTERVAL:
72085220d71SJohannes Berg 		case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
721b2e506bfSJohannes Berg 		case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
722b2e506bfSJohannes Berg 		/*
723b2e506bfSJohannes Berg 		 * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible
724b2e506bfSJohannes Berg 		 * that if the content gets bigger it might be needed more than once
725b2e506bfSJohannes Berg 		 */
7269690fb16SJohannes Berg 			if (test_bit(id, seen_elems)) {
727fcff4f10SPaul Stewart 				elems->parse_error = true;
728fcff4f10SPaul Stewart 				left -= elen;
729fcff4f10SPaul Stewart 				pos += elen;
730fcff4f10SPaul Stewart 				continue;
731fcff4f10SPaul Stewart 			}
7329690fb16SJohannes Berg 			break;
7339690fb16SJohannes Berg 		}
734dd76986bSJohannes Berg 
735dd76986bSJohannes Berg 		if (calc_crc && id < 64 && (filter & (1ULL << id)))
736dd76986bSJohannes Berg 			crc = crc32_be(crc, pos - 2, elen + 2);
737dd76986bSJohannes Berg 
738fcff4f10SPaul Stewart 		elem_parse_failed = false;
739fcff4f10SPaul Stewart 
740dd76986bSJohannes Berg 		switch (id) {
741dd76986bSJohannes Berg 		case WLAN_EID_SSID:
742dd76986bSJohannes Berg 			elems->ssid = pos;
743dd76986bSJohannes Berg 			elems->ssid_len = elen;
744dd76986bSJohannes Berg 			break;
745dd76986bSJohannes Berg 		case WLAN_EID_SUPP_RATES:
746dd76986bSJohannes Berg 			elems->supp_rates = pos;
747dd76986bSJohannes Berg 			elems->supp_rates_len = elen;
748dd76986bSJohannes Berg 			break;
749dd76986bSJohannes Berg 		case WLAN_EID_DS_PARAMS:
7501cd8e88eSJohannes Berg 			if (elen >= 1)
751dd76986bSJohannes Berg 				elems->ds_params = pos;
7521cd8e88eSJohannes Berg 			else
7531cd8e88eSJohannes Berg 				elem_parse_failed = true;
754dd76986bSJohannes Berg 			break;
755dd76986bSJohannes Berg 		case WLAN_EID_TIM:
756dd76986bSJohannes Berg 			if (elen >= sizeof(struct ieee80211_tim_ie)) {
757dd76986bSJohannes Berg 				elems->tim = (void *)pos;
758dd76986bSJohannes Berg 				elems->tim_len = elen;
759fcff4f10SPaul Stewart 			} else
760fcff4f10SPaul Stewart 				elem_parse_failed = true;
761dd76986bSJohannes Berg 			break;
762dd76986bSJohannes Berg 		case WLAN_EID_CHALLENGE:
763dd76986bSJohannes Berg 			elems->challenge = pos;
764dd76986bSJohannes Berg 			elems->challenge_len = elen;
765dd76986bSJohannes Berg 			break;
766dd76986bSJohannes Berg 		case WLAN_EID_VENDOR_SPECIFIC:
767dd76986bSJohannes Berg 			if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
768dd76986bSJohannes Berg 			    pos[2] == 0xf2) {
769dd76986bSJohannes Berg 				/* Microsoft OUI (00:50:F2) */
770dd76986bSJohannes Berg 
771dd76986bSJohannes Berg 				if (calc_crc)
772dd76986bSJohannes Berg 					crc = crc32_be(crc, pos - 2, elen + 2);
773dd76986bSJohannes Berg 
774441a33baSJohannes Berg 				if (elen >= 5 && pos[3] == 2) {
775dd76986bSJohannes Berg 					/* OUI Type 2 - WMM IE */
776dd76986bSJohannes Berg 					if (pos[4] == 0) {
777dd76986bSJohannes Berg 						elems->wmm_info = pos;
778dd76986bSJohannes Berg 						elems->wmm_info_len = elen;
779dd76986bSJohannes Berg 					} else if (pos[4] == 1) {
780dd76986bSJohannes Berg 						elems->wmm_param = pos;
781dd76986bSJohannes Berg 						elems->wmm_param_len = elen;
782dd76986bSJohannes Berg 					}
783dd76986bSJohannes Berg 				}
784dd76986bSJohannes Berg 			}
785dd76986bSJohannes Berg 			break;
786dd76986bSJohannes Berg 		case WLAN_EID_RSN:
787dd76986bSJohannes Berg 			elems->rsn = pos;
788dd76986bSJohannes Berg 			elems->rsn_len = elen;
789dd76986bSJohannes Berg 			break;
790dd76986bSJohannes Berg 		case WLAN_EID_ERP_INFO:
7911946bed9SJohannes Berg 			if (elen >= 1)
792dd76986bSJohannes Berg 				elems->erp_info = pos;
7931946bed9SJohannes Berg 			else
7941946bed9SJohannes Berg 				elem_parse_failed = true;
795dd76986bSJohannes Berg 			break;
796dd76986bSJohannes Berg 		case WLAN_EID_EXT_SUPP_RATES:
797dd76986bSJohannes Berg 			elems->ext_supp_rates = pos;
798dd76986bSJohannes Berg 			elems->ext_supp_rates_len = elen;
799dd76986bSJohannes Berg 			break;
800dd76986bSJohannes Berg 		case WLAN_EID_HT_CAPABILITY:
801dd76986bSJohannes Berg 			if (elen >= sizeof(struct ieee80211_ht_cap))
802dd76986bSJohannes Berg 				elems->ht_cap_elem = (void *)pos;
803fcff4f10SPaul Stewart 			else
804fcff4f10SPaul Stewart 				elem_parse_failed = true;
805dd76986bSJohannes Berg 			break;
806074d46d1SJohannes Berg 		case WLAN_EID_HT_OPERATION:
807074d46d1SJohannes Berg 			if (elen >= sizeof(struct ieee80211_ht_operation))
808074d46d1SJohannes Berg 				elems->ht_operation = (void *)pos;
809fcff4f10SPaul Stewart 			else
810fcff4f10SPaul Stewart 				elem_parse_failed = true;
811dd76986bSJohannes Berg 			break;
812818255eaSMahesh Palivela 		case WLAN_EID_VHT_CAPABILITY:
813818255eaSMahesh Palivela 			if (elen >= sizeof(struct ieee80211_vht_cap))
814818255eaSMahesh Palivela 				elems->vht_cap_elem = (void *)pos;
815818255eaSMahesh Palivela 			else
816818255eaSMahesh Palivela 				elem_parse_failed = true;
817818255eaSMahesh Palivela 			break;
818818255eaSMahesh Palivela 		case WLAN_EID_VHT_OPERATION:
819818255eaSMahesh Palivela 			if (elen >= sizeof(struct ieee80211_vht_operation))
820818255eaSMahesh Palivela 				elems->vht_operation = (void *)pos;
821818255eaSMahesh Palivela 			else
822818255eaSMahesh Palivela 				elem_parse_failed = true;
823818255eaSMahesh Palivela 			break;
824bee7f586SJohannes Berg 		case WLAN_EID_OPMODE_NOTIF:
825bee7f586SJohannes Berg 			if (elen > 0)
826bee7f586SJohannes Berg 				elems->opmode_notif = pos;
827bee7f586SJohannes Berg 			else
828bee7f586SJohannes Berg 				elem_parse_failed = true;
829bee7f586SJohannes Berg 			break;
830dd76986bSJohannes Berg 		case WLAN_EID_MESH_ID:
831dd76986bSJohannes Berg 			elems->mesh_id = pos;
832dd76986bSJohannes Berg 			elems->mesh_id_len = elen;
833dd76986bSJohannes Berg 			break;
834dd76986bSJohannes Berg 		case WLAN_EID_MESH_CONFIG:
835dd76986bSJohannes Berg 			if (elen >= sizeof(struct ieee80211_meshconf_ie))
836dd76986bSJohannes Berg 				elems->mesh_config = (void *)pos;
837fcff4f10SPaul Stewart 			else
838fcff4f10SPaul Stewart 				elem_parse_failed = true;
839dd76986bSJohannes Berg 			break;
840dd76986bSJohannes Berg 		case WLAN_EID_PEER_MGMT:
841dd76986bSJohannes Berg 			elems->peering = pos;
842dd76986bSJohannes Berg 			elems->peering_len = elen;
843dd76986bSJohannes Berg 			break;
8443f52b7e3SMarco Porsch 		case WLAN_EID_MESH_AWAKE_WINDOW:
8453f52b7e3SMarco Porsch 			if (elen >= 2)
8463f52b7e3SMarco Porsch 				elems->awake_window = (void *)pos;
8473f52b7e3SMarco Porsch 			break;
848dd76986bSJohannes Berg 		case WLAN_EID_PREQ:
849dd76986bSJohannes Berg 			elems->preq = pos;
850dd76986bSJohannes Berg 			elems->preq_len = elen;
851dd76986bSJohannes Berg 			break;
852dd76986bSJohannes Berg 		case WLAN_EID_PREP:
853dd76986bSJohannes Berg 			elems->prep = pos;
854dd76986bSJohannes Berg 			elems->prep_len = elen;
855dd76986bSJohannes Berg 			break;
856dd76986bSJohannes Berg 		case WLAN_EID_PERR:
857dd76986bSJohannes Berg 			elems->perr = pos;
858dd76986bSJohannes Berg 			elems->perr_len = elen;
859dd76986bSJohannes Berg 			break;
860dd76986bSJohannes Berg 		case WLAN_EID_RANN:
861dd76986bSJohannes Berg 			if (elen >= sizeof(struct ieee80211_rann_ie))
862dd76986bSJohannes Berg 				elems->rann = (void *)pos;
863fcff4f10SPaul Stewart 			else
864fcff4f10SPaul Stewart 				elem_parse_failed = true;
865dd76986bSJohannes Berg 			break;
866dd76986bSJohannes Berg 		case WLAN_EID_CHANNEL_SWITCH:
8675bc1420bSJohannes Berg 			if (elen != sizeof(struct ieee80211_channel_sw_ie)) {
8685bc1420bSJohannes Berg 				elem_parse_failed = true;
8695bc1420bSJohannes Berg 				break;
8705bc1420bSJohannes Berg 			}
8715bc1420bSJohannes Berg 			elems->ch_switch_ie = (void *)pos;
872dd76986bSJohannes Berg 			break;
873b4f286a1SJohannes Berg 		case WLAN_EID_EXT_CHANSWITCH_ANN:
874b4f286a1SJohannes Berg 			if (elen != sizeof(struct ieee80211_ext_chansw_ie)) {
875b4f286a1SJohannes Berg 				elem_parse_failed = true;
876b4f286a1SJohannes Berg 				break;
877b4f286a1SJohannes Berg 			}
878b4f286a1SJohannes Berg 			elems->ext_chansw_ie = (void *)pos;
879b4f286a1SJohannes Berg 			break;
88085220d71SJohannes Berg 		case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
88185220d71SJohannes Berg 			if (elen != sizeof(struct ieee80211_sec_chan_offs_ie)) {
88285220d71SJohannes Berg 				elem_parse_failed = true;
88385220d71SJohannes Berg 				break;
88485220d71SJohannes Berg 			}
88585220d71SJohannes Berg 			elems->sec_chan_offs = (void *)pos;
88685220d71SJohannes Berg 			break;
887b2e506bfSJohannes Berg 		case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
888b2e506bfSJohannes Berg 			if (!action ||
889b2e506bfSJohannes Berg 			    elen != sizeof(*elems->wide_bw_chansw_ie)) {
890b2e506bfSJohannes Berg 				elem_parse_failed = true;
891b2e506bfSJohannes Berg 				break;
892b2e506bfSJohannes Berg 			}
893b2e506bfSJohannes Berg 			elems->wide_bw_chansw_ie = (void *)pos;
894b2e506bfSJohannes Berg 			break;
895b2e506bfSJohannes Berg 		case WLAN_EID_CHANNEL_SWITCH_WRAPPER:
896b2e506bfSJohannes Berg 			if (action) {
897b2e506bfSJohannes Berg 				elem_parse_failed = true;
898b2e506bfSJohannes Berg 				break;
899b2e506bfSJohannes Berg 			}
900b2e506bfSJohannes Berg 			/*
901b2e506bfSJohannes Berg 			 * This is a bit tricky, but as we only care about
902b2e506bfSJohannes Berg 			 * the wide bandwidth channel switch element, so
903b2e506bfSJohannes Berg 			 * just parse it out manually.
904b2e506bfSJohannes Berg 			 */
905b2e506bfSJohannes Berg 			ie = cfg80211_find_ie(WLAN_EID_WIDE_BW_CHANNEL_SWITCH,
906b2e506bfSJohannes Berg 					      pos, elen);
907b2e506bfSJohannes Berg 			if (ie) {
908b2e506bfSJohannes Berg 				if (ie[1] == sizeof(*elems->wide_bw_chansw_ie))
909b2e506bfSJohannes Berg 					elems->wide_bw_chansw_ie =
910b2e506bfSJohannes Berg 						(void *)(ie + 2);
911b2e506bfSJohannes Berg 				else
912b2e506bfSJohannes Berg 					elem_parse_failed = true;
913b2e506bfSJohannes Berg 			}
914b2e506bfSJohannes Berg 			break;
915dd76986bSJohannes Berg 		case WLAN_EID_COUNTRY:
916dd76986bSJohannes Berg 			elems->country_elem = pos;
917dd76986bSJohannes Berg 			elems->country_elem_len = elen;
918dd76986bSJohannes Berg 			break;
919dd76986bSJohannes Berg 		case WLAN_EID_PWR_CONSTRAINT:
920761a48d2SJohannes Berg 			if (elen != 1) {
921761a48d2SJohannes Berg 				elem_parse_failed = true;
922761a48d2SJohannes Berg 				break;
923761a48d2SJohannes Berg 			}
924dd76986bSJohannes Berg 			elems->pwr_constr_elem = pos;
925dd76986bSJohannes Berg 			break;
926dd76986bSJohannes Berg 		case WLAN_EID_TIMEOUT_INTERVAL:
92779ba1d89SJohannes Berg 			if (elen >= sizeof(struct ieee80211_timeout_interval_ie))
92879ba1d89SJohannes Berg 				elems->timeout_int = (void *)pos;
92979ba1d89SJohannes Berg 			else
93079ba1d89SJohannes Berg 				elem_parse_failed = true;
931dd76986bSJohannes Berg 			break;
932dd76986bSJohannes Berg 		default:
933dd76986bSJohannes Berg 			break;
934dd76986bSJohannes Berg 		}
935dd76986bSJohannes Berg 
936fcff4f10SPaul Stewart 		if (elem_parse_failed)
937fcff4f10SPaul Stewart 			elems->parse_error = true;
938fcff4f10SPaul Stewart 		else
9395df45690SJohannes Berg 			__set_bit(id, seen_elems);
940fcff4f10SPaul Stewart 
941dd76986bSJohannes Berg 		left -= elen;
942dd76986bSJohannes Berg 		pos += elen;
943dd76986bSJohannes Berg 	}
944dd76986bSJohannes Berg 
945fcff4f10SPaul Stewart 	if (left != 0)
946fcff4f10SPaul Stewart 		elems->parse_error = true;
947fcff4f10SPaul Stewart 
948dd76986bSJohannes Berg 	return crc;
949dd76986bSJohannes Berg }
950dd76986bSJohannes Berg 
9513abead59SJohannes Berg void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
9523abead59SJohannes Berg 			       bool bss_notify)
9535825fe10SJohannes Berg {
9545825fe10SJohannes Berg 	struct ieee80211_local *local = sdata->local;
9555825fe10SJohannes Berg 	struct ieee80211_tx_queue_params qparam;
95655de908aSJohannes Berg 	struct ieee80211_chanctx_conf *chanctx_conf;
95754bcbc69SJohannes Berg 	int ac;
958a8ce8544SStanislaw Gruszka 	bool use_11b, enable_qos;
959aa837e1dSJohannes Berg 	int aCWmin, aCWmax;
9605825fe10SJohannes Berg 
9615825fe10SJohannes Berg 	if (!local->ops->conf_tx)
9625825fe10SJohannes Berg 		return;
9635825fe10SJohannes Berg 
96454bcbc69SJohannes Berg 	if (local->hw.queues < IEEE80211_NUM_ACS)
96554bcbc69SJohannes Berg 		return;
96654bcbc69SJohannes Berg 
9675825fe10SJohannes Berg 	memset(&qparam, 0, sizeof(qparam));
9685825fe10SJohannes Berg 
96955de908aSJohannes Berg 	rcu_read_lock();
97055de908aSJohannes Berg 	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
97155de908aSJohannes Berg 	use_11b = (chanctx_conf &&
9724bf88530SJohannes Berg 		   chanctx_conf->def.chan->band == IEEE80211_BAND_2GHZ) &&
973aa837e1dSJohannes Berg 		 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
97455de908aSJohannes Berg 	rcu_read_unlock();
9755825fe10SJohannes Berg 
976a8ce8544SStanislaw Gruszka 	/*
977a8ce8544SStanislaw Gruszka 	 * By default disable QoS in STA mode for old access points, which do
978a8ce8544SStanislaw Gruszka 	 * not support 802.11e. New APs will provide proper queue parameters,
979a8ce8544SStanislaw Gruszka 	 * that we will configure later.
980a8ce8544SStanislaw Gruszka 	 */
981a8ce8544SStanislaw Gruszka 	enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION);
982a8ce8544SStanislaw Gruszka 
98354bcbc69SJohannes Berg 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
984aa837e1dSJohannes Berg 		/* Set defaults according to 802.11-2007 Table 7-37 */
985aa837e1dSJohannes Berg 		aCWmax = 1023;
986aa837e1dSJohannes Berg 		if (use_11b)
987aa837e1dSJohannes Berg 			aCWmin = 31;
9885825fe10SJohannes Berg 		else
989aa837e1dSJohannes Berg 			aCWmin = 15;
9905825fe10SJohannes Berg 
991a8ce8544SStanislaw Gruszka 		if (enable_qos) {
99254bcbc69SJohannes Berg 			switch (ac) {
9931d98fb12SJohannes Berg 			case IEEE80211_AC_BK:
9947ba10a8eSJohannes Berg 				qparam.cw_max = aCWmax;
9957ba10a8eSJohannes Berg 				qparam.cw_min = aCWmin;
9965825fe10SJohannes Berg 				qparam.txop = 0;
997aa837e1dSJohannes Berg 				qparam.aifs = 7;
998aa837e1dSJohannes Berg 				break;
999a8ce8544SStanislaw Gruszka 			/* never happens but let's not leave undefined */
1000a8ce8544SStanislaw Gruszka 			default:
10011d98fb12SJohannes Berg 			case IEEE80211_AC_BE:
10027ba10a8eSJohannes Berg 				qparam.cw_max = aCWmax;
10037ba10a8eSJohannes Berg 				qparam.cw_min = aCWmin;
1004aa837e1dSJohannes Berg 				qparam.txop = 0;
1005aa837e1dSJohannes Berg 				qparam.aifs = 3;
1006aa837e1dSJohannes Berg 				break;
10071d98fb12SJohannes Berg 			case IEEE80211_AC_VI:
1008aa837e1dSJohannes Berg 				qparam.cw_max = aCWmin;
1009aa837e1dSJohannes Berg 				qparam.cw_min = (aCWmin + 1) / 2 - 1;
1010aa837e1dSJohannes Berg 				if (use_11b)
1011aa837e1dSJohannes Berg 					qparam.txop = 6016/32;
1012aa837e1dSJohannes Berg 				else
1013aa837e1dSJohannes Berg 					qparam.txop = 3008/32;
1014aa837e1dSJohannes Berg 				qparam.aifs = 2;
1015aa837e1dSJohannes Berg 				break;
10161d98fb12SJohannes Berg 			case IEEE80211_AC_VO:
1017aa837e1dSJohannes Berg 				qparam.cw_max = (aCWmin + 1) / 2 - 1;
1018aa837e1dSJohannes Berg 				qparam.cw_min = (aCWmin + 1) / 4 - 1;
1019aa837e1dSJohannes Berg 				if (use_11b)
1020aa837e1dSJohannes Berg 					qparam.txop = 3264/32;
1021aa837e1dSJohannes Berg 				else
1022aa837e1dSJohannes Berg 					qparam.txop = 1504/32;
1023aa837e1dSJohannes Berg 				qparam.aifs = 2;
1024aa837e1dSJohannes Berg 				break;
1025aa837e1dSJohannes Berg 			}
1026a8ce8544SStanislaw Gruszka 		} else {
1027a8ce8544SStanislaw Gruszka 			/* Confiure old 802.11b/g medium access rules. */
1028a8ce8544SStanislaw Gruszka 			qparam.cw_max = aCWmax;
1029a8ce8544SStanislaw Gruszka 			qparam.cw_min = aCWmin;
1030a8ce8544SStanislaw Gruszka 			qparam.txop = 0;
1031a8ce8544SStanislaw Gruszka 			qparam.aifs = 2;
1032a8ce8544SStanislaw Gruszka 		}
10335825fe10SJohannes Berg 
1034ab13315aSKalle Valo 		qparam.uapsd = false;
1035ab13315aSKalle Valo 
103654bcbc69SJohannes Berg 		sdata->tx_conf[ac] = qparam;
103754bcbc69SJohannes Berg 		drv_conf_tx(local, sdata, ac, &qparam);
1038aa837e1dSJohannes Berg 	}
1039e1b3ec1aSStanislaw Gruszka 
1040f142c6b9SJohannes Berg 	if (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
1041f142c6b9SJohannes Berg 	    sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) {
1042a8ce8544SStanislaw Gruszka 		sdata->vif.bss_conf.qos = enable_qos;
10433abead59SJohannes Berg 		if (bss_notify)
10443abead59SJohannes Berg 			ieee80211_bss_info_change_notify(sdata,
10453abead59SJohannes Berg 							 BSS_CHANGED_QOS);
10465825fe10SJohannes Berg 	}
1047d9734979SSujith }
1048e50db65cSJohannes Berg 
104946900298SJohannes Berg void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
105046900298SJohannes Berg 				  const size_t supp_rates_len,
105146900298SJohannes Berg 				  const u8 *supp_rates)
105246900298SJohannes Berg {
105355de908aSJohannes Berg 	struct ieee80211_chanctx_conf *chanctx_conf;
105446900298SJohannes Berg 	int i, have_higher_than_11mbit = 0;
105546900298SJohannes Berg 
105646900298SJohannes Berg 	/* cf. IEEE 802.11 9.2.12 */
105746900298SJohannes Berg 	for (i = 0; i < supp_rates_len; i++)
105846900298SJohannes Berg 		if ((supp_rates[i] & 0x7f) * 5 > 110)
105946900298SJohannes Berg 			have_higher_than_11mbit = 1;
106046900298SJohannes Berg 
106155de908aSJohannes Berg 	rcu_read_lock();
106255de908aSJohannes Berg 	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
106355de908aSJohannes Berg 
106455de908aSJohannes Berg 	if (chanctx_conf &&
10654bf88530SJohannes Berg 	    chanctx_conf->def.chan->band == IEEE80211_BAND_2GHZ &&
106646900298SJohannes Berg 	    have_higher_than_11mbit)
106746900298SJohannes Berg 		sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
106846900298SJohannes Berg 	else
106946900298SJohannes Berg 		sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
107055de908aSJohannes Berg 	rcu_read_unlock();
107146900298SJohannes Berg 
10723abead59SJohannes Berg 	ieee80211_set_wmm_default(sdata, true);
107346900298SJohannes Berg }
107446900298SJohannes Berg 
107546900298SJohannes Berg void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
1076700e8ea6SJouni Malinen 			 u16 transaction, u16 auth_alg, u16 status,
10774a3cb702SJohannes Berg 			 const u8 *extra, size_t extra_len, const u8 *da,
10781672c0e3SJohannes Berg 			 const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx,
10791672c0e3SJohannes Berg 			 u32 tx_flags)
108046900298SJohannes Berg {
108146900298SJohannes Berg 	struct ieee80211_local *local = sdata->local;
108246900298SJohannes Berg 	struct sk_buff *skb;
108346900298SJohannes Berg 	struct ieee80211_mgmt *mgmt;
1084fffd0934SJohannes Berg 	int err;
108546900298SJohannes Berg 
108646900298SJohannes Berg 	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
108765fc73acSJouni Malinen 			    sizeof(*mgmt) + 6 + extra_len);
1088d15b8459SJoe Perches 	if (!skb)
108946900298SJohannes Berg 		return;
1090d15b8459SJoe Perches 
109146900298SJohannes Berg 	skb_reserve(skb, local->hw.extra_tx_headroom);
109246900298SJohannes Berg 
109346900298SJohannes Berg 	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
109446900298SJohannes Berg 	memset(mgmt, 0, 24 + 6);
109546900298SJohannes Berg 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
109646900298SJohannes Berg 					  IEEE80211_STYPE_AUTH);
1097efa6a09dSAntonio Quartulli 	memcpy(mgmt->da, da, ETH_ALEN);
109847846c9bSJohannes Berg 	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
109946900298SJohannes Berg 	memcpy(mgmt->bssid, bssid, ETH_ALEN);
110046900298SJohannes Berg 	mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg);
110146900298SJohannes Berg 	mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
1102700e8ea6SJouni Malinen 	mgmt->u.auth.status_code = cpu_to_le16(status);
110346900298SJohannes Berg 	if (extra)
110446900298SJohannes Berg 		memcpy(skb_put(skb, extra_len), extra, extra_len);
110546900298SJohannes Berg 
1106fffd0934SJohannes Berg 	if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
1107fffd0934SJohannes Berg 		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
1108fffd0934SJohannes Berg 		err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx);
1109fffd0934SJohannes Berg 		WARN_ON(err);
1110fffd0934SJohannes Berg 	}
1111fffd0934SJohannes Berg 
11121672c0e3SJohannes Berg 	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
11131672c0e3SJohannes Berg 					tx_flags;
111462ae67beSJohannes Berg 	ieee80211_tx_skb(sdata, skb);
111546900298SJohannes Berg }
111646900298SJohannes Berg 
11176ae16775SAntonio Quartulli void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
11186ae16775SAntonio Quartulli 				    const u8 *bssid, u16 stype, u16 reason,
11196ae16775SAntonio Quartulli 				    bool send_frame, u8 *frame_buf)
11206ae16775SAntonio Quartulli {
11216ae16775SAntonio Quartulli 	struct ieee80211_local *local = sdata->local;
11226ae16775SAntonio Quartulli 	struct sk_buff *skb;
11236ae16775SAntonio Quartulli 	struct ieee80211_mgmt *mgmt = (void *)frame_buf;
11246ae16775SAntonio Quartulli 
11256ae16775SAntonio Quartulli 	/* build frame */
11266ae16775SAntonio Quartulli 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
11276ae16775SAntonio Quartulli 	mgmt->duration = 0; /* initialize only */
11286ae16775SAntonio Quartulli 	mgmt->seq_ctrl = 0; /* initialize only */
11296ae16775SAntonio Quartulli 	memcpy(mgmt->da, bssid, ETH_ALEN);
11306ae16775SAntonio Quartulli 	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
11316ae16775SAntonio Quartulli 	memcpy(mgmt->bssid, bssid, ETH_ALEN);
11326ae16775SAntonio Quartulli 	/* u.deauth.reason_code == u.disassoc.reason_code */
11336ae16775SAntonio Quartulli 	mgmt->u.deauth.reason_code = cpu_to_le16(reason);
11346ae16775SAntonio Quartulli 
11356ae16775SAntonio Quartulli 	if (send_frame) {
11366ae16775SAntonio Quartulli 		skb = dev_alloc_skb(local->hw.extra_tx_headroom +
11376ae16775SAntonio Quartulli 				    IEEE80211_DEAUTH_FRAME_LEN);
11386ae16775SAntonio Quartulli 		if (!skb)
11396ae16775SAntonio Quartulli 			return;
11406ae16775SAntonio Quartulli 
11416ae16775SAntonio Quartulli 		skb_reserve(skb, local->hw.extra_tx_headroom);
11426ae16775SAntonio Quartulli 
11436ae16775SAntonio Quartulli 		/* copy in frame */
11446ae16775SAntonio Quartulli 		memcpy(skb_put(skb, IEEE80211_DEAUTH_FRAME_LEN),
11456ae16775SAntonio Quartulli 		       mgmt, IEEE80211_DEAUTH_FRAME_LEN);
11466ae16775SAntonio Quartulli 
11476ae16775SAntonio Quartulli 		if (sdata->vif.type != NL80211_IFTYPE_STATION ||
11486ae16775SAntonio Quartulli 		    !(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED))
11496ae16775SAntonio Quartulli 			IEEE80211_SKB_CB(skb)->flags |=
11506ae16775SAntonio Quartulli 				IEEE80211_TX_INTFL_DONT_ENCRYPT;
11516ae16775SAntonio Quartulli 
11526ae16775SAntonio Quartulli 		ieee80211_tx_skb(sdata, skb);
11536ae16775SAntonio Quartulli 	}
11546ae16775SAntonio Quartulli }
11556ae16775SAntonio Quartulli 
1156de95a54bSJohannes Berg int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1157c604b9f2SJohannes Berg 			     size_t buffer_len, const u8 *ie, size_t ie_len,
1158651b5225SJouni Malinen 			     enum ieee80211_band band, u32 rate_mask,
1159651b5225SJouni Malinen 			     u8 channel)
1160de95a54bSJohannes Berg {
1161de95a54bSJohannes Berg 	struct ieee80211_supported_band *sband;
1162c604b9f2SJohannes Berg 	u8 *pos = buffer, *end = buffer + buffer_len;
11638e664fb3SJohannes Berg 	size_t offset = 0, noffset;
11648e664fb3SJohannes Berg 	int supp_rates_len, i;
11658dcb2003SJouni Malinen 	u8 rates[32];
11668dcb2003SJouni Malinen 	int num_rates;
11678dcb2003SJouni Malinen 	int ext_rates_len;
1168de95a54bSJohannes Berg 
11694d36ec58SJohannes Berg 	sband = local->hw.wiphy->bands[band];
1170d811b3d5SArik Nemtsov 	if (WARN_ON_ONCE(!sband))
1171d811b3d5SArik Nemtsov 		return 0;
1172de95a54bSJohannes Berg 
11738dcb2003SJouni Malinen 	num_rates = 0;
11748dcb2003SJouni Malinen 	for (i = 0; i < sband->n_bitrates; i++) {
11758dcb2003SJouni Malinen 		if ((BIT(i) & rate_mask) == 0)
11768dcb2003SJouni Malinen 			continue; /* skip rate */
11778dcb2003SJouni Malinen 		rates[num_rates++] = (u8) (sband->bitrates[i].bitrate / 5);
11788dcb2003SJouni Malinen 	}
11798dcb2003SJouni Malinen 
11808dcb2003SJouni Malinen 	supp_rates_len = min_t(int, num_rates, 8);
11818e664fb3SJohannes Berg 
1182c604b9f2SJohannes Berg 	if (end - pos < 2 + supp_rates_len)
1183c604b9f2SJohannes Berg 		goto out_err;
1184de95a54bSJohannes Berg 	*pos++ = WLAN_EID_SUPP_RATES;
11858e664fb3SJohannes Berg 	*pos++ = supp_rates_len;
11868dcb2003SJouni Malinen 	memcpy(pos, rates, supp_rates_len);
11878dcb2003SJouni Malinen 	pos += supp_rates_len;
1188de95a54bSJohannes Berg 
11898e664fb3SJohannes Berg 	/* insert "request information" if in custom IEs */
11908e664fb3SJohannes Berg 	if (ie && ie_len) {
11918e664fb3SJohannes Berg 		static const u8 before_extrates[] = {
11928e664fb3SJohannes Berg 			WLAN_EID_SSID,
11938e664fb3SJohannes Berg 			WLAN_EID_SUPP_RATES,
11948e664fb3SJohannes Berg 			WLAN_EID_REQUEST,
11958e664fb3SJohannes Berg 		};
11968e664fb3SJohannes Berg 		noffset = ieee80211_ie_split(ie, ie_len,
11978e664fb3SJohannes Berg 					     before_extrates,
11988e664fb3SJohannes Berg 					     ARRAY_SIZE(before_extrates),
11998e664fb3SJohannes Berg 					     offset);
1200c604b9f2SJohannes Berg 		if (end - pos < noffset - offset)
1201c604b9f2SJohannes Berg 			goto out_err;
12028e664fb3SJohannes Berg 		memcpy(pos, ie + offset, noffset - offset);
12038e664fb3SJohannes Berg 		pos += noffset - offset;
12048e664fb3SJohannes Berg 		offset = noffset;
12058e664fb3SJohannes Berg 	}
12068e664fb3SJohannes Berg 
12078dcb2003SJouni Malinen 	ext_rates_len = num_rates - supp_rates_len;
12088dcb2003SJouni Malinen 	if (ext_rates_len > 0) {
1209c604b9f2SJohannes Berg 		if (end - pos < 2 + ext_rates_len)
1210c604b9f2SJohannes Berg 			goto out_err;
1211de95a54bSJohannes Berg 		*pos++ = WLAN_EID_EXT_SUPP_RATES;
12128dcb2003SJouni Malinen 		*pos++ = ext_rates_len;
12138dcb2003SJouni Malinen 		memcpy(pos, rates + supp_rates_len, ext_rates_len);
12148dcb2003SJouni Malinen 		pos += ext_rates_len;
12158e664fb3SJohannes Berg 	}
12168e664fb3SJohannes Berg 
1217651b5225SJouni Malinen 	if (channel && sband->band == IEEE80211_BAND_2GHZ) {
1218c604b9f2SJohannes Berg 		if (end - pos < 3)
1219c604b9f2SJohannes Berg 			goto out_err;
1220651b5225SJouni Malinen 		*pos++ = WLAN_EID_DS_PARAMS;
1221651b5225SJouni Malinen 		*pos++ = 1;
1222651b5225SJouni Malinen 		*pos++ = channel;
1223651b5225SJouni Malinen 	}
1224651b5225SJouni Malinen 
12258e664fb3SJohannes Berg 	/* insert custom IEs that go before HT */
12268e664fb3SJohannes Berg 	if (ie && ie_len) {
12278e664fb3SJohannes Berg 		static const u8 before_ht[] = {
12288e664fb3SJohannes Berg 			WLAN_EID_SSID,
12298e664fb3SJohannes Berg 			WLAN_EID_SUPP_RATES,
12308e664fb3SJohannes Berg 			WLAN_EID_REQUEST,
12318e664fb3SJohannes Berg 			WLAN_EID_EXT_SUPP_RATES,
12328e664fb3SJohannes Berg 			WLAN_EID_DS_PARAMS,
12338e664fb3SJohannes Berg 			WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
12348e664fb3SJohannes Berg 		};
12358e664fb3SJohannes Berg 		noffset = ieee80211_ie_split(ie, ie_len,
12368e664fb3SJohannes Berg 					     before_ht, ARRAY_SIZE(before_ht),
12378e664fb3SJohannes Berg 					     offset);
1238c604b9f2SJohannes Berg 		if (end - pos < noffset - offset)
1239c604b9f2SJohannes Berg 			goto out_err;
12408e664fb3SJohannes Berg 		memcpy(pos, ie + offset, noffset - offset);
12418e664fb3SJohannes Berg 		pos += noffset - offset;
12428e664fb3SJohannes Berg 		offset = noffset;
1243de95a54bSJohannes Berg 	}
1244de95a54bSJohannes Berg 
1245c604b9f2SJohannes Berg 	if (sband->ht_cap.ht_supported) {
1246c604b9f2SJohannes Berg 		if (end - pos < 2 + sizeof(struct ieee80211_ht_cap))
1247c604b9f2SJohannes Berg 			goto out_err;
1248ef96a842SBen Greear 		pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
1249ef96a842SBen Greear 						sband->ht_cap.cap);
1250c604b9f2SJohannes Berg 	}
12515ef2d41aSJohannes Berg 
1252de95a54bSJohannes Berg 	/*
1253de95a54bSJohannes Berg 	 * If adding more here, adjust code in main.c
1254de95a54bSJohannes Berg 	 * that calculates local->scan_ies_len.
1255de95a54bSJohannes Berg 	 */
1256de95a54bSJohannes Berg 
12578e664fb3SJohannes Berg 	/* add any remaining custom IEs */
12588e664fb3SJohannes Berg 	if (ie && ie_len) {
12598e664fb3SJohannes Berg 		noffset = ie_len;
1260c604b9f2SJohannes Berg 		if (end - pos < noffset - offset)
1261c604b9f2SJohannes Berg 			goto out_err;
12628e664fb3SJohannes Berg 		memcpy(pos, ie + offset, noffset - offset);
12638e664fb3SJohannes Berg 		pos += noffset - offset;
1264de95a54bSJohannes Berg 	}
1265de95a54bSJohannes Berg 
1266c604b9f2SJohannes Berg 	if (sband->vht_cap.vht_supported) {
1267c604b9f2SJohannes Berg 		if (end - pos < 2 + sizeof(struct ieee80211_vht_cap))
1268c604b9f2SJohannes Berg 			goto out_err;
1269ba0afa2fSMahesh Palivela 		pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap,
1270ba0afa2fSMahesh Palivela 						 sband->vht_cap.cap);
1271c604b9f2SJohannes Berg 	}
1272ba0afa2fSMahesh Palivela 
1273de95a54bSJohannes Berg 	return pos - buffer;
1274c604b9f2SJohannes Berg  out_err:
1275c604b9f2SJohannes Berg 	WARN_ONCE(1, "not enough space for preq IEs\n");
1276c604b9f2SJohannes Berg 	return pos - buffer;
1277de95a54bSJohannes Berg }
1278de95a54bSJohannes Berg 
1279a619a4c0SJuuso Oikarinen struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
128085a237feSJohannes Berg 					  u8 *dst, u32 ratemask,
12816b77863bSJohannes Berg 					  struct ieee80211_channel *chan,
1282de95a54bSJohannes Berg 					  const u8 *ssid, size_t ssid_len,
1283a806c558SPaul Stewart 					  const u8 *ie, size_t ie_len,
1284a806c558SPaul Stewart 					  bool directed)
128546900298SJohannes Berg {
128646900298SJohannes Berg 	struct ieee80211_local *local = sdata->local;
128746900298SJohannes Berg 	struct sk_buff *skb;
128846900298SJohannes Berg 	struct ieee80211_mgmt *mgmt;
12896b77863bSJohannes Berg 	u8 chan_no;
1290b9a9ada1SJohannes Berg 	int ies_len;
129146900298SJohannes Berg 
1292a806c558SPaul Stewart 	/*
1293a806c558SPaul Stewart 	 * Do not send DS Channel parameter for directed probe requests
1294a806c558SPaul Stewart 	 * in order to maximize the chance that we get a response.  Some
1295a806c558SPaul Stewart 	 * badly-behaved APs don't respond when this parameter is included.
1296a806c558SPaul Stewart 	 */
1297a806c558SPaul Stewart 	if (directed)
12986b77863bSJohannes Berg 		chan_no = 0;
1299a806c558SPaul Stewart 	else
13006b77863bSJohannes Berg 		chan_no = ieee80211_frequency_to_channel(chan->center_freq);
1301651b5225SJouni Malinen 
13027c12ce8bSKalle Valo 	skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
1303b9a9ada1SJohannes Berg 				     ssid, ssid_len, 100 + ie_len);
13045b2bbf75SJohannes Berg 	if (!skb)
1305b9a9ada1SJohannes Berg 		return NULL;
1306b9a9ada1SJohannes Berg 
1307b9a9ada1SJohannes Berg 	ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb),
1308b9a9ada1SJohannes Berg 					   skb_tailroom(skb),
1309c604b9f2SJohannes Berg 					   ie, ie_len, chan->band,
131062ae67beSJohannes Berg 					   ratemask, chan_no);
1311b9a9ada1SJohannes Berg 	skb_put(skb, ies_len);
131246900298SJohannes Berg 
131346900298SJohannes Berg 	if (dst) {
131446900298SJohannes Berg 		mgmt = (struct ieee80211_mgmt *) skb->data;
131546900298SJohannes Berg 		memcpy(mgmt->da, dst, ETH_ALEN);
131646900298SJohannes Berg 		memcpy(mgmt->bssid, dst, ETH_ALEN);
131746900298SJohannes Berg 	}
131846900298SJohannes Berg 
131946900298SJohannes Berg 	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
13205b2bbf75SJohannes Berg 
1321a619a4c0SJuuso Oikarinen 	return skb;
1322a619a4c0SJuuso Oikarinen }
1323a619a4c0SJuuso Oikarinen 
1324a619a4c0SJuuso Oikarinen void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
1325a619a4c0SJuuso Oikarinen 			      const u8 *ssid, size_t ssid_len,
1326a806c558SPaul Stewart 			      const u8 *ie, size_t ie_len,
13271672c0e3SJohannes Berg 			      u32 ratemask, bool directed, u32 tx_flags,
132855de908aSJohannes Berg 			      struct ieee80211_channel *channel, bool scan)
1329a619a4c0SJuuso Oikarinen {
1330a619a4c0SJuuso Oikarinen 	struct sk_buff *skb;
1331a619a4c0SJuuso Oikarinen 
1332fe94fe05SJohannes Berg 	skb = ieee80211_build_probe_req(sdata, dst, ratemask, channel,
13336b77863bSJohannes Berg 					ssid, ssid_len,
133485a237feSJohannes Berg 					ie, ie_len, directed);
1335aad14cebSRajkumar Manoharan 	if (skb) {
13361672c0e3SJohannes Berg 		IEEE80211_SKB_CB(skb)->flags |= tx_flags;
133755de908aSJohannes Berg 		if (scan)
133855de908aSJohannes Berg 			ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band);
133955de908aSJohannes Berg 		else
1340a619a4c0SJuuso Oikarinen 			ieee80211_tx_skb(sdata, skb);
134146900298SJohannes Berg 	}
1342aad14cebSRajkumar Manoharan }
134346900298SJohannes Berg 
134446900298SJohannes Berg u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
134546900298SJohannes Berg 			    struct ieee802_11_elems *elems,
13469ebb61a2SAshok Nagarajan 			    enum ieee80211_band band, u32 *basic_rates)
134746900298SJohannes Berg {
134846900298SJohannes Berg 	struct ieee80211_supported_band *sband;
134946900298SJohannes Berg 	struct ieee80211_rate *bitrates;
135046900298SJohannes Berg 	size_t num_rates;
135146900298SJohannes Berg 	u32 supp_rates;
135246900298SJohannes Berg 	int i, j;
135346900298SJohannes Berg 	sband = local->hw.wiphy->bands[band];
135446900298SJohannes Berg 
13554ee73f33SMichal Kazior 	if (WARN_ON(!sband))
13564ee73f33SMichal Kazior 		return 1;
135746900298SJohannes Berg 
135846900298SJohannes Berg 	bitrates = sband->bitrates;
135946900298SJohannes Berg 	num_rates = sband->n_bitrates;
136046900298SJohannes Berg 	supp_rates = 0;
136146900298SJohannes Berg 	for (i = 0; i < elems->supp_rates_len +
136246900298SJohannes Berg 		     elems->ext_supp_rates_len; i++) {
136346900298SJohannes Berg 		u8 rate = 0;
136446900298SJohannes Berg 		int own_rate;
13659ebb61a2SAshok Nagarajan 		bool is_basic;
136646900298SJohannes Berg 		if (i < elems->supp_rates_len)
136746900298SJohannes Berg 			rate = elems->supp_rates[i];
136846900298SJohannes Berg 		else if (elems->ext_supp_rates)
136946900298SJohannes Berg 			rate = elems->ext_supp_rates
137046900298SJohannes Berg 				[i - elems->supp_rates_len];
137146900298SJohannes Berg 		own_rate = 5 * (rate & 0x7f);
13729ebb61a2SAshok Nagarajan 		is_basic = !!(rate & 0x80);
13739ebb61a2SAshok Nagarajan 
13749ebb61a2SAshok Nagarajan 		if (is_basic && (rate & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
13759ebb61a2SAshok Nagarajan 			continue;
13769ebb61a2SAshok Nagarajan 
13779ebb61a2SAshok Nagarajan 		for (j = 0; j < num_rates; j++) {
13789ebb61a2SAshok Nagarajan 			if (bitrates[j].bitrate == own_rate) {
137946900298SJohannes Berg 				supp_rates |= BIT(j);
13809ebb61a2SAshok Nagarajan 				if (basic_rates && is_basic)
13819ebb61a2SAshok Nagarajan 					*basic_rates |= BIT(j);
13829ebb61a2SAshok Nagarajan 			}
13839ebb61a2SAshok Nagarajan 		}
138446900298SJohannes Berg 	}
138546900298SJohannes Berg 	return supp_rates;
138646900298SJohannes Berg }
1387f2753ddbSJohannes Berg 
138884f6a01cSJohannes Berg void ieee80211_stop_device(struct ieee80211_local *local)
138984f6a01cSJohannes Berg {
139084f6a01cSJohannes Berg 	ieee80211_led_radio(local, false);
139167408c8cSJohannes Berg 	ieee80211_mod_tpt_led_trig(local, 0, IEEE80211_TPT_LEDTRIG_FL_RADIO);
139284f6a01cSJohannes Berg 
139384f6a01cSJohannes Berg 	cancel_work_sync(&local->reconfig_filter);
139484f6a01cSJohannes Berg 
139584f6a01cSJohannes Berg 	flush_workqueue(local->workqueue);
1396678f415fSLennert Buytenhek 	drv_stop(local);
139784f6a01cSJohannes Berg }
139884f6a01cSJohannes Berg 
1399153a5fc4SStanislaw Gruszka static void ieee80211_assign_chanctx(struct ieee80211_local *local,
1400153a5fc4SStanislaw Gruszka 				     struct ieee80211_sub_if_data *sdata)
1401153a5fc4SStanislaw Gruszka {
1402153a5fc4SStanislaw Gruszka 	struct ieee80211_chanctx_conf *conf;
1403153a5fc4SStanislaw Gruszka 	struct ieee80211_chanctx *ctx;
1404153a5fc4SStanislaw Gruszka 
1405153a5fc4SStanislaw Gruszka 	if (!local->use_chanctx)
1406153a5fc4SStanislaw Gruszka 		return;
1407153a5fc4SStanislaw Gruszka 
1408153a5fc4SStanislaw Gruszka 	mutex_lock(&local->chanctx_mtx);
1409153a5fc4SStanislaw Gruszka 	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
1410153a5fc4SStanislaw Gruszka 					 lockdep_is_held(&local->chanctx_mtx));
1411153a5fc4SStanislaw Gruszka 	if (conf) {
1412153a5fc4SStanislaw Gruszka 		ctx = container_of(conf, struct ieee80211_chanctx, conf);
1413153a5fc4SStanislaw Gruszka 		drv_assign_vif_chanctx(local, sdata, ctx);
1414153a5fc4SStanislaw Gruszka 	}
1415153a5fc4SStanislaw Gruszka 	mutex_unlock(&local->chanctx_mtx);
1416153a5fc4SStanislaw Gruszka }
1417153a5fc4SStanislaw Gruszka 
1418f2753ddbSJohannes Berg int ieee80211_reconfig(struct ieee80211_local *local)
1419f2753ddbSJohannes Berg {
1420f2753ddbSJohannes Berg 	struct ieee80211_hw *hw = &local->hw;
1421f2753ddbSJohannes Berg 	struct ieee80211_sub_if_data *sdata;
142255de908aSJohannes Berg 	struct ieee80211_chanctx *ctx;
1423f2753ddbSJohannes Berg 	struct sta_info *sta;
14242683d65bSEliad Peller 	int res, i;
1425d888130aSJohannes Berg 	bool reconfig_due_to_wowlan = false;
1426d888130aSJohannes Berg 
14278f21b0adSJohannes Berg #ifdef CONFIG_PM
1428ceb99fe0SJohannes Berg 	if (local->suspended)
1429ceb99fe0SJohannes Berg 		local->resuming = true;
1430f2753ddbSJohannes Berg 
1431eecc4800SJohannes Berg 	if (local->wowlan) {
1432eecc4800SJohannes Berg 		local->wowlan = false;
1433eecc4800SJohannes Berg 		res = drv_resume(local);
1434eecc4800SJohannes Berg 		if (res < 0) {
1435eecc4800SJohannes Berg 			local->resuming = false;
1436eecc4800SJohannes Berg 			return res;
1437eecc4800SJohannes Berg 		}
1438eecc4800SJohannes Berg 		if (res == 0)
1439eecc4800SJohannes Berg 			goto wake_up;
1440eecc4800SJohannes Berg 		WARN_ON(res > 1);
1441eecc4800SJohannes Berg 		/*
1442eecc4800SJohannes Berg 		 * res is 1, which means the driver requested
1443eecc4800SJohannes Berg 		 * to go through a regular reset on wakeup.
1444eecc4800SJohannes Berg 		 */
1445d888130aSJohannes Berg 		reconfig_due_to_wowlan = true;
1446eecc4800SJohannes Berg 	}
1447eecc4800SJohannes Berg #endif
144894f9b97bSJohannes Berg 	/* everything else happens only if HW was up & running */
144994f9b97bSJohannes Berg 	if (!local->open_count)
145094f9b97bSJohannes Berg 		goto wake_up;
145194f9b97bSJohannes Berg 
145224feda00SLuis R. Rodriguez 	/*
145324feda00SLuis R. Rodriguez 	 * Upon resume hardware can sometimes be goofy due to
145424feda00SLuis R. Rodriguez 	 * various platform / driver / bus issues, so restarting
145524feda00SLuis R. Rodriguez 	 * the device may at times not work immediately. Propagate
145624feda00SLuis R. Rodriguez 	 * the error.
145724feda00SLuis R. Rodriguez 	 */
145824487981SJohannes Berg 	res = drv_start(local);
145924feda00SLuis R. Rodriguez 	if (res) {
1460c7a00dc7SJohn W. Linville 		WARN(local->suspended, "Hardware became unavailable "
1461c7a00dc7SJohn W. Linville 		     "upon resume. This could be a software issue "
1462c7a00dc7SJohn W. Linville 		     "prior to suspend or a hardware issue.\n");
146324feda00SLuis R. Rodriguez 		return res;
146424feda00SLuis R. Rodriguez 	}
1465f2753ddbSJohannes Berg 
14667f281975SYogesh Ashok Powar 	/* setup fragmentation threshold */
14677f281975SYogesh Ashok Powar 	drv_set_frag_threshold(local, hw->wiphy->frag_threshold);
14687f281975SYogesh Ashok Powar 
14697f281975SYogesh Ashok Powar 	/* setup RTS threshold */
14707f281975SYogesh Ashok Powar 	drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
14717f281975SYogesh Ashok Powar 
14727f281975SYogesh Ashok Powar 	/* reset coverage class */
14737f281975SYogesh Ashok Powar 	drv_set_coverage_class(local, hw->wiphy->coverage_class);
14747f281975SYogesh Ashok Powar 
14751f87f7d3SJohannes Berg 	ieee80211_led_radio(local, true);
147667408c8cSJohannes Berg 	ieee80211_mod_tpt_led_trig(local,
147767408c8cSJohannes Berg 				   IEEE80211_TPT_LEDTRIG_FL_RADIO, 0);
1478f2753ddbSJohannes Berg 
1479f2753ddbSJohannes Berg 	/* add interfaces */
14804b6f1dd6SJohannes Berg 	sdata = rtnl_dereference(local->monitor_sdata);
14814b6f1dd6SJohannes Berg 	if (sdata) {
14823c3e21e7SJohannes Berg 		/* in HW restart it exists already */
14833c3e21e7SJohannes Berg 		WARN_ON(local->resuming);
14844b6f1dd6SJohannes Berg 		res = drv_add_interface(local, sdata);
14854b6f1dd6SJohannes Berg 		if (WARN_ON(res)) {
14864b6f1dd6SJohannes Berg 			rcu_assign_pointer(local->monitor_sdata, NULL);
14874b6f1dd6SJohannes Berg 			synchronize_net();
14884b6f1dd6SJohannes Berg 			kfree(sdata);
14894b6f1dd6SJohannes Berg 		}
14904b6f1dd6SJohannes Berg 	}
14914b6f1dd6SJohannes Berg 
1492f2753ddbSJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
1493f2753ddbSJohannes Berg 		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
1494f2753ddbSJohannes Berg 		    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
14951ed32e4fSJohannes Berg 		    ieee80211_sdata_running(sdata))
14967b7eab6fSJohannes Berg 			res = drv_add_interface(local, sdata);
1497f2753ddbSJohannes Berg 	}
1498f2753ddbSJohannes Berg 
149955de908aSJohannes Berg 	/* add channel contexts */
1500f0dea9c7SArend van Spriel 	if (local->use_chanctx) {
150155de908aSJohannes Berg 		mutex_lock(&local->chanctx_mtx);
150255de908aSJohannes Berg 		list_for_each_entry(ctx, &local->chanctx_list, list)
150355de908aSJohannes Berg 			WARN_ON(drv_add_chanctx(local, ctx));
150455de908aSJohannes Berg 		mutex_unlock(&local->chanctx_mtx);
1505f0dea9c7SArend van Spriel 	}
150655de908aSJohannes Berg 
15076352c87fSJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
15086352c87fSJohannes Berg 		if (!ieee80211_sdata_running(sdata))
15096352c87fSJohannes Berg 			continue;
1510153a5fc4SStanislaw Gruszka 		ieee80211_assign_chanctx(local, sdata);
15116352c87fSJohannes Berg 	}
15126352c87fSJohannes Berg 
1513fe5f2559SJohannes Berg 	sdata = rtnl_dereference(local->monitor_sdata);
1514153a5fc4SStanislaw Gruszka 	if (sdata && ieee80211_sdata_running(sdata))
1515153a5fc4SStanislaw Gruszka 		ieee80211_assign_chanctx(local, sdata);
1516fe5f2559SJohannes Berg 
1517f2753ddbSJohannes Berg 	/* add STAs back */
151834e89507SJohannes Berg 	mutex_lock(&local->sta_mtx);
1519f2753ddbSJohannes Berg 	list_for_each_entry(sta, &local->sta_list, list) {
1520f09603a2SJohannes Berg 		enum ieee80211_sta_state state;
1521f09603a2SJohannes Berg 
15222e8d397eSArik Nemtsov 		if (!sta->uploaded)
15232e8d397eSArik Nemtsov 			continue;
15242e8d397eSArik Nemtsov 
15252e8d397eSArik Nemtsov 		/* AP-mode stations will be added later */
15262e8d397eSArik Nemtsov 		if (sta->sdata->vif.type == NL80211_IFTYPE_AP)
15272e8d397eSArik Nemtsov 			continue;
15282e8d397eSArik Nemtsov 
1529f09603a2SJohannes Berg 		for (state = IEEE80211_STA_NOTEXIST;
1530bd34ab62SMeenakshi Venkataraman 		     state < sta->sta_state; state++)
15312e8d397eSArik Nemtsov 			WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
15322e8d397eSArik Nemtsov 					      state + 1));
1533f2753ddbSJohannes Berg 	}
153434e89507SJohannes Berg 	mutex_unlock(&local->sta_mtx);
1535f2753ddbSJohannes Berg 
15362683d65bSEliad Peller 	/* reconfigure tx conf */
153754bcbc69SJohannes Berg 	if (hw->queues >= IEEE80211_NUM_ACS) {
1538f6f3def3SEliad Peller 		list_for_each_entry(sdata, &local->interfaces, list) {
1539f6f3def3SEliad Peller 			if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
1540f6f3def3SEliad Peller 			    sdata->vif.type == NL80211_IFTYPE_MONITOR ||
1541f6f3def3SEliad Peller 			    !ieee80211_sdata_running(sdata))
1542f6f3def3SEliad Peller 				continue;
1543f6f3def3SEliad Peller 
154454bcbc69SJohannes Berg 			for (i = 0; i < IEEE80211_NUM_ACS; i++)
154554bcbc69SJohannes Berg 				drv_conf_tx(local, sdata, i,
154654bcbc69SJohannes Berg 					    &sdata->tx_conf[i]);
154754bcbc69SJohannes Berg 		}
1548f6f3def3SEliad Peller 	}
15492683d65bSEliad Peller 
1550f2753ddbSJohannes Berg 	/* reconfigure hardware */
1551f2753ddbSJohannes Berg 	ieee80211_hw_config(local, ~0);
1552f2753ddbSJohannes Berg 
1553f2753ddbSJohannes Berg 	ieee80211_configure_filter(local);
1554f2753ddbSJohannes Berg 
1555f2753ddbSJohannes Berg 	/* Finally also reconfigure all the BSS information */
1556f2753ddbSJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
1557ac8dd506SJohannes Berg 		u32 changed;
1558ac8dd506SJohannes Berg 
15599607e6b6SJohannes Berg 		if (!ieee80211_sdata_running(sdata))
1560f2753ddbSJohannes Berg 			continue;
1561ac8dd506SJohannes Berg 
1562ac8dd506SJohannes Berg 		/* common change flags for all interface types */
1563ac8dd506SJohannes Berg 		changed = BSS_CHANGED_ERP_CTS_PROT |
1564ac8dd506SJohannes Berg 			  BSS_CHANGED_ERP_PREAMBLE |
1565ac8dd506SJohannes Berg 			  BSS_CHANGED_ERP_SLOT |
1566ac8dd506SJohannes Berg 			  BSS_CHANGED_HT |
1567ac8dd506SJohannes Berg 			  BSS_CHANGED_BASIC_RATES |
1568ac8dd506SJohannes Berg 			  BSS_CHANGED_BEACON_INT |
1569ac8dd506SJohannes Berg 			  BSS_CHANGED_BSSID |
15704ced3f74SJohannes Berg 			  BSS_CHANGED_CQM |
157155de47f6SEliad Peller 			  BSS_CHANGED_QOS |
15721ea6f9c0SJohannes Berg 			  BSS_CHANGED_IDLE |
15731ea6f9c0SJohannes Berg 			  BSS_CHANGED_TXPOWER;
1574ac8dd506SJohannes Berg 
1575f2753ddbSJohannes Berg 		switch (sdata->vif.type) {
1576f2753ddbSJohannes Berg 		case NL80211_IFTYPE_STATION:
15770d392e93SEliad Peller 			changed |= BSS_CHANGED_ASSOC |
1578ab095877SEliad Peller 				   BSS_CHANGED_ARP_FILTER |
1579ab095877SEliad Peller 				   BSS_CHANGED_PS;
1580c65dd147SEmmanuel Grumbach 
1581c65dd147SEmmanuel Grumbach 			if (sdata->u.mgd.dtim_period)
1582c65dd147SEmmanuel Grumbach 				changed |= BSS_CHANGED_DTIM_PERIOD;
1583c65dd147SEmmanuel Grumbach 
15848d61ffa5SJohannes Berg 			sdata_lock(sdata);
1585ac8dd506SJohannes Berg 			ieee80211_bss_info_change_notify(sdata, changed);
15868d61ffa5SJohannes Berg 			sdata_unlock(sdata);
1587ac8dd506SJohannes Berg 			break;
1588f2753ddbSJohannes Berg 		case NL80211_IFTYPE_ADHOC:
1589ac8dd506SJohannes Berg 			changed |= BSS_CHANGED_IBSS;
1590ac8dd506SJohannes Berg 			/* fall through */
1591f2753ddbSJohannes Berg 		case NL80211_IFTYPE_AP:
1592339afbf4SJohannes Berg 			changed |= BSS_CHANGED_SSID | BSS_CHANGED_P2P_PS;
1593e7979ac7SArik Nemtsov 
15941041638fSJohannes Berg 			if (sdata->vif.type == NL80211_IFTYPE_AP) {
1595e7979ac7SArik Nemtsov 				changed |= BSS_CHANGED_AP_PROBE_RESP;
1596e7979ac7SArik Nemtsov 
15971041638fSJohannes Berg 				if (rcu_access_pointer(sdata->u.ap.beacon))
15981041638fSJohannes Berg 					drv_start_ap(local, sdata);
15991041638fSJohannes Berg 			}
16001041638fSJohannes Berg 
16017827493bSArik Nemtsov 			/* fall through */
1602f2753ddbSJohannes Berg 		case NL80211_IFTYPE_MESH_POINT:
16038da34932SJohannes Berg 			if (sdata->vif.bss_conf.enable_beacon) {
1604ac8dd506SJohannes Berg 				changed |= BSS_CHANGED_BEACON |
1605ac8dd506SJohannes Berg 					   BSS_CHANGED_BEACON_ENABLED;
16062d0ddec5SJohannes Berg 				ieee80211_bss_info_change_notify(sdata, changed);
16078da34932SJohannes Berg 			}
1608f2753ddbSJohannes Berg 			break;
1609f2753ddbSJohannes Berg 		case NL80211_IFTYPE_WDS:
1610f2753ddbSJohannes Berg 			break;
1611f2753ddbSJohannes Berg 		case NL80211_IFTYPE_AP_VLAN:
1612f2753ddbSJohannes Berg 		case NL80211_IFTYPE_MONITOR:
1613f2753ddbSJohannes Berg 			/* ignore virtual */
1614f2753ddbSJohannes Berg 			break;
161598104fdeSJohannes Berg 		case NL80211_IFTYPE_P2P_DEVICE:
1616f142c6b9SJohannes Berg 			changed = BSS_CHANGED_IDLE;
1617f142c6b9SJohannes Berg 			break;
1618f2753ddbSJohannes Berg 		case NL80211_IFTYPE_UNSPECIFIED:
16192e161f78SJohannes Berg 		case NUM_NL80211_IFTYPES:
16202ca27bcfSJohannes Berg 		case NL80211_IFTYPE_P2P_CLIENT:
16212ca27bcfSJohannes Berg 		case NL80211_IFTYPE_P2P_GO:
1622f2753ddbSJohannes Berg 			WARN_ON(1);
1623f2753ddbSJohannes Berg 			break;
1624f2753ddbSJohannes Berg 		}
1625f2753ddbSJohannes Berg 	}
1626f2753ddbSJohannes Berg 
16278e1b23b9SEyal Shapira 	ieee80211_recalc_ps(local, -1);
16288e1b23b9SEyal Shapira 
16292a419056SJohannes Berg 	/*
16306e1b1b24SEliad Peller 	 * The sta might be in psm against the ap (e.g. because
16316e1b1b24SEliad Peller 	 * this was the state before a hw restart), so we
16326e1b1b24SEliad Peller 	 * explicitly send a null packet in order to make sure
16336e1b1b24SEliad Peller 	 * it'll sync against the ap (and get out of psm).
16346e1b1b24SEliad Peller 	 */
16356e1b1b24SEliad Peller 	if (!(local->hw.conf.flags & IEEE80211_CONF_PS)) {
16366e1b1b24SEliad Peller 		list_for_each_entry(sdata, &local->interfaces, list) {
16376e1b1b24SEliad Peller 			if (sdata->vif.type != NL80211_IFTYPE_STATION)
16386e1b1b24SEliad Peller 				continue;
163920f544eeSJohannes Berg 			if (!sdata->u.mgd.associated)
164020f544eeSJohannes Berg 				continue;
16416e1b1b24SEliad Peller 
16426e1b1b24SEliad Peller 			ieee80211_send_nullfunc(local, sdata, 0);
16436e1b1b24SEliad Peller 		}
16446e1b1b24SEliad Peller 	}
16456e1b1b24SEliad Peller 
16462e8d397eSArik Nemtsov 	/* APs are now beaconing, add back stations */
16472e8d397eSArik Nemtsov 	mutex_lock(&local->sta_mtx);
16482e8d397eSArik Nemtsov 	list_for_each_entry(sta, &local->sta_list, list) {
16492e8d397eSArik Nemtsov 		enum ieee80211_sta_state state;
16502e8d397eSArik Nemtsov 
16512e8d397eSArik Nemtsov 		if (!sta->uploaded)
16522e8d397eSArik Nemtsov 			continue;
16532e8d397eSArik Nemtsov 
16542e8d397eSArik Nemtsov 		if (sta->sdata->vif.type != NL80211_IFTYPE_AP)
16552e8d397eSArik Nemtsov 			continue;
16562e8d397eSArik Nemtsov 
16572e8d397eSArik Nemtsov 		for (state = IEEE80211_STA_NOTEXIST;
16582e8d397eSArik Nemtsov 		     state < sta->sta_state; state++)
16592e8d397eSArik Nemtsov 			WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
16602e8d397eSArik Nemtsov 					      state + 1));
16612e8d397eSArik Nemtsov 	}
16622e8d397eSArik Nemtsov 	mutex_unlock(&local->sta_mtx);
16632e8d397eSArik Nemtsov 
16647b21aea0SEyal Shapira 	/* add back keys */
16657b21aea0SEyal Shapira 	list_for_each_entry(sdata, &local->interfaces, list)
16667b21aea0SEyal Shapira 		if (ieee80211_sdata_running(sdata))
16677b21aea0SEyal Shapira 			ieee80211_enable_keys(sdata);
16687b21aea0SEyal Shapira 
1669c6209488SEliad Peller  wake_up:
167004800adaSArik Nemtsov 	local->in_reconfig = false;
167104800adaSArik Nemtsov 	barrier();
167204800adaSArik Nemtsov 
16733c3e21e7SJohannes Berg 	if (local->monitors == local->open_count && local->monitors > 0)
16743c3e21e7SJohannes Berg 		ieee80211_add_virtual_monitor(local);
16753c3e21e7SJohannes Berg 
16766e1b1b24SEliad Peller 	/*
16772a419056SJohannes Berg 	 * Clear the WLAN_STA_BLOCK_BA flag so new aggregation
16782a419056SJohannes Berg 	 * sessions can be established after a resume.
16792a419056SJohannes Berg 	 *
16802a419056SJohannes Berg 	 * Also tear down aggregation sessions since reconfiguring
16812a419056SJohannes Berg 	 * them in a hardware restart scenario is not easily done
16822a419056SJohannes Berg 	 * right now, and the hardware will have lost information
16832a419056SJohannes Berg 	 * about the sessions, but we and the AP still think they
16842a419056SJohannes Berg 	 * are active. This is really a workaround though.
16852a419056SJohannes Berg 	 */
168674e2bd1fSWey-Yi Guy 	if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
16872a419056SJohannes Berg 		mutex_lock(&local->sta_mtx);
16882a419056SJohannes Berg 
16892a419056SJohannes Berg 		list_for_each_entry(sta, &local->sta_list, list) {
1690c82c4a80SJohannes Berg 			ieee80211_sta_tear_down_BA_sessions(
1691c82c4a80SJohannes Berg 					sta, AGG_STOP_LOCAL_REQUEST);
1692c2c98fdeSJohannes Berg 			clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
169374e2bd1fSWey-Yi Guy 		}
16942a419056SJohannes Berg 
16952a419056SJohannes Berg 		mutex_unlock(&local->sta_mtx);
169674e2bd1fSWey-Yi Guy 	}
169774e2bd1fSWey-Yi Guy 
1698445ea4e8SJohannes Berg 	ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
1699f2753ddbSJohannes Berg 					IEEE80211_QUEUE_STOP_REASON_SUSPEND);
1700f2753ddbSJohannes Berg 
17015bb644a0SJohannes Berg 	/*
17025bb644a0SJohannes Berg 	 * If this is for hw restart things are still running.
17035bb644a0SJohannes Berg 	 * We may want to change that later, however.
17045bb644a0SJohannes Berg 	 */
17058f21b0adSJohannes Berg 	if (!local->suspended || reconfig_due_to_wowlan)
17069214ad7fSJohannes Berg 		drv_restart_complete(local);
17078f21b0adSJohannes Berg 
17088f21b0adSJohannes Berg 	if (!local->suspended)
17095bb644a0SJohannes Berg 		return 0;
17105bb644a0SJohannes Berg 
17115bb644a0SJohannes Berg #ifdef CONFIG_PM
1712ceb99fe0SJohannes Berg 	/* first set suspended false, then resuming */
17135bb644a0SJohannes Berg 	local->suspended = false;
1714ceb99fe0SJohannes Berg 	mb();
1715ceb99fe0SJohannes Berg 	local->resuming = false;
17165bb644a0SJohannes Berg 
1717b8360ab8SJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
1718b8360ab8SJohannes Berg 		if (!ieee80211_sdata_running(sdata))
1719b8360ab8SJohannes Berg 			continue;
1720b8360ab8SJohannes Berg 		if (sdata->vif.type == NL80211_IFTYPE_STATION)
1721b8360ab8SJohannes Berg 			ieee80211_sta_restart(sdata);
1722b8360ab8SJohannes Berg 	}
1723b8360ab8SJohannes Berg 
172426d59535SJohannes Berg 	mod_timer(&local->sta_cleanup, jiffies + 1);
17255bb644a0SJohannes Berg #else
17265bb644a0SJohannes Berg 	WARN_ON(1);
17275bb644a0SJohannes Berg #endif
1728f2753ddbSJohannes Berg 	return 0;
1729f2753ddbSJohannes Berg }
173042935ecaSLuis R. Rodriguez 
173195acac61SJohannes Berg void ieee80211_resume_disconnect(struct ieee80211_vif *vif)
173295acac61SJohannes Berg {
173395acac61SJohannes Berg 	struct ieee80211_sub_if_data *sdata;
173495acac61SJohannes Berg 	struct ieee80211_local *local;
173595acac61SJohannes Berg 	struct ieee80211_key *key;
173695acac61SJohannes Berg 
173795acac61SJohannes Berg 	if (WARN_ON(!vif))
173895acac61SJohannes Berg 		return;
173995acac61SJohannes Berg 
174095acac61SJohannes Berg 	sdata = vif_to_sdata(vif);
174195acac61SJohannes Berg 	local = sdata->local;
174295acac61SJohannes Berg 
174395acac61SJohannes Berg 	if (WARN_ON(!local->resuming))
174495acac61SJohannes Berg 		return;
174595acac61SJohannes Berg 
174695acac61SJohannes Berg 	if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
174795acac61SJohannes Berg 		return;
174895acac61SJohannes Berg 
174995acac61SJohannes Berg 	sdata->flags |= IEEE80211_SDATA_DISCONNECT_RESUME;
175095acac61SJohannes Berg 
175195acac61SJohannes Berg 	mutex_lock(&local->key_mtx);
175295acac61SJohannes Berg 	list_for_each_entry(key, &sdata->key_list, list)
175395acac61SJohannes Berg 		key->flags |= KEY_FLAG_TAINTED;
175495acac61SJohannes Berg 	mutex_unlock(&local->key_mtx);
175595acac61SJohannes Berg }
175695acac61SJohannes Berg EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect);
175795acac61SJohannes Berg 
175804ecd257SJohannes Berg void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata)
17590f78231bSJohannes Berg {
176004ecd257SJohannes Berg 	struct ieee80211_local *local = sdata->local;
176104ecd257SJohannes Berg 	struct ieee80211_chanctx_conf *chanctx_conf;
176204ecd257SJohannes Berg 	struct ieee80211_chanctx *chanctx;
17630f78231bSJohannes Berg 
176404ecd257SJohannes Berg 	mutex_lock(&local->chanctx_mtx);
17650f78231bSJohannes Berg 
176604ecd257SJohannes Berg 	chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
176704ecd257SJohannes Berg 					lockdep_is_held(&local->chanctx_mtx));
17680f78231bSJohannes Berg 
176904ecd257SJohannes Berg 	if (WARN_ON_ONCE(!chanctx_conf))
17705d8e4237SJohannes Berg 		goto unlock;
17710f78231bSJohannes Berg 
177204ecd257SJohannes Berg 	chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
177304ecd257SJohannes Berg 	ieee80211_recalc_smps_chanctx(local, chanctx);
17745d8e4237SJohannes Berg  unlock:
177504ecd257SJohannes Berg 	mutex_unlock(&local->chanctx_mtx);
17760f78231bSJohannes Berg }
17778e664fb3SJohannes Berg 
17788e664fb3SJohannes Berg static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
17798e664fb3SJohannes Berg {
17808e664fb3SJohannes Berg 	int i;
17818e664fb3SJohannes Berg 
17828e664fb3SJohannes Berg 	for (i = 0; i < n_ids; i++)
17838e664fb3SJohannes Berg 		if (ids[i] == id)
17848e664fb3SJohannes Berg 			return true;
17858e664fb3SJohannes Berg 	return false;
17868e664fb3SJohannes Berg }
17878e664fb3SJohannes Berg 
17888e664fb3SJohannes Berg /**
17898e664fb3SJohannes Berg  * ieee80211_ie_split - split an IE buffer according to ordering
17908e664fb3SJohannes Berg  *
17918e664fb3SJohannes Berg  * @ies: the IE buffer
17928e664fb3SJohannes Berg  * @ielen: the length of the IE buffer
17938e664fb3SJohannes Berg  * @ids: an array with element IDs that are allowed before
17948e664fb3SJohannes Berg  *	the split
17958e664fb3SJohannes Berg  * @n_ids: the size of the element ID array
17968e664fb3SJohannes Berg  * @offset: offset where to start splitting in the buffer
17978e664fb3SJohannes Berg  *
17988e664fb3SJohannes Berg  * This function splits an IE buffer by updating the @offset
17998e664fb3SJohannes Berg  * variable to point to the location where the buffer should be
18008e664fb3SJohannes Berg  * split.
18018e664fb3SJohannes Berg  *
18028e664fb3SJohannes Berg  * It assumes that the given IE buffer is well-formed, this
18038e664fb3SJohannes Berg  * has to be guaranteed by the caller!
18048e664fb3SJohannes Berg  *
18058e664fb3SJohannes Berg  * It also assumes that the IEs in the buffer are ordered
18068e664fb3SJohannes Berg  * correctly, if not the result of using this function will not
18078e664fb3SJohannes Berg  * be ordered correctly either, i.e. it does no reordering.
18088e664fb3SJohannes Berg  *
18098e664fb3SJohannes Berg  * The function returns the offset where the next part of the
18108e664fb3SJohannes Berg  * buffer starts, which may be @ielen if the entire (remainder)
18118e664fb3SJohannes Berg  * of the buffer should be used.
18128e664fb3SJohannes Berg  */
18138e664fb3SJohannes Berg size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
18148e664fb3SJohannes Berg 			  const u8 *ids, int n_ids, size_t offset)
18158e664fb3SJohannes Berg {
18168e664fb3SJohannes Berg 	size_t pos = offset;
18178e664fb3SJohannes Berg 
18188e664fb3SJohannes Berg 	while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos]))
18198e664fb3SJohannes Berg 		pos += 2 + ies[pos + 1];
18208e664fb3SJohannes Berg 
18218e664fb3SJohannes Berg 	return pos;
18228e664fb3SJohannes Berg }
18238e664fb3SJohannes Berg 
18248e664fb3SJohannes Berg size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)
18258e664fb3SJohannes Berg {
18268e664fb3SJohannes Berg 	size_t pos = offset;
18278e664fb3SJohannes Berg 
18288e664fb3SJohannes Berg 	while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC)
18298e664fb3SJohannes Berg 		pos += 2 + ies[pos + 1];
18308e664fb3SJohannes Berg 
18318e664fb3SJohannes Berg 	return pos;
18328e664fb3SJohannes Berg }
1833615f7b9bSMeenakshi Venkataraman 
1834615f7b9bSMeenakshi Venkataraman static void _ieee80211_enable_rssi_reports(struct ieee80211_sub_if_data *sdata,
1835615f7b9bSMeenakshi Venkataraman 					    int rssi_min_thold,
1836615f7b9bSMeenakshi Venkataraman 					    int rssi_max_thold)
1837615f7b9bSMeenakshi Venkataraman {
1838615f7b9bSMeenakshi Venkataraman 	trace_api_enable_rssi_reports(sdata, rssi_min_thold, rssi_max_thold);
1839615f7b9bSMeenakshi Venkataraman 
1840615f7b9bSMeenakshi Venkataraman 	if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
1841615f7b9bSMeenakshi Venkataraman 		return;
1842615f7b9bSMeenakshi Venkataraman 
1843615f7b9bSMeenakshi Venkataraman 	/*
1844615f7b9bSMeenakshi Venkataraman 	 * Scale up threshold values before storing it, as the RSSI averaging
1845615f7b9bSMeenakshi Venkataraman 	 * algorithm uses a scaled up value as well. Change this scaling
1846615f7b9bSMeenakshi Venkataraman 	 * factor if the RSSI averaging algorithm changes.
1847615f7b9bSMeenakshi Venkataraman 	 */
1848615f7b9bSMeenakshi Venkataraman 	sdata->u.mgd.rssi_min_thold = rssi_min_thold*16;
1849615f7b9bSMeenakshi Venkataraman 	sdata->u.mgd.rssi_max_thold = rssi_max_thold*16;
1850615f7b9bSMeenakshi Venkataraman }
1851615f7b9bSMeenakshi Venkataraman 
1852615f7b9bSMeenakshi Venkataraman void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
1853615f7b9bSMeenakshi Venkataraman 				    int rssi_min_thold,
1854615f7b9bSMeenakshi Venkataraman 				    int rssi_max_thold)
1855615f7b9bSMeenakshi Venkataraman {
1856615f7b9bSMeenakshi Venkataraman 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
1857615f7b9bSMeenakshi Venkataraman 
1858615f7b9bSMeenakshi Venkataraman 	WARN_ON(rssi_min_thold == rssi_max_thold ||
1859615f7b9bSMeenakshi Venkataraman 		rssi_min_thold > rssi_max_thold);
1860615f7b9bSMeenakshi Venkataraman 
1861615f7b9bSMeenakshi Venkataraman 	_ieee80211_enable_rssi_reports(sdata, rssi_min_thold,
1862615f7b9bSMeenakshi Venkataraman 				       rssi_max_thold);
1863615f7b9bSMeenakshi Venkataraman }
1864615f7b9bSMeenakshi Venkataraman EXPORT_SYMBOL(ieee80211_enable_rssi_reports);
1865615f7b9bSMeenakshi Venkataraman 
1866615f7b9bSMeenakshi Venkataraman void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
1867615f7b9bSMeenakshi Venkataraman {
1868615f7b9bSMeenakshi Venkataraman 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
1869615f7b9bSMeenakshi Venkataraman 
1870615f7b9bSMeenakshi Venkataraman 	_ieee80211_enable_rssi_reports(sdata, 0, 0);
1871615f7b9bSMeenakshi Venkataraman }
1872615f7b9bSMeenakshi Venkataraman EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
1873768db343SArik Nemtsov 
1874ef96a842SBen Greear u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
187542e7aa77SAlexander Simon 			      u16 cap)
187642e7aa77SAlexander Simon {
187742e7aa77SAlexander Simon 	__le16 tmp;
187842e7aa77SAlexander Simon 
187942e7aa77SAlexander Simon 	*pos++ = WLAN_EID_HT_CAPABILITY;
188042e7aa77SAlexander Simon 	*pos++ = sizeof(struct ieee80211_ht_cap);
188142e7aa77SAlexander Simon 	memset(pos, 0, sizeof(struct ieee80211_ht_cap));
188242e7aa77SAlexander Simon 
188342e7aa77SAlexander Simon 	/* capability flags */
188442e7aa77SAlexander Simon 	tmp = cpu_to_le16(cap);
188542e7aa77SAlexander Simon 	memcpy(pos, &tmp, sizeof(u16));
188642e7aa77SAlexander Simon 	pos += sizeof(u16);
188742e7aa77SAlexander Simon 
188842e7aa77SAlexander Simon 	/* AMPDU parameters */
1889ef96a842SBen Greear 	*pos++ = ht_cap->ampdu_factor |
1890ef96a842SBen Greear 		 (ht_cap->ampdu_density <<
189142e7aa77SAlexander Simon 			IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
189242e7aa77SAlexander Simon 
189342e7aa77SAlexander Simon 	/* MCS set */
1894ef96a842SBen Greear 	memcpy(pos, &ht_cap->mcs, sizeof(ht_cap->mcs));
1895ef96a842SBen Greear 	pos += sizeof(ht_cap->mcs);
189642e7aa77SAlexander Simon 
189742e7aa77SAlexander Simon 	/* extended capabilities */
189842e7aa77SAlexander Simon 	pos += sizeof(__le16);
189942e7aa77SAlexander Simon 
190042e7aa77SAlexander Simon 	/* BF capabilities */
190142e7aa77SAlexander Simon 	pos += sizeof(__le32);
190242e7aa77SAlexander Simon 
190342e7aa77SAlexander Simon 	/* antenna selection */
190442e7aa77SAlexander Simon 	pos += sizeof(u8);
190542e7aa77SAlexander Simon 
190642e7aa77SAlexander Simon 	return pos;
190742e7aa77SAlexander Simon }
190842e7aa77SAlexander Simon 
1909ba0afa2fSMahesh Palivela u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
1910ba0afa2fSMahesh Palivela 			       u32 cap)
1911ba0afa2fSMahesh Palivela {
1912ba0afa2fSMahesh Palivela 	__le32 tmp;
1913ba0afa2fSMahesh Palivela 
1914ba0afa2fSMahesh Palivela 	*pos++ = WLAN_EID_VHT_CAPABILITY;
1915d4950281SMahesh Palivela 	*pos++ = sizeof(struct ieee80211_vht_cap);
1916d4950281SMahesh Palivela 	memset(pos, 0, sizeof(struct ieee80211_vht_cap));
1917ba0afa2fSMahesh Palivela 
1918ba0afa2fSMahesh Palivela 	/* capability flags */
1919ba0afa2fSMahesh Palivela 	tmp = cpu_to_le32(cap);
1920ba0afa2fSMahesh Palivela 	memcpy(pos, &tmp, sizeof(u32));
1921ba0afa2fSMahesh Palivela 	pos += sizeof(u32);
1922ba0afa2fSMahesh Palivela 
1923ba0afa2fSMahesh Palivela 	/* VHT MCS set */
1924ba0afa2fSMahesh Palivela 	memcpy(pos, &vht_cap->vht_mcs, sizeof(vht_cap->vht_mcs));
1925ba0afa2fSMahesh Palivela 	pos += sizeof(vht_cap->vht_mcs);
1926ba0afa2fSMahesh Palivela 
1927ba0afa2fSMahesh Palivela 	return pos;
1928ba0afa2fSMahesh Palivela }
1929ba0afa2fSMahesh Palivela 
1930074d46d1SJohannes Berg u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
19314bf88530SJohannes Berg 			       const struct cfg80211_chan_def *chandef,
1932431e3154SAshok Nagarajan 			       u16 prot_mode)
193342e7aa77SAlexander Simon {
1934074d46d1SJohannes Berg 	struct ieee80211_ht_operation *ht_oper;
193542e7aa77SAlexander Simon 	/* Build HT Information */
1936074d46d1SJohannes Berg 	*pos++ = WLAN_EID_HT_OPERATION;
1937074d46d1SJohannes Berg 	*pos++ = sizeof(struct ieee80211_ht_operation);
1938074d46d1SJohannes Berg 	ht_oper = (struct ieee80211_ht_operation *)pos;
19394bf88530SJohannes Berg 	ht_oper->primary_chan = ieee80211_frequency_to_channel(
19404bf88530SJohannes Berg 					chandef->chan->center_freq);
19414bf88530SJohannes Berg 	switch (chandef->width) {
19424bf88530SJohannes Berg 	case NL80211_CHAN_WIDTH_160:
19434bf88530SJohannes Berg 	case NL80211_CHAN_WIDTH_80P80:
19444bf88530SJohannes Berg 	case NL80211_CHAN_WIDTH_80:
19454bf88530SJohannes Berg 	case NL80211_CHAN_WIDTH_40:
19464bf88530SJohannes Berg 		if (chandef->center_freq1 > chandef->chan->center_freq)
19474bf88530SJohannes Berg 			ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
19484bf88530SJohannes Berg 		else
1949074d46d1SJohannes Berg 			ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
195042e7aa77SAlexander Simon 		break;
195142e7aa77SAlexander Simon 	default:
1952074d46d1SJohannes Berg 		ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
195342e7aa77SAlexander Simon 		break;
195442e7aa77SAlexander Simon 	}
1955aee286c2SThomas Pedersen 	if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
19564bf88530SJohannes Berg 	    chandef->width != NL80211_CHAN_WIDTH_20_NOHT &&
19574bf88530SJohannes Berg 	    chandef->width != NL80211_CHAN_WIDTH_20)
1958074d46d1SJohannes Berg 		ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
1959ff3cc5f4SSimon Wunderlich 
1960431e3154SAshok Nagarajan 	ht_oper->operation_mode = cpu_to_le16(prot_mode);
1961074d46d1SJohannes Berg 	ht_oper->stbc_param = 0x0000;
196242e7aa77SAlexander Simon 
196342e7aa77SAlexander Simon 	/* It seems that Basic MCS set and Supported MCS set
196442e7aa77SAlexander Simon 	   are identical for the first 10 bytes */
1965074d46d1SJohannes Berg 	memset(&ht_oper->basic_set, 0, 16);
1966074d46d1SJohannes Berg 	memcpy(&ht_oper->basic_set, &ht_cap->mcs, 10);
196742e7aa77SAlexander Simon 
1968074d46d1SJohannes Berg 	return pos + sizeof(struct ieee80211_ht_operation);
196942e7aa77SAlexander Simon }
197042e7aa77SAlexander Simon 
19714bf88530SJohannes Berg void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
19724a3cb702SJohannes Berg 				  const struct ieee80211_ht_operation *ht_oper,
19734bf88530SJohannes Berg 				  struct cfg80211_chan_def *chandef)
197442e7aa77SAlexander Simon {
197542e7aa77SAlexander Simon 	enum nl80211_channel_type channel_type;
197642e7aa77SAlexander Simon 
19774bf88530SJohannes Berg 	if (!ht_oper) {
19784bf88530SJohannes Berg 		cfg80211_chandef_create(chandef, control_chan,
19794bf88530SJohannes Berg 					NL80211_CHAN_NO_HT);
19804bf88530SJohannes Berg 		return;
19814bf88530SJohannes Berg 	}
198242e7aa77SAlexander Simon 
1983074d46d1SJohannes Berg 	switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
198442e7aa77SAlexander Simon 	case IEEE80211_HT_PARAM_CHA_SEC_NONE:
198542e7aa77SAlexander Simon 		channel_type = NL80211_CHAN_HT20;
198642e7aa77SAlexander Simon 		break;
198742e7aa77SAlexander Simon 	case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
198842e7aa77SAlexander Simon 		channel_type = NL80211_CHAN_HT40PLUS;
198942e7aa77SAlexander Simon 		break;
199042e7aa77SAlexander Simon 	case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
199142e7aa77SAlexander Simon 		channel_type = NL80211_CHAN_HT40MINUS;
199242e7aa77SAlexander Simon 		break;
199342e7aa77SAlexander Simon 	default:
199442e7aa77SAlexander Simon 		channel_type = NL80211_CHAN_NO_HT;
199542e7aa77SAlexander Simon 	}
199642e7aa77SAlexander Simon 
19974bf88530SJohannes Berg 	cfg80211_chandef_create(chandef, control_chan, channel_type);
199842e7aa77SAlexander Simon }
199942e7aa77SAlexander Simon 
2000fc8a7321SJohannes Berg int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
20016b77863bSJohannes Berg 			    struct sk_buff *skb, bool need_basic,
20026b77863bSJohannes Berg 			    enum ieee80211_band band)
2003768db343SArik Nemtsov {
2004768db343SArik Nemtsov 	struct ieee80211_local *local = sdata->local;
2005768db343SArik Nemtsov 	struct ieee80211_supported_band *sband;
2006768db343SArik Nemtsov 	int rate;
2007768db343SArik Nemtsov 	u8 i, rates, *pos;
2008fc8a7321SJohannes Berg 	u32 basic_rates = sdata->vif.bss_conf.basic_rates;
2009768db343SArik Nemtsov 
20106b77863bSJohannes Berg 	sband = local->hw.wiphy->bands[band];
2011768db343SArik Nemtsov 	rates = sband->n_bitrates;
2012768db343SArik Nemtsov 	if (rates > 8)
2013768db343SArik Nemtsov 		rates = 8;
2014768db343SArik Nemtsov 
2015768db343SArik Nemtsov 	if (skb_tailroom(skb) < rates + 2)
2016768db343SArik Nemtsov 		return -ENOMEM;
2017768db343SArik Nemtsov 
2018768db343SArik Nemtsov 	pos = skb_put(skb, rates + 2);
2019768db343SArik Nemtsov 	*pos++ = WLAN_EID_SUPP_RATES;
2020768db343SArik Nemtsov 	*pos++ = rates;
2021768db343SArik Nemtsov 	for (i = 0; i < rates; i++) {
2022657c3e0cSAshok Nagarajan 		u8 basic = 0;
2023657c3e0cSAshok Nagarajan 		if (need_basic && basic_rates & BIT(i))
2024657c3e0cSAshok Nagarajan 			basic = 0x80;
2025768db343SArik Nemtsov 		rate = sband->bitrates[i].bitrate;
2026657c3e0cSAshok Nagarajan 		*pos++ = basic | (u8) (rate / 5);
2027768db343SArik Nemtsov 	}
2028768db343SArik Nemtsov 
2029768db343SArik Nemtsov 	return 0;
2030768db343SArik Nemtsov }
2031768db343SArik Nemtsov 
2032fc8a7321SJohannes Berg int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
20336b77863bSJohannes Berg 				struct sk_buff *skb, bool need_basic,
20346b77863bSJohannes Berg 				enum ieee80211_band band)
2035768db343SArik Nemtsov {
2036768db343SArik Nemtsov 	struct ieee80211_local *local = sdata->local;
2037768db343SArik Nemtsov 	struct ieee80211_supported_band *sband;
2038768db343SArik Nemtsov 	int rate;
2039768db343SArik Nemtsov 	u8 i, exrates, *pos;
2040fc8a7321SJohannes Berg 	u32 basic_rates = sdata->vif.bss_conf.basic_rates;
2041768db343SArik Nemtsov 
20426b77863bSJohannes Berg 	sband = local->hw.wiphy->bands[band];
2043768db343SArik Nemtsov 	exrates = sband->n_bitrates;
2044768db343SArik Nemtsov 	if (exrates > 8)
2045768db343SArik Nemtsov 		exrates -= 8;
2046768db343SArik Nemtsov 	else
2047768db343SArik Nemtsov 		exrates = 0;
2048768db343SArik Nemtsov 
2049768db343SArik Nemtsov 	if (skb_tailroom(skb) < exrates + 2)
2050768db343SArik Nemtsov 		return -ENOMEM;
2051768db343SArik Nemtsov 
2052768db343SArik Nemtsov 	if (exrates) {
2053768db343SArik Nemtsov 		pos = skb_put(skb, exrates + 2);
2054768db343SArik Nemtsov 		*pos++ = WLAN_EID_EXT_SUPP_RATES;
2055768db343SArik Nemtsov 		*pos++ = exrates;
2056768db343SArik Nemtsov 		for (i = 8; i < sband->n_bitrates; i++) {
2057657c3e0cSAshok Nagarajan 			u8 basic = 0;
2058657c3e0cSAshok Nagarajan 			if (need_basic && basic_rates & BIT(i))
2059657c3e0cSAshok Nagarajan 				basic = 0x80;
2060768db343SArik Nemtsov 			rate = sband->bitrates[i].bitrate;
2061657c3e0cSAshok Nagarajan 			*pos++ = basic | (u8) (rate / 5);
2062768db343SArik Nemtsov 		}
2063768db343SArik Nemtsov 	}
2064768db343SArik Nemtsov 	return 0;
2065768db343SArik Nemtsov }
20661dae27f8SWey-Yi Guy 
20671dae27f8SWey-Yi Guy int ieee80211_ave_rssi(struct ieee80211_vif *vif)
20681dae27f8SWey-Yi Guy {
20691dae27f8SWey-Yi Guy 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
20701dae27f8SWey-Yi Guy 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
20711dae27f8SWey-Yi Guy 
2072be6bcabcSWey-Yi Guy 	if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION)) {
2073be6bcabcSWey-Yi Guy 		/* non-managed type inferfaces */
2074be6bcabcSWey-Yi Guy 		return 0;
2075be6bcabcSWey-Yi Guy 	}
20763a7bba64SEmmanuel Grumbach 	return ifmgd->ave_beacon_signal / 16;
20771dae27f8SWey-Yi Guy }
20780d8a0a17SWey-Yi Guy EXPORT_SYMBOL_GPL(ieee80211_ave_rssi);
207904ecd257SJohannes Berg 
208004ecd257SJohannes Berg u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs)
208104ecd257SJohannes Berg {
208204ecd257SJohannes Berg 	if (!mcs)
208304ecd257SJohannes Berg 		return 1;
208404ecd257SJohannes Berg 
208504ecd257SJohannes Berg 	/* TODO: consider rx_highest */
208604ecd257SJohannes Berg 
208704ecd257SJohannes Berg 	if (mcs->rx_mask[3])
208804ecd257SJohannes Berg 		return 4;
208904ecd257SJohannes Berg 	if (mcs->rx_mask[2])
209004ecd257SJohannes Berg 		return 3;
209104ecd257SJohannes Berg 	if (mcs->rx_mask[1])
209204ecd257SJohannes Berg 		return 2;
209304ecd257SJohannes Berg 	return 1;
209404ecd257SJohannes Berg }
2095f4bda337SThomas Pedersen 
2096f4bda337SThomas Pedersen /**
2097f4bda337SThomas Pedersen  * ieee80211_calculate_rx_timestamp - calculate timestamp in frame
2098f4bda337SThomas Pedersen  * @local: mac80211 hw info struct
2099f4bda337SThomas Pedersen  * @status: RX status
2100f4bda337SThomas Pedersen  * @mpdu_len: total MPDU length (including FCS)
2101f4bda337SThomas Pedersen  * @mpdu_offset: offset into MPDU to calculate timestamp at
2102f4bda337SThomas Pedersen  *
2103f4bda337SThomas Pedersen  * This function calculates the RX timestamp at the given MPDU offset, taking
2104f4bda337SThomas Pedersen  * into account what the RX timestamp was. An offset of 0 will just normalize
2105f4bda337SThomas Pedersen  * the timestamp to TSF at beginning of MPDU reception.
2106f4bda337SThomas Pedersen  */
2107f4bda337SThomas Pedersen u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
2108f4bda337SThomas Pedersen 				     struct ieee80211_rx_status *status,
2109f4bda337SThomas Pedersen 				     unsigned int mpdu_len,
2110f4bda337SThomas Pedersen 				     unsigned int mpdu_offset)
2111f4bda337SThomas Pedersen {
2112f4bda337SThomas Pedersen 	u64 ts = status->mactime;
2113f4bda337SThomas Pedersen 	struct rate_info ri;
2114f4bda337SThomas Pedersen 	u16 rate;
2115f4bda337SThomas Pedersen 
2116f4bda337SThomas Pedersen 	if (WARN_ON(!ieee80211_have_rx_timestamp(status)))
2117f4bda337SThomas Pedersen 		return 0;
2118f4bda337SThomas Pedersen 
2119f4bda337SThomas Pedersen 	memset(&ri, 0, sizeof(ri));
2120f4bda337SThomas Pedersen 
2121f4bda337SThomas Pedersen 	/* Fill cfg80211 rate info */
2122f4bda337SThomas Pedersen 	if (status->flag & RX_FLAG_HT) {
2123f4bda337SThomas Pedersen 		ri.mcs = status->rate_idx;
2124f4bda337SThomas Pedersen 		ri.flags |= RATE_INFO_FLAGS_MCS;
2125f4bda337SThomas Pedersen 		if (status->flag & RX_FLAG_40MHZ)
2126f4bda337SThomas Pedersen 			ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
2127f4bda337SThomas Pedersen 		if (status->flag & RX_FLAG_SHORT_GI)
2128f4bda337SThomas Pedersen 			ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
21295614618eSJohannes Berg 	} else if (status->flag & RX_FLAG_VHT) {
21305614618eSJohannes Berg 		ri.flags |= RATE_INFO_FLAGS_VHT_MCS;
21315614618eSJohannes Berg 		ri.mcs = status->rate_idx;
21325614618eSJohannes Berg 		ri.nss = status->vht_nss;
21335614618eSJohannes Berg 		if (status->flag & RX_FLAG_40MHZ)
21345614618eSJohannes Berg 			ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
21355614618eSJohannes Berg 		if (status->flag & RX_FLAG_80MHZ)
21365614618eSJohannes Berg 			ri.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
21375614618eSJohannes Berg 		if (status->flag & RX_FLAG_80P80MHZ)
21385614618eSJohannes Berg 			ri.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH;
21395614618eSJohannes Berg 		if (status->flag & RX_FLAG_160MHZ)
21405614618eSJohannes Berg 			ri.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
21415614618eSJohannes Berg 		if (status->flag & RX_FLAG_SHORT_GI)
21425614618eSJohannes Berg 			ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
2143f4bda337SThomas Pedersen 	} else {
2144f4bda337SThomas Pedersen 		struct ieee80211_supported_band *sband;
2145f4bda337SThomas Pedersen 
2146f4bda337SThomas Pedersen 		sband = local->hw.wiphy->bands[status->band];
2147f4bda337SThomas Pedersen 		ri.legacy = sband->bitrates[status->rate_idx].bitrate;
2148f4bda337SThomas Pedersen 	}
2149f4bda337SThomas Pedersen 
2150f4bda337SThomas Pedersen 	rate = cfg80211_calculate_bitrate(&ri);
2151f4bda337SThomas Pedersen 
2152f4bda337SThomas Pedersen 	/* rewind from end of MPDU */
2153f4bda337SThomas Pedersen 	if (status->flag & RX_FLAG_MACTIME_END)
2154f4bda337SThomas Pedersen 		ts -= mpdu_len * 8 * 10 / rate;
2155f4bda337SThomas Pedersen 
2156f4bda337SThomas Pedersen 	ts += mpdu_offset * 8 * 10 / rate;
2157f4bda337SThomas Pedersen 
2158f4bda337SThomas Pedersen 	return ts;
2159f4bda337SThomas Pedersen }
2160164eb02dSSimon Wunderlich 
2161164eb02dSSimon Wunderlich void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
2162164eb02dSSimon Wunderlich {
2163164eb02dSSimon Wunderlich 	struct ieee80211_sub_if_data *sdata;
2164164eb02dSSimon Wunderlich 
2165164eb02dSSimon Wunderlich 	mutex_lock(&local->iflist_mtx);
2166164eb02dSSimon Wunderlich 	list_for_each_entry(sdata, &local->interfaces, list) {
2167164eb02dSSimon Wunderlich 		cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
2168164eb02dSSimon Wunderlich 
2169164eb02dSSimon Wunderlich 		if (sdata->wdev.cac_started) {
2170164eb02dSSimon Wunderlich 			ieee80211_vif_release_channel(sdata);
2171164eb02dSSimon Wunderlich 			cfg80211_cac_event(sdata->dev,
2172164eb02dSSimon Wunderlich 					   NL80211_RADAR_CAC_ABORTED,
2173164eb02dSSimon Wunderlich 					   GFP_KERNEL);
2174164eb02dSSimon Wunderlich 		}
2175164eb02dSSimon Wunderlich 	}
2176164eb02dSSimon Wunderlich 	mutex_unlock(&local->iflist_mtx);
2177164eb02dSSimon Wunderlich }
2178164eb02dSSimon Wunderlich 
2179164eb02dSSimon Wunderlich void ieee80211_dfs_radar_detected_work(struct work_struct *work)
2180164eb02dSSimon Wunderlich {
2181164eb02dSSimon Wunderlich 	struct ieee80211_local *local =
2182164eb02dSSimon Wunderlich 		container_of(work, struct ieee80211_local, radar_detected_work);
2183164eb02dSSimon Wunderlich 	struct cfg80211_chan_def chandef;
2184164eb02dSSimon Wunderlich 
2185164eb02dSSimon Wunderlich 	ieee80211_dfs_cac_cancel(local);
2186164eb02dSSimon Wunderlich 
2187164eb02dSSimon Wunderlich 	if (local->use_chanctx)
2188164eb02dSSimon Wunderlich 		/* currently not handled */
2189164eb02dSSimon Wunderlich 		WARN_ON(1);
2190164eb02dSSimon Wunderlich 	else {
2191675a0b04SKarl Beldan 		chandef = local->hw.conf.chandef;
2192164eb02dSSimon Wunderlich 		cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL);
2193164eb02dSSimon Wunderlich 	}
2194164eb02dSSimon Wunderlich }
2195164eb02dSSimon Wunderlich 
2196164eb02dSSimon Wunderlich void ieee80211_radar_detected(struct ieee80211_hw *hw)
2197164eb02dSSimon Wunderlich {
2198164eb02dSSimon Wunderlich 	struct ieee80211_local *local = hw_to_local(hw);
2199164eb02dSSimon Wunderlich 
2200164eb02dSSimon Wunderlich 	trace_api_radar_detected(local);
2201164eb02dSSimon Wunderlich 
2202164eb02dSSimon Wunderlich 	ieee80211_queue_work(hw, &local->radar_detected_work);
2203164eb02dSSimon Wunderlich }
2204164eb02dSSimon Wunderlich EXPORT_SYMBOL(ieee80211_radar_detected);
2205