xref: /openbmc/linux/net/mac80211/util.c (revision a7bc376c)
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 
51437ffc8daSJohannes Berg void ieee802_11_parse_elems(u8 *start, size_t len,
51537ffc8daSJohannes Berg 			    struct ieee802_11_elems *elems)
51637ffc8daSJohannes Berg {
517d91f36dbSJohannes Berg 	ieee802_11_parse_elems_crc(start, len, elems, 0, 0);
518d91f36dbSJohannes Berg }
519d91f36dbSJohannes Berg 
520d91f36dbSJohannes Berg u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
521d91f36dbSJohannes Berg 			       struct ieee802_11_elems *elems,
522d91f36dbSJohannes Berg 			       u64 filter, u32 crc)
523d91f36dbSJohannes Berg {
52437ffc8daSJohannes Berg 	size_t left = len;
52537ffc8daSJohannes Berg 	u8 *pos = start;
526d91f36dbSJohannes Berg 	bool calc_crc = filter != 0;
52737ffc8daSJohannes Berg 
52837ffc8daSJohannes Berg 	memset(elems, 0, sizeof(*elems));
52937ffc8daSJohannes Berg 	elems->ie_start = start;
53037ffc8daSJohannes Berg 	elems->total_len = len;
53137ffc8daSJohannes Berg 
53237ffc8daSJohannes Berg 	while (left >= 2) {
53337ffc8daSJohannes Berg 		u8 id, elen;
53437ffc8daSJohannes Berg 
53537ffc8daSJohannes Berg 		id = *pos++;
53637ffc8daSJohannes Berg 		elen = *pos++;
53737ffc8daSJohannes Berg 		left -= 2;
53837ffc8daSJohannes Berg 
53937ffc8daSJohannes Berg 		if (elen > left)
540d91f36dbSJohannes Berg 			break;
541d91f36dbSJohannes Berg 
542d91f36dbSJohannes Berg 		if (calc_crc && id < 64 && (filter & BIT(id)))
543d91f36dbSJohannes Berg 			crc = crc32_be(crc, pos - 2, elen + 2);
54437ffc8daSJohannes Berg 
54537ffc8daSJohannes Berg 		switch (id) {
54637ffc8daSJohannes Berg 		case WLAN_EID_SSID:
54737ffc8daSJohannes Berg 			elems->ssid = pos;
54837ffc8daSJohannes Berg 			elems->ssid_len = elen;
54937ffc8daSJohannes Berg 			break;
55037ffc8daSJohannes Berg 		case WLAN_EID_SUPP_RATES:
55137ffc8daSJohannes Berg 			elems->supp_rates = pos;
55237ffc8daSJohannes Berg 			elems->supp_rates_len = elen;
55337ffc8daSJohannes Berg 			break;
55437ffc8daSJohannes Berg 		case WLAN_EID_FH_PARAMS:
55537ffc8daSJohannes Berg 			elems->fh_params = pos;
55637ffc8daSJohannes Berg 			elems->fh_params_len = elen;
55737ffc8daSJohannes Berg 			break;
55837ffc8daSJohannes Berg 		case WLAN_EID_DS_PARAMS:
55937ffc8daSJohannes Berg 			elems->ds_params = pos;
56037ffc8daSJohannes Berg 			elems->ds_params_len = elen;
56137ffc8daSJohannes Berg 			break;
56237ffc8daSJohannes Berg 		case WLAN_EID_CF_PARAMS:
56337ffc8daSJohannes Berg 			elems->cf_params = pos;
56437ffc8daSJohannes Berg 			elems->cf_params_len = elen;
56537ffc8daSJohannes Berg 			break;
56637ffc8daSJohannes Berg 		case WLAN_EID_TIM:
567e7ec86f5SJohannes Berg 			if (elen >= sizeof(struct ieee80211_tim_ie)) {
568e7ec86f5SJohannes Berg 				elems->tim = (void *)pos;
56937ffc8daSJohannes Berg 				elems->tim_len = elen;
570e7ec86f5SJohannes Berg 			}
57137ffc8daSJohannes Berg 			break;
57237ffc8daSJohannes Berg 		case WLAN_EID_IBSS_PARAMS:
57337ffc8daSJohannes Berg 			elems->ibss_params = pos;
57437ffc8daSJohannes Berg 			elems->ibss_params_len = elen;
57537ffc8daSJohannes Berg 			break;
57637ffc8daSJohannes Berg 		case WLAN_EID_CHALLENGE:
57737ffc8daSJohannes Berg 			elems->challenge = pos;
57837ffc8daSJohannes Berg 			elems->challenge_len = elen;
57937ffc8daSJohannes Berg 			break;
580d91f36dbSJohannes Berg 		case WLAN_EID_VENDOR_SPECIFIC:
58137ffc8daSJohannes Berg 			if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
58237ffc8daSJohannes Berg 			    pos[2] == 0xf2) {
58337ffc8daSJohannes Berg 				/* Microsoft OUI (00:50:F2) */
584d91f36dbSJohannes Berg 
585d91f36dbSJohannes Berg 				if (calc_crc)
586d91f36dbSJohannes Berg 					crc = crc32_be(crc, pos - 2, elen + 2);
587d91f36dbSJohannes Berg 
58837ffc8daSJohannes Berg 				if (pos[3] == 1) {
58937ffc8daSJohannes Berg 					/* OUI Type 1 - WPA IE */
59037ffc8daSJohannes Berg 					elems->wpa = pos;
59137ffc8daSJohannes Berg 					elems->wpa_len = elen;
59237ffc8daSJohannes Berg 				} else if (elen >= 5 && pos[3] == 2) {
593d91f36dbSJohannes Berg 					/* OUI Type 2 - WMM IE */
59437ffc8daSJohannes Berg 					if (pos[4] == 0) {
59537ffc8daSJohannes Berg 						elems->wmm_info = pos;
59637ffc8daSJohannes Berg 						elems->wmm_info_len = elen;
59737ffc8daSJohannes Berg 					} else if (pos[4] == 1) {
59837ffc8daSJohannes Berg 						elems->wmm_param = pos;
59937ffc8daSJohannes Berg 						elems->wmm_param_len = elen;
60037ffc8daSJohannes Berg 					}
60137ffc8daSJohannes Berg 				}
60237ffc8daSJohannes Berg 			}
60337ffc8daSJohannes Berg 			break;
60437ffc8daSJohannes Berg 		case WLAN_EID_RSN:
60537ffc8daSJohannes Berg 			elems->rsn = pos;
60637ffc8daSJohannes Berg 			elems->rsn_len = elen;
60737ffc8daSJohannes Berg 			break;
60837ffc8daSJohannes Berg 		case WLAN_EID_ERP_INFO:
60937ffc8daSJohannes Berg 			elems->erp_info = pos;
61037ffc8daSJohannes Berg 			elems->erp_info_len = elen;
61137ffc8daSJohannes Berg 			break;
61237ffc8daSJohannes Berg 		case WLAN_EID_EXT_SUPP_RATES:
61337ffc8daSJohannes Berg 			elems->ext_supp_rates = pos;
61437ffc8daSJohannes Berg 			elems->ext_supp_rates_len = elen;
61537ffc8daSJohannes Berg 			break;
61637ffc8daSJohannes Berg 		case WLAN_EID_HT_CAPABILITY:
61709914813SJohannes Berg 			if (elen >= sizeof(struct ieee80211_ht_cap))
61809914813SJohannes Berg 				elems->ht_cap_elem = (void *)pos;
61937ffc8daSJohannes Berg 			break;
620d9fe60deSJohannes Berg 		case WLAN_EID_HT_INFORMATION:
621d9fe60deSJohannes Berg 			if (elen >= sizeof(struct ieee80211_ht_info))
62209914813SJohannes Berg 				elems->ht_info_elem = (void *)pos;
62337ffc8daSJohannes Berg 			break;
62437ffc8daSJohannes Berg 		case WLAN_EID_MESH_ID:
62537ffc8daSJohannes Berg 			elems->mesh_id = pos;
62637ffc8daSJohannes Berg 			elems->mesh_id_len = elen;
62737ffc8daSJohannes Berg 			break;
62837ffc8daSJohannes Berg 		case WLAN_EID_MESH_CONFIG:
62937ffc8daSJohannes Berg 			elems->mesh_config = pos;
63037ffc8daSJohannes Berg 			elems->mesh_config_len = elen;
63137ffc8daSJohannes Berg 			break;
63237ffc8daSJohannes Berg 		case WLAN_EID_PEER_LINK:
63337ffc8daSJohannes Berg 			elems->peer_link = pos;
63437ffc8daSJohannes Berg 			elems->peer_link_len = elen;
63537ffc8daSJohannes Berg 			break;
63637ffc8daSJohannes Berg 		case WLAN_EID_PREQ:
63737ffc8daSJohannes Berg 			elems->preq = pos;
63837ffc8daSJohannes Berg 			elems->preq_len = elen;
63937ffc8daSJohannes Berg 			break;
64037ffc8daSJohannes Berg 		case WLAN_EID_PREP:
64137ffc8daSJohannes Berg 			elems->prep = pos;
64237ffc8daSJohannes Berg 			elems->prep_len = elen;
64337ffc8daSJohannes Berg 			break;
64437ffc8daSJohannes Berg 		case WLAN_EID_PERR:
64537ffc8daSJohannes Berg 			elems->perr = pos;
64637ffc8daSJohannes Berg 			elems->perr_len = elen;
64737ffc8daSJohannes Berg 			break;
64837ffc8daSJohannes Berg 		case WLAN_EID_CHANNEL_SWITCH:
64937ffc8daSJohannes Berg 			elems->ch_switch_elem = pos;
65037ffc8daSJohannes Berg 			elems->ch_switch_elem_len = elen;
65137ffc8daSJohannes Berg 			break;
65237ffc8daSJohannes Berg 		case WLAN_EID_QUIET:
65337ffc8daSJohannes Berg 			if (!elems->quiet_elem) {
65437ffc8daSJohannes Berg 				elems->quiet_elem = pos;
65537ffc8daSJohannes Berg 				elems->quiet_elem_len = elen;
65637ffc8daSJohannes Berg 			}
65737ffc8daSJohannes Berg 			elems->num_of_quiet_elem++;
65837ffc8daSJohannes Berg 			break;
65937ffc8daSJohannes Berg 		case WLAN_EID_COUNTRY:
66037ffc8daSJohannes Berg 			elems->country_elem = pos;
66137ffc8daSJohannes Berg 			elems->country_elem_len = elen;
66237ffc8daSJohannes Berg 			break;
66337ffc8daSJohannes Berg 		case WLAN_EID_PWR_CONSTRAINT:
66437ffc8daSJohannes Berg 			elems->pwr_constr_elem = pos;
66537ffc8daSJohannes Berg 			elems->pwr_constr_elem_len = elen;
66637ffc8daSJohannes Berg 			break;
667f797eb7eSJouni Malinen 		case WLAN_EID_TIMEOUT_INTERVAL:
668f797eb7eSJouni Malinen 			elems->timeout_int = pos;
669f797eb7eSJouni Malinen 			elems->timeout_int_len = elen;
67063a5ab82SJouni Malinen 			break;
67137ffc8daSJohannes Berg 		default:
67237ffc8daSJohannes Berg 			break;
67337ffc8daSJohannes Berg 		}
67437ffc8daSJohannes Berg 
67537ffc8daSJohannes Berg 		left -= elen;
67637ffc8daSJohannes Berg 		pos += elen;
67737ffc8daSJohannes Berg 	}
678d91f36dbSJohannes Berg 
679d91f36dbSJohannes Berg 	return crc;
68037ffc8daSJohannes Berg }
6815825fe10SJohannes Berg 
6825825fe10SJohannes Berg void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
6835825fe10SJohannes Berg {
6845825fe10SJohannes Berg 	struct ieee80211_local *local = sdata->local;
6855825fe10SJohannes Berg 	struct ieee80211_tx_queue_params qparam;
686aa837e1dSJohannes Berg 	int queue;
687aa837e1dSJohannes Berg 	bool use_11b;
688aa837e1dSJohannes Berg 	int aCWmin, aCWmax;
6895825fe10SJohannes Berg 
6905825fe10SJohannes Berg 	if (!local->ops->conf_tx)
6915825fe10SJohannes Berg 		return;
6925825fe10SJohannes Berg 
6935825fe10SJohannes Berg 	memset(&qparam, 0, sizeof(qparam));
6945825fe10SJohannes Berg 
695aa837e1dSJohannes Berg 	use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
696aa837e1dSJohannes Berg 		 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
6975825fe10SJohannes Berg 
698aa837e1dSJohannes Berg 	for (queue = 0; queue < local_to_hw(local)->queues; queue++) {
699aa837e1dSJohannes Berg 		/* Set defaults according to 802.11-2007 Table 7-37 */
700aa837e1dSJohannes Berg 		aCWmax = 1023;
701aa837e1dSJohannes Berg 		if (use_11b)
702aa837e1dSJohannes Berg 			aCWmin = 31;
7035825fe10SJohannes Berg 		else
704aa837e1dSJohannes Berg 			aCWmin = 15;
7055825fe10SJohannes Berg 
706aa837e1dSJohannes Berg 		switch (queue) {
707aa837e1dSJohannes Berg 		case 3: /* AC_BK */
7087ba10a8eSJohannes Berg 			qparam.cw_max = aCWmax;
7097ba10a8eSJohannes Berg 			qparam.cw_min = aCWmin;
7105825fe10SJohannes Berg 			qparam.txop = 0;
711aa837e1dSJohannes Berg 			qparam.aifs = 7;
712aa837e1dSJohannes Berg 			break;
713aa837e1dSJohannes Berg 		default: /* never happens but let's not leave undefined */
714aa837e1dSJohannes Berg 		case 2: /* AC_BE */
7157ba10a8eSJohannes Berg 			qparam.cw_max = aCWmax;
7167ba10a8eSJohannes Berg 			qparam.cw_min = aCWmin;
717aa837e1dSJohannes Berg 			qparam.txop = 0;
718aa837e1dSJohannes Berg 			qparam.aifs = 3;
719aa837e1dSJohannes Berg 			break;
720aa837e1dSJohannes Berg 		case 1: /* AC_VI */
721aa837e1dSJohannes Berg 			qparam.cw_max = aCWmin;
722aa837e1dSJohannes Berg 			qparam.cw_min = (aCWmin + 1) / 2 - 1;
723aa837e1dSJohannes Berg 			if (use_11b)
724aa837e1dSJohannes Berg 				qparam.txop = 6016/32;
725aa837e1dSJohannes Berg 			else
726aa837e1dSJohannes Berg 				qparam.txop = 3008/32;
727aa837e1dSJohannes Berg 			qparam.aifs = 2;
728aa837e1dSJohannes Berg 			break;
729aa837e1dSJohannes Berg 		case 0: /* AC_VO */
730aa837e1dSJohannes Berg 			qparam.cw_max = (aCWmin + 1) / 2 - 1;
731aa837e1dSJohannes Berg 			qparam.cw_min = (aCWmin + 1) / 4 - 1;
732aa837e1dSJohannes Berg 			if (use_11b)
733aa837e1dSJohannes Berg 				qparam.txop = 3264/32;
734aa837e1dSJohannes Berg 			else
735aa837e1dSJohannes Berg 				qparam.txop = 1504/32;
736aa837e1dSJohannes Berg 			qparam.aifs = 2;
737aa837e1dSJohannes Berg 			break;
738aa837e1dSJohannes Berg 		}
7395825fe10SJohannes Berg 
740aa837e1dSJohannes Berg 		drv_conf_tx(local, queue, &qparam);
741aa837e1dSJohannes Berg 	}
7425825fe10SJohannes Berg }
743e50db65cSJohannes Berg 
74446900298SJohannes Berg void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
74546900298SJohannes Berg 				  const size_t supp_rates_len,
74646900298SJohannes Berg 				  const u8 *supp_rates)
74746900298SJohannes Berg {
74846900298SJohannes Berg 	struct ieee80211_local *local = sdata->local;
74946900298SJohannes Berg 	int i, have_higher_than_11mbit = 0;
75046900298SJohannes Berg 
75146900298SJohannes Berg 	/* cf. IEEE 802.11 9.2.12 */
75246900298SJohannes Berg 	for (i = 0; i < supp_rates_len; i++)
75346900298SJohannes Berg 		if ((supp_rates[i] & 0x7f) * 5 > 110)
75446900298SJohannes Berg 			have_higher_than_11mbit = 1;
75546900298SJohannes Berg 
75646900298SJohannes Berg 	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
75746900298SJohannes Berg 	    have_higher_than_11mbit)
75846900298SJohannes Berg 		sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
75946900298SJohannes Berg 	else
76046900298SJohannes Berg 		sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
76146900298SJohannes Berg 
76246900298SJohannes Berg 	ieee80211_set_wmm_default(sdata);
76346900298SJohannes Berg }
76446900298SJohannes Berg 
765881d948cSJohannes Berg u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
76696dd22acSJohannes Berg 			      enum ieee80211_band band)
76796dd22acSJohannes Berg {
76896dd22acSJohannes Berg 	struct ieee80211_supported_band *sband;
76996dd22acSJohannes Berg 	struct ieee80211_rate *bitrates;
770881d948cSJohannes Berg 	u32 mandatory_rates;
77196dd22acSJohannes Berg 	enum ieee80211_rate_flags mandatory_flag;
77296dd22acSJohannes Berg 	int i;
77396dd22acSJohannes Berg 
77496dd22acSJohannes Berg 	sband = local->hw.wiphy->bands[band];
77596dd22acSJohannes Berg 	if (!sband) {
77696dd22acSJohannes Berg 		WARN_ON(1);
77796dd22acSJohannes Berg 		sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
77896dd22acSJohannes Berg 	}
77996dd22acSJohannes Berg 
78096dd22acSJohannes Berg 	if (band == IEEE80211_BAND_2GHZ)
78196dd22acSJohannes Berg 		mandatory_flag = IEEE80211_RATE_MANDATORY_B;
78296dd22acSJohannes Berg 	else
78396dd22acSJohannes Berg 		mandatory_flag = IEEE80211_RATE_MANDATORY_A;
78496dd22acSJohannes Berg 
78596dd22acSJohannes Berg 	bitrates = sband->bitrates;
78696dd22acSJohannes Berg 	mandatory_rates = 0;
78796dd22acSJohannes Berg 	for (i = 0; i < sband->n_bitrates; i++)
78896dd22acSJohannes Berg 		if (bitrates[i].flags & mandatory_flag)
78996dd22acSJohannes Berg 			mandatory_rates |= BIT(i);
79096dd22acSJohannes Berg 	return mandatory_rates;
79196dd22acSJohannes Berg }
79246900298SJohannes Berg 
79346900298SJohannes Berg void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
79446900298SJohannes Berg 			 u16 transaction, u16 auth_alg,
795fffd0934SJohannes Berg 			 u8 *extra, size_t extra_len, const u8 *bssid,
796fffd0934SJohannes Berg 			 const u8 *key, u8 key_len, u8 key_idx)
79746900298SJohannes Berg {
79846900298SJohannes Berg 	struct ieee80211_local *local = sdata->local;
79946900298SJohannes Berg 	struct sk_buff *skb;
80046900298SJohannes Berg 	struct ieee80211_mgmt *mgmt;
801fffd0934SJohannes Berg 	int err;
80246900298SJohannes Berg 
80346900298SJohannes Berg 	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
80465fc73acSJouni Malinen 			    sizeof(*mgmt) + 6 + extra_len);
80546900298SJohannes Berg 	if (!skb) {
80646900298SJohannes Berg 		printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
80746900298SJohannes Berg 		       "frame\n", sdata->dev->name);
80846900298SJohannes Berg 		return;
80946900298SJohannes Berg 	}
81046900298SJohannes Berg 	skb_reserve(skb, local->hw.extra_tx_headroom);
81146900298SJohannes Berg 
81246900298SJohannes Berg 	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
81346900298SJohannes Berg 	memset(mgmt, 0, 24 + 6);
81446900298SJohannes Berg 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
81546900298SJohannes Berg 					  IEEE80211_STYPE_AUTH);
81646900298SJohannes Berg 	memcpy(mgmt->da, bssid, ETH_ALEN);
81746900298SJohannes Berg 	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
81846900298SJohannes Berg 	memcpy(mgmt->bssid, bssid, ETH_ALEN);
81946900298SJohannes Berg 	mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg);
82046900298SJohannes Berg 	mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
82146900298SJohannes Berg 	mgmt->u.auth.status_code = cpu_to_le16(0);
82246900298SJohannes Berg 	if (extra)
82346900298SJohannes Berg 		memcpy(skb_put(skb, extra_len), extra, extra_len);
82446900298SJohannes Berg 
825fffd0934SJohannes Berg 	if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
826fffd0934SJohannes Berg 		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
827fffd0934SJohannes Berg 		err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx);
828fffd0934SJohannes Berg 		WARN_ON(err);
829fffd0934SJohannes Berg 	}
830fffd0934SJohannes Berg 
831fffd0934SJohannes Berg 	ieee80211_tx_skb(sdata, skb, 0);
83246900298SJohannes Berg }
83346900298SJohannes Berg 
834de95a54bSJohannes Berg int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
835de95a54bSJohannes Berg 			     const u8 *ie, size_t ie_len)
836de95a54bSJohannes Berg {
837de95a54bSJohannes Berg 	struct ieee80211_supported_band *sband;
838de95a54bSJohannes Berg 	u8 *pos, *supp_rates_len, *esupp_rates_len = NULL;
839de95a54bSJohannes Berg 	int i;
840de95a54bSJohannes Berg 
841de95a54bSJohannes Berg 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
842de95a54bSJohannes Berg 
843de95a54bSJohannes Berg 	pos = buffer;
844de95a54bSJohannes Berg 
845de95a54bSJohannes Berg 	*pos++ = WLAN_EID_SUPP_RATES;
846de95a54bSJohannes Berg 	supp_rates_len = pos;
847de95a54bSJohannes Berg 	*pos++ = 0;
848de95a54bSJohannes Berg 
849de95a54bSJohannes Berg 	for (i = 0; i < sband->n_bitrates; i++) {
850de95a54bSJohannes Berg 		struct ieee80211_rate *rate = &sband->bitrates[i];
851de95a54bSJohannes Berg 
852de95a54bSJohannes Berg 		if (esupp_rates_len) {
853de95a54bSJohannes Berg 			*esupp_rates_len += 1;
854de95a54bSJohannes Berg 		} else if (*supp_rates_len == 8) {
855de95a54bSJohannes Berg 			*pos++ = WLAN_EID_EXT_SUPP_RATES;
856de95a54bSJohannes Berg 			esupp_rates_len = pos;
857de95a54bSJohannes Berg 			*pos++ = 1;
858de95a54bSJohannes Berg 		} else
859de95a54bSJohannes Berg 			*supp_rates_len += 1;
860de95a54bSJohannes Berg 
861de95a54bSJohannes Berg 		*pos++ = rate->bitrate / 5;
862de95a54bSJohannes Berg 	}
863de95a54bSJohannes Berg 
8645ef2d41aSJohannes Berg 	if (sband->ht_cap.ht_supported) {
8655ef2d41aSJohannes Berg 		__le16 tmp = cpu_to_le16(sband->ht_cap.cap);
8665ef2d41aSJohannes Berg 
8675ef2d41aSJohannes Berg 		*pos++ = WLAN_EID_HT_CAPABILITY;
8685ef2d41aSJohannes Berg 		*pos++ = sizeof(struct ieee80211_ht_cap);
8695ef2d41aSJohannes Berg 		memset(pos, 0, sizeof(struct ieee80211_ht_cap));
8705ef2d41aSJohannes Berg 		memcpy(pos, &tmp, sizeof(u16));
8715ef2d41aSJohannes Berg 		pos += sizeof(u16);
8725ef2d41aSJohannes Berg 		/* TODO: needs a define here for << 2 */
8735ef2d41aSJohannes Berg 		*pos++ = sband->ht_cap.ampdu_factor |
8745ef2d41aSJohannes Berg 			 (sband->ht_cap.ampdu_density << 2);
8755ef2d41aSJohannes Berg 		memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
8765ef2d41aSJohannes Berg 		pos += sizeof(sband->ht_cap.mcs);
8775ef2d41aSJohannes Berg 		pos += 2 + 4 + 1; /* ext info, BF cap, antsel */
8785ef2d41aSJohannes Berg 	}
8795ef2d41aSJohannes Berg 
880de95a54bSJohannes Berg 	/*
881de95a54bSJohannes Berg 	 * If adding more here, adjust code in main.c
882de95a54bSJohannes Berg 	 * that calculates local->scan_ies_len.
883de95a54bSJohannes Berg 	 */
884de95a54bSJohannes Berg 
885de95a54bSJohannes Berg 	if (ie) {
886de95a54bSJohannes Berg 		memcpy(pos, ie, ie_len);
887de95a54bSJohannes Berg 		pos += ie_len;
888de95a54bSJohannes Berg 	}
889de95a54bSJohannes Berg 
890de95a54bSJohannes Berg 	return pos - buffer;
891de95a54bSJohannes Berg }
892de95a54bSJohannes Berg 
89346900298SJohannes Berg void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
894de95a54bSJohannes Berg 			      const u8 *ssid, size_t ssid_len,
895de95a54bSJohannes Berg 			      const u8 *ie, size_t ie_len)
89646900298SJohannes Berg {
89746900298SJohannes Berg 	struct ieee80211_local *local = sdata->local;
89846900298SJohannes Berg 	struct sk_buff *skb;
89946900298SJohannes Berg 	struct ieee80211_mgmt *mgmt;
900de95a54bSJohannes Berg 	u8 *pos;
90146900298SJohannes Berg 
90246900298SJohannes Berg 	skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 +
90365fc73acSJouni Malinen 			    ie_len);
90446900298SJohannes Berg 	if (!skb) {
90546900298SJohannes Berg 		printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
90646900298SJohannes Berg 		       "request\n", sdata->dev->name);
90746900298SJohannes Berg 		return;
90846900298SJohannes Berg 	}
90946900298SJohannes Berg 	skb_reserve(skb, local->hw.extra_tx_headroom);
91046900298SJohannes Berg 
91146900298SJohannes Berg 	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
91246900298SJohannes Berg 	memset(mgmt, 0, 24);
91346900298SJohannes Berg 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
91446900298SJohannes Berg 					  IEEE80211_STYPE_PROBE_REQ);
91546900298SJohannes Berg 	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
91646900298SJohannes Berg 	if (dst) {
91746900298SJohannes Berg 		memcpy(mgmt->da, dst, ETH_ALEN);
91846900298SJohannes Berg 		memcpy(mgmt->bssid, dst, ETH_ALEN);
91946900298SJohannes Berg 	} else {
92046900298SJohannes Berg 		memset(mgmt->da, 0xff, ETH_ALEN);
92146900298SJohannes Berg 		memset(mgmt->bssid, 0xff, ETH_ALEN);
92246900298SJohannes Berg 	}
92346900298SJohannes Berg 	pos = skb_put(skb, 2 + ssid_len);
92446900298SJohannes Berg 	*pos++ = WLAN_EID_SSID;
92546900298SJohannes Berg 	*pos++ = ssid_len;
92646900298SJohannes Berg 	memcpy(pos, ssid, ssid_len);
927de95a54bSJohannes Berg 	pos += ssid_len;
92846900298SJohannes Berg 
929de95a54bSJohannes Berg 	skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len));
93046900298SJohannes Berg 
93146900298SJohannes Berg 	ieee80211_tx_skb(sdata, skb, 0);
93246900298SJohannes Berg }
93346900298SJohannes Berg 
93446900298SJohannes Berg u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
93546900298SJohannes Berg 			    struct ieee802_11_elems *elems,
93646900298SJohannes Berg 			    enum ieee80211_band band)
93746900298SJohannes Berg {
93846900298SJohannes Berg 	struct ieee80211_supported_band *sband;
93946900298SJohannes Berg 	struct ieee80211_rate *bitrates;
94046900298SJohannes Berg 	size_t num_rates;
94146900298SJohannes Berg 	u32 supp_rates;
94246900298SJohannes Berg 	int i, j;
94346900298SJohannes Berg 	sband = local->hw.wiphy->bands[band];
94446900298SJohannes Berg 
94546900298SJohannes Berg 	if (!sband) {
94646900298SJohannes Berg 		WARN_ON(1);
94746900298SJohannes Berg 		sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
94846900298SJohannes Berg 	}
94946900298SJohannes Berg 
95046900298SJohannes Berg 	bitrates = sband->bitrates;
95146900298SJohannes Berg 	num_rates = sband->n_bitrates;
95246900298SJohannes Berg 	supp_rates = 0;
95346900298SJohannes Berg 	for (i = 0; i < elems->supp_rates_len +
95446900298SJohannes Berg 		     elems->ext_supp_rates_len; i++) {
95546900298SJohannes Berg 		u8 rate = 0;
95646900298SJohannes Berg 		int own_rate;
95746900298SJohannes Berg 		if (i < elems->supp_rates_len)
95846900298SJohannes Berg 			rate = elems->supp_rates[i];
95946900298SJohannes Berg 		else if (elems->ext_supp_rates)
96046900298SJohannes Berg 			rate = elems->ext_supp_rates
96146900298SJohannes Berg 				[i - elems->supp_rates_len];
96246900298SJohannes Berg 		own_rate = 5 * (rate & 0x7f);
96346900298SJohannes Berg 		for (j = 0; j < num_rates; j++)
96446900298SJohannes Berg 			if (bitrates[j].bitrate == own_rate)
96546900298SJohannes Berg 				supp_rates |= BIT(j);
96646900298SJohannes Berg 	}
96746900298SJohannes Berg 	return supp_rates;
96846900298SJohannes Berg }
969f2753ddbSJohannes Berg 
970f2753ddbSJohannes Berg int ieee80211_reconfig(struct ieee80211_local *local)
971f2753ddbSJohannes Berg {
972f2753ddbSJohannes Berg 	struct ieee80211_hw *hw = &local->hw;
973f2753ddbSJohannes Berg 	struct ieee80211_sub_if_data *sdata;
974f2753ddbSJohannes Berg 	struct ieee80211_if_init_conf conf;
975f2753ddbSJohannes Berg 	struct sta_info *sta;
976f2753ddbSJohannes Berg 	unsigned long flags;
977f2753ddbSJohannes Berg 	int res;
9785bb644a0SJohannes Berg 	bool from_suspend = local->suspended;
9795bb644a0SJohannes Berg 
9805bb644a0SJohannes Berg 	/*
9815bb644a0SJohannes Berg 	 * We're going to start the hardware, at that point
9825bb644a0SJohannes Berg 	 * we are no longer suspended and can RX frames.
9835bb644a0SJohannes Berg 	 */
9845bb644a0SJohannes Berg 	local->suspended = false;
985f2753ddbSJohannes Berg 
986f2753ddbSJohannes Berg 	/* restart hardware */
987f2753ddbSJohannes Berg 	if (local->open_count) {
98824487981SJohannes Berg 		res = drv_start(local);
989f2753ddbSJohannes Berg 
9901f87f7d3SJohannes Berg 		ieee80211_led_radio(local, true);
991f2753ddbSJohannes Berg 	}
992f2753ddbSJohannes Berg 
993f2753ddbSJohannes Berg 	/* add interfaces */
994f2753ddbSJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
995f2753ddbSJohannes Berg 		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
996f2753ddbSJohannes Berg 		    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
997f2753ddbSJohannes Berg 		    netif_running(sdata->dev)) {
998f2753ddbSJohannes Berg 			conf.vif = &sdata->vif;
999f2753ddbSJohannes Berg 			conf.type = sdata->vif.type;
1000f2753ddbSJohannes Berg 			conf.mac_addr = sdata->dev->dev_addr;
100124487981SJohannes Berg 			res = drv_add_interface(local, &conf);
1002f2753ddbSJohannes Berg 		}
1003f2753ddbSJohannes Berg 	}
1004f2753ddbSJohannes Berg 
1005f2753ddbSJohannes Berg 	/* add STAs back */
1006f2753ddbSJohannes Berg 	if (local->ops->sta_notify) {
1007f2753ddbSJohannes Berg 		spin_lock_irqsave(&local->sta_lock, flags);
1008f2753ddbSJohannes Berg 		list_for_each_entry(sta, &local->sta_list, list) {
10095bb644a0SJohannes Berg 			sdata = sta->sdata;
1010f2753ddbSJohannes Berg 			if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
1011f2753ddbSJohannes Berg 				sdata = container_of(sdata->bss,
1012f2753ddbSJohannes Berg 					     struct ieee80211_sub_if_data,
1013f2753ddbSJohannes Berg 					     u.ap);
1014f2753ddbSJohannes Berg 
101524487981SJohannes Berg 			drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD,
101624487981SJohannes Berg 				       &sta->sta);
1017f2753ddbSJohannes Berg 		}
1018f2753ddbSJohannes Berg 		spin_unlock_irqrestore(&local->sta_lock, flags);
1019f2753ddbSJohannes Berg 	}
1020f2753ddbSJohannes Berg 
1021f2753ddbSJohannes Berg 	/* Clear Suspend state so that ADDBA requests can be processed */
1022f2753ddbSJohannes Berg 
1023f2753ddbSJohannes Berg 	rcu_read_lock();
1024f2753ddbSJohannes Berg 
1025f2753ddbSJohannes Berg 	if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
1026f2753ddbSJohannes Berg 		list_for_each_entry_rcu(sta, &local->sta_list, list) {
1027f2753ddbSJohannes Berg 			clear_sta_flags(sta, WLAN_STA_SUSPEND);
1028f2753ddbSJohannes Berg 		}
1029f2753ddbSJohannes Berg 	}
1030f2753ddbSJohannes Berg 
1031f2753ddbSJohannes Berg 	rcu_read_unlock();
1032f2753ddbSJohannes Berg 
1033f2753ddbSJohannes Berg 	/* setup RTS threshold */
103424487981SJohannes Berg 	drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
1035f2753ddbSJohannes Berg 
1036f2753ddbSJohannes Berg 	/* reconfigure hardware */
1037f2753ddbSJohannes Berg 	ieee80211_hw_config(local, ~0);
1038f2753ddbSJohannes Berg 
10393b8d81e0SJohannes Berg 	spin_lock_bh(&local->filter_lock);
1040f2753ddbSJohannes Berg 	ieee80211_configure_filter(local);
10413b8d81e0SJohannes Berg 	spin_unlock_bh(&local->filter_lock);
1042f2753ddbSJohannes Berg 
1043f2753ddbSJohannes Berg 	/* Finally also reconfigure all the BSS information */
1044f2753ddbSJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
1045f2753ddbSJohannes Berg 		u32 changed = ~0;
1046f2753ddbSJohannes Berg 		if (!netif_running(sdata->dev))
1047f2753ddbSJohannes Berg 			continue;
1048f2753ddbSJohannes Berg 		switch (sdata->vif.type) {
1049f2753ddbSJohannes Berg 		case NL80211_IFTYPE_STATION:
1050f2753ddbSJohannes Berg 			/* disable beacon change bits */
10512d0ddec5SJohannes Berg 			changed &= ~(BSS_CHANGED_BEACON |
10522d0ddec5SJohannes Berg 				     BSS_CHANGED_BEACON_ENABLED);
1053f2753ddbSJohannes Berg 			/* fall through */
1054f2753ddbSJohannes Berg 		case NL80211_IFTYPE_ADHOC:
1055f2753ddbSJohannes Berg 		case NL80211_IFTYPE_AP:
1056f2753ddbSJohannes Berg 		case NL80211_IFTYPE_MESH_POINT:
10572d0ddec5SJohannes Berg 			ieee80211_bss_info_change_notify(sdata, changed);
1058f2753ddbSJohannes Berg 			break;
1059f2753ddbSJohannes Berg 		case NL80211_IFTYPE_WDS:
1060f2753ddbSJohannes Berg 			break;
1061f2753ddbSJohannes Berg 		case NL80211_IFTYPE_AP_VLAN:
1062f2753ddbSJohannes Berg 		case NL80211_IFTYPE_MONITOR:
1063f2753ddbSJohannes Berg 			/* ignore virtual */
1064f2753ddbSJohannes Berg 			break;
1065f2753ddbSJohannes Berg 		case NL80211_IFTYPE_UNSPECIFIED:
1066f2753ddbSJohannes Berg 		case __NL80211_IFTYPE_AFTER_LAST:
1067f2753ddbSJohannes Berg 			WARN_ON(1);
1068f2753ddbSJohannes Berg 			break;
1069f2753ddbSJohannes Berg 		}
1070f2753ddbSJohannes Berg 	}
1071f2753ddbSJohannes Berg 
1072f2753ddbSJohannes Berg 	/* add back keys */
1073f2753ddbSJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list)
1074f2753ddbSJohannes Berg 		if (netif_running(sdata->dev))
1075f2753ddbSJohannes Berg 			ieee80211_enable_keys(sdata);
1076f2753ddbSJohannes Berg 
1077f2753ddbSJohannes Berg 	ieee80211_wake_queues_by_reason(hw,
1078f2753ddbSJohannes Berg 			IEEE80211_QUEUE_STOP_REASON_SUSPEND);
1079f2753ddbSJohannes Berg 
10805bb644a0SJohannes Berg 	/*
10815bb644a0SJohannes Berg 	 * If this is for hw restart things are still running.
10825bb644a0SJohannes Berg 	 * We may want to change that later, however.
10835bb644a0SJohannes Berg 	 */
10845bb644a0SJohannes Berg 	if (!from_suspend)
10855bb644a0SJohannes Berg 		return 0;
10865bb644a0SJohannes Berg 
10875bb644a0SJohannes Berg #ifdef CONFIG_PM
10885bb644a0SJohannes Berg 	local->suspended = false;
10895bb644a0SJohannes Berg 
10905bb644a0SJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
10915bb644a0SJohannes Berg 		switch(sdata->vif.type) {
10925bb644a0SJohannes Berg 		case NL80211_IFTYPE_STATION:
10935bb644a0SJohannes Berg 			ieee80211_sta_restart(sdata);
10945bb644a0SJohannes Berg 			break;
10955bb644a0SJohannes Berg 		case NL80211_IFTYPE_ADHOC:
10965bb644a0SJohannes Berg 			ieee80211_ibss_restart(sdata);
10975bb644a0SJohannes Berg 			break;
10985bb644a0SJohannes Berg 		case NL80211_IFTYPE_MESH_POINT:
10995bb644a0SJohannes Berg 			ieee80211_mesh_restart(sdata);
11005bb644a0SJohannes Berg 			break;
11015bb644a0SJohannes Berg 		default:
11025bb644a0SJohannes Berg 			break;
11035bb644a0SJohannes Berg 		}
11045bb644a0SJohannes Berg 	}
11055bb644a0SJohannes Berg 
11065bb644a0SJohannes Berg 	add_timer(&local->sta_cleanup);
11075bb644a0SJohannes Berg 
11085bb644a0SJohannes Berg 	spin_lock_irqsave(&local->sta_lock, flags);
11095bb644a0SJohannes Berg 	list_for_each_entry(sta, &local->sta_list, list)
11105bb644a0SJohannes Berg 		mesh_plink_restart(sta);
11115bb644a0SJohannes Berg 	spin_unlock_irqrestore(&local->sta_lock, flags);
11125bb644a0SJohannes Berg #else
11135bb644a0SJohannes Berg 	WARN_ON(1);
11145bb644a0SJohannes Berg #endif
1115f2753ddbSJohannes Berg 	return 0;
1116f2753ddbSJohannes Berg }
1117