xref: /openbmc/linux/net/mac80211/util.c (revision 20f544ee)
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)) {
4090819663dSRoel Kluin 		kfree_skb(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)) {
4340819663dSRoel Kluin 			kfree_skb(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,
456ce7c9111SKalle Valo 				    enum queue_stop_reason reason)
457c2d1560aSJohannes Berg {
458ce7c9111SKalle Valo 	struct ieee80211_local *local = hw_to_local(hw);
459ce7c9111SKalle Valo 	unsigned long flags;
460c2d1560aSJohannes Berg 	int i;
461c2d1560aSJohannes Berg 
462ce7c9111SKalle Valo 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
463ce7c9111SKalle Valo 
46496f5e66eSJohannes Berg 	for (i = 0; i < hw->queues; i++)
465ce7c9111SKalle Valo 		__ieee80211_stop_queue(hw, i, reason);
466ce7c9111SKalle Valo 
467ce7c9111SKalle Valo 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
468ce7c9111SKalle Valo }
469ce7c9111SKalle Valo 
470ce7c9111SKalle Valo void ieee80211_stop_queues(struct ieee80211_hw *hw)
471ce7c9111SKalle Valo {
472ce7c9111SKalle Valo 	ieee80211_stop_queues_by_reason(hw,
473ce7c9111SKalle Valo 					IEEE80211_QUEUE_STOP_REASON_DRIVER);
474c2d1560aSJohannes Berg }
475c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queues);
476c2d1560aSJohannes Berg 
47792ab8535STomas Winkler int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
47892ab8535STomas Winkler {
47992ab8535STomas Winkler 	struct ieee80211_local *local = hw_to_local(hw);
4803b8d81e0SJohannes Berg 	unsigned long flags;
4813b8d81e0SJohannes Berg 	int ret;
48296f5e66eSJohannes Berg 
483e4e72fb4SJohannes Berg 	if (WARN_ON(queue >= hw->queues))
48496f5e66eSJohannes Berg 		return true;
48596f5e66eSJohannes Berg 
4863b8d81e0SJohannes Berg 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
4873b8d81e0SJohannes Berg 	ret = !!local->queue_stop_reasons[queue];
4883b8d81e0SJohannes Berg 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
4893b8d81e0SJohannes Berg 	return ret;
49092ab8535STomas Winkler }
49192ab8535STomas Winkler EXPORT_SYMBOL(ieee80211_queue_stopped);
49292ab8535STomas Winkler 
493ce7c9111SKalle Valo void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
494ce7c9111SKalle Valo 				     enum queue_stop_reason reason)
495c2d1560aSJohannes Berg {
496ce7c9111SKalle Valo 	struct ieee80211_local *local = hw_to_local(hw);
497ce7c9111SKalle Valo 	unsigned long flags;
498c2d1560aSJohannes Berg 	int i;
499c2d1560aSJohannes Berg 
500ce7c9111SKalle Valo 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
501ce7c9111SKalle Valo 
502e4e72fb4SJohannes Berg 	for (i = 0; i < hw->queues; i++)
503ce7c9111SKalle Valo 		__ieee80211_wake_queue(hw, i, reason);
504ce7c9111SKalle Valo 
505ce7c9111SKalle Valo 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
506ce7c9111SKalle Valo }
507ce7c9111SKalle Valo 
508ce7c9111SKalle Valo void ieee80211_wake_queues(struct ieee80211_hw *hw)
509ce7c9111SKalle Valo {
510ce7c9111SKalle Valo 	ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER);
511c2d1560aSJohannes Berg }
512c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queues);
513dabeb344SJohannes Berg 
51432bfd35dSJohannes Berg void ieee80211_iterate_active_interfaces(
51532bfd35dSJohannes Berg 	struct ieee80211_hw *hw,
516dabeb344SJohannes Berg 	void (*iterator)(void *data, u8 *mac,
51732bfd35dSJohannes Berg 			 struct ieee80211_vif *vif),
518dabeb344SJohannes Berg 	void *data)
519dabeb344SJohannes Berg {
520dabeb344SJohannes Berg 	struct ieee80211_local *local = hw_to_local(hw);
521dabeb344SJohannes Berg 	struct ieee80211_sub_if_data *sdata;
522dabeb344SJohannes Berg 
523c771c9d8SJohannes Berg 	mutex_lock(&local->iflist_mtx);
5242f561febSIvo van Doorn 
5252f561febSIvo van Doorn 	list_for_each_entry(sdata, &local->interfaces, list) {
5262f561febSIvo van Doorn 		switch (sdata->vif.type) {
52705c914feSJohannes Berg 		case NL80211_IFTYPE_MONITOR:
52805c914feSJohannes Berg 		case NL80211_IFTYPE_AP_VLAN:
5292f561febSIvo van Doorn 			continue;
5302ca27bcfSJohannes Berg 		default:
5312f561febSIvo van Doorn 			break;
5322f561febSIvo van Doorn 		}
5339607e6b6SJohannes Berg 		if (ieee80211_sdata_running(sdata))
53447846c9bSJohannes Berg 			iterator(data, sdata->vif.addr,
5352f561febSIvo van Doorn 				 &sdata->vif);
5362f561febSIvo van Doorn 	}
5372f561febSIvo van Doorn 
538685fb72bSJohannes Berg 	sdata = rcu_dereference_protected(local->monitor_sdata,
539685fb72bSJohannes Berg 					  lockdep_is_held(&local->iflist_mtx));
540685fb72bSJohannes Berg 	if (sdata)
541685fb72bSJohannes Berg 		iterator(data, sdata->vif.addr, &sdata->vif);
542685fb72bSJohannes Berg 
543c771c9d8SJohannes Berg 	mutex_unlock(&local->iflist_mtx);
5442f561febSIvo van Doorn }
5452f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
5462f561febSIvo van Doorn 
5472f561febSIvo van Doorn void ieee80211_iterate_active_interfaces_atomic(
5482f561febSIvo van Doorn 	struct ieee80211_hw *hw,
5492f561febSIvo van Doorn 	void (*iterator)(void *data, u8 *mac,
5502f561febSIvo van Doorn 			 struct ieee80211_vif *vif),
5512f561febSIvo van Doorn 	void *data)
5522f561febSIvo van Doorn {
5532f561febSIvo van Doorn 	struct ieee80211_local *local = hw_to_local(hw);
5542f561febSIvo van Doorn 	struct ieee80211_sub_if_data *sdata;
5552f561febSIvo van Doorn 
556e38bad47SJohannes Berg 	rcu_read_lock();
557dabeb344SJohannes Berg 
558e38bad47SJohannes Berg 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
55951fb61e7SJohannes Berg 		switch (sdata->vif.type) {
56005c914feSJohannes Berg 		case NL80211_IFTYPE_MONITOR:
56105c914feSJohannes Berg 		case NL80211_IFTYPE_AP_VLAN:
562dabeb344SJohannes Berg 			continue;
5632ca27bcfSJohannes Berg 		default:
564dabeb344SJohannes Berg 			break;
565dabeb344SJohannes Berg 		}
5669607e6b6SJohannes Berg 		if (ieee80211_sdata_running(sdata))
56747846c9bSJohannes Berg 			iterator(data, sdata->vif.addr,
56832bfd35dSJohannes Berg 				 &sdata->vif);
569dabeb344SJohannes Berg 	}
570e38bad47SJohannes Berg 
571685fb72bSJohannes Berg 	sdata = rcu_dereference(local->monitor_sdata);
572685fb72bSJohannes Berg 	if (sdata)
573685fb72bSJohannes Berg 		iterator(data, sdata->vif.addr, &sdata->vif);
574685fb72bSJohannes Berg 
575e38bad47SJohannes Berg 	rcu_read_unlock();
576dabeb344SJohannes Berg }
5772f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
57837ffc8daSJohannes Berg 
57942935ecaSLuis R. Rodriguez /*
58042935ecaSLuis R. Rodriguez  * Nothing should have been stuffed into the workqueue during
58142935ecaSLuis R. Rodriguez  * the suspend->resume cycle. If this WARN is seen then there
58242935ecaSLuis R. Rodriguez  * is a bug with either the driver suspend or something in
58342935ecaSLuis R. Rodriguez  * mac80211 stuffing into the workqueue which we haven't yet
58442935ecaSLuis R. Rodriguez  * cleared during mac80211's suspend cycle.
58542935ecaSLuis R. Rodriguez  */
58642935ecaSLuis R. Rodriguez static bool ieee80211_can_queue_work(struct ieee80211_local *local)
58742935ecaSLuis R. Rodriguez {
588ceb99fe0SJohannes Berg 	if (WARN(local->suspended && !local->resuming,
589ceb99fe0SJohannes Berg 		 "queueing ieee80211 work while going to suspend\n"))
59042935ecaSLuis R. Rodriguez 		return false;
59142935ecaSLuis R. Rodriguez 
59242935ecaSLuis R. Rodriguez 	return true;
59342935ecaSLuis R. Rodriguez }
59442935ecaSLuis R. Rodriguez 
59542935ecaSLuis R. Rodriguez void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work)
59642935ecaSLuis R. Rodriguez {
59742935ecaSLuis R. Rodriguez 	struct ieee80211_local *local = hw_to_local(hw);
59842935ecaSLuis R. Rodriguez 
59942935ecaSLuis R. Rodriguez 	if (!ieee80211_can_queue_work(local))
60042935ecaSLuis R. Rodriguez 		return;
60142935ecaSLuis R. Rodriguez 
60242935ecaSLuis R. Rodriguez 	queue_work(local->workqueue, work);
60342935ecaSLuis R. Rodriguez }
60442935ecaSLuis R. Rodriguez EXPORT_SYMBOL(ieee80211_queue_work);
60542935ecaSLuis R. Rodriguez 
60642935ecaSLuis R. Rodriguez void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
60742935ecaSLuis R. Rodriguez 				  struct delayed_work *dwork,
60842935ecaSLuis R. Rodriguez 				  unsigned long delay)
60942935ecaSLuis R. Rodriguez {
61042935ecaSLuis R. Rodriguez 	struct ieee80211_local *local = hw_to_local(hw);
61142935ecaSLuis R. Rodriguez 
61242935ecaSLuis R. Rodriguez 	if (!ieee80211_can_queue_work(local))
61342935ecaSLuis R. Rodriguez 		return;
61442935ecaSLuis R. Rodriguez 
61542935ecaSLuis R. Rodriguez 	queue_delayed_work(local->workqueue, dwork, delay);
61642935ecaSLuis R. Rodriguez }
61742935ecaSLuis R. Rodriguez EXPORT_SYMBOL(ieee80211_queue_delayed_work);
61842935ecaSLuis R. Rodriguez 
619dd76986bSJohannes Berg u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
620dd76986bSJohannes Berg 			       struct ieee802_11_elems *elems,
621dd76986bSJohannes Berg 			       u64 filter, u32 crc)
622dd76986bSJohannes Berg {
623dd76986bSJohannes Berg 	size_t left = len;
624dd76986bSJohannes Berg 	u8 *pos = start;
625dd76986bSJohannes Berg 	bool calc_crc = filter != 0;
626fcff4f10SPaul Stewart 	DECLARE_BITMAP(seen_elems, 256);
627dd76986bSJohannes Berg 
628fcff4f10SPaul Stewart 	bitmap_zero(seen_elems, 256);
629dd76986bSJohannes Berg 	memset(elems, 0, sizeof(*elems));
630dd76986bSJohannes Berg 	elems->ie_start = start;
631dd76986bSJohannes Berg 	elems->total_len = len;
632dd76986bSJohannes Berg 
633dd76986bSJohannes Berg 	while (left >= 2) {
634dd76986bSJohannes Berg 		u8 id, elen;
635fcff4f10SPaul Stewart 		bool elem_parse_failed;
636dd76986bSJohannes Berg 
637dd76986bSJohannes Berg 		id = *pos++;
638dd76986bSJohannes Berg 		elen = *pos++;
639dd76986bSJohannes Berg 		left -= 2;
640dd76986bSJohannes Berg 
641fcff4f10SPaul Stewart 		if (elen > left) {
642fcff4f10SPaul Stewart 			elems->parse_error = true;
643dd76986bSJohannes Berg 			break;
644fcff4f10SPaul Stewart 		}
645fcff4f10SPaul Stewart 
6469690fb16SJohannes Berg 		switch (id) {
6479690fb16SJohannes Berg 		case WLAN_EID_SSID:
6489690fb16SJohannes Berg 		case WLAN_EID_SUPP_RATES:
6499690fb16SJohannes Berg 		case WLAN_EID_FH_PARAMS:
6509690fb16SJohannes Berg 		case WLAN_EID_DS_PARAMS:
6519690fb16SJohannes Berg 		case WLAN_EID_CF_PARAMS:
6529690fb16SJohannes Berg 		case WLAN_EID_TIM:
6539690fb16SJohannes Berg 		case WLAN_EID_IBSS_PARAMS:
6549690fb16SJohannes Berg 		case WLAN_EID_CHALLENGE:
6559690fb16SJohannes Berg 		case WLAN_EID_RSN:
6569690fb16SJohannes Berg 		case WLAN_EID_ERP_INFO:
6579690fb16SJohannes Berg 		case WLAN_EID_EXT_SUPP_RATES:
6589690fb16SJohannes Berg 		case WLAN_EID_HT_CAPABILITY:
6599690fb16SJohannes Berg 		case WLAN_EID_HT_OPERATION:
6609690fb16SJohannes Berg 		case WLAN_EID_VHT_CAPABILITY:
6619690fb16SJohannes Berg 		case WLAN_EID_VHT_OPERATION:
6629690fb16SJohannes Berg 		case WLAN_EID_MESH_ID:
6639690fb16SJohannes Berg 		case WLAN_EID_MESH_CONFIG:
6649690fb16SJohannes Berg 		case WLAN_EID_PEER_MGMT:
6659690fb16SJohannes Berg 		case WLAN_EID_PREQ:
6669690fb16SJohannes Berg 		case WLAN_EID_PREP:
6679690fb16SJohannes Berg 		case WLAN_EID_PERR:
6689690fb16SJohannes Berg 		case WLAN_EID_RANN:
6699690fb16SJohannes Berg 		case WLAN_EID_CHANNEL_SWITCH:
6709690fb16SJohannes Berg 		case WLAN_EID_EXT_CHANSWITCH_ANN:
6719690fb16SJohannes Berg 		case WLAN_EID_COUNTRY:
6729690fb16SJohannes Berg 		case WLAN_EID_PWR_CONSTRAINT:
6739690fb16SJohannes Berg 		case WLAN_EID_TIMEOUT_INTERVAL:
6749690fb16SJohannes Berg 			if (test_bit(id, seen_elems)) {
675fcff4f10SPaul Stewart 				elems->parse_error = true;
676fcff4f10SPaul Stewart 				left -= elen;
677fcff4f10SPaul Stewart 				pos += elen;
678fcff4f10SPaul Stewart 				continue;
679fcff4f10SPaul Stewart 			}
6809690fb16SJohannes Berg 			break;
6819690fb16SJohannes Berg 		}
682dd76986bSJohannes Berg 
683dd76986bSJohannes Berg 		if (calc_crc && id < 64 && (filter & (1ULL << id)))
684dd76986bSJohannes Berg 			crc = crc32_be(crc, pos - 2, elen + 2);
685dd76986bSJohannes Berg 
686fcff4f10SPaul Stewart 		elem_parse_failed = false;
687fcff4f10SPaul Stewart 
688dd76986bSJohannes Berg 		switch (id) {
689dd76986bSJohannes Berg 		case WLAN_EID_SSID:
690dd76986bSJohannes Berg 			elems->ssid = pos;
691dd76986bSJohannes Berg 			elems->ssid_len = elen;
692dd76986bSJohannes Berg 			break;
693dd76986bSJohannes Berg 		case WLAN_EID_SUPP_RATES:
694dd76986bSJohannes Berg 			elems->supp_rates = pos;
695dd76986bSJohannes Berg 			elems->supp_rates_len = elen;
696dd76986bSJohannes Berg 			break;
697dd76986bSJohannes Berg 		case WLAN_EID_FH_PARAMS:
698dd76986bSJohannes Berg 			elems->fh_params = pos;
699dd76986bSJohannes Berg 			elems->fh_params_len = elen;
700dd76986bSJohannes Berg 			break;
701dd76986bSJohannes Berg 		case WLAN_EID_DS_PARAMS:
702dd76986bSJohannes Berg 			elems->ds_params = pos;
703dd76986bSJohannes Berg 			elems->ds_params_len = elen;
704dd76986bSJohannes Berg 			break;
705dd76986bSJohannes Berg 		case WLAN_EID_CF_PARAMS:
706dd76986bSJohannes Berg 			elems->cf_params = pos;
707dd76986bSJohannes Berg 			elems->cf_params_len = elen;
708dd76986bSJohannes Berg 			break;
709dd76986bSJohannes Berg 		case WLAN_EID_TIM:
710dd76986bSJohannes Berg 			if (elen >= sizeof(struct ieee80211_tim_ie)) {
711dd76986bSJohannes Berg 				elems->tim = (void *)pos;
712dd76986bSJohannes Berg 				elems->tim_len = elen;
713fcff4f10SPaul Stewart 			} else
714fcff4f10SPaul Stewart 				elem_parse_failed = true;
715dd76986bSJohannes Berg 			break;
716dd76986bSJohannes Berg 		case WLAN_EID_IBSS_PARAMS:
717dd76986bSJohannes Berg 			elems->ibss_params = pos;
718dd76986bSJohannes Berg 			elems->ibss_params_len = elen;
719dd76986bSJohannes Berg 			break;
720dd76986bSJohannes Berg 		case WLAN_EID_CHALLENGE:
721dd76986bSJohannes Berg 			elems->challenge = pos;
722dd76986bSJohannes Berg 			elems->challenge_len = elen;
723dd76986bSJohannes Berg 			break;
724dd76986bSJohannes Berg 		case WLAN_EID_VENDOR_SPECIFIC:
725dd76986bSJohannes Berg 			if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
726dd76986bSJohannes Berg 			    pos[2] == 0xf2) {
727dd76986bSJohannes Berg 				/* Microsoft OUI (00:50:F2) */
728dd76986bSJohannes Berg 
729dd76986bSJohannes Berg 				if (calc_crc)
730dd76986bSJohannes Berg 					crc = crc32_be(crc, pos - 2, elen + 2);
731dd76986bSJohannes Berg 
732dd76986bSJohannes Berg 				if (pos[3] == 1) {
733dd76986bSJohannes Berg 					/* OUI Type 1 - WPA IE */
734dd76986bSJohannes Berg 					elems->wpa = pos;
735dd76986bSJohannes Berg 					elems->wpa_len = elen;
736dd76986bSJohannes Berg 				} else if (elen >= 5 && pos[3] == 2) {
737dd76986bSJohannes Berg 					/* OUI Type 2 - WMM IE */
738dd76986bSJohannes Berg 					if (pos[4] == 0) {
739dd76986bSJohannes Berg 						elems->wmm_info = pos;
740dd76986bSJohannes Berg 						elems->wmm_info_len = elen;
741dd76986bSJohannes Berg 					} else if (pos[4] == 1) {
742dd76986bSJohannes Berg 						elems->wmm_param = pos;
743dd76986bSJohannes Berg 						elems->wmm_param_len = elen;
744dd76986bSJohannes Berg 					}
745dd76986bSJohannes Berg 				}
746dd76986bSJohannes Berg 			}
747dd76986bSJohannes Berg 			break;
748dd76986bSJohannes Berg 		case WLAN_EID_RSN:
749dd76986bSJohannes Berg 			elems->rsn = pos;
750dd76986bSJohannes Berg 			elems->rsn_len = elen;
751dd76986bSJohannes Berg 			break;
752dd76986bSJohannes Berg 		case WLAN_EID_ERP_INFO:
753dd76986bSJohannes Berg 			elems->erp_info = pos;
754dd76986bSJohannes Berg 			elems->erp_info_len = elen;
755dd76986bSJohannes Berg 			break;
756dd76986bSJohannes Berg 		case WLAN_EID_EXT_SUPP_RATES:
757dd76986bSJohannes Berg 			elems->ext_supp_rates = pos;
758dd76986bSJohannes Berg 			elems->ext_supp_rates_len = elen;
759dd76986bSJohannes Berg 			break;
760dd76986bSJohannes Berg 		case WLAN_EID_HT_CAPABILITY:
761dd76986bSJohannes Berg 			if (elen >= sizeof(struct ieee80211_ht_cap))
762dd76986bSJohannes Berg 				elems->ht_cap_elem = (void *)pos;
763fcff4f10SPaul Stewart 			else
764fcff4f10SPaul Stewart 				elem_parse_failed = true;
765dd76986bSJohannes Berg 			break;
766074d46d1SJohannes Berg 		case WLAN_EID_HT_OPERATION:
767074d46d1SJohannes Berg 			if (elen >= sizeof(struct ieee80211_ht_operation))
768074d46d1SJohannes Berg 				elems->ht_operation = (void *)pos;
769fcff4f10SPaul Stewart 			else
770fcff4f10SPaul Stewart 				elem_parse_failed = true;
771dd76986bSJohannes Berg 			break;
772dd76986bSJohannes Berg 		case WLAN_EID_MESH_ID:
773dd76986bSJohannes Berg 			elems->mesh_id = pos;
774dd76986bSJohannes Berg 			elems->mesh_id_len = elen;
775dd76986bSJohannes Berg 			break;
776dd76986bSJohannes Berg 		case WLAN_EID_MESH_CONFIG:
777dd76986bSJohannes Berg 			if (elen >= sizeof(struct ieee80211_meshconf_ie))
778dd76986bSJohannes Berg 				elems->mesh_config = (void *)pos;
779fcff4f10SPaul Stewart 			else
780fcff4f10SPaul Stewart 				elem_parse_failed = true;
781dd76986bSJohannes Berg 			break;
782dd76986bSJohannes Berg 		case WLAN_EID_PEER_MGMT:
783dd76986bSJohannes Berg 			elems->peering = pos;
784dd76986bSJohannes Berg 			elems->peering_len = elen;
785dd76986bSJohannes Berg 			break;
786dd76986bSJohannes Berg 		case WLAN_EID_PREQ:
787dd76986bSJohannes Berg 			elems->preq = pos;
788dd76986bSJohannes Berg 			elems->preq_len = elen;
789dd76986bSJohannes Berg 			break;
790dd76986bSJohannes Berg 		case WLAN_EID_PREP:
791dd76986bSJohannes Berg 			elems->prep = pos;
792dd76986bSJohannes Berg 			elems->prep_len = elen;
793dd76986bSJohannes Berg 			break;
794dd76986bSJohannes Berg 		case WLAN_EID_PERR:
795dd76986bSJohannes Berg 			elems->perr = pos;
796dd76986bSJohannes Berg 			elems->perr_len = elen;
797dd76986bSJohannes Berg 			break;
798dd76986bSJohannes Berg 		case WLAN_EID_RANN:
799dd76986bSJohannes Berg 			if (elen >= sizeof(struct ieee80211_rann_ie))
800dd76986bSJohannes Berg 				elems->rann = (void *)pos;
801fcff4f10SPaul Stewart 			else
802fcff4f10SPaul Stewart 				elem_parse_failed = true;
803dd76986bSJohannes Berg 			break;
804dd76986bSJohannes Berg 		case WLAN_EID_CHANNEL_SWITCH:
8055bc1420bSJohannes Berg 			if (elen != sizeof(struct ieee80211_channel_sw_ie)) {
8065bc1420bSJohannes Berg 				elem_parse_failed = true;
8075bc1420bSJohannes Berg 				break;
8085bc1420bSJohannes Berg 			}
8095bc1420bSJohannes Berg 			elems->ch_switch_ie = (void *)pos;
810dd76986bSJohannes Berg 			break;
811dd76986bSJohannes Berg 		case WLAN_EID_QUIET:
812dd76986bSJohannes Berg 			if (!elems->quiet_elem) {
813dd76986bSJohannes Berg 				elems->quiet_elem = pos;
814dd76986bSJohannes Berg 				elems->quiet_elem_len = elen;
815dd76986bSJohannes Berg 			}
816dd76986bSJohannes Berg 			elems->num_of_quiet_elem++;
817dd76986bSJohannes Berg 			break;
818dd76986bSJohannes Berg 		case WLAN_EID_COUNTRY:
819dd76986bSJohannes Berg 			elems->country_elem = pos;
820dd76986bSJohannes Berg 			elems->country_elem_len = elen;
821dd76986bSJohannes Berg 			break;
822dd76986bSJohannes Berg 		case WLAN_EID_PWR_CONSTRAINT:
823761a48d2SJohannes Berg 			if (elen != 1) {
824761a48d2SJohannes Berg 				elem_parse_failed = true;
825761a48d2SJohannes Berg 				break;
826761a48d2SJohannes Berg 			}
827dd76986bSJohannes Berg 			elems->pwr_constr_elem = pos;
828dd76986bSJohannes Berg 			break;
829dd76986bSJohannes Berg 		case WLAN_EID_TIMEOUT_INTERVAL:
830dd76986bSJohannes Berg 			elems->timeout_int = pos;
831dd76986bSJohannes Berg 			elems->timeout_int_len = elen;
832dd76986bSJohannes Berg 			break;
833dd76986bSJohannes Berg 		default:
834dd76986bSJohannes Berg 			break;
835dd76986bSJohannes Berg 		}
836dd76986bSJohannes Berg 
837fcff4f10SPaul Stewart 		if (elem_parse_failed)
838fcff4f10SPaul Stewart 			elems->parse_error = true;
839fcff4f10SPaul Stewart 		else
840fcff4f10SPaul Stewart 			set_bit(id, seen_elems);
841fcff4f10SPaul Stewart 
842dd76986bSJohannes Berg 		left -= elen;
843dd76986bSJohannes Berg 		pos += elen;
844dd76986bSJohannes Berg 	}
845dd76986bSJohannes Berg 
846fcff4f10SPaul Stewart 	if (left != 0)
847fcff4f10SPaul Stewart 		elems->parse_error = true;
848fcff4f10SPaul Stewart 
849dd76986bSJohannes Berg 	return crc;
850dd76986bSJohannes Berg }
851dd76986bSJohannes Berg 
85237ffc8daSJohannes Berg void ieee802_11_parse_elems(u8 *start, size_t len,
85337ffc8daSJohannes Berg 			    struct ieee802_11_elems *elems)
85437ffc8daSJohannes Berg {
855d91f36dbSJohannes Berg 	ieee802_11_parse_elems_crc(start, len, elems, 0, 0);
856d91f36dbSJohannes Berg }
857d91f36dbSJohannes Berg 
8583abead59SJohannes Berg void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
8593abead59SJohannes Berg 			       bool bss_notify)
8605825fe10SJohannes Berg {
8615825fe10SJohannes Berg 	struct ieee80211_local *local = sdata->local;
8625825fe10SJohannes Berg 	struct ieee80211_tx_queue_params qparam;
86354bcbc69SJohannes Berg 	int ac;
864a8ce8544SStanislaw Gruszka 	bool use_11b, enable_qos;
865aa837e1dSJohannes Berg 	int aCWmin, aCWmax;
8665825fe10SJohannes Berg 
8675825fe10SJohannes Berg 	if (!local->ops->conf_tx)
8685825fe10SJohannes Berg 		return;
8695825fe10SJohannes Berg 
87054bcbc69SJohannes Berg 	if (local->hw.queues < IEEE80211_NUM_ACS)
87154bcbc69SJohannes Berg 		return;
87254bcbc69SJohannes Berg 
8735825fe10SJohannes Berg 	memset(&qparam, 0, sizeof(qparam));
8745825fe10SJohannes Berg 
875679ef4eaSJohannes Berg 	use_11b = (local->oper_channel->band == IEEE80211_BAND_2GHZ) &&
876aa837e1dSJohannes Berg 		 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
8775825fe10SJohannes Berg 
878a8ce8544SStanislaw Gruszka 	/*
879a8ce8544SStanislaw Gruszka 	 * By default disable QoS in STA mode for old access points, which do
880a8ce8544SStanislaw Gruszka 	 * not support 802.11e. New APs will provide proper queue parameters,
881a8ce8544SStanislaw Gruszka 	 * that we will configure later.
882a8ce8544SStanislaw Gruszka 	 */
883a8ce8544SStanislaw Gruszka 	enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION);
884a8ce8544SStanislaw Gruszka 
88554bcbc69SJohannes Berg 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
886aa837e1dSJohannes Berg 		/* Set defaults according to 802.11-2007 Table 7-37 */
887aa837e1dSJohannes Berg 		aCWmax = 1023;
888aa837e1dSJohannes Berg 		if (use_11b)
889aa837e1dSJohannes Berg 			aCWmin = 31;
8905825fe10SJohannes Berg 		else
891aa837e1dSJohannes Berg 			aCWmin = 15;
8925825fe10SJohannes Berg 
893a8ce8544SStanislaw Gruszka 		if (enable_qos) {
89454bcbc69SJohannes Berg 			switch (ac) {
8951d98fb12SJohannes Berg 			case IEEE80211_AC_BK:
8967ba10a8eSJohannes Berg 				qparam.cw_max = aCWmax;
8977ba10a8eSJohannes Berg 				qparam.cw_min = aCWmin;
8985825fe10SJohannes Berg 				qparam.txop = 0;
899aa837e1dSJohannes Berg 				qparam.aifs = 7;
900aa837e1dSJohannes Berg 				break;
901a8ce8544SStanislaw Gruszka 			/* never happens but let's not leave undefined */
902a8ce8544SStanislaw Gruszka 			default:
9031d98fb12SJohannes Berg 			case IEEE80211_AC_BE:
9047ba10a8eSJohannes Berg 				qparam.cw_max = aCWmax;
9057ba10a8eSJohannes Berg 				qparam.cw_min = aCWmin;
906aa837e1dSJohannes Berg 				qparam.txop = 0;
907aa837e1dSJohannes Berg 				qparam.aifs = 3;
908aa837e1dSJohannes Berg 				break;
9091d98fb12SJohannes Berg 			case IEEE80211_AC_VI:
910aa837e1dSJohannes Berg 				qparam.cw_max = aCWmin;
911aa837e1dSJohannes Berg 				qparam.cw_min = (aCWmin + 1) / 2 - 1;
912aa837e1dSJohannes Berg 				if (use_11b)
913aa837e1dSJohannes Berg 					qparam.txop = 6016/32;
914aa837e1dSJohannes Berg 				else
915aa837e1dSJohannes Berg 					qparam.txop = 3008/32;
916aa837e1dSJohannes Berg 				qparam.aifs = 2;
917aa837e1dSJohannes Berg 				break;
9181d98fb12SJohannes Berg 			case IEEE80211_AC_VO:
919aa837e1dSJohannes Berg 				qparam.cw_max = (aCWmin + 1) / 2 - 1;
920aa837e1dSJohannes Berg 				qparam.cw_min = (aCWmin + 1) / 4 - 1;
921aa837e1dSJohannes Berg 				if (use_11b)
922aa837e1dSJohannes Berg 					qparam.txop = 3264/32;
923aa837e1dSJohannes Berg 				else
924aa837e1dSJohannes Berg 					qparam.txop = 1504/32;
925aa837e1dSJohannes Berg 				qparam.aifs = 2;
926aa837e1dSJohannes Berg 				break;
927aa837e1dSJohannes Berg 			}
928a8ce8544SStanislaw Gruszka 		} else {
929a8ce8544SStanislaw Gruszka 			/* Confiure old 802.11b/g medium access rules. */
930a8ce8544SStanislaw Gruszka 			qparam.cw_max = aCWmax;
931a8ce8544SStanislaw Gruszka 			qparam.cw_min = aCWmin;
932a8ce8544SStanislaw Gruszka 			qparam.txop = 0;
933a8ce8544SStanislaw Gruszka 			qparam.aifs = 2;
934a8ce8544SStanislaw Gruszka 		}
9355825fe10SJohannes Berg 
936ab13315aSKalle Valo 		qparam.uapsd = false;
937ab13315aSKalle Valo 
93854bcbc69SJohannes Berg 		sdata->tx_conf[ac] = qparam;
93954bcbc69SJohannes Berg 		drv_conf_tx(local, sdata, ac, &qparam);
940aa837e1dSJohannes Berg 	}
941e1b3ec1aSStanislaw Gruszka 
942f142c6b9SJohannes Berg 	if (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
943f142c6b9SJohannes Berg 	    sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) {
944a8ce8544SStanislaw Gruszka 		sdata->vif.bss_conf.qos = enable_qos;
9453abead59SJohannes Berg 		if (bss_notify)
9463abead59SJohannes Berg 			ieee80211_bss_info_change_notify(sdata,
9473abead59SJohannes Berg 							 BSS_CHANGED_QOS);
9485825fe10SJohannes Berg 	}
949d9734979SSujith }
950e50db65cSJohannes Berg 
95146900298SJohannes Berg void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
95246900298SJohannes Berg 				  const size_t supp_rates_len,
95346900298SJohannes Berg 				  const u8 *supp_rates)
95446900298SJohannes Berg {
95546900298SJohannes Berg 	struct ieee80211_local *local = sdata->local;
95646900298SJohannes Berg 	int i, have_higher_than_11mbit = 0;
95746900298SJohannes Berg 
95846900298SJohannes Berg 	/* cf. IEEE 802.11 9.2.12 */
95946900298SJohannes Berg 	for (i = 0; i < supp_rates_len; i++)
96046900298SJohannes Berg 		if ((supp_rates[i] & 0x7f) * 5 > 110)
96146900298SJohannes Berg 			have_higher_than_11mbit = 1;
96246900298SJohannes Berg 
963679ef4eaSJohannes Berg 	if (local->oper_channel->band == IEEE80211_BAND_2GHZ &&
96446900298SJohannes Berg 	    have_higher_than_11mbit)
96546900298SJohannes Berg 		sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
96646900298SJohannes Berg 	else
96746900298SJohannes Berg 		sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
96846900298SJohannes Berg 
9693abead59SJohannes Berg 	ieee80211_set_wmm_default(sdata, true);
97046900298SJohannes Berg }
97146900298SJohannes Berg 
972881d948cSJohannes Berg u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
97396dd22acSJohannes Berg 			      enum ieee80211_band band)
97496dd22acSJohannes Berg {
97596dd22acSJohannes Berg 	struct ieee80211_supported_band *sband;
97696dd22acSJohannes Berg 	struct ieee80211_rate *bitrates;
977881d948cSJohannes Berg 	u32 mandatory_rates;
97896dd22acSJohannes Berg 	enum ieee80211_rate_flags mandatory_flag;
97996dd22acSJohannes Berg 	int i;
98096dd22acSJohannes Berg 
98196dd22acSJohannes Berg 	sband = local->hw.wiphy->bands[band];
9824ee73f33SMichal Kazior 	if (WARN_ON(!sband))
9834ee73f33SMichal Kazior 		return 1;
98496dd22acSJohannes Berg 
98596dd22acSJohannes Berg 	if (band == IEEE80211_BAND_2GHZ)
98696dd22acSJohannes Berg 		mandatory_flag = IEEE80211_RATE_MANDATORY_B;
98796dd22acSJohannes Berg 	else
98896dd22acSJohannes Berg 		mandatory_flag = IEEE80211_RATE_MANDATORY_A;
98996dd22acSJohannes Berg 
99096dd22acSJohannes Berg 	bitrates = sband->bitrates;
99196dd22acSJohannes Berg 	mandatory_rates = 0;
99296dd22acSJohannes Berg 	for (i = 0; i < sband->n_bitrates; i++)
99396dd22acSJohannes Berg 		if (bitrates[i].flags & mandatory_flag)
99496dd22acSJohannes Berg 			mandatory_rates |= BIT(i);
99596dd22acSJohannes Berg 	return mandatory_rates;
99696dd22acSJohannes Berg }
99746900298SJohannes Berg 
99846900298SJohannes Berg void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
99946900298SJohannes Berg 			 u16 transaction, u16 auth_alg,
1000efa6a09dSAntonio Quartulli 			 u8 *extra, size_t extra_len, const u8 *da,
1001efa6a09dSAntonio Quartulli 			 const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx)
100246900298SJohannes Berg {
100346900298SJohannes Berg 	struct ieee80211_local *local = sdata->local;
100446900298SJohannes Berg 	struct sk_buff *skb;
100546900298SJohannes Berg 	struct ieee80211_mgmt *mgmt;
1006fffd0934SJohannes Berg 	int err;
100746900298SJohannes Berg 
100846900298SJohannes Berg 	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
100965fc73acSJouni Malinen 			    sizeof(*mgmt) + 6 + extra_len);
1010d15b8459SJoe Perches 	if (!skb)
101146900298SJohannes Berg 		return;
1012d15b8459SJoe Perches 
101346900298SJohannes Berg 	skb_reserve(skb, local->hw.extra_tx_headroom);
101446900298SJohannes Berg 
101546900298SJohannes Berg 	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
101646900298SJohannes Berg 	memset(mgmt, 0, 24 + 6);
101746900298SJohannes Berg 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
101846900298SJohannes Berg 					  IEEE80211_STYPE_AUTH);
1019efa6a09dSAntonio Quartulli 	memcpy(mgmt->da, da, ETH_ALEN);
102047846c9bSJohannes Berg 	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
102146900298SJohannes Berg 	memcpy(mgmt->bssid, bssid, ETH_ALEN);
102246900298SJohannes Berg 	mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg);
102346900298SJohannes Berg 	mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
102446900298SJohannes Berg 	mgmt->u.auth.status_code = cpu_to_le16(0);
102546900298SJohannes Berg 	if (extra)
102646900298SJohannes Berg 		memcpy(skb_put(skb, extra_len), extra, extra_len);
102746900298SJohannes Berg 
1028fffd0934SJohannes Berg 	if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
1029fffd0934SJohannes Berg 		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
1030fffd0934SJohannes Berg 		err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx);
1031fffd0934SJohannes Berg 		WARN_ON(err);
1032fffd0934SJohannes Berg 	}
1033fffd0934SJohannes Berg 
103462ae67beSJohannes Berg 	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
103562ae67beSJohannes Berg 	ieee80211_tx_skb(sdata, skb);
103646900298SJohannes Berg }
103746900298SJohannes Berg 
10386ae16775SAntonio Quartulli void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
10396ae16775SAntonio Quartulli 				    const u8 *bssid, u16 stype, u16 reason,
10406ae16775SAntonio Quartulli 				    bool send_frame, u8 *frame_buf)
10416ae16775SAntonio Quartulli {
10426ae16775SAntonio Quartulli 	struct ieee80211_local *local = sdata->local;
10436ae16775SAntonio Quartulli 	struct sk_buff *skb;
10446ae16775SAntonio Quartulli 	struct ieee80211_mgmt *mgmt = (void *)frame_buf;
10456ae16775SAntonio Quartulli 
10466ae16775SAntonio Quartulli 	/* build frame */
10476ae16775SAntonio Quartulli 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
10486ae16775SAntonio Quartulli 	mgmt->duration = 0; /* initialize only */
10496ae16775SAntonio Quartulli 	mgmt->seq_ctrl = 0; /* initialize only */
10506ae16775SAntonio Quartulli 	memcpy(mgmt->da, bssid, ETH_ALEN);
10516ae16775SAntonio Quartulli 	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
10526ae16775SAntonio Quartulli 	memcpy(mgmt->bssid, bssid, ETH_ALEN);
10536ae16775SAntonio Quartulli 	/* u.deauth.reason_code == u.disassoc.reason_code */
10546ae16775SAntonio Quartulli 	mgmt->u.deauth.reason_code = cpu_to_le16(reason);
10556ae16775SAntonio Quartulli 
10566ae16775SAntonio Quartulli 	if (send_frame) {
10576ae16775SAntonio Quartulli 		skb = dev_alloc_skb(local->hw.extra_tx_headroom +
10586ae16775SAntonio Quartulli 				    IEEE80211_DEAUTH_FRAME_LEN);
10596ae16775SAntonio Quartulli 		if (!skb)
10606ae16775SAntonio Quartulli 			return;
10616ae16775SAntonio Quartulli 
10626ae16775SAntonio Quartulli 		skb_reserve(skb, local->hw.extra_tx_headroom);
10636ae16775SAntonio Quartulli 
10646ae16775SAntonio Quartulli 		/* copy in frame */
10656ae16775SAntonio Quartulli 		memcpy(skb_put(skb, IEEE80211_DEAUTH_FRAME_LEN),
10666ae16775SAntonio Quartulli 		       mgmt, IEEE80211_DEAUTH_FRAME_LEN);
10676ae16775SAntonio Quartulli 
10686ae16775SAntonio Quartulli 		if (sdata->vif.type != NL80211_IFTYPE_STATION ||
10696ae16775SAntonio Quartulli 		    !(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED))
10706ae16775SAntonio Quartulli 			IEEE80211_SKB_CB(skb)->flags |=
10716ae16775SAntonio Quartulli 				IEEE80211_TX_INTFL_DONT_ENCRYPT;
10726ae16775SAntonio Quartulli 
10736ae16775SAntonio Quartulli 		ieee80211_tx_skb(sdata, skb);
10746ae16775SAntonio Quartulli 	}
10756ae16775SAntonio Quartulli }
10766ae16775SAntonio Quartulli 
1077de95a54bSJohannes Berg int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
10784d36ec58SJohannes Berg 			     const u8 *ie, size_t ie_len,
1079651b5225SJouni Malinen 			     enum ieee80211_band band, u32 rate_mask,
1080651b5225SJouni Malinen 			     u8 channel)
1081de95a54bSJohannes Berg {
1082de95a54bSJohannes Berg 	struct ieee80211_supported_band *sband;
10838e664fb3SJohannes Berg 	u8 *pos;
10848e664fb3SJohannes Berg 	size_t offset = 0, noffset;
10858e664fb3SJohannes Berg 	int supp_rates_len, i;
10868dcb2003SJouni Malinen 	u8 rates[32];
10878dcb2003SJouni Malinen 	int num_rates;
10888dcb2003SJouni Malinen 	int ext_rates_len;
1089de95a54bSJohannes Berg 
10904d36ec58SJohannes Berg 	sband = local->hw.wiphy->bands[band];
1091d811b3d5SArik Nemtsov 	if (WARN_ON_ONCE(!sband))
1092d811b3d5SArik Nemtsov 		return 0;
1093de95a54bSJohannes Berg 
1094de95a54bSJohannes Berg 	pos = buffer;
1095de95a54bSJohannes Berg 
10968dcb2003SJouni Malinen 	num_rates = 0;
10978dcb2003SJouni Malinen 	for (i = 0; i < sband->n_bitrates; i++) {
10988dcb2003SJouni Malinen 		if ((BIT(i) & rate_mask) == 0)
10998dcb2003SJouni Malinen 			continue; /* skip rate */
11008dcb2003SJouni Malinen 		rates[num_rates++] = (u8) (sband->bitrates[i].bitrate / 5);
11018dcb2003SJouni Malinen 	}
11028dcb2003SJouni Malinen 
11038dcb2003SJouni Malinen 	supp_rates_len = min_t(int, num_rates, 8);
11048e664fb3SJohannes Berg 
1105de95a54bSJohannes Berg 	*pos++ = WLAN_EID_SUPP_RATES;
11068e664fb3SJohannes Berg 	*pos++ = supp_rates_len;
11078dcb2003SJouni Malinen 	memcpy(pos, rates, supp_rates_len);
11088dcb2003SJouni Malinen 	pos += supp_rates_len;
1109de95a54bSJohannes Berg 
11108e664fb3SJohannes Berg 	/* insert "request information" if in custom IEs */
11118e664fb3SJohannes Berg 	if (ie && ie_len) {
11128e664fb3SJohannes Berg 		static const u8 before_extrates[] = {
11138e664fb3SJohannes Berg 			WLAN_EID_SSID,
11148e664fb3SJohannes Berg 			WLAN_EID_SUPP_RATES,
11158e664fb3SJohannes Berg 			WLAN_EID_REQUEST,
11168e664fb3SJohannes Berg 		};
11178e664fb3SJohannes Berg 		noffset = ieee80211_ie_split(ie, ie_len,
11188e664fb3SJohannes Berg 					     before_extrates,
11198e664fb3SJohannes Berg 					     ARRAY_SIZE(before_extrates),
11208e664fb3SJohannes Berg 					     offset);
11218e664fb3SJohannes Berg 		memcpy(pos, ie + offset, noffset - offset);
11228e664fb3SJohannes Berg 		pos += noffset - offset;
11238e664fb3SJohannes Berg 		offset = noffset;
11248e664fb3SJohannes Berg 	}
11258e664fb3SJohannes Berg 
11268dcb2003SJouni Malinen 	ext_rates_len = num_rates - supp_rates_len;
11278dcb2003SJouni Malinen 	if (ext_rates_len > 0) {
1128de95a54bSJohannes Berg 		*pos++ = WLAN_EID_EXT_SUPP_RATES;
11298dcb2003SJouni Malinen 		*pos++ = ext_rates_len;
11308dcb2003SJouni Malinen 		memcpy(pos, rates + supp_rates_len, ext_rates_len);
11318dcb2003SJouni Malinen 		pos += ext_rates_len;
11328e664fb3SJohannes Berg 	}
11338e664fb3SJohannes Berg 
1134651b5225SJouni Malinen 	if (channel && sband->band == IEEE80211_BAND_2GHZ) {
1135651b5225SJouni Malinen 		*pos++ = WLAN_EID_DS_PARAMS;
1136651b5225SJouni Malinen 		*pos++ = 1;
1137651b5225SJouni Malinen 		*pos++ = channel;
1138651b5225SJouni Malinen 	}
1139651b5225SJouni Malinen 
11408e664fb3SJohannes Berg 	/* insert custom IEs that go before HT */
11418e664fb3SJohannes Berg 	if (ie && ie_len) {
11428e664fb3SJohannes Berg 		static const u8 before_ht[] = {
11438e664fb3SJohannes Berg 			WLAN_EID_SSID,
11448e664fb3SJohannes Berg 			WLAN_EID_SUPP_RATES,
11458e664fb3SJohannes Berg 			WLAN_EID_REQUEST,
11468e664fb3SJohannes Berg 			WLAN_EID_EXT_SUPP_RATES,
11478e664fb3SJohannes Berg 			WLAN_EID_DS_PARAMS,
11488e664fb3SJohannes Berg 			WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
11498e664fb3SJohannes Berg 		};
11508e664fb3SJohannes Berg 		noffset = ieee80211_ie_split(ie, ie_len,
11518e664fb3SJohannes Berg 					     before_ht, ARRAY_SIZE(before_ht),
11528e664fb3SJohannes Berg 					     offset);
11538e664fb3SJohannes Berg 		memcpy(pos, ie + offset, noffset - offset);
11548e664fb3SJohannes Berg 		pos += noffset - offset;
11558e664fb3SJohannes Berg 		offset = noffset;
1156de95a54bSJohannes Berg 	}
1157de95a54bSJohannes Berg 
115842e7aa77SAlexander Simon 	if (sband->ht_cap.ht_supported)
1159ef96a842SBen Greear 		pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
1160ef96a842SBen Greear 						sband->ht_cap.cap);
11615ef2d41aSJohannes Berg 
1162de95a54bSJohannes Berg 	/*
1163de95a54bSJohannes Berg 	 * If adding more here, adjust code in main.c
1164de95a54bSJohannes Berg 	 * that calculates local->scan_ies_len.
1165de95a54bSJohannes Berg 	 */
1166de95a54bSJohannes Berg 
11678e664fb3SJohannes Berg 	/* add any remaining custom IEs */
11688e664fb3SJohannes Berg 	if (ie && ie_len) {
11698e664fb3SJohannes Berg 		noffset = ie_len;
11708e664fb3SJohannes Berg 		memcpy(pos, ie + offset, noffset - offset);
11718e664fb3SJohannes Berg 		pos += noffset - offset;
1172de95a54bSJohannes Berg 	}
1173de95a54bSJohannes Berg 
1174ba0afa2fSMahesh Palivela 	if (sband->vht_cap.vht_supported)
1175ba0afa2fSMahesh Palivela 		pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap,
1176ba0afa2fSMahesh Palivela 						 sband->vht_cap.cap);
1177ba0afa2fSMahesh Palivela 
1178de95a54bSJohannes Berg 	return pos - buffer;
1179de95a54bSJohannes Berg }
1180de95a54bSJohannes Berg 
1181a619a4c0SJuuso Oikarinen struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
118285a237feSJohannes Berg 					  u8 *dst, u32 ratemask,
11836b77863bSJohannes Berg 					  struct ieee80211_channel *chan,
1184de95a54bSJohannes Berg 					  const u8 *ssid, size_t ssid_len,
1185a806c558SPaul Stewart 					  const u8 *ie, size_t ie_len,
1186a806c558SPaul Stewart 					  bool directed)
118746900298SJohannes Berg {
118846900298SJohannes Berg 	struct ieee80211_local *local = sdata->local;
118946900298SJohannes Berg 	struct sk_buff *skb;
119046900298SJohannes Berg 	struct ieee80211_mgmt *mgmt;
11917c12ce8bSKalle Valo 	size_t buf_len;
11927c12ce8bSKalle Valo 	u8 *buf;
11936b77863bSJohannes Berg 	u8 chan_no;
119446900298SJohannes Berg 
11957c12ce8bSKalle Valo 	/* FIXME: come up with a proper value */
11967c12ce8bSKalle Valo 	buf = kmalloc(200 + ie_len, GFP_KERNEL);
1197d15b8459SJoe Perches 	if (!buf)
1198a619a4c0SJuuso Oikarinen 		return NULL;
119946900298SJohannes Berg 
1200a806c558SPaul Stewart 	/*
1201a806c558SPaul Stewart 	 * Do not send DS Channel parameter for directed probe requests
1202a806c558SPaul Stewart 	 * in order to maximize the chance that we get a response.  Some
1203a806c558SPaul Stewart 	 * badly-behaved APs don't respond when this parameter is included.
1204a806c558SPaul Stewart 	 */
1205a806c558SPaul Stewart 	if (directed)
12066b77863bSJohannes Berg 		chan_no = 0;
1207a806c558SPaul Stewart 	else
12086b77863bSJohannes Berg 		chan_no = ieee80211_frequency_to_channel(chan->center_freq);
1209651b5225SJouni Malinen 
12106b77863bSJohannes Berg 	buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, chan->band,
12116b77863bSJohannes Berg 					   ratemask, chan_no);
12127c12ce8bSKalle Valo 
12137c12ce8bSKalle Valo 	skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
12147c12ce8bSKalle Valo 				     ssid, ssid_len,
12157c12ce8bSKalle Valo 				     buf, buf_len);
12165b2bbf75SJohannes Berg 	if (!skb)
12175b2bbf75SJohannes Berg 		goto out;
12187c12ce8bSKalle Valo 
121946900298SJohannes Berg 	if (dst) {
12207c12ce8bSKalle Valo 		mgmt = (struct ieee80211_mgmt *) skb->data;
122146900298SJohannes Berg 		memcpy(mgmt->da, dst, ETH_ALEN);
122246900298SJohannes Berg 		memcpy(mgmt->bssid, dst, ETH_ALEN);
122346900298SJohannes Berg 	}
122446900298SJohannes Berg 
122562ae67beSJohannes Berg 	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
12265b2bbf75SJohannes Berg 
12275b2bbf75SJohannes Berg  out:
1228145b6d1aSMing Lei 	kfree(buf);
1229a619a4c0SJuuso Oikarinen 
1230a619a4c0SJuuso Oikarinen 	return skb;
1231a619a4c0SJuuso Oikarinen }
1232a619a4c0SJuuso Oikarinen 
1233a619a4c0SJuuso Oikarinen void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
1234a619a4c0SJuuso Oikarinen 			      const u8 *ssid, size_t ssid_len,
1235a806c558SPaul Stewart 			      const u8 *ie, size_t ie_len,
1236fe94fe05SJohannes Berg 			      u32 ratemask, bool directed, bool no_cck,
1237fe94fe05SJohannes Berg 			      struct ieee80211_channel *channel)
1238a619a4c0SJuuso Oikarinen {
1239a619a4c0SJuuso Oikarinen 	struct sk_buff *skb;
1240a619a4c0SJuuso Oikarinen 
1241fe94fe05SJohannes Berg 	skb = ieee80211_build_probe_req(sdata, dst, ratemask, channel,
12426b77863bSJohannes Berg 					ssid, ssid_len,
124385a237feSJohannes Berg 					ie, ie_len, directed);
1244aad14cebSRajkumar Manoharan 	if (skb) {
1245aad14cebSRajkumar Manoharan 		if (no_cck)
1246aad14cebSRajkumar Manoharan 			IEEE80211_SKB_CB(skb)->flags |=
1247aad14cebSRajkumar Manoharan 				IEEE80211_TX_CTL_NO_CCK_RATE;
1248a619a4c0SJuuso Oikarinen 		ieee80211_tx_skb(sdata, skb);
124946900298SJohannes Berg 	}
1250aad14cebSRajkumar Manoharan }
125146900298SJohannes Berg 
125246900298SJohannes Berg u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
125346900298SJohannes Berg 			    struct ieee802_11_elems *elems,
12549ebb61a2SAshok Nagarajan 			    enum ieee80211_band band, u32 *basic_rates)
125546900298SJohannes Berg {
125646900298SJohannes Berg 	struct ieee80211_supported_band *sband;
125746900298SJohannes Berg 	struct ieee80211_rate *bitrates;
125846900298SJohannes Berg 	size_t num_rates;
125946900298SJohannes Berg 	u32 supp_rates;
126046900298SJohannes Berg 	int i, j;
126146900298SJohannes Berg 	sband = local->hw.wiphy->bands[band];
126246900298SJohannes Berg 
12634ee73f33SMichal Kazior 	if (WARN_ON(!sband))
12644ee73f33SMichal Kazior 		return 1;
126546900298SJohannes Berg 
126646900298SJohannes Berg 	bitrates = sband->bitrates;
126746900298SJohannes Berg 	num_rates = sband->n_bitrates;
126846900298SJohannes Berg 	supp_rates = 0;
126946900298SJohannes Berg 	for (i = 0; i < elems->supp_rates_len +
127046900298SJohannes Berg 		     elems->ext_supp_rates_len; i++) {
127146900298SJohannes Berg 		u8 rate = 0;
127246900298SJohannes Berg 		int own_rate;
12739ebb61a2SAshok Nagarajan 		bool is_basic;
127446900298SJohannes Berg 		if (i < elems->supp_rates_len)
127546900298SJohannes Berg 			rate = elems->supp_rates[i];
127646900298SJohannes Berg 		else if (elems->ext_supp_rates)
127746900298SJohannes Berg 			rate = elems->ext_supp_rates
127846900298SJohannes Berg 				[i - elems->supp_rates_len];
127946900298SJohannes Berg 		own_rate = 5 * (rate & 0x7f);
12809ebb61a2SAshok Nagarajan 		is_basic = !!(rate & 0x80);
12819ebb61a2SAshok Nagarajan 
12829ebb61a2SAshok Nagarajan 		if (is_basic && (rate & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
12839ebb61a2SAshok Nagarajan 			continue;
12849ebb61a2SAshok Nagarajan 
12859ebb61a2SAshok Nagarajan 		for (j = 0; j < num_rates; j++) {
12869ebb61a2SAshok Nagarajan 			if (bitrates[j].bitrate == own_rate) {
128746900298SJohannes Berg 				supp_rates |= BIT(j);
12889ebb61a2SAshok Nagarajan 				if (basic_rates && is_basic)
12899ebb61a2SAshok Nagarajan 					*basic_rates |= BIT(j);
12909ebb61a2SAshok Nagarajan 			}
12919ebb61a2SAshok Nagarajan 		}
129246900298SJohannes Berg 	}
129346900298SJohannes Berg 	return supp_rates;
129446900298SJohannes Berg }
1295f2753ddbSJohannes Berg 
129684f6a01cSJohannes Berg void ieee80211_stop_device(struct ieee80211_local *local)
129784f6a01cSJohannes Berg {
129884f6a01cSJohannes Berg 	ieee80211_led_radio(local, false);
129967408c8cSJohannes Berg 	ieee80211_mod_tpt_led_trig(local, 0, IEEE80211_TPT_LEDTRIG_FL_RADIO);
130084f6a01cSJohannes Berg 
130184f6a01cSJohannes Berg 	cancel_work_sync(&local->reconfig_filter);
130284f6a01cSJohannes Berg 
130384f6a01cSJohannes Berg 	flush_workqueue(local->workqueue);
1304678f415fSLennert Buytenhek 	drv_stop(local);
130584f6a01cSJohannes Berg }
130684f6a01cSJohannes Berg 
1307f2753ddbSJohannes Berg int ieee80211_reconfig(struct ieee80211_local *local)
1308f2753ddbSJohannes Berg {
1309f2753ddbSJohannes Berg 	struct ieee80211_hw *hw = &local->hw;
1310f2753ddbSJohannes Berg 	struct ieee80211_sub_if_data *sdata;
1311f2753ddbSJohannes Berg 	struct sta_info *sta;
13122683d65bSEliad Peller 	int res, i;
13135bb644a0SJohannes Berg 
1314eecc4800SJohannes Berg #ifdef CONFIG_PM
1315ceb99fe0SJohannes Berg 	if (local->suspended)
1316ceb99fe0SJohannes Berg 		local->resuming = true;
1317f2753ddbSJohannes Berg 
1318eecc4800SJohannes Berg 	if (local->wowlan) {
1319eecc4800SJohannes Berg 		local->wowlan = false;
1320eecc4800SJohannes Berg 		res = drv_resume(local);
1321eecc4800SJohannes Berg 		if (res < 0) {
1322eecc4800SJohannes Berg 			local->resuming = false;
1323eecc4800SJohannes Berg 			return res;
1324eecc4800SJohannes Berg 		}
1325eecc4800SJohannes Berg 		if (res == 0)
1326eecc4800SJohannes Berg 			goto wake_up;
1327eecc4800SJohannes Berg 		WARN_ON(res > 1);
1328eecc4800SJohannes Berg 		/*
1329eecc4800SJohannes Berg 		 * res is 1, which means the driver requested
1330eecc4800SJohannes Berg 		 * to go through a regular reset on wakeup.
1331eecc4800SJohannes Berg 		 */
1332eecc4800SJohannes Berg 	}
1333eecc4800SJohannes Berg #endif
133494f9b97bSJohannes Berg 	/* everything else happens only if HW was up & running */
133594f9b97bSJohannes Berg 	if (!local->open_count)
133694f9b97bSJohannes Berg 		goto wake_up;
133794f9b97bSJohannes Berg 
133824feda00SLuis R. Rodriguez 	/*
133924feda00SLuis R. Rodriguez 	 * Upon resume hardware can sometimes be goofy due to
134024feda00SLuis R. Rodriguez 	 * various platform / driver / bus issues, so restarting
134124feda00SLuis R. Rodriguez 	 * the device may at times not work immediately. Propagate
134224feda00SLuis R. Rodriguez 	 * the error.
134324feda00SLuis R. Rodriguez 	 */
134424487981SJohannes Berg 	res = drv_start(local);
134524feda00SLuis R. Rodriguez 	if (res) {
1346c7a00dc7SJohn W. Linville 		WARN(local->suspended, "Hardware became unavailable "
1347c7a00dc7SJohn W. Linville 		     "upon resume. This could be a software issue "
1348c7a00dc7SJohn W. Linville 		     "prior to suspend or a hardware issue.\n");
134924feda00SLuis R. Rodriguez 		return res;
135024feda00SLuis R. Rodriguez 	}
1351f2753ddbSJohannes Berg 
13527f281975SYogesh Ashok Powar 	/* setup fragmentation threshold */
13537f281975SYogesh Ashok Powar 	drv_set_frag_threshold(local, hw->wiphy->frag_threshold);
13547f281975SYogesh Ashok Powar 
13557f281975SYogesh Ashok Powar 	/* setup RTS threshold */
13567f281975SYogesh Ashok Powar 	drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
13577f281975SYogesh Ashok Powar 
13587f281975SYogesh Ashok Powar 	/* reset coverage class */
13597f281975SYogesh Ashok Powar 	drv_set_coverage_class(local, hw->wiphy->coverage_class);
13607f281975SYogesh Ashok Powar 
13611f87f7d3SJohannes Berg 	ieee80211_led_radio(local, true);
136267408c8cSJohannes Berg 	ieee80211_mod_tpt_led_trig(local,
136367408c8cSJohannes Berg 				   IEEE80211_TPT_LEDTRIG_FL_RADIO, 0);
1364f2753ddbSJohannes Berg 
1365f2753ddbSJohannes Berg 	/* add interfaces */
13664b6f1dd6SJohannes Berg 	sdata = rtnl_dereference(local->monitor_sdata);
13674b6f1dd6SJohannes Berg 	if (sdata) {
13684b6f1dd6SJohannes Berg 		res = drv_add_interface(local, sdata);
13694b6f1dd6SJohannes Berg 		if (WARN_ON(res)) {
13704b6f1dd6SJohannes Berg 			rcu_assign_pointer(local->monitor_sdata, NULL);
13714b6f1dd6SJohannes Berg 			synchronize_net();
13724b6f1dd6SJohannes Berg 			kfree(sdata);
13734b6f1dd6SJohannes Berg 		}
13744b6f1dd6SJohannes Berg 	}
13754b6f1dd6SJohannes Berg 
1376f2753ddbSJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
1377f2753ddbSJohannes Berg 		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
1378f2753ddbSJohannes Berg 		    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
13791ed32e4fSJohannes Berg 		    ieee80211_sdata_running(sdata))
13807b7eab6fSJohannes Berg 			res = drv_add_interface(local, sdata);
1381f2753ddbSJohannes Berg 	}
1382f2753ddbSJohannes Berg 
1383f2753ddbSJohannes Berg 	/* add STAs back */
138434e89507SJohannes Berg 	mutex_lock(&local->sta_mtx);
1385f2753ddbSJohannes Berg 	list_for_each_entry(sta, &local->sta_list, list) {
1386f09603a2SJohannes Berg 		enum ieee80211_sta_state state;
1387f09603a2SJohannes Berg 
13882e8d397eSArik Nemtsov 		if (!sta->uploaded)
13892e8d397eSArik Nemtsov 			continue;
13902e8d397eSArik Nemtsov 
13912e8d397eSArik Nemtsov 		/* AP-mode stations will be added later */
13922e8d397eSArik Nemtsov 		if (sta->sdata->vif.type == NL80211_IFTYPE_AP)
13932e8d397eSArik Nemtsov 			continue;
13942e8d397eSArik Nemtsov 
1395f09603a2SJohannes Berg 		for (state = IEEE80211_STA_NOTEXIST;
1396bd34ab62SMeenakshi Venkataraman 		     state < sta->sta_state; state++)
13972e8d397eSArik Nemtsov 			WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
13982e8d397eSArik Nemtsov 					      state + 1));
1399f2753ddbSJohannes Berg 	}
140034e89507SJohannes Berg 	mutex_unlock(&local->sta_mtx);
1401f2753ddbSJohannes Berg 
14022683d65bSEliad Peller 	/* reconfigure tx conf */
140354bcbc69SJohannes Berg 	if (hw->queues >= IEEE80211_NUM_ACS) {
1404f6f3def3SEliad Peller 		list_for_each_entry(sdata, &local->interfaces, list) {
1405f6f3def3SEliad Peller 			if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
1406f6f3def3SEliad Peller 			    sdata->vif.type == NL80211_IFTYPE_MONITOR ||
1407f6f3def3SEliad Peller 			    !ieee80211_sdata_running(sdata))
1408f6f3def3SEliad Peller 				continue;
1409f6f3def3SEliad Peller 
141054bcbc69SJohannes Berg 			for (i = 0; i < IEEE80211_NUM_ACS; i++)
141154bcbc69SJohannes Berg 				drv_conf_tx(local, sdata, i,
141254bcbc69SJohannes Berg 					    &sdata->tx_conf[i]);
141354bcbc69SJohannes Berg 		}
1414f6f3def3SEliad Peller 	}
14152683d65bSEliad Peller 
1416f2753ddbSJohannes Berg 	/* reconfigure hardware */
1417f2753ddbSJohannes Berg 	ieee80211_hw_config(local, ~0);
1418f2753ddbSJohannes Berg 
1419f2753ddbSJohannes Berg 	ieee80211_configure_filter(local);
1420f2753ddbSJohannes Berg 
1421f2753ddbSJohannes Berg 	/* Finally also reconfigure all the BSS information */
1422f2753ddbSJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
1423ac8dd506SJohannes Berg 		u32 changed;
1424ac8dd506SJohannes Berg 
14259607e6b6SJohannes Berg 		if (!ieee80211_sdata_running(sdata))
1426f2753ddbSJohannes Berg 			continue;
1427ac8dd506SJohannes Berg 
1428ac8dd506SJohannes Berg 		/* common change flags for all interface types */
1429ac8dd506SJohannes Berg 		changed = BSS_CHANGED_ERP_CTS_PROT |
1430ac8dd506SJohannes Berg 			  BSS_CHANGED_ERP_PREAMBLE |
1431ac8dd506SJohannes Berg 			  BSS_CHANGED_ERP_SLOT |
1432ac8dd506SJohannes Berg 			  BSS_CHANGED_HT |
1433ac8dd506SJohannes Berg 			  BSS_CHANGED_BASIC_RATES |
1434ac8dd506SJohannes Berg 			  BSS_CHANGED_BEACON_INT |
1435ac8dd506SJohannes Berg 			  BSS_CHANGED_BSSID |
14364ced3f74SJohannes Berg 			  BSS_CHANGED_CQM |
143755de47f6SEliad Peller 			  BSS_CHANGED_QOS |
143855de47f6SEliad Peller 			  BSS_CHANGED_IDLE;
1439ac8dd506SJohannes Berg 
1440f2753ddbSJohannes Berg 		switch (sdata->vif.type) {
1441f2753ddbSJohannes Berg 		case NL80211_IFTYPE_STATION:
14420d392e93SEliad Peller 			changed |= BSS_CHANGED_ASSOC |
1443ab095877SEliad Peller 				   BSS_CHANGED_ARP_FILTER |
1444ab095877SEliad Peller 				   BSS_CHANGED_PS;
1445a7b545f7SEliad Peller 			mutex_lock(&sdata->u.mgd.mtx);
1446ac8dd506SJohannes Berg 			ieee80211_bss_info_change_notify(sdata, changed);
1447a7b545f7SEliad Peller 			mutex_unlock(&sdata->u.mgd.mtx);
1448ac8dd506SJohannes Berg 			break;
1449f2753ddbSJohannes Berg 		case NL80211_IFTYPE_ADHOC:
1450ac8dd506SJohannes Berg 			changed |= BSS_CHANGED_IBSS;
1451ac8dd506SJohannes Berg 			/* fall through */
1452f2753ddbSJohannes Berg 		case NL80211_IFTYPE_AP:
1453e7979ac7SArik Nemtsov 			changed |= BSS_CHANGED_SSID;
1454e7979ac7SArik Nemtsov 
1455e7979ac7SArik Nemtsov 			if (sdata->vif.type == NL80211_IFTYPE_AP)
1456e7979ac7SArik Nemtsov 				changed |= BSS_CHANGED_AP_PROBE_RESP;
1457e7979ac7SArik Nemtsov 
14587827493bSArik Nemtsov 			/* fall through */
1459f2753ddbSJohannes Berg 		case NL80211_IFTYPE_MESH_POINT:
1460ac8dd506SJohannes Berg 			changed |= BSS_CHANGED_BEACON |
1461ac8dd506SJohannes Berg 				   BSS_CHANGED_BEACON_ENABLED;
14622d0ddec5SJohannes Berg 			ieee80211_bss_info_change_notify(sdata, changed);
1463f2753ddbSJohannes Berg 			break;
1464f2753ddbSJohannes Berg 		case NL80211_IFTYPE_WDS:
1465f2753ddbSJohannes Berg 			break;
1466f2753ddbSJohannes Berg 		case NL80211_IFTYPE_AP_VLAN:
1467f2753ddbSJohannes Berg 		case NL80211_IFTYPE_MONITOR:
1468f2753ddbSJohannes Berg 			/* ignore virtual */
1469f2753ddbSJohannes Berg 			break;
147098104fdeSJohannes Berg 		case NL80211_IFTYPE_P2P_DEVICE:
1471f142c6b9SJohannes Berg 			changed = BSS_CHANGED_IDLE;
1472f142c6b9SJohannes Berg 			break;
1473f2753ddbSJohannes Berg 		case NL80211_IFTYPE_UNSPECIFIED:
14742e161f78SJohannes Berg 		case NUM_NL80211_IFTYPES:
14752ca27bcfSJohannes Berg 		case NL80211_IFTYPE_P2P_CLIENT:
14762ca27bcfSJohannes Berg 		case NL80211_IFTYPE_P2P_GO:
1477f2753ddbSJohannes Berg 			WARN_ON(1);
1478f2753ddbSJohannes Berg 			break;
1479f2753ddbSJohannes Berg 		}
1480f2753ddbSJohannes Berg 	}
1481f2753ddbSJohannes Berg 
14828e1b23b9SEyal Shapira 	ieee80211_recalc_ps(local, -1);
14838e1b23b9SEyal Shapira 
14842a419056SJohannes Berg 	/*
14856e1b1b24SEliad Peller 	 * The sta might be in psm against the ap (e.g. because
14866e1b1b24SEliad Peller 	 * this was the state before a hw restart), so we
14876e1b1b24SEliad Peller 	 * explicitly send a null packet in order to make sure
14886e1b1b24SEliad Peller 	 * it'll sync against the ap (and get out of psm).
14896e1b1b24SEliad Peller 	 */
14906e1b1b24SEliad Peller 	if (!(local->hw.conf.flags & IEEE80211_CONF_PS)) {
14916e1b1b24SEliad Peller 		list_for_each_entry(sdata, &local->interfaces, list) {
14926e1b1b24SEliad Peller 			if (sdata->vif.type != NL80211_IFTYPE_STATION)
14936e1b1b24SEliad Peller 				continue;
149420f544eeSJohannes Berg 			if (!sdata->u.mgd.associated)
149520f544eeSJohannes Berg 				continue;
14966e1b1b24SEliad Peller 
14976e1b1b24SEliad Peller 			ieee80211_send_nullfunc(local, sdata, 0);
14986e1b1b24SEliad Peller 		}
14996e1b1b24SEliad Peller 	}
15006e1b1b24SEliad Peller 
15012e8d397eSArik Nemtsov 	/* APs are now beaconing, add back stations */
15022e8d397eSArik Nemtsov 	mutex_lock(&local->sta_mtx);
15032e8d397eSArik Nemtsov 	list_for_each_entry(sta, &local->sta_list, list) {
15042e8d397eSArik Nemtsov 		enum ieee80211_sta_state state;
15052e8d397eSArik Nemtsov 
15062e8d397eSArik Nemtsov 		if (!sta->uploaded)
15072e8d397eSArik Nemtsov 			continue;
15082e8d397eSArik Nemtsov 
15092e8d397eSArik Nemtsov 		if (sta->sdata->vif.type != NL80211_IFTYPE_AP)
15102e8d397eSArik Nemtsov 			continue;
15112e8d397eSArik Nemtsov 
15122e8d397eSArik Nemtsov 		for (state = IEEE80211_STA_NOTEXIST;
15132e8d397eSArik Nemtsov 		     state < sta->sta_state; state++)
15142e8d397eSArik Nemtsov 			WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
15152e8d397eSArik Nemtsov 					      state + 1));
15162e8d397eSArik Nemtsov 	}
15172e8d397eSArik Nemtsov 	mutex_unlock(&local->sta_mtx);
15182e8d397eSArik Nemtsov 
15197b21aea0SEyal Shapira 	/* add back keys */
15207b21aea0SEyal Shapira 	list_for_each_entry(sdata, &local->interfaces, list)
15217b21aea0SEyal Shapira 		if (ieee80211_sdata_running(sdata))
15227b21aea0SEyal Shapira 			ieee80211_enable_keys(sdata);
15237b21aea0SEyal Shapira 
1524c6209488SEliad Peller  wake_up:
152504800adaSArik Nemtsov 	local->in_reconfig = false;
152604800adaSArik Nemtsov 	barrier();
152704800adaSArik Nemtsov 
15286e1b1b24SEliad Peller 	/*
15292a419056SJohannes Berg 	 * Clear the WLAN_STA_BLOCK_BA flag so new aggregation
15302a419056SJohannes Berg 	 * sessions can be established after a resume.
15312a419056SJohannes Berg 	 *
15322a419056SJohannes Berg 	 * Also tear down aggregation sessions since reconfiguring
15332a419056SJohannes Berg 	 * them in a hardware restart scenario is not easily done
15342a419056SJohannes Berg 	 * right now, and the hardware will have lost information
15352a419056SJohannes Berg 	 * about the sessions, but we and the AP still think they
15362a419056SJohannes Berg 	 * are active. This is really a workaround though.
15372a419056SJohannes Berg 	 */
153874e2bd1fSWey-Yi Guy 	if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
15392a419056SJohannes Berg 		mutex_lock(&local->sta_mtx);
15402a419056SJohannes Berg 
15412a419056SJohannes Berg 		list_for_each_entry(sta, &local->sta_list, list) {
154253f73c09SJohannes Berg 			ieee80211_sta_tear_down_BA_sessions(sta, true);
1543c2c98fdeSJohannes Berg 			clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
154474e2bd1fSWey-Yi Guy 		}
15452a419056SJohannes Berg 
15462a419056SJohannes Berg 		mutex_unlock(&local->sta_mtx);
154774e2bd1fSWey-Yi Guy 	}
154874e2bd1fSWey-Yi Guy 
1549f2753ddbSJohannes Berg 	ieee80211_wake_queues_by_reason(hw,
1550f2753ddbSJohannes Berg 			IEEE80211_QUEUE_STOP_REASON_SUSPEND);
1551f2753ddbSJohannes Berg 
15525bb644a0SJohannes Berg 	/*
15535bb644a0SJohannes Berg 	 * If this is for hw restart things are still running.
15545bb644a0SJohannes Berg 	 * We may want to change that later, however.
15555bb644a0SJohannes Berg 	 */
1556ceb99fe0SJohannes Berg 	if (!local->suspended)
15575bb644a0SJohannes Berg 		return 0;
15585bb644a0SJohannes Berg 
15595bb644a0SJohannes Berg #ifdef CONFIG_PM
1560ceb99fe0SJohannes Berg 	/* first set suspended false, then resuming */
15615bb644a0SJohannes Berg 	local->suspended = false;
1562ceb99fe0SJohannes Berg 	mb();
1563ceb99fe0SJohannes Berg 	local->resuming = false;
15645bb644a0SJohannes Berg 
15655bb644a0SJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
15665bb644a0SJohannes Berg 		switch(sdata->vif.type) {
15675bb644a0SJohannes Berg 		case NL80211_IFTYPE_STATION:
15685bb644a0SJohannes Berg 			ieee80211_sta_restart(sdata);
15695bb644a0SJohannes Berg 			break;
15705bb644a0SJohannes Berg 		case NL80211_IFTYPE_ADHOC:
15715bb644a0SJohannes Berg 			ieee80211_ibss_restart(sdata);
15725bb644a0SJohannes Berg 			break;
15735bb644a0SJohannes Berg 		case NL80211_IFTYPE_MESH_POINT:
15745bb644a0SJohannes Berg 			ieee80211_mesh_restart(sdata);
15755bb644a0SJohannes Berg 			break;
15765bb644a0SJohannes Berg 		default:
15775bb644a0SJohannes Berg 			break;
15785bb644a0SJohannes Berg 		}
15795bb644a0SJohannes Berg 	}
15805bb644a0SJohannes Berg 
158126d59535SJohannes Berg 	mod_timer(&local->sta_cleanup, jiffies + 1);
15825bb644a0SJohannes Berg 
158334e89507SJohannes Berg 	mutex_lock(&local->sta_mtx);
15845bb644a0SJohannes Berg 	list_for_each_entry(sta, &local->sta_list, list)
15855bb644a0SJohannes Berg 		mesh_plink_restart(sta);
158634e89507SJohannes Berg 	mutex_unlock(&local->sta_mtx);
15875bb644a0SJohannes Berg #else
15885bb644a0SJohannes Berg 	WARN_ON(1);
15895bb644a0SJohannes Berg #endif
1590f2753ddbSJohannes Berg 	return 0;
1591f2753ddbSJohannes Berg }
159242935ecaSLuis R. Rodriguez 
159395acac61SJohannes Berg void ieee80211_resume_disconnect(struct ieee80211_vif *vif)
159495acac61SJohannes Berg {
159595acac61SJohannes Berg 	struct ieee80211_sub_if_data *sdata;
159695acac61SJohannes Berg 	struct ieee80211_local *local;
159795acac61SJohannes Berg 	struct ieee80211_key *key;
159895acac61SJohannes Berg 
159995acac61SJohannes Berg 	if (WARN_ON(!vif))
160095acac61SJohannes Berg 		return;
160195acac61SJohannes Berg 
160295acac61SJohannes Berg 	sdata = vif_to_sdata(vif);
160395acac61SJohannes Berg 	local = sdata->local;
160495acac61SJohannes Berg 
160595acac61SJohannes Berg 	if (WARN_ON(!local->resuming))
160695acac61SJohannes Berg 		return;
160795acac61SJohannes Berg 
160895acac61SJohannes Berg 	if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
160995acac61SJohannes Berg 		return;
161095acac61SJohannes Berg 
161195acac61SJohannes Berg 	sdata->flags |= IEEE80211_SDATA_DISCONNECT_RESUME;
161295acac61SJohannes Berg 
161395acac61SJohannes Berg 	mutex_lock(&local->key_mtx);
161495acac61SJohannes Berg 	list_for_each_entry(key, &sdata->key_list, list)
161595acac61SJohannes Berg 		key->flags |= KEY_FLAG_TAINTED;
161695acac61SJohannes Berg 	mutex_unlock(&local->key_mtx);
161795acac61SJohannes Berg }
161895acac61SJohannes Berg EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect);
161995acac61SJohannes Berg 
16200f78231bSJohannes Berg static int check_mgd_smps(struct ieee80211_if_managed *ifmgd,
16210f78231bSJohannes Berg 			  enum ieee80211_smps_mode *smps_mode)
16220f78231bSJohannes Berg {
16230f78231bSJohannes Berg 	if (ifmgd->associated) {
16240f78231bSJohannes Berg 		*smps_mode = ifmgd->ap_smps;
16250f78231bSJohannes Berg 
16260f78231bSJohannes Berg 		if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) {
16270f78231bSJohannes Berg 			if (ifmgd->powersave)
16280f78231bSJohannes Berg 				*smps_mode = IEEE80211_SMPS_DYNAMIC;
16290f78231bSJohannes Berg 			else
16300f78231bSJohannes Berg 				*smps_mode = IEEE80211_SMPS_OFF;
16310f78231bSJohannes Berg 		}
16320f78231bSJohannes Berg 
16330f78231bSJohannes Berg 		return 1;
16340f78231bSJohannes Berg 	}
16350f78231bSJohannes Berg 
16360f78231bSJohannes Berg 	return 0;
16370f78231bSJohannes Berg }
16380f78231bSJohannes Berg 
1639025e6be2SJohannes Berg void ieee80211_recalc_smps(struct ieee80211_local *local)
16400f78231bSJohannes Berg {
16410f78231bSJohannes Berg 	struct ieee80211_sub_if_data *sdata;
16420f78231bSJohannes Berg 	enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF;
16430f78231bSJohannes Berg 	int count = 0;
16440f78231bSJohannes Berg 
16455d8e4237SJohannes Berg 	mutex_lock(&local->iflist_mtx);
16460f78231bSJohannes Berg 
16470f78231bSJohannes Berg 	/*
16480f78231bSJohannes Berg 	 * This function could be improved to handle multiple
16490f78231bSJohannes Berg 	 * interfaces better, but right now it makes any
16500f78231bSJohannes Berg 	 * non-station interfaces force SM PS to be turned
16510f78231bSJohannes Berg 	 * off. If there are multiple station interfaces it
16520f78231bSJohannes Berg 	 * could also use the best possible mode, e.g. if
16530f78231bSJohannes Berg 	 * one is in static and the other in dynamic then
16540f78231bSJohannes Berg 	 * dynamic is ok.
16550f78231bSJohannes Berg 	 */
16560f78231bSJohannes Berg 
16570f78231bSJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
165826a58456SJohannes Berg 		if (!ieee80211_sdata_running(sdata))
16590f78231bSJohannes Berg 			continue;
1660f142c6b9SJohannes Berg 		if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
1661f142c6b9SJohannes Berg 			continue;
16620f78231bSJohannes Berg 		if (sdata->vif.type != NL80211_IFTYPE_STATION)
16630f78231bSJohannes Berg 			goto set;
1664025e6be2SJohannes Berg 
16650f78231bSJohannes Berg 		count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
16660f78231bSJohannes Berg 
16670f78231bSJohannes Berg 		if (count > 1) {
16680f78231bSJohannes Berg 			smps_mode = IEEE80211_SMPS_OFF;
16690f78231bSJohannes Berg 			break;
16700f78231bSJohannes Berg 		}
16710f78231bSJohannes Berg 	}
16720f78231bSJohannes Berg 
16730f78231bSJohannes Berg 	if (smps_mode == local->smps_mode)
16745d8e4237SJohannes Berg 		goto unlock;
16750f78231bSJohannes Berg 
16760f78231bSJohannes Berg  set:
16770f78231bSJohannes Berg 	local->smps_mode = smps_mode;
16780f78231bSJohannes Berg 	/* changed flag is auto-detected for this */
16790f78231bSJohannes Berg 	ieee80211_hw_config(local, 0);
16805d8e4237SJohannes Berg  unlock:
16815d8e4237SJohannes Berg 	mutex_unlock(&local->iflist_mtx);
16820f78231bSJohannes Berg }
16838e664fb3SJohannes Berg 
16848e664fb3SJohannes Berg static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
16858e664fb3SJohannes Berg {
16868e664fb3SJohannes Berg 	int i;
16878e664fb3SJohannes Berg 
16888e664fb3SJohannes Berg 	for (i = 0; i < n_ids; i++)
16898e664fb3SJohannes Berg 		if (ids[i] == id)
16908e664fb3SJohannes Berg 			return true;
16918e664fb3SJohannes Berg 	return false;
16928e664fb3SJohannes Berg }
16938e664fb3SJohannes Berg 
16948e664fb3SJohannes Berg /**
16958e664fb3SJohannes Berg  * ieee80211_ie_split - split an IE buffer according to ordering
16968e664fb3SJohannes Berg  *
16978e664fb3SJohannes Berg  * @ies: the IE buffer
16988e664fb3SJohannes Berg  * @ielen: the length of the IE buffer
16998e664fb3SJohannes Berg  * @ids: an array with element IDs that are allowed before
17008e664fb3SJohannes Berg  *	the split
17018e664fb3SJohannes Berg  * @n_ids: the size of the element ID array
17028e664fb3SJohannes Berg  * @offset: offset where to start splitting in the buffer
17038e664fb3SJohannes Berg  *
17048e664fb3SJohannes Berg  * This function splits an IE buffer by updating the @offset
17058e664fb3SJohannes Berg  * variable to point to the location where the buffer should be
17068e664fb3SJohannes Berg  * split.
17078e664fb3SJohannes Berg  *
17088e664fb3SJohannes Berg  * It assumes that the given IE buffer is well-formed, this
17098e664fb3SJohannes Berg  * has to be guaranteed by the caller!
17108e664fb3SJohannes Berg  *
17118e664fb3SJohannes Berg  * It also assumes that the IEs in the buffer are ordered
17128e664fb3SJohannes Berg  * correctly, if not the result of using this function will not
17138e664fb3SJohannes Berg  * be ordered correctly either, i.e. it does no reordering.
17148e664fb3SJohannes Berg  *
17158e664fb3SJohannes Berg  * The function returns the offset where the next part of the
17168e664fb3SJohannes Berg  * buffer starts, which may be @ielen if the entire (remainder)
17178e664fb3SJohannes Berg  * of the buffer should be used.
17188e664fb3SJohannes Berg  */
17198e664fb3SJohannes Berg size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
17208e664fb3SJohannes Berg 			  const u8 *ids, int n_ids, size_t offset)
17218e664fb3SJohannes Berg {
17228e664fb3SJohannes Berg 	size_t pos = offset;
17238e664fb3SJohannes Berg 
17248e664fb3SJohannes Berg 	while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos]))
17258e664fb3SJohannes Berg 		pos += 2 + ies[pos + 1];
17268e664fb3SJohannes Berg 
17278e664fb3SJohannes Berg 	return pos;
17288e664fb3SJohannes Berg }
17298e664fb3SJohannes Berg 
17308e664fb3SJohannes Berg size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)
17318e664fb3SJohannes Berg {
17328e664fb3SJohannes Berg 	size_t pos = offset;
17338e664fb3SJohannes Berg 
17348e664fb3SJohannes Berg 	while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC)
17358e664fb3SJohannes Berg 		pos += 2 + ies[pos + 1];
17368e664fb3SJohannes Berg 
17378e664fb3SJohannes Berg 	return pos;
17388e664fb3SJohannes Berg }
1739615f7b9bSMeenakshi Venkataraman 
1740615f7b9bSMeenakshi Venkataraman static void _ieee80211_enable_rssi_reports(struct ieee80211_sub_if_data *sdata,
1741615f7b9bSMeenakshi Venkataraman 					    int rssi_min_thold,
1742615f7b9bSMeenakshi Venkataraman 					    int rssi_max_thold)
1743615f7b9bSMeenakshi Venkataraman {
1744615f7b9bSMeenakshi Venkataraman 	trace_api_enable_rssi_reports(sdata, rssi_min_thold, rssi_max_thold);
1745615f7b9bSMeenakshi Venkataraman 
1746615f7b9bSMeenakshi Venkataraman 	if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
1747615f7b9bSMeenakshi Venkataraman 		return;
1748615f7b9bSMeenakshi Venkataraman 
1749615f7b9bSMeenakshi Venkataraman 	/*
1750615f7b9bSMeenakshi Venkataraman 	 * Scale up threshold values before storing it, as the RSSI averaging
1751615f7b9bSMeenakshi Venkataraman 	 * algorithm uses a scaled up value as well. Change this scaling
1752615f7b9bSMeenakshi Venkataraman 	 * factor if the RSSI averaging algorithm changes.
1753615f7b9bSMeenakshi Venkataraman 	 */
1754615f7b9bSMeenakshi Venkataraman 	sdata->u.mgd.rssi_min_thold = rssi_min_thold*16;
1755615f7b9bSMeenakshi Venkataraman 	sdata->u.mgd.rssi_max_thold = rssi_max_thold*16;
1756615f7b9bSMeenakshi Venkataraman }
1757615f7b9bSMeenakshi Venkataraman 
1758615f7b9bSMeenakshi Venkataraman void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
1759615f7b9bSMeenakshi Venkataraman 				    int rssi_min_thold,
1760615f7b9bSMeenakshi Venkataraman 				    int rssi_max_thold)
1761615f7b9bSMeenakshi Venkataraman {
1762615f7b9bSMeenakshi Venkataraman 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
1763615f7b9bSMeenakshi Venkataraman 
1764615f7b9bSMeenakshi Venkataraman 	WARN_ON(rssi_min_thold == rssi_max_thold ||
1765615f7b9bSMeenakshi Venkataraman 		rssi_min_thold > rssi_max_thold);
1766615f7b9bSMeenakshi Venkataraman 
1767615f7b9bSMeenakshi Venkataraman 	_ieee80211_enable_rssi_reports(sdata, rssi_min_thold,
1768615f7b9bSMeenakshi Venkataraman 				       rssi_max_thold);
1769615f7b9bSMeenakshi Venkataraman }
1770615f7b9bSMeenakshi Venkataraman EXPORT_SYMBOL(ieee80211_enable_rssi_reports);
1771615f7b9bSMeenakshi Venkataraman 
1772615f7b9bSMeenakshi Venkataraman void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
1773615f7b9bSMeenakshi Venkataraman {
1774615f7b9bSMeenakshi Venkataraman 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
1775615f7b9bSMeenakshi Venkataraman 
1776615f7b9bSMeenakshi Venkataraman 	_ieee80211_enable_rssi_reports(sdata, 0, 0);
1777615f7b9bSMeenakshi Venkataraman }
1778615f7b9bSMeenakshi Venkataraman EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
1779768db343SArik Nemtsov 
1780ef96a842SBen Greear u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
178142e7aa77SAlexander Simon 			      u16 cap)
178242e7aa77SAlexander Simon {
178342e7aa77SAlexander Simon 	__le16 tmp;
178442e7aa77SAlexander Simon 
178542e7aa77SAlexander Simon 	*pos++ = WLAN_EID_HT_CAPABILITY;
178642e7aa77SAlexander Simon 	*pos++ = sizeof(struct ieee80211_ht_cap);
178742e7aa77SAlexander Simon 	memset(pos, 0, sizeof(struct ieee80211_ht_cap));
178842e7aa77SAlexander Simon 
178942e7aa77SAlexander Simon 	/* capability flags */
179042e7aa77SAlexander Simon 	tmp = cpu_to_le16(cap);
179142e7aa77SAlexander Simon 	memcpy(pos, &tmp, sizeof(u16));
179242e7aa77SAlexander Simon 	pos += sizeof(u16);
179342e7aa77SAlexander Simon 
179442e7aa77SAlexander Simon 	/* AMPDU parameters */
1795ef96a842SBen Greear 	*pos++ = ht_cap->ampdu_factor |
1796ef96a842SBen Greear 		 (ht_cap->ampdu_density <<
179742e7aa77SAlexander Simon 			IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
179842e7aa77SAlexander Simon 
179942e7aa77SAlexander Simon 	/* MCS set */
1800ef96a842SBen Greear 	memcpy(pos, &ht_cap->mcs, sizeof(ht_cap->mcs));
1801ef96a842SBen Greear 	pos += sizeof(ht_cap->mcs);
180242e7aa77SAlexander Simon 
180342e7aa77SAlexander Simon 	/* extended capabilities */
180442e7aa77SAlexander Simon 	pos += sizeof(__le16);
180542e7aa77SAlexander Simon 
180642e7aa77SAlexander Simon 	/* BF capabilities */
180742e7aa77SAlexander Simon 	pos += sizeof(__le32);
180842e7aa77SAlexander Simon 
180942e7aa77SAlexander Simon 	/* antenna selection */
181042e7aa77SAlexander Simon 	pos += sizeof(u8);
181142e7aa77SAlexander Simon 
181242e7aa77SAlexander Simon 	return pos;
181342e7aa77SAlexander Simon }
181442e7aa77SAlexander Simon 
1815ba0afa2fSMahesh Palivela u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
1816ba0afa2fSMahesh Palivela 							   u32 cap)
1817ba0afa2fSMahesh Palivela {
1818ba0afa2fSMahesh Palivela 	__le32 tmp;
1819ba0afa2fSMahesh Palivela 
1820ba0afa2fSMahesh Palivela 	*pos++ = WLAN_EID_VHT_CAPABILITY;
1821ba0afa2fSMahesh Palivela 	*pos++ = sizeof(struct ieee80211_vht_capabilities);
1822ba0afa2fSMahesh Palivela 	memset(pos, 0, sizeof(struct ieee80211_vht_capabilities));
1823ba0afa2fSMahesh Palivela 
1824ba0afa2fSMahesh Palivela 	/* capability flags */
1825ba0afa2fSMahesh Palivela 	tmp = cpu_to_le32(cap);
1826ba0afa2fSMahesh Palivela 	memcpy(pos, &tmp, sizeof(u32));
1827ba0afa2fSMahesh Palivela 	pos += sizeof(u32);
1828ba0afa2fSMahesh Palivela 
1829ba0afa2fSMahesh Palivela 	/* VHT MCS set */
1830ba0afa2fSMahesh Palivela 	memcpy(pos, &vht_cap->vht_mcs, sizeof(vht_cap->vht_mcs));
1831ba0afa2fSMahesh Palivela 	pos += sizeof(vht_cap->vht_mcs);
1832ba0afa2fSMahesh Palivela 
1833ba0afa2fSMahesh Palivela 	return pos;
1834ba0afa2fSMahesh Palivela }
1835ba0afa2fSMahesh Palivela 
1836074d46d1SJohannes Berg u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
183742e7aa77SAlexander Simon 			       struct ieee80211_channel *channel,
1838431e3154SAshok Nagarajan 			       enum nl80211_channel_type channel_type,
1839431e3154SAshok Nagarajan 			       u16 prot_mode)
184042e7aa77SAlexander Simon {
1841074d46d1SJohannes Berg 	struct ieee80211_ht_operation *ht_oper;
184242e7aa77SAlexander Simon 	/* Build HT Information */
1843074d46d1SJohannes Berg 	*pos++ = WLAN_EID_HT_OPERATION;
1844074d46d1SJohannes Berg 	*pos++ = sizeof(struct ieee80211_ht_operation);
1845074d46d1SJohannes Berg 	ht_oper = (struct ieee80211_ht_operation *)pos;
1846074d46d1SJohannes Berg 	ht_oper->primary_chan =
184742e7aa77SAlexander Simon 			ieee80211_frequency_to_channel(channel->center_freq);
184842e7aa77SAlexander Simon 	switch (channel_type) {
184942e7aa77SAlexander Simon 	case NL80211_CHAN_HT40MINUS:
1850074d46d1SJohannes Berg 		ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
185142e7aa77SAlexander Simon 		break;
185242e7aa77SAlexander Simon 	case NL80211_CHAN_HT40PLUS:
1853074d46d1SJohannes Berg 		ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
185442e7aa77SAlexander Simon 		break;
185542e7aa77SAlexander Simon 	case NL80211_CHAN_HT20:
185642e7aa77SAlexander Simon 	default:
1857074d46d1SJohannes Berg 		ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
185842e7aa77SAlexander Simon 		break;
185942e7aa77SAlexander Simon 	}
1860aee286c2SThomas Pedersen 	if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
1861aee286c2SThomas Pedersen 	    channel_type != NL80211_CHAN_NO_HT &&
1862aee286c2SThomas Pedersen 	    channel_type != NL80211_CHAN_HT20)
1863074d46d1SJohannes Berg 		ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
1864ff3cc5f4SSimon Wunderlich 
1865431e3154SAshok Nagarajan 	ht_oper->operation_mode = cpu_to_le16(prot_mode);
1866074d46d1SJohannes Berg 	ht_oper->stbc_param = 0x0000;
186742e7aa77SAlexander Simon 
186842e7aa77SAlexander Simon 	/* It seems that Basic MCS set and Supported MCS set
186942e7aa77SAlexander Simon 	   are identical for the first 10 bytes */
1870074d46d1SJohannes Berg 	memset(&ht_oper->basic_set, 0, 16);
1871074d46d1SJohannes Berg 	memcpy(&ht_oper->basic_set, &ht_cap->mcs, 10);
187242e7aa77SAlexander Simon 
1873074d46d1SJohannes Berg 	return pos + sizeof(struct ieee80211_ht_operation);
187442e7aa77SAlexander Simon }
187542e7aa77SAlexander Simon 
187642e7aa77SAlexander Simon enum nl80211_channel_type
1877074d46d1SJohannes Berg ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper)
187842e7aa77SAlexander Simon {
187942e7aa77SAlexander Simon 	enum nl80211_channel_type channel_type;
188042e7aa77SAlexander Simon 
1881074d46d1SJohannes Berg 	if (!ht_oper)
188242e7aa77SAlexander Simon 		return NL80211_CHAN_NO_HT;
188342e7aa77SAlexander Simon 
1884074d46d1SJohannes Berg 	switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
188542e7aa77SAlexander Simon 	case IEEE80211_HT_PARAM_CHA_SEC_NONE:
188642e7aa77SAlexander Simon 		channel_type = NL80211_CHAN_HT20;
188742e7aa77SAlexander Simon 		break;
188842e7aa77SAlexander Simon 	case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
188942e7aa77SAlexander Simon 		channel_type = NL80211_CHAN_HT40PLUS;
189042e7aa77SAlexander Simon 		break;
189142e7aa77SAlexander Simon 	case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
189242e7aa77SAlexander Simon 		channel_type = NL80211_CHAN_HT40MINUS;
189342e7aa77SAlexander Simon 		break;
189442e7aa77SAlexander Simon 	default:
189542e7aa77SAlexander Simon 		channel_type = NL80211_CHAN_NO_HT;
189642e7aa77SAlexander Simon 	}
189742e7aa77SAlexander Simon 
189842e7aa77SAlexander Simon 	return channel_type;
189942e7aa77SAlexander Simon }
190042e7aa77SAlexander Simon 
1901fc8a7321SJohannes Berg int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
19026b77863bSJohannes Berg 			    struct sk_buff *skb, bool need_basic,
19036b77863bSJohannes Berg 			    enum ieee80211_band band)
1904768db343SArik Nemtsov {
1905768db343SArik Nemtsov 	struct ieee80211_local *local = sdata->local;
1906768db343SArik Nemtsov 	struct ieee80211_supported_band *sband;
1907768db343SArik Nemtsov 	int rate;
1908768db343SArik Nemtsov 	u8 i, rates, *pos;
1909fc8a7321SJohannes Berg 	u32 basic_rates = sdata->vif.bss_conf.basic_rates;
1910768db343SArik Nemtsov 
19116b77863bSJohannes Berg 	sband = local->hw.wiphy->bands[band];
1912768db343SArik Nemtsov 	rates = sband->n_bitrates;
1913768db343SArik Nemtsov 	if (rates > 8)
1914768db343SArik Nemtsov 		rates = 8;
1915768db343SArik Nemtsov 
1916768db343SArik Nemtsov 	if (skb_tailroom(skb) < rates + 2)
1917768db343SArik Nemtsov 		return -ENOMEM;
1918768db343SArik Nemtsov 
1919768db343SArik Nemtsov 	pos = skb_put(skb, rates + 2);
1920768db343SArik Nemtsov 	*pos++ = WLAN_EID_SUPP_RATES;
1921768db343SArik Nemtsov 	*pos++ = rates;
1922768db343SArik Nemtsov 	for (i = 0; i < rates; i++) {
1923657c3e0cSAshok Nagarajan 		u8 basic = 0;
1924657c3e0cSAshok Nagarajan 		if (need_basic && basic_rates & BIT(i))
1925657c3e0cSAshok Nagarajan 			basic = 0x80;
1926768db343SArik Nemtsov 		rate = sband->bitrates[i].bitrate;
1927657c3e0cSAshok Nagarajan 		*pos++ = basic | (u8) (rate / 5);
1928768db343SArik Nemtsov 	}
1929768db343SArik Nemtsov 
1930768db343SArik Nemtsov 	return 0;
1931768db343SArik Nemtsov }
1932768db343SArik Nemtsov 
1933fc8a7321SJohannes Berg int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
19346b77863bSJohannes Berg 				struct sk_buff *skb, bool need_basic,
19356b77863bSJohannes Berg 				enum ieee80211_band band)
1936768db343SArik Nemtsov {
1937768db343SArik Nemtsov 	struct ieee80211_local *local = sdata->local;
1938768db343SArik Nemtsov 	struct ieee80211_supported_band *sband;
1939768db343SArik Nemtsov 	int rate;
1940768db343SArik Nemtsov 	u8 i, exrates, *pos;
1941fc8a7321SJohannes Berg 	u32 basic_rates = sdata->vif.bss_conf.basic_rates;
1942768db343SArik Nemtsov 
19436b77863bSJohannes Berg 	sband = local->hw.wiphy->bands[band];
1944768db343SArik Nemtsov 	exrates = sband->n_bitrates;
1945768db343SArik Nemtsov 	if (exrates > 8)
1946768db343SArik Nemtsov 		exrates -= 8;
1947768db343SArik Nemtsov 	else
1948768db343SArik Nemtsov 		exrates = 0;
1949768db343SArik Nemtsov 
1950768db343SArik Nemtsov 	if (skb_tailroom(skb) < exrates + 2)
1951768db343SArik Nemtsov 		return -ENOMEM;
1952768db343SArik Nemtsov 
1953768db343SArik Nemtsov 	if (exrates) {
1954768db343SArik Nemtsov 		pos = skb_put(skb, exrates + 2);
1955768db343SArik Nemtsov 		*pos++ = WLAN_EID_EXT_SUPP_RATES;
1956768db343SArik Nemtsov 		*pos++ = exrates;
1957768db343SArik Nemtsov 		for (i = 8; i < sband->n_bitrates; i++) {
1958657c3e0cSAshok Nagarajan 			u8 basic = 0;
1959657c3e0cSAshok Nagarajan 			if (need_basic && basic_rates & BIT(i))
1960657c3e0cSAshok Nagarajan 				basic = 0x80;
1961768db343SArik Nemtsov 			rate = sband->bitrates[i].bitrate;
1962657c3e0cSAshok Nagarajan 			*pos++ = basic | (u8) (rate / 5);
1963768db343SArik Nemtsov 		}
1964768db343SArik Nemtsov 	}
1965768db343SArik Nemtsov 	return 0;
1966768db343SArik Nemtsov }
19671dae27f8SWey-Yi Guy 
19681dae27f8SWey-Yi Guy int ieee80211_ave_rssi(struct ieee80211_vif *vif)
19691dae27f8SWey-Yi Guy {
19701dae27f8SWey-Yi Guy 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
19711dae27f8SWey-Yi Guy 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
19721dae27f8SWey-Yi Guy 
1973be6bcabcSWey-Yi Guy 	if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION)) {
1974be6bcabcSWey-Yi Guy 		/* non-managed type inferfaces */
1975be6bcabcSWey-Yi Guy 		return 0;
1976be6bcabcSWey-Yi Guy 	}
19771dae27f8SWey-Yi Guy 	return ifmgd->ave_beacon_signal;
19781dae27f8SWey-Yi Guy }
19790d8a0a17SWey-Yi Guy EXPORT_SYMBOL_GPL(ieee80211_ave_rssi);
1980