xref: /openbmc/linux/net/mac80211/util.c (revision 42935eca)
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>
16c2d1560aSJohannes Berg #include <linux/types.h>
17c2d1560aSJohannes Berg #include <linux/slab.h>
18c2d1560aSJohannes Berg #include <linux/skbuff.h>
19c2d1560aSJohannes Berg #include <linux/etherdevice.h>
20c2d1560aSJohannes Berg #include <linux/if_arp.h>
21c2d1560aSJohannes Berg #include <linux/wireless.h>
22c2d1560aSJohannes Berg #include <linux/bitmap.h>
23d91f36dbSJohannes 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 {
1002de8e0d9SJohannes Berg 	struct sk_buff *skb = tx->skb;
1012de8e0d9SJohannes Berg 	struct ieee80211_hdr *hdr;
102c2d1560aSJohannes Berg 
1032de8e0d9SJohannes Berg 	do {
1042de8e0d9SJohannes Berg 		hdr = (struct ieee80211_hdr *) skb->data;
105c2d1560aSJohannes Berg 		hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
1062de8e0d9SJohannes Berg 	} while ((skb = skb->next));
107c2d1560aSJohannes Berg }
108c2d1560aSJohannes Berg 
109c2d1560aSJohannes Berg int ieee80211_frame_duration(struct ieee80211_local *local, 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 
1238318d78aSJohannes Berg 	if (local->hw.conf.channel->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,
1658318d78aSJohannes Berg 					size_t frame_len,
1668318d78aSJohannes Berg 					struct ieee80211_rate *rate)
167c2d1560aSJohannes Berg {
168c2d1560aSJohannes Berg 	struct ieee80211_local *local = hw_to_local(hw);
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 
1828318d78aSJohannes Berg 	dur = ieee80211_frame_duration(local, 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 
2012e92e6f2SJohannes Berg 	sband = local->hw.wiphy->bands[local->hw.conf.channel->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 */
2168318d78aSJohannes Berg 	dur = ieee80211_frame_duration(local, 10, rate->bitrate,
217c2d1560aSJohannes Berg 				       erp, short_preamble);
218c2d1560aSJohannes Berg 	/* Data frame duration */
2198318d78aSJohannes Berg 	dur += ieee80211_frame_duration(local, frame_len, rate->bitrate,
220c2d1560aSJohannes Berg 					erp, short_preamble);
221c2d1560aSJohannes Berg 	/* ACK duration */
2228318d78aSJohannes Berg 	dur += ieee80211_frame_duration(local, 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 
2422e92e6f2SJohannes Berg 	sband = local->hw.wiphy->bands[local->hw.conf.channel->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 */
2568318d78aSJohannes Berg 	dur = ieee80211_frame_duration(local, frame_len, rate->bitrate,
257c2d1560aSJohannes Berg 				       erp, short_preamble);
258e039fa4aSJohannes Berg 	if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) {
259c2d1560aSJohannes Berg 		/* ACK duration */
2608318d78aSJohannes Berg 		dur += ieee80211_frame_duration(local, 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 
268ce7c9111SKalle Valo static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
269ce7c9111SKalle Valo 				   enum queue_stop_reason reason)
270c2d1560aSJohannes Berg {
271c2d1560aSJohannes Berg 	struct ieee80211_local *local = hw_to_local(hw);
272c2d1560aSJohannes Berg 
273e4e72fb4SJohannes Berg 	if (WARN_ON(queue >= hw->queues))
27496f5e66eSJohannes Berg 		return;
27596f5e66eSJohannes Berg 
276ce7c9111SKalle Valo 	__clear_bit(reason, &local->queue_stop_reasons[queue]);
277ce7c9111SKalle Valo 
278ce7c9111SKalle Valo 	if (local->queue_stop_reasons[queue] != 0)
279ce7c9111SKalle Valo 		/* someone still has this queue stopped */
280ce7c9111SKalle Valo 		return;
281ce7c9111SKalle Valo 
2823b8d81e0SJohannes Berg 	if (!skb_queue_empty(&local->pending[queue]))
2833b8d81e0SJohannes Berg 		tasklet_schedule(&local->tx_pending_tasklet);
284c2d1560aSJohannes Berg }
285ce7c9111SKalle Valo 
28696f5e66eSJohannes Berg void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
287ce7c9111SKalle Valo 				    enum queue_stop_reason reason)
288ce7c9111SKalle Valo {
289ce7c9111SKalle Valo 	struct ieee80211_local *local = hw_to_local(hw);
290ce7c9111SKalle Valo 	unsigned long flags;
291ce7c9111SKalle Valo 
292ce7c9111SKalle Valo 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
293ce7c9111SKalle Valo 	__ieee80211_wake_queue(hw, queue, reason);
294ce7c9111SKalle Valo 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
295ce7c9111SKalle Valo }
296ce7c9111SKalle Valo 
297ce7c9111SKalle Valo void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
298ce7c9111SKalle Valo {
299ce7c9111SKalle Valo 	ieee80211_wake_queue_by_reason(hw, queue,
300ce7c9111SKalle Valo 				       IEEE80211_QUEUE_STOP_REASON_DRIVER);
301ce7c9111SKalle Valo }
302c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queue);
303c2d1560aSJohannes Berg 
304ce7c9111SKalle Valo static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
305ce7c9111SKalle Valo 				   enum queue_stop_reason reason)
306c2d1560aSJohannes Berg {
307c2d1560aSJohannes Berg 	struct ieee80211_local *local = hw_to_local(hw);
308c2d1560aSJohannes Berg 
309e4e72fb4SJohannes Berg 	if (WARN_ON(queue >= hw->queues))
31096f5e66eSJohannes Berg 		return;
31196f5e66eSJohannes Berg 
3122a577d98SJohannes Berg 	__set_bit(reason, &local->queue_stop_reasons[queue]);
313c2d1560aSJohannes Berg }
314ce7c9111SKalle Valo 
31596f5e66eSJohannes Berg void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
316ce7c9111SKalle Valo 				    enum queue_stop_reason reason)
317ce7c9111SKalle Valo {
318ce7c9111SKalle Valo 	struct ieee80211_local *local = hw_to_local(hw);
319ce7c9111SKalle Valo 	unsigned long flags;
320ce7c9111SKalle Valo 
321ce7c9111SKalle Valo 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
322ce7c9111SKalle Valo 	__ieee80211_stop_queue(hw, queue, reason);
323ce7c9111SKalle Valo 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
324ce7c9111SKalle Valo }
325ce7c9111SKalle Valo 
326ce7c9111SKalle Valo void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
327ce7c9111SKalle Valo {
328ce7c9111SKalle Valo 	ieee80211_stop_queue_by_reason(hw, queue,
329ce7c9111SKalle Valo 				       IEEE80211_QUEUE_STOP_REASON_DRIVER);
330ce7c9111SKalle Valo }
331c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queue);
332c2d1560aSJohannes Berg 
3338f77f384SJohannes Berg void ieee80211_add_pending_skb(struct ieee80211_local *local,
3348f77f384SJohannes Berg 			       struct sk_buff *skb)
3358f77f384SJohannes Berg {
3368f77f384SJohannes Berg 	struct ieee80211_hw *hw = &local->hw;
3378f77f384SJohannes Berg 	unsigned long flags;
3388f77f384SJohannes Berg 	int queue = skb_get_queue_mapping(skb);
339a7bc376cSJohannes Berg 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
340a7bc376cSJohannes Berg 
341a7bc376cSJohannes Berg 	if (WARN_ON(!info->control.vif)) {
342a7bc376cSJohannes Berg 		kfree(skb);
343a7bc376cSJohannes Berg 		return;
344a7bc376cSJohannes Berg 	}
3458f77f384SJohannes Berg 
3468f77f384SJohannes Berg 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
3478f77f384SJohannes Berg 	__ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
3483b8d81e0SJohannes Berg 	__skb_queue_tail(&local->pending[queue], skb);
3498f77f384SJohannes Berg 	__ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
3508f77f384SJohannes Berg 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
3518f77f384SJohannes Berg }
3528f77f384SJohannes Berg 
3538f77f384SJohannes Berg int ieee80211_add_pending_skbs(struct ieee80211_local *local,
3548f77f384SJohannes Berg 			       struct sk_buff_head *skbs)
3558f77f384SJohannes Berg {
3568f77f384SJohannes Berg 	struct ieee80211_hw *hw = &local->hw;
3578f77f384SJohannes Berg 	struct sk_buff *skb;
3588f77f384SJohannes Berg 	unsigned long flags;
3598f77f384SJohannes Berg 	int queue, ret = 0, i;
3608f77f384SJohannes Berg 
3618f77f384SJohannes Berg 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
3628f77f384SJohannes Berg 	for (i = 0; i < hw->queues; i++)
3638f77f384SJohannes Berg 		__ieee80211_stop_queue(hw, i,
3648f77f384SJohannes Berg 			IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
3658f77f384SJohannes Berg 
3668f77f384SJohannes Berg 	while ((skb = skb_dequeue(skbs))) {
367a7bc376cSJohannes Berg 		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
368a7bc376cSJohannes Berg 
369a7bc376cSJohannes Berg 		if (WARN_ON(!info->control.vif)) {
370a7bc376cSJohannes Berg 			kfree(skb);
371a7bc376cSJohannes Berg 			continue;
372a7bc376cSJohannes Berg 		}
373a7bc376cSJohannes Berg 
3748f77f384SJohannes Berg 		ret++;
3758f77f384SJohannes Berg 		queue = skb_get_queue_mapping(skb);
3763b8d81e0SJohannes Berg 		__skb_queue_tail(&local->pending[queue], skb);
3778f77f384SJohannes Berg 	}
3788f77f384SJohannes Berg 
3793b8d81e0SJohannes Berg 	for (i = 0; i < hw->queues; i++)
3808f77f384SJohannes Berg 		__ieee80211_wake_queue(hw, i,
3818f77f384SJohannes Berg 			IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
3828f77f384SJohannes Berg 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
3838f77f384SJohannes Berg 
3848f77f384SJohannes Berg 	return ret;
3858f77f384SJohannes Berg }
3868f77f384SJohannes Berg 
387ce7c9111SKalle Valo void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
388ce7c9111SKalle Valo 				    enum queue_stop_reason reason)
389c2d1560aSJohannes Berg {
390ce7c9111SKalle Valo 	struct ieee80211_local *local = hw_to_local(hw);
391ce7c9111SKalle Valo 	unsigned long flags;
392c2d1560aSJohannes Berg 	int i;
393c2d1560aSJohannes Berg 
394ce7c9111SKalle Valo 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
395ce7c9111SKalle Valo 
39696f5e66eSJohannes Berg 	for (i = 0; i < hw->queues; i++)
397ce7c9111SKalle Valo 		__ieee80211_stop_queue(hw, i, reason);
398ce7c9111SKalle Valo 
399ce7c9111SKalle Valo 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
400ce7c9111SKalle Valo }
401ce7c9111SKalle Valo 
402ce7c9111SKalle Valo void ieee80211_stop_queues(struct ieee80211_hw *hw)
403ce7c9111SKalle Valo {
404ce7c9111SKalle Valo 	ieee80211_stop_queues_by_reason(hw,
405ce7c9111SKalle Valo 					IEEE80211_QUEUE_STOP_REASON_DRIVER);
406c2d1560aSJohannes Berg }
407c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queues);
408c2d1560aSJohannes Berg 
40992ab8535STomas Winkler int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
41092ab8535STomas Winkler {
41192ab8535STomas Winkler 	struct ieee80211_local *local = hw_to_local(hw);
4123b8d81e0SJohannes Berg 	unsigned long flags;
4133b8d81e0SJohannes Berg 	int ret;
41496f5e66eSJohannes Berg 
415e4e72fb4SJohannes Berg 	if (WARN_ON(queue >= hw->queues))
41696f5e66eSJohannes Berg 		return true;
41796f5e66eSJohannes Berg 
4183b8d81e0SJohannes Berg 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
4193b8d81e0SJohannes Berg 	ret = !!local->queue_stop_reasons[queue];
4203b8d81e0SJohannes Berg 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
4213b8d81e0SJohannes Berg 	return ret;
42292ab8535STomas Winkler }
42392ab8535STomas Winkler EXPORT_SYMBOL(ieee80211_queue_stopped);
42492ab8535STomas Winkler 
425ce7c9111SKalle Valo void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
426ce7c9111SKalle Valo 				     enum queue_stop_reason reason)
427c2d1560aSJohannes Berg {
428ce7c9111SKalle Valo 	struct ieee80211_local *local = hw_to_local(hw);
429ce7c9111SKalle Valo 	unsigned long flags;
430c2d1560aSJohannes Berg 	int i;
431c2d1560aSJohannes Berg 
432ce7c9111SKalle Valo 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
433ce7c9111SKalle Valo 
434e4e72fb4SJohannes Berg 	for (i = 0; i < hw->queues; i++)
435ce7c9111SKalle Valo 		__ieee80211_wake_queue(hw, i, reason);
436ce7c9111SKalle Valo 
437ce7c9111SKalle Valo 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
438ce7c9111SKalle Valo }
439ce7c9111SKalle Valo 
440ce7c9111SKalle Valo void ieee80211_wake_queues(struct ieee80211_hw *hw)
441ce7c9111SKalle Valo {
442ce7c9111SKalle Valo 	ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER);
443c2d1560aSJohannes Berg }
444c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queues);
445dabeb344SJohannes Berg 
44632bfd35dSJohannes Berg void ieee80211_iterate_active_interfaces(
44732bfd35dSJohannes Berg 	struct ieee80211_hw *hw,
448dabeb344SJohannes Berg 	void (*iterator)(void *data, u8 *mac,
44932bfd35dSJohannes Berg 			 struct ieee80211_vif *vif),
450dabeb344SJohannes Berg 	void *data)
451dabeb344SJohannes Berg {
452dabeb344SJohannes Berg 	struct ieee80211_local *local = hw_to_local(hw);
453dabeb344SJohannes Berg 	struct ieee80211_sub_if_data *sdata;
454dabeb344SJohannes Berg 
455c771c9d8SJohannes Berg 	mutex_lock(&local->iflist_mtx);
4562f561febSIvo van Doorn 
4572f561febSIvo van Doorn 	list_for_each_entry(sdata, &local->interfaces, list) {
4582f561febSIvo van Doorn 		switch (sdata->vif.type) {
45905c914feSJohannes Berg 		case __NL80211_IFTYPE_AFTER_LAST:
46005c914feSJohannes Berg 		case NL80211_IFTYPE_UNSPECIFIED:
46105c914feSJohannes Berg 		case NL80211_IFTYPE_MONITOR:
46205c914feSJohannes Berg 		case NL80211_IFTYPE_AP_VLAN:
4632f561febSIvo van Doorn 			continue;
46405c914feSJohannes Berg 		case NL80211_IFTYPE_AP:
46505c914feSJohannes Berg 		case NL80211_IFTYPE_STATION:
46605c914feSJohannes Berg 		case NL80211_IFTYPE_ADHOC:
46705c914feSJohannes Berg 		case NL80211_IFTYPE_WDS:
46805c914feSJohannes Berg 		case NL80211_IFTYPE_MESH_POINT:
4692f561febSIvo van Doorn 			break;
4702f561febSIvo van Doorn 		}
4712f561febSIvo van Doorn 		if (netif_running(sdata->dev))
4722f561febSIvo van Doorn 			iterator(data, sdata->dev->dev_addr,
4732f561febSIvo van Doorn 				 &sdata->vif);
4742f561febSIvo van Doorn 	}
4752f561febSIvo van Doorn 
476c771c9d8SJohannes Berg 	mutex_unlock(&local->iflist_mtx);
4772f561febSIvo van Doorn }
4782f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
4792f561febSIvo van Doorn 
4802f561febSIvo van Doorn void ieee80211_iterate_active_interfaces_atomic(
4812f561febSIvo van Doorn 	struct ieee80211_hw *hw,
4822f561febSIvo van Doorn 	void (*iterator)(void *data, u8 *mac,
4832f561febSIvo van Doorn 			 struct ieee80211_vif *vif),
4842f561febSIvo van Doorn 	void *data)
4852f561febSIvo van Doorn {
4862f561febSIvo van Doorn 	struct ieee80211_local *local = hw_to_local(hw);
4872f561febSIvo van Doorn 	struct ieee80211_sub_if_data *sdata;
4882f561febSIvo van Doorn 
489e38bad47SJohannes Berg 	rcu_read_lock();
490dabeb344SJohannes Berg 
491e38bad47SJohannes Berg 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
49251fb61e7SJohannes Berg 		switch (sdata->vif.type) {
49305c914feSJohannes Berg 		case __NL80211_IFTYPE_AFTER_LAST:
49405c914feSJohannes Berg 		case NL80211_IFTYPE_UNSPECIFIED:
49505c914feSJohannes Berg 		case NL80211_IFTYPE_MONITOR:
49605c914feSJohannes Berg 		case NL80211_IFTYPE_AP_VLAN:
497dabeb344SJohannes Berg 			continue;
49805c914feSJohannes Berg 		case NL80211_IFTYPE_AP:
49905c914feSJohannes Berg 		case NL80211_IFTYPE_STATION:
50005c914feSJohannes Berg 		case NL80211_IFTYPE_ADHOC:
50105c914feSJohannes Berg 		case NL80211_IFTYPE_WDS:
50205c914feSJohannes Berg 		case NL80211_IFTYPE_MESH_POINT:
503dabeb344SJohannes Berg 			break;
504dabeb344SJohannes Berg 		}
505dabeb344SJohannes Berg 		if (netif_running(sdata->dev))
506dabeb344SJohannes Berg 			iterator(data, sdata->dev->dev_addr,
50732bfd35dSJohannes Berg 				 &sdata->vif);
508dabeb344SJohannes Berg 	}
509e38bad47SJohannes Berg 
510e38bad47SJohannes Berg 	rcu_read_unlock();
511dabeb344SJohannes Berg }
5122f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
51337ffc8daSJohannes Berg 
51442935ecaSLuis R. Rodriguez /*
51542935ecaSLuis R. Rodriguez  * Nothing should have been stuffed into the workqueue during
51642935ecaSLuis R. Rodriguez  * the suspend->resume cycle. If this WARN is seen then there
51742935ecaSLuis R. Rodriguez  * is a bug with either the driver suspend or something in
51842935ecaSLuis R. Rodriguez  * mac80211 stuffing into the workqueue which we haven't yet
51942935ecaSLuis R. Rodriguez  * cleared during mac80211's suspend cycle.
52042935ecaSLuis R. Rodriguez  */
52142935ecaSLuis R. Rodriguez static bool ieee80211_can_queue_work(struct ieee80211_local *local)
52242935ecaSLuis R. Rodriguez {
52342935ecaSLuis R. Rodriguez         if (WARN(local->suspended, "queueing ieee80211 work while "
52442935ecaSLuis R. Rodriguez 		 "going to suspend\n"))
52542935ecaSLuis R. Rodriguez                 return false;
52642935ecaSLuis R. Rodriguez 
52742935ecaSLuis R. Rodriguez 	return true;
52842935ecaSLuis R. Rodriguez }
52942935ecaSLuis R. Rodriguez 
53042935ecaSLuis R. Rodriguez void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work)
53142935ecaSLuis R. Rodriguez {
53242935ecaSLuis R. Rodriguez 	struct ieee80211_local *local = hw_to_local(hw);
53342935ecaSLuis R. Rodriguez 
53442935ecaSLuis R. Rodriguez 	if (!ieee80211_can_queue_work(local))
53542935ecaSLuis R. Rodriguez 		return;
53642935ecaSLuis R. Rodriguez 
53742935ecaSLuis R. Rodriguez 	queue_work(local->workqueue, work);
53842935ecaSLuis R. Rodriguez }
53942935ecaSLuis R. Rodriguez EXPORT_SYMBOL(ieee80211_queue_work);
54042935ecaSLuis R. Rodriguez 
54142935ecaSLuis R. Rodriguez void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
54242935ecaSLuis R. Rodriguez 				  struct delayed_work *dwork,
54342935ecaSLuis R. Rodriguez 				  unsigned long delay)
54442935ecaSLuis R. Rodriguez {
54542935ecaSLuis R. Rodriguez 	struct ieee80211_local *local = hw_to_local(hw);
54642935ecaSLuis R. Rodriguez 
54742935ecaSLuis R. Rodriguez 	if (!ieee80211_can_queue_work(local))
54842935ecaSLuis R. Rodriguez 		return;
54942935ecaSLuis R. Rodriguez 
55042935ecaSLuis R. Rodriguez 	queue_delayed_work(local->workqueue, dwork, delay);
55142935ecaSLuis R. Rodriguez }
55242935ecaSLuis R. Rodriguez EXPORT_SYMBOL(ieee80211_queue_delayed_work);
55342935ecaSLuis R. Rodriguez 
55437ffc8daSJohannes Berg void ieee802_11_parse_elems(u8 *start, size_t len,
55537ffc8daSJohannes Berg 			    struct ieee802_11_elems *elems)
55637ffc8daSJohannes Berg {
557d91f36dbSJohannes Berg 	ieee802_11_parse_elems_crc(start, len, elems, 0, 0);
558d91f36dbSJohannes Berg }
559d91f36dbSJohannes Berg 
560d91f36dbSJohannes Berg u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
561d91f36dbSJohannes Berg 			       struct ieee802_11_elems *elems,
562d91f36dbSJohannes Berg 			       u64 filter, u32 crc)
563d91f36dbSJohannes Berg {
56437ffc8daSJohannes Berg 	size_t left = len;
56537ffc8daSJohannes Berg 	u8 *pos = start;
566d91f36dbSJohannes Berg 	bool calc_crc = filter != 0;
56737ffc8daSJohannes Berg 
56837ffc8daSJohannes Berg 	memset(elems, 0, sizeof(*elems));
56937ffc8daSJohannes Berg 	elems->ie_start = start;
57037ffc8daSJohannes Berg 	elems->total_len = len;
57137ffc8daSJohannes Berg 
57237ffc8daSJohannes Berg 	while (left >= 2) {
57337ffc8daSJohannes Berg 		u8 id, elen;
57437ffc8daSJohannes Berg 
57537ffc8daSJohannes Berg 		id = *pos++;
57637ffc8daSJohannes Berg 		elen = *pos++;
57737ffc8daSJohannes Berg 		left -= 2;
57837ffc8daSJohannes Berg 
57937ffc8daSJohannes Berg 		if (elen > left)
580d91f36dbSJohannes Berg 			break;
581d91f36dbSJohannes Berg 
582d91f36dbSJohannes Berg 		if (calc_crc && id < 64 && (filter & BIT(id)))
583d91f36dbSJohannes Berg 			crc = crc32_be(crc, pos - 2, elen + 2);
58437ffc8daSJohannes Berg 
58537ffc8daSJohannes Berg 		switch (id) {
58637ffc8daSJohannes Berg 		case WLAN_EID_SSID:
58737ffc8daSJohannes Berg 			elems->ssid = pos;
58837ffc8daSJohannes Berg 			elems->ssid_len = elen;
58937ffc8daSJohannes Berg 			break;
59037ffc8daSJohannes Berg 		case WLAN_EID_SUPP_RATES:
59137ffc8daSJohannes Berg 			elems->supp_rates = pos;
59237ffc8daSJohannes Berg 			elems->supp_rates_len = elen;
59337ffc8daSJohannes Berg 			break;
59437ffc8daSJohannes Berg 		case WLAN_EID_FH_PARAMS:
59537ffc8daSJohannes Berg 			elems->fh_params = pos;
59637ffc8daSJohannes Berg 			elems->fh_params_len = elen;
59737ffc8daSJohannes Berg 			break;
59837ffc8daSJohannes Berg 		case WLAN_EID_DS_PARAMS:
59937ffc8daSJohannes Berg 			elems->ds_params = pos;
60037ffc8daSJohannes Berg 			elems->ds_params_len = elen;
60137ffc8daSJohannes Berg 			break;
60237ffc8daSJohannes Berg 		case WLAN_EID_CF_PARAMS:
60337ffc8daSJohannes Berg 			elems->cf_params = pos;
60437ffc8daSJohannes Berg 			elems->cf_params_len = elen;
60537ffc8daSJohannes Berg 			break;
60637ffc8daSJohannes Berg 		case WLAN_EID_TIM:
607e7ec86f5SJohannes Berg 			if (elen >= sizeof(struct ieee80211_tim_ie)) {
608e7ec86f5SJohannes Berg 				elems->tim = (void *)pos;
60937ffc8daSJohannes Berg 				elems->tim_len = elen;
610e7ec86f5SJohannes Berg 			}
61137ffc8daSJohannes Berg 			break;
61237ffc8daSJohannes Berg 		case WLAN_EID_IBSS_PARAMS:
61337ffc8daSJohannes Berg 			elems->ibss_params = pos;
61437ffc8daSJohannes Berg 			elems->ibss_params_len = elen;
61537ffc8daSJohannes Berg 			break;
61637ffc8daSJohannes Berg 		case WLAN_EID_CHALLENGE:
61737ffc8daSJohannes Berg 			elems->challenge = pos;
61837ffc8daSJohannes Berg 			elems->challenge_len = elen;
61937ffc8daSJohannes Berg 			break;
620d91f36dbSJohannes Berg 		case WLAN_EID_VENDOR_SPECIFIC:
62137ffc8daSJohannes Berg 			if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
62237ffc8daSJohannes Berg 			    pos[2] == 0xf2) {
62337ffc8daSJohannes Berg 				/* Microsoft OUI (00:50:F2) */
624d91f36dbSJohannes Berg 
625d91f36dbSJohannes Berg 				if (calc_crc)
626d91f36dbSJohannes Berg 					crc = crc32_be(crc, pos - 2, elen + 2);
627d91f36dbSJohannes Berg 
62837ffc8daSJohannes Berg 				if (pos[3] == 1) {
62937ffc8daSJohannes Berg 					/* OUI Type 1 - WPA IE */
63037ffc8daSJohannes Berg 					elems->wpa = pos;
63137ffc8daSJohannes Berg 					elems->wpa_len = elen;
63237ffc8daSJohannes Berg 				} else if (elen >= 5 && pos[3] == 2) {
633d91f36dbSJohannes Berg 					/* OUI Type 2 - WMM IE */
63437ffc8daSJohannes Berg 					if (pos[4] == 0) {
63537ffc8daSJohannes Berg 						elems->wmm_info = pos;
63637ffc8daSJohannes Berg 						elems->wmm_info_len = elen;
63737ffc8daSJohannes Berg 					} else if (pos[4] == 1) {
63837ffc8daSJohannes Berg 						elems->wmm_param = pos;
63937ffc8daSJohannes Berg 						elems->wmm_param_len = elen;
64037ffc8daSJohannes Berg 					}
64137ffc8daSJohannes Berg 				}
64237ffc8daSJohannes Berg 			}
64337ffc8daSJohannes Berg 			break;
64437ffc8daSJohannes Berg 		case WLAN_EID_RSN:
64537ffc8daSJohannes Berg 			elems->rsn = pos;
64637ffc8daSJohannes Berg 			elems->rsn_len = elen;
64737ffc8daSJohannes Berg 			break;
64837ffc8daSJohannes Berg 		case WLAN_EID_ERP_INFO:
64937ffc8daSJohannes Berg 			elems->erp_info = pos;
65037ffc8daSJohannes Berg 			elems->erp_info_len = elen;
65137ffc8daSJohannes Berg 			break;
65237ffc8daSJohannes Berg 		case WLAN_EID_EXT_SUPP_RATES:
65337ffc8daSJohannes Berg 			elems->ext_supp_rates = pos;
65437ffc8daSJohannes Berg 			elems->ext_supp_rates_len = elen;
65537ffc8daSJohannes Berg 			break;
65637ffc8daSJohannes Berg 		case WLAN_EID_HT_CAPABILITY:
65709914813SJohannes Berg 			if (elen >= sizeof(struct ieee80211_ht_cap))
65809914813SJohannes Berg 				elems->ht_cap_elem = (void *)pos;
65937ffc8daSJohannes Berg 			break;
660d9fe60deSJohannes Berg 		case WLAN_EID_HT_INFORMATION:
661d9fe60deSJohannes Berg 			if (elen >= sizeof(struct ieee80211_ht_info))
66209914813SJohannes Berg 				elems->ht_info_elem = (void *)pos;
66337ffc8daSJohannes Berg 			break;
66437ffc8daSJohannes Berg 		case WLAN_EID_MESH_ID:
66537ffc8daSJohannes Berg 			elems->mesh_id = pos;
66637ffc8daSJohannes Berg 			elems->mesh_id_len = elen;
66737ffc8daSJohannes Berg 			break;
66837ffc8daSJohannes Berg 		case WLAN_EID_MESH_CONFIG:
66937ffc8daSJohannes Berg 			elems->mesh_config = pos;
67037ffc8daSJohannes Berg 			elems->mesh_config_len = elen;
67137ffc8daSJohannes Berg 			break;
67237ffc8daSJohannes Berg 		case WLAN_EID_PEER_LINK:
67337ffc8daSJohannes Berg 			elems->peer_link = pos;
67437ffc8daSJohannes Berg 			elems->peer_link_len = elen;
67537ffc8daSJohannes Berg 			break;
67637ffc8daSJohannes Berg 		case WLAN_EID_PREQ:
67737ffc8daSJohannes Berg 			elems->preq = pos;
67837ffc8daSJohannes Berg 			elems->preq_len = elen;
67937ffc8daSJohannes Berg 			break;
68037ffc8daSJohannes Berg 		case WLAN_EID_PREP:
68137ffc8daSJohannes Berg 			elems->prep = pos;
68237ffc8daSJohannes Berg 			elems->prep_len = elen;
68337ffc8daSJohannes Berg 			break;
68437ffc8daSJohannes Berg 		case WLAN_EID_PERR:
68537ffc8daSJohannes Berg 			elems->perr = pos;
68637ffc8daSJohannes Berg 			elems->perr_len = elen;
68737ffc8daSJohannes Berg 			break;
68837ffc8daSJohannes Berg 		case WLAN_EID_CHANNEL_SWITCH:
68937ffc8daSJohannes Berg 			elems->ch_switch_elem = pos;
69037ffc8daSJohannes Berg 			elems->ch_switch_elem_len = elen;
69137ffc8daSJohannes Berg 			break;
69237ffc8daSJohannes Berg 		case WLAN_EID_QUIET:
69337ffc8daSJohannes Berg 			if (!elems->quiet_elem) {
69437ffc8daSJohannes Berg 				elems->quiet_elem = pos;
69537ffc8daSJohannes Berg 				elems->quiet_elem_len = elen;
69637ffc8daSJohannes Berg 			}
69737ffc8daSJohannes Berg 			elems->num_of_quiet_elem++;
69837ffc8daSJohannes Berg 			break;
69937ffc8daSJohannes Berg 		case WLAN_EID_COUNTRY:
70037ffc8daSJohannes Berg 			elems->country_elem = pos;
70137ffc8daSJohannes Berg 			elems->country_elem_len = elen;
70237ffc8daSJohannes Berg 			break;
70337ffc8daSJohannes Berg 		case WLAN_EID_PWR_CONSTRAINT:
70437ffc8daSJohannes Berg 			elems->pwr_constr_elem = pos;
70537ffc8daSJohannes Berg 			elems->pwr_constr_elem_len = elen;
70637ffc8daSJohannes Berg 			break;
707f797eb7eSJouni Malinen 		case WLAN_EID_TIMEOUT_INTERVAL:
708f797eb7eSJouni Malinen 			elems->timeout_int = pos;
709f797eb7eSJouni Malinen 			elems->timeout_int_len = elen;
71063a5ab82SJouni Malinen 			break;
71137ffc8daSJohannes Berg 		default:
71237ffc8daSJohannes Berg 			break;
71337ffc8daSJohannes Berg 		}
71437ffc8daSJohannes Berg 
71537ffc8daSJohannes Berg 		left -= elen;
71637ffc8daSJohannes Berg 		pos += elen;
71737ffc8daSJohannes Berg 	}
718d91f36dbSJohannes Berg 
719d91f36dbSJohannes Berg 	return crc;
72037ffc8daSJohannes Berg }
7215825fe10SJohannes Berg 
7225825fe10SJohannes Berg void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
7235825fe10SJohannes Berg {
7245825fe10SJohannes Berg 	struct ieee80211_local *local = sdata->local;
7255825fe10SJohannes Berg 	struct ieee80211_tx_queue_params qparam;
726aa837e1dSJohannes Berg 	int queue;
727aa837e1dSJohannes Berg 	bool use_11b;
728aa837e1dSJohannes Berg 	int aCWmin, aCWmax;
7295825fe10SJohannes Berg 
7305825fe10SJohannes Berg 	if (!local->ops->conf_tx)
7315825fe10SJohannes Berg 		return;
7325825fe10SJohannes Berg 
7335825fe10SJohannes Berg 	memset(&qparam, 0, sizeof(qparam));
7345825fe10SJohannes Berg 
735aa837e1dSJohannes Berg 	use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
736aa837e1dSJohannes Berg 		 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
7375825fe10SJohannes Berg 
738aa837e1dSJohannes Berg 	for (queue = 0; queue < local_to_hw(local)->queues; queue++) {
739aa837e1dSJohannes Berg 		/* Set defaults according to 802.11-2007 Table 7-37 */
740aa837e1dSJohannes Berg 		aCWmax = 1023;
741aa837e1dSJohannes Berg 		if (use_11b)
742aa837e1dSJohannes Berg 			aCWmin = 31;
7435825fe10SJohannes Berg 		else
744aa837e1dSJohannes Berg 			aCWmin = 15;
7455825fe10SJohannes Berg 
746aa837e1dSJohannes Berg 		switch (queue) {
747aa837e1dSJohannes Berg 		case 3: /* AC_BK */
7487ba10a8eSJohannes Berg 			qparam.cw_max = aCWmax;
7497ba10a8eSJohannes Berg 			qparam.cw_min = aCWmin;
7505825fe10SJohannes Berg 			qparam.txop = 0;
751aa837e1dSJohannes Berg 			qparam.aifs = 7;
752aa837e1dSJohannes Berg 			break;
753aa837e1dSJohannes Berg 		default: /* never happens but let's not leave undefined */
754aa837e1dSJohannes Berg 		case 2: /* AC_BE */
7557ba10a8eSJohannes Berg 			qparam.cw_max = aCWmax;
7567ba10a8eSJohannes Berg 			qparam.cw_min = aCWmin;
757aa837e1dSJohannes Berg 			qparam.txop = 0;
758aa837e1dSJohannes Berg 			qparam.aifs = 3;
759aa837e1dSJohannes Berg 			break;
760aa837e1dSJohannes Berg 		case 1: /* AC_VI */
761aa837e1dSJohannes Berg 			qparam.cw_max = aCWmin;
762aa837e1dSJohannes Berg 			qparam.cw_min = (aCWmin + 1) / 2 - 1;
763aa837e1dSJohannes Berg 			if (use_11b)
764aa837e1dSJohannes Berg 				qparam.txop = 6016/32;
765aa837e1dSJohannes Berg 			else
766aa837e1dSJohannes Berg 				qparam.txop = 3008/32;
767aa837e1dSJohannes Berg 			qparam.aifs = 2;
768aa837e1dSJohannes Berg 			break;
769aa837e1dSJohannes Berg 		case 0: /* AC_VO */
770aa837e1dSJohannes Berg 			qparam.cw_max = (aCWmin + 1) / 2 - 1;
771aa837e1dSJohannes Berg 			qparam.cw_min = (aCWmin + 1) / 4 - 1;
772aa837e1dSJohannes Berg 			if (use_11b)
773aa837e1dSJohannes Berg 				qparam.txop = 3264/32;
774aa837e1dSJohannes Berg 			else
775aa837e1dSJohannes Berg 				qparam.txop = 1504/32;
776aa837e1dSJohannes Berg 			qparam.aifs = 2;
777aa837e1dSJohannes Berg 			break;
778aa837e1dSJohannes Berg 		}
7795825fe10SJohannes Berg 
780aa837e1dSJohannes Berg 		drv_conf_tx(local, queue, &qparam);
781aa837e1dSJohannes Berg 	}
7825825fe10SJohannes Berg }
783e50db65cSJohannes Berg 
78446900298SJohannes Berg void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
78546900298SJohannes Berg 				  const size_t supp_rates_len,
78646900298SJohannes Berg 				  const u8 *supp_rates)
78746900298SJohannes Berg {
78846900298SJohannes Berg 	struct ieee80211_local *local = sdata->local;
78946900298SJohannes Berg 	int i, have_higher_than_11mbit = 0;
79046900298SJohannes Berg 
79146900298SJohannes Berg 	/* cf. IEEE 802.11 9.2.12 */
79246900298SJohannes Berg 	for (i = 0; i < supp_rates_len; i++)
79346900298SJohannes Berg 		if ((supp_rates[i] & 0x7f) * 5 > 110)
79446900298SJohannes Berg 			have_higher_than_11mbit = 1;
79546900298SJohannes Berg 
79646900298SJohannes Berg 	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
79746900298SJohannes Berg 	    have_higher_than_11mbit)
79846900298SJohannes Berg 		sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
79946900298SJohannes Berg 	else
80046900298SJohannes Berg 		sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
80146900298SJohannes Berg 
80246900298SJohannes Berg 	ieee80211_set_wmm_default(sdata);
80346900298SJohannes Berg }
80446900298SJohannes Berg 
805881d948cSJohannes Berg u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
80696dd22acSJohannes Berg 			      enum ieee80211_band band)
80796dd22acSJohannes Berg {
80896dd22acSJohannes Berg 	struct ieee80211_supported_band *sband;
80996dd22acSJohannes Berg 	struct ieee80211_rate *bitrates;
810881d948cSJohannes Berg 	u32 mandatory_rates;
81196dd22acSJohannes Berg 	enum ieee80211_rate_flags mandatory_flag;
81296dd22acSJohannes Berg 	int i;
81396dd22acSJohannes Berg 
81496dd22acSJohannes Berg 	sband = local->hw.wiphy->bands[band];
81596dd22acSJohannes Berg 	if (!sband) {
81696dd22acSJohannes Berg 		WARN_ON(1);
81796dd22acSJohannes Berg 		sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
81896dd22acSJohannes Berg 	}
81996dd22acSJohannes Berg 
82096dd22acSJohannes Berg 	if (band == IEEE80211_BAND_2GHZ)
82196dd22acSJohannes Berg 		mandatory_flag = IEEE80211_RATE_MANDATORY_B;
82296dd22acSJohannes Berg 	else
82396dd22acSJohannes Berg 		mandatory_flag = IEEE80211_RATE_MANDATORY_A;
82496dd22acSJohannes Berg 
82596dd22acSJohannes Berg 	bitrates = sband->bitrates;
82696dd22acSJohannes Berg 	mandatory_rates = 0;
82796dd22acSJohannes Berg 	for (i = 0; i < sband->n_bitrates; i++)
82896dd22acSJohannes Berg 		if (bitrates[i].flags & mandatory_flag)
82996dd22acSJohannes Berg 			mandatory_rates |= BIT(i);
83096dd22acSJohannes Berg 	return mandatory_rates;
83196dd22acSJohannes Berg }
83246900298SJohannes Berg 
83346900298SJohannes Berg void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
83446900298SJohannes Berg 			 u16 transaction, u16 auth_alg,
835fffd0934SJohannes Berg 			 u8 *extra, size_t extra_len, const u8 *bssid,
836fffd0934SJohannes Berg 			 const u8 *key, u8 key_len, u8 key_idx)
83746900298SJohannes Berg {
83846900298SJohannes Berg 	struct ieee80211_local *local = sdata->local;
83946900298SJohannes Berg 	struct sk_buff *skb;
84046900298SJohannes Berg 	struct ieee80211_mgmt *mgmt;
841fffd0934SJohannes Berg 	int err;
84246900298SJohannes Berg 
84346900298SJohannes Berg 	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
84465fc73acSJouni Malinen 			    sizeof(*mgmt) + 6 + extra_len);
84546900298SJohannes Berg 	if (!skb) {
84646900298SJohannes Berg 		printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
84746900298SJohannes Berg 		       "frame\n", sdata->dev->name);
84846900298SJohannes Berg 		return;
84946900298SJohannes Berg 	}
85046900298SJohannes Berg 	skb_reserve(skb, local->hw.extra_tx_headroom);
85146900298SJohannes Berg 
85246900298SJohannes Berg 	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
85346900298SJohannes Berg 	memset(mgmt, 0, 24 + 6);
85446900298SJohannes Berg 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
85546900298SJohannes Berg 					  IEEE80211_STYPE_AUTH);
85646900298SJohannes Berg 	memcpy(mgmt->da, bssid, ETH_ALEN);
85746900298SJohannes Berg 	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
85846900298SJohannes Berg 	memcpy(mgmt->bssid, bssid, ETH_ALEN);
85946900298SJohannes Berg 	mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg);
86046900298SJohannes Berg 	mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
86146900298SJohannes Berg 	mgmt->u.auth.status_code = cpu_to_le16(0);
86246900298SJohannes Berg 	if (extra)
86346900298SJohannes Berg 		memcpy(skb_put(skb, extra_len), extra, extra_len);
86446900298SJohannes Berg 
865fffd0934SJohannes Berg 	if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
866fffd0934SJohannes Berg 		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
867fffd0934SJohannes Berg 		err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx);
868fffd0934SJohannes Berg 		WARN_ON(err);
869fffd0934SJohannes Berg 	}
870fffd0934SJohannes Berg 
871fffd0934SJohannes Berg 	ieee80211_tx_skb(sdata, skb, 0);
87246900298SJohannes Berg }
87346900298SJohannes Berg 
874de95a54bSJohannes Berg int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
875de95a54bSJohannes Berg 			     const u8 *ie, size_t ie_len)
876de95a54bSJohannes Berg {
877de95a54bSJohannes Berg 	struct ieee80211_supported_band *sband;
878de95a54bSJohannes Berg 	u8 *pos, *supp_rates_len, *esupp_rates_len = NULL;
879de95a54bSJohannes Berg 	int i;
880de95a54bSJohannes Berg 
881de95a54bSJohannes Berg 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
882de95a54bSJohannes Berg 
883de95a54bSJohannes Berg 	pos = buffer;
884de95a54bSJohannes Berg 
885de95a54bSJohannes Berg 	*pos++ = WLAN_EID_SUPP_RATES;
886de95a54bSJohannes Berg 	supp_rates_len = pos;
887de95a54bSJohannes Berg 	*pos++ = 0;
888de95a54bSJohannes Berg 
889de95a54bSJohannes Berg 	for (i = 0; i < sband->n_bitrates; i++) {
890de95a54bSJohannes Berg 		struct ieee80211_rate *rate = &sband->bitrates[i];
891de95a54bSJohannes Berg 
892de95a54bSJohannes Berg 		if (esupp_rates_len) {
893de95a54bSJohannes Berg 			*esupp_rates_len += 1;
894de95a54bSJohannes Berg 		} else if (*supp_rates_len == 8) {
895de95a54bSJohannes Berg 			*pos++ = WLAN_EID_EXT_SUPP_RATES;
896de95a54bSJohannes Berg 			esupp_rates_len = pos;
897de95a54bSJohannes Berg 			*pos++ = 1;
898de95a54bSJohannes Berg 		} else
899de95a54bSJohannes Berg 			*supp_rates_len += 1;
900de95a54bSJohannes Berg 
901de95a54bSJohannes Berg 		*pos++ = rate->bitrate / 5;
902de95a54bSJohannes Berg 	}
903de95a54bSJohannes Berg 
9045ef2d41aSJohannes Berg 	if (sband->ht_cap.ht_supported) {
9055ef2d41aSJohannes Berg 		__le16 tmp = cpu_to_le16(sband->ht_cap.cap);
9065ef2d41aSJohannes Berg 
9075ef2d41aSJohannes Berg 		*pos++ = WLAN_EID_HT_CAPABILITY;
9085ef2d41aSJohannes Berg 		*pos++ = sizeof(struct ieee80211_ht_cap);
9095ef2d41aSJohannes Berg 		memset(pos, 0, sizeof(struct ieee80211_ht_cap));
9105ef2d41aSJohannes Berg 		memcpy(pos, &tmp, sizeof(u16));
9115ef2d41aSJohannes Berg 		pos += sizeof(u16);
9125ef2d41aSJohannes Berg 		/* TODO: needs a define here for << 2 */
9135ef2d41aSJohannes Berg 		*pos++ = sband->ht_cap.ampdu_factor |
9145ef2d41aSJohannes Berg 			 (sband->ht_cap.ampdu_density << 2);
9155ef2d41aSJohannes Berg 		memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
9165ef2d41aSJohannes Berg 		pos += sizeof(sband->ht_cap.mcs);
9175ef2d41aSJohannes Berg 		pos += 2 + 4 + 1; /* ext info, BF cap, antsel */
9185ef2d41aSJohannes Berg 	}
9195ef2d41aSJohannes Berg 
920de95a54bSJohannes Berg 	/*
921de95a54bSJohannes Berg 	 * If adding more here, adjust code in main.c
922de95a54bSJohannes Berg 	 * that calculates local->scan_ies_len.
923de95a54bSJohannes Berg 	 */
924de95a54bSJohannes Berg 
925de95a54bSJohannes Berg 	if (ie) {
926de95a54bSJohannes Berg 		memcpy(pos, ie, ie_len);
927de95a54bSJohannes Berg 		pos += ie_len;
928de95a54bSJohannes Berg 	}
929de95a54bSJohannes Berg 
930de95a54bSJohannes Berg 	return pos - buffer;
931de95a54bSJohannes Berg }
932de95a54bSJohannes Berg 
93346900298SJohannes Berg void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
934de95a54bSJohannes Berg 			      const u8 *ssid, size_t ssid_len,
935de95a54bSJohannes Berg 			      const u8 *ie, size_t ie_len)
93646900298SJohannes Berg {
93746900298SJohannes Berg 	struct ieee80211_local *local = sdata->local;
93846900298SJohannes Berg 	struct sk_buff *skb;
93946900298SJohannes Berg 	struct ieee80211_mgmt *mgmt;
940de95a54bSJohannes Berg 	u8 *pos;
94146900298SJohannes Berg 
94246900298SJohannes Berg 	skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 +
94365fc73acSJouni Malinen 			    ie_len);
94446900298SJohannes Berg 	if (!skb) {
94546900298SJohannes Berg 		printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
94646900298SJohannes Berg 		       "request\n", sdata->dev->name);
94746900298SJohannes Berg 		return;
94846900298SJohannes Berg 	}
94946900298SJohannes Berg 	skb_reserve(skb, local->hw.extra_tx_headroom);
95046900298SJohannes Berg 
95146900298SJohannes Berg 	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
95246900298SJohannes Berg 	memset(mgmt, 0, 24);
95346900298SJohannes Berg 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
95446900298SJohannes Berg 					  IEEE80211_STYPE_PROBE_REQ);
95546900298SJohannes Berg 	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
95646900298SJohannes Berg 	if (dst) {
95746900298SJohannes Berg 		memcpy(mgmt->da, dst, ETH_ALEN);
95846900298SJohannes Berg 		memcpy(mgmt->bssid, dst, ETH_ALEN);
95946900298SJohannes Berg 	} else {
96046900298SJohannes Berg 		memset(mgmt->da, 0xff, ETH_ALEN);
96146900298SJohannes Berg 		memset(mgmt->bssid, 0xff, ETH_ALEN);
96246900298SJohannes Berg 	}
96346900298SJohannes Berg 	pos = skb_put(skb, 2 + ssid_len);
96446900298SJohannes Berg 	*pos++ = WLAN_EID_SSID;
96546900298SJohannes Berg 	*pos++ = ssid_len;
96646900298SJohannes Berg 	memcpy(pos, ssid, ssid_len);
967de95a54bSJohannes Berg 	pos += ssid_len;
96846900298SJohannes Berg 
969de95a54bSJohannes Berg 	skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len));
97046900298SJohannes Berg 
97146900298SJohannes Berg 	ieee80211_tx_skb(sdata, skb, 0);
97246900298SJohannes Berg }
97346900298SJohannes Berg 
97446900298SJohannes Berg u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
97546900298SJohannes Berg 			    struct ieee802_11_elems *elems,
97646900298SJohannes Berg 			    enum ieee80211_band band)
97746900298SJohannes Berg {
97846900298SJohannes Berg 	struct ieee80211_supported_band *sband;
97946900298SJohannes Berg 	struct ieee80211_rate *bitrates;
98046900298SJohannes Berg 	size_t num_rates;
98146900298SJohannes Berg 	u32 supp_rates;
98246900298SJohannes Berg 	int i, j;
98346900298SJohannes Berg 	sband = local->hw.wiphy->bands[band];
98446900298SJohannes Berg 
98546900298SJohannes Berg 	if (!sband) {
98646900298SJohannes Berg 		WARN_ON(1);
98746900298SJohannes Berg 		sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
98846900298SJohannes Berg 	}
98946900298SJohannes Berg 
99046900298SJohannes Berg 	bitrates = sband->bitrates;
99146900298SJohannes Berg 	num_rates = sband->n_bitrates;
99246900298SJohannes Berg 	supp_rates = 0;
99346900298SJohannes Berg 	for (i = 0; i < elems->supp_rates_len +
99446900298SJohannes Berg 		     elems->ext_supp_rates_len; i++) {
99546900298SJohannes Berg 		u8 rate = 0;
99646900298SJohannes Berg 		int own_rate;
99746900298SJohannes Berg 		if (i < elems->supp_rates_len)
99846900298SJohannes Berg 			rate = elems->supp_rates[i];
99946900298SJohannes Berg 		else if (elems->ext_supp_rates)
100046900298SJohannes Berg 			rate = elems->ext_supp_rates
100146900298SJohannes Berg 				[i - elems->supp_rates_len];
100246900298SJohannes Berg 		own_rate = 5 * (rate & 0x7f);
100346900298SJohannes Berg 		for (j = 0; j < num_rates; j++)
100446900298SJohannes Berg 			if (bitrates[j].bitrate == own_rate)
100546900298SJohannes Berg 				supp_rates |= BIT(j);
100646900298SJohannes Berg 	}
100746900298SJohannes Berg 	return supp_rates;
100846900298SJohannes Berg }
1009f2753ddbSJohannes Berg 
1010f2753ddbSJohannes Berg int ieee80211_reconfig(struct ieee80211_local *local)
1011f2753ddbSJohannes Berg {
1012f2753ddbSJohannes Berg 	struct ieee80211_hw *hw = &local->hw;
1013f2753ddbSJohannes Berg 	struct ieee80211_sub_if_data *sdata;
1014f2753ddbSJohannes Berg 	struct ieee80211_if_init_conf conf;
1015f2753ddbSJohannes Berg 	struct sta_info *sta;
1016f2753ddbSJohannes Berg 	unsigned long flags;
1017f2753ddbSJohannes Berg 	int res;
10185bb644a0SJohannes Berg 	bool from_suspend = local->suspended;
10195bb644a0SJohannes Berg 
10205bb644a0SJohannes Berg 	/*
10215bb644a0SJohannes Berg 	 * We're going to start the hardware, at that point
10225bb644a0SJohannes Berg 	 * we are no longer suspended and can RX frames.
10235bb644a0SJohannes Berg 	 */
10245bb644a0SJohannes Berg 	local->suspended = false;
1025f2753ddbSJohannes Berg 
1026f2753ddbSJohannes Berg 	/* restart hardware */
1027f2753ddbSJohannes Berg 	if (local->open_count) {
102824487981SJohannes Berg 		res = drv_start(local);
1029f2753ddbSJohannes Berg 
10301f87f7d3SJohannes Berg 		ieee80211_led_radio(local, true);
1031f2753ddbSJohannes Berg 	}
1032f2753ddbSJohannes Berg 
1033f2753ddbSJohannes Berg 	/* add interfaces */
1034f2753ddbSJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
1035f2753ddbSJohannes Berg 		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
1036f2753ddbSJohannes Berg 		    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
1037f2753ddbSJohannes Berg 		    netif_running(sdata->dev)) {
1038f2753ddbSJohannes Berg 			conf.vif = &sdata->vif;
1039f2753ddbSJohannes Berg 			conf.type = sdata->vif.type;
1040f2753ddbSJohannes Berg 			conf.mac_addr = sdata->dev->dev_addr;
104124487981SJohannes Berg 			res = drv_add_interface(local, &conf);
1042f2753ddbSJohannes Berg 		}
1043f2753ddbSJohannes Berg 	}
1044f2753ddbSJohannes Berg 
1045f2753ddbSJohannes Berg 	/* add STAs back */
1046f2753ddbSJohannes Berg 	if (local->ops->sta_notify) {
1047f2753ddbSJohannes Berg 		spin_lock_irqsave(&local->sta_lock, flags);
1048f2753ddbSJohannes Berg 		list_for_each_entry(sta, &local->sta_list, list) {
10495bb644a0SJohannes Berg 			sdata = sta->sdata;
1050f2753ddbSJohannes Berg 			if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
1051f2753ddbSJohannes Berg 				sdata = container_of(sdata->bss,
1052f2753ddbSJohannes Berg 					     struct ieee80211_sub_if_data,
1053f2753ddbSJohannes Berg 					     u.ap);
1054f2753ddbSJohannes Berg 
105524487981SJohannes Berg 			drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD,
105624487981SJohannes Berg 				       &sta->sta);
1057f2753ddbSJohannes Berg 		}
1058f2753ddbSJohannes Berg 		spin_unlock_irqrestore(&local->sta_lock, flags);
1059f2753ddbSJohannes Berg 	}
1060f2753ddbSJohannes Berg 
1061f2753ddbSJohannes Berg 	/* Clear Suspend state so that ADDBA requests can be processed */
1062f2753ddbSJohannes Berg 
1063f2753ddbSJohannes Berg 	rcu_read_lock();
1064f2753ddbSJohannes Berg 
1065f2753ddbSJohannes Berg 	if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
1066f2753ddbSJohannes Berg 		list_for_each_entry_rcu(sta, &local->sta_list, list) {
1067f2753ddbSJohannes Berg 			clear_sta_flags(sta, WLAN_STA_SUSPEND);
1068f2753ddbSJohannes Berg 		}
1069f2753ddbSJohannes Berg 	}
1070f2753ddbSJohannes Berg 
1071f2753ddbSJohannes Berg 	rcu_read_unlock();
1072f2753ddbSJohannes Berg 
1073f2753ddbSJohannes Berg 	/* setup RTS threshold */
107424487981SJohannes Berg 	drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
1075f2753ddbSJohannes Berg 
1076f2753ddbSJohannes Berg 	/* reconfigure hardware */
1077f2753ddbSJohannes Berg 	ieee80211_hw_config(local, ~0);
1078f2753ddbSJohannes Berg 
10793b8d81e0SJohannes Berg 	spin_lock_bh(&local->filter_lock);
1080f2753ddbSJohannes Berg 	ieee80211_configure_filter(local);
10813b8d81e0SJohannes Berg 	spin_unlock_bh(&local->filter_lock);
1082f2753ddbSJohannes Berg 
1083f2753ddbSJohannes Berg 	/* Finally also reconfigure all the BSS information */
1084f2753ddbSJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
1085f2753ddbSJohannes Berg 		u32 changed = ~0;
1086f2753ddbSJohannes Berg 		if (!netif_running(sdata->dev))
1087f2753ddbSJohannes Berg 			continue;
1088f2753ddbSJohannes Berg 		switch (sdata->vif.type) {
1089f2753ddbSJohannes Berg 		case NL80211_IFTYPE_STATION:
1090f2753ddbSJohannes Berg 			/* disable beacon change bits */
10912d0ddec5SJohannes Berg 			changed &= ~(BSS_CHANGED_BEACON |
10922d0ddec5SJohannes Berg 				     BSS_CHANGED_BEACON_ENABLED);
1093f2753ddbSJohannes Berg 			/* fall through */
1094f2753ddbSJohannes Berg 		case NL80211_IFTYPE_ADHOC:
1095f2753ddbSJohannes Berg 		case NL80211_IFTYPE_AP:
1096f2753ddbSJohannes Berg 		case NL80211_IFTYPE_MESH_POINT:
10972d0ddec5SJohannes Berg 			ieee80211_bss_info_change_notify(sdata, changed);
1098f2753ddbSJohannes Berg 			break;
1099f2753ddbSJohannes Berg 		case NL80211_IFTYPE_WDS:
1100f2753ddbSJohannes Berg 			break;
1101f2753ddbSJohannes Berg 		case NL80211_IFTYPE_AP_VLAN:
1102f2753ddbSJohannes Berg 		case NL80211_IFTYPE_MONITOR:
1103f2753ddbSJohannes Berg 			/* ignore virtual */
1104f2753ddbSJohannes Berg 			break;
1105f2753ddbSJohannes Berg 		case NL80211_IFTYPE_UNSPECIFIED:
1106f2753ddbSJohannes Berg 		case __NL80211_IFTYPE_AFTER_LAST:
1107f2753ddbSJohannes Berg 			WARN_ON(1);
1108f2753ddbSJohannes Berg 			break;
1109f2753ddbSJohannes Berg 		}
1110f2753ddbSJohannes Berg 	}
1111f2753ddbSJohannes Berg 
1112f2753ddbSJohannes Berg 	/* add back keys */
1113f2753ddbSJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list)
1114f2753ddbSJohannes Berg 		if (netif_running(sdata->dev))
1115f2753ddbSJohannes Berg 			ieee80211_enable_keys(sdata);
1116f2753ddbSJohannes Berg 
1117f2753ddbSJohannes Berg 	ieee80211_wake_queues_by_reason(hw,
1118f2753ddbSJohannes Berg 			IEEE80211_QUEUE_STOP_REASON_SUSPEND);
1119f2753ddbSJohannes Berg 
11205bb644a0SJohannes Berg 	/*
11215bb644a0SJohannes Berg 	 * If this is for hw restart things are still running.
11225bb644a0SJohannes Berg 	 * We may want to change that later, however.
11235bb644a0SJohannes Berg 	 */
11245bb644a0SJohannes Berg 	if (!from_suspend)
11255bb644a0SJohannes Berg 		return 0;
11265bb644a0SJohannes Berg 
11275bb644a0SJohannes Berg #ifdef CONFIG_PM
11285bb644a0SJohannes Berg 	local->suspended = false;
11295bb644a0SJohannes Berg 
11305bb644a0SJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
11315bb644a0SJohannes Berg 		switch(sdata->vif.type) {
11325bb644a0SJohannes Berg 		case NL80211_IFTYPE_STATION:
11335bb644a0SJohannes Berg 			ieee80211_sta_restart(sdata);
11345bb644a0SJohannes Berg 			break;
11355bb644a0SJohannes Berg 		case NL80211_IFTYPE_ADHOC:
11365bb644a0SJohannes Berg 			ieee80211_ibss_restart(sdata);
11375bb644a0SJohannes Berg 			break;
11385bb644a0SJohannes Berg 		case NL80211_IFTYPE_MESH_POINT:
11395bb644a0SJohannes Berg 			ieee80211_mesh_restart(sdata);
11405bb644a0SJohannes Berg 			break;
11415bb644a0SJohannes Berg 		default:
11425bb644a0SJohannes Berg 			break;
11435bb644a0SJohannes Berg 		}
11445bb644a0SJohannes Berg 	}
11455bb644a0SJohannes Berg 
11465bb644a0SJohannes Berg 	add_timer(&local->sta_cleanup);
11475bb644a0SJohannes Berg 
11485bb644a0SJohannes Berg 	spin_lock_irqsave(&local->sta_lock, flags);
11495bb644a0SJohannes Berg 	list_for_each_entry(sta, &local->sta_list, list)
11505bb644a0SJohannes Berg 		mesh_plink_restart(sta);
11515bb644a0SJohannes Berg 	spin_unlock_irqrestore(&local->sta_lock, flags);
11525bb644a0SJohannes Berg #else
11535bb644a0SJohannes Berg 	WARN_ON(1);
11545bb644a0SJohannes Berg #endif
1155f2753ddbSJohannes Berg 	return 0;
1156f2753ddbSJohannes Berg }
115742935ecaSLuis R. Rodriguez 
1158