Blame view

net/mac80211/cfg.c 55.1 KB
f0706e828   Jiri Benc   [MAC80211]: Add m...
1
2
3
  /*
   * mac80211 configuration hooks for cfg80211
   *
026331c4d   Jouni Malinen   cfg80211/mac80211...
4
   * Copyright 2006-2010	Johannes Berg <johannes@sipsolutions.net>
f0706e828   Jiri Benc   [MAC80211]: Add m...
5
6
7
   *
   * This file is GPLv2 as found in COPYING.
   */
e8cbb4cbe   Johannes Berg   mac80211: support...
8
  #include <linux/ieee80211.h>
f0706e828   Jiri Benc   [MAC80211]: Add m...
9
10
  #include <linux/nl80211.h>
  #include <linux/rtnetlink.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
11
  #include <linux/slab.h>
881d966b4   Eric W. Biederman   [NET]: Make the d...
12
  #include <net/net_namespace.h>
5dfdaf58d   Johannes Berg   mac80211: add bea...
13
  #include <linux/rcupdate.h>
f0706e828   Jiri Benc   [MAC80211]: Add m...
14
15
  #include <net/cfg80211.h>
  #include "ieee80211_i.h"
244879813   Johannes Berg   mac80211: add dri...
16
  #include "driver-ops.h"
e0eb68596   Michael Wu   [MAC80211]: renam...
17
  #include "cfg.h"
2c8dccc77   Johannes Berg   mac80211: rename ...
18
  #include "rate.h"
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
19
  #include "mesh.h"
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
20

f9e10ce4c   Johannes Berg   cfg80211: require...
21
22
23
24
  static struct net_device *ieee80211_add_iface(struct wiphy *wiphy, char *name,
  					      enum nl80211_iftype type,
  					      u32 *flags,
  					      struct vif_params *params)
f0706e828   Jiri Benc   [MAC80211]: Add m...
25
26
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
8cc9a7391   Michael Wu   mac80211: Use mon...
27
28
29
  	struct net_device *dev;
  	struct ieee80211_sub_if_data *sdata;
  	int err;
f0706e828   Jiri Benc   [MAC80211]: Add m...
30

05c914fe3   Johannes Berg   mac80211: use nl8...
31
  	err = ieee80211_if_add(local, name, &dev, type, params);
f9e10ce4c   Johannes Berg   cfg80211: require...
32
33
  	if (err)
  		return ERR_PTR(err);
8cc9a7391   Michael Wu   mac80211: Use mon...
34

f9e10ce4c   Johannes Berg   cfg80211: require...
35
36
37
38
39
40
  	if (type == NL80211_IFTYPE_MONITOR && flags) {
  		sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  		sdata->u.mntr_flags = *flags;
  	}
  
  	return dev;
f0706e828   Jiri Benc   [MAC80211]: Add m...
41
  }
463d01832   Johannes Berg   cfg80211: make aw...
42
  static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev)
f0706e828   Jiri Benc   [MAC80211]: Add m...
43
  {
463d01832   Johannes Berg   cfg80211: make aw...
44
  	ieee80211_if_remove(IEEE80211_DEV_TO_SUB_IF(dev));
f0706e828   Jiri Benc   [MAC80211]: Add m...
45

75636525f   Johannes Berg   mac80211: revamp ...
46
  	return 0;
f0706e828   Jiri Benc   [MAC80211]: Add m...
47
  }
e36d56b64   Johannes Berg   cfg80211: pass ne...
48
49
  static int ieee80211_change_iface(struct wiphy *wiphy,
  				  struct net_device *dev,
2ec600d67   Luis Carlos Cobo   nl80211/cfg80211:...
50
51
  				  enum nl80211_iftype type, u32 *flags,
  				  struct vif_params *params)
42613db76   Johannes Berg   [MAC80211]: imple...
52
  {
9607e6b66   Johannes Berg   mac80211: add iee...
53
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
f3947e2df   Johannes Berg   mac80211: push in...
54
  	int ret;
42613db76   Johannes Berg   [MAC80211]: imple...
55

05c914fe3   Johannes Berg   mac80211: use nl8...
56
  	ret = ieee80211_if_change_type(sdata, type);
f3947e2df   Johannes Berg   mac80211: push in...
57
58
  	if (ret)
  		return ret;
42613db76   Johannes Berg   [MAC80211]: imple...
59

9bc383de3   Johannes Berg   cfg80211: introdu...
60
61
62
63
64
65
  	if (type == NL80211_IFTYPE_AP_VLAN &&
  	    params && params->use_4addr == 0)
  		rcu_assign_pointer(sdata->u.vlan.sta, NULL);
  	else if (type == NL80211_IFTYPE_STATION &&
  		 params && params->use_4addr >= 0)
  		sdata->u.mgd.use_4addr = params->use_4addr;
85416a4fa   Christian Lamparter   mac80211: fix rx ...
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  	if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) {
  		struct ieee80211_local *local = sdata->local;
  
  		if (ieee80211_sdata_running(sdata)) {
  			/*
  			 * Prohibit MONITOR_FLAG_COOK_FRAMES to be
  			 * changed while the interface is up.
  			 * Else we would need to add a lot of cruft
  			 * to update everything:
  			 *	cooked_mntrs, monitor and all fif_* counters
  			 *	reconfigure hardware
  			 */
  			if ((*flags & MONITOR_FLAG_COOK_FRAMES) !=
  			    (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
  				return -EBUSY;
  
  			ieee80211_adjust_monitor_flags(sdata, -1);
  			sdata->u.mntr_flags = *flags;
  			ieee80211_adjust_monitor_flags(sdata, 1);
  
  			ieee80211_configure_filter(local);
  		} else {
  			/*
  			 * Because the interface is down, ieee80211_do_stop
  			 * and ieee80211_do_open take care of "everything"
  			 * mentioned in the comment above.
  			 */
  			sdata->u.mntr_flags = *flags;
  		}
  	}
f7917af92   Felix Fietkau   mac80211: fix han...
96

42613db76   Johannes Berg   [MAC80211]: imple...
97
98
  	return 0;
  }
e8cbb4cbe   Johannes Berg   mac80211: support...
99
  static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
e31b82136   Johannes Berg   cfg80211/mac80211...
100
  			     u8 key_idx, bool pairwise, const u8 *mac_addr,
e8cbb4cbe   Johannes Berg   mac80211: support...
101
102
  			     struct key_params *params)
  {
26a58456b   Johannes Berg   mac80211: switch ...
103
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
e8cbb4cbe   Johannes Berg   mac80211: support...
104
  	struct sta_info *sta = NULL;
db4d1169d   Johannes Berg   mac80211: split i...
105
  	struct ieee80211_key *key;
3b96766f0   Johannes Berg   mac80211: fix key...
106
  	int err;
e8cbb4cbe   Johannes Berg   mac80211: support...
107

26a58456b   Johannes Berg   mac80211: switch ...
108
  	if (!ieee80211_sdata_running(sdata))
ad0e2b5a0   Johannes Berg   mac80211: simplif...
109
  		return -ENETDOWN;
97359d123   Johannes Berg   mac80211: use cip...
110
  	/* reject WEP and TKIP keys if WEP failed to initialize */
e8cbb4cbe   Johannes Berg   mac80211: support...
111
112
  	switch (params->cipher) {
  	case WLAN_CIPHER_SUITE_WEP40:
e8cbb4cbe   Johannes Berg   mac80211: support...
113
  	case WLAN_CIPHER_SUITE_TKIP:
97359d123   Johannes Berg   mac80211: use cip...
114
115
116
  	case WLAN_CIPHER_SUITE_WEP104:
  		if (IS_ERR(sdata->local->wep_tx_tfm))
  			return -EINVAL;
3cfcf6ac6   Jouni Malinen   mac80211: 802.11w...
117
  		break;
e8cbb4cbe   Johannes Berg   mac80211: support...
118
  	default:
97359d123   Johannes Berg   mac80211: use cip...
119
  		break;
e8cbb4cbe   Johannes Berg   mac80211: support...
120
  	}
97359d123   Johannes Berg   mac80211: use cip...
121
122
  	key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len,
  				  params->key, params->seq_len, params->seq);
1ac62ba7c   Ben Hutchings   mac80211: Don't s...
123
124
  	if (IS_ERR(key))
  		return PTR_ERR(key);
db4d1169d   Johannes Berg   mac80211: split i...
125

e31b82136   Johannes Berg   cfg80211/mac80211...
126
127
  	if (pairwise)
  		key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
ad0e2b5a0   Johannes Berg   mac80211: simplif...
128
  	mutex_lock(&sdata->local->sta_mtx);
3b96766f0   Johannes Berg   mac80211: fix key...
129

e8cbb4cbe   Johannes Berg   mac80211: support...
130
  	if (mac_addr) {
ff973af74   Thomas Pedersen   nl80211: allow in...
131
132
133
134
  		if (ieee80211_vif_is_mesh(&sdata->vif))
  			sta = sta_info_get(sdata, mac_addr);
  		else
  			sta = sta_info_get_bss(sdata, mac_addr);
db4d1169d   Johannes Berg   mac80211: split i...
135
  		if (!sta) {
32162a4da   Jouni Malinen   mac80211: Fix key...
136
  			ieee80211_key_free(sdata->local, key);
3b96766f0   Johannes Berg   mac80211: fix key...
137
138
  			err = -ENOENT;
  			goto out_unlock;
db4d1169d   Johannes Berg   mac80211: split i...
139
  		}
e8cbb4cbe   Johannes Berg   mac80211: support...
140
  	}
3ffc2a905   Johannes Berg   mac80211: allow v...
141
142
143
  	err = ieee80211_key_link(key, sdata, sta);
  	if (err)
  		ieee80211_key_free(sdata->local, key);
db4d1169d   Johannes Berg   mac80211: split i...
144

3b96766f0   Johannes Berg   mac80211: fix key...
145
   out_unlock:
ad0e2b5a0   Johannes Berg   mac80211: simplif...
146
  	mutex_unlock(&sdata->local->sta_mtx);
3b96766f0   Johannes Berg   mac80211: fix key...
147
148
  
  	return err;
e8cbb4cbe   Johannes Berg   mac80211: support...
149
150
151
  }
  
  static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
e31b82136   Johannes Berg   cfg80211/mac80211...
152
  			     u8 key_idx, bool pairwise, const u8 *mac_addr)
e8cbb4cbe   Johannes Berg   mac80211: support...
153
  {
5c0c36412   Johannes Berg   mac80211: make ke...
154
155
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  	struct ieee80211_local *local = sdata->local;
e8cbb4cbe   Johannes Berg   mac80211: support...
156
  	struct sta_info *sta;
5c0c36412   Johannes Berg   mac80211: make ke...
157
  	struct ieee80211_key *key = NULL;
e8cbb4cbe   Johannes Berg   mac80211: support...
158
  	int ret;
5c0c36412   Johannes Berg   mac80211: make ke...
159
160
  	mutex_lock(&local->sta_mtx);
  	mutex_lock(&local->key_mtx);
3b96766f0   Johannes Berg   mac80211: fix key...
161

e8cbb4cbe   Johannes Berg   mac80211: support...
162
  	if (mac_addr) {
3b96766f0   Johannes Berg   mac80211: fix key...
163
  		ret = -ENOENT;
0e5ded5a8   Felix Fietkau   mac80211: allow s...
164
  		sta = sta_info_get_bss(sdata, mac_addr);
e8cbb4cbe   Johannes Berg   mac80211: support...
165
  		if (!sta)
3b96766f0   Johannes Berg   mac80211: fix key...
166
  			goto out_unlock;
e8cbb4cbe   Johannes Berg   mac80211: support...
167

5c0c36412   Johannes Berg   mac80211: make ke...
168
  		if (pairwise)
40b275b69   Johannes Berg   mac80211: sparse ...
169
  			key = key_mtx_dereference(local, sta->ptk);
5c0c36412   Johannes Berg   mac80211: make ke...
170
  		else
40b275b69   Johannes Berg   mac80211: sparse ...
171
  			key = key_mtx_dereference(local, sta->gtk[key_idx]);
5c0c36412   Johannes Berg   mac80211: make ke...
172
  	} else
40b275b69   Johannes Berg   mac80211: sparse ...
173
  		key = key_mtx_dereference(local, sdata->keys[key_idx]);
e8cbb4cbe   Johannes Berg   mac80211: support...
174

5c0c36412   Johannes Berg   mac80211: make ke...
175
  	if (!key) {
3b96766f0   Johannes Berg   mac80211: fix key...
176
177
178
  		ret = -ENOENT;
  		goto out_unlock;
  	}
e8cbb4cbe   Johannes Berg   mac80211: support...
179

5c0c36412   Johannes Berg   mac80211: make ke...
180
  	__ieee80211_key_free(key);
e8cbb4cbe   Johannes Berg   mac80211: support...
181

3b96766f0   Johannes Berg   mac80211: fix key...
182
183
  	ret = 0;
   out_unlock:
5c0c36412   Johannes Berg   mac80211: make ke...
184
185
  	mutex_unlock(&local->key_mtx);
  	mutex_unlock(&local->sta_mtx);
3b96766f0   Johannes Berg   mac80211: fix key...
186
187
  
  	return ret;
e8cbb4cbe   Johannes Berg   mac80211: support...
188
  }
62da92fb7   Johannes Berg   mac80211: support...
189
  static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
e31b82136   Johannes Berg   cfg80211/mac80211...
190
191
  			     u8 key_idx, bool pairwise, const u8 *mac_addr,
  			     void *cookie,
62da92fb7   Johannes Berg   mac80211: support...
192
193
194
  			     void (*callback)(void *cookie,
  					      struct key_params *params))
  {
14db74bcc   Johannes Berg   mac80211: fix cfg...
195
  	struct ieee80211_sub_if_data *sdata;
62da92fb7   Johannes Berg   mac80211: support...
196
197
198
  	struct sta_info *sta = NULL;
  	u8 seq[6] = {0};
  	struct key_params params;
e31b82136   Johannes Berg   cfg80211/mac80211...
199
  	struct ieee80211_key *key = NULL;
aba83a0b3   Johannes Berg   mac80211: fix CCM...
200
  	u64 pn64;
62da92fb7   Johannes Berg   mac80211: support...
201
202
203
  	u32 iv32;
  	u16 iv16;
  	int err = -ENOENT;
14db74bcc   Johannes Berg   mac80211: fix cfg...
204
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3b96766f0   Johannes Berg   mac80211: fix key...
205
  	rcu_read_lock();
62da92fb7   Johannes Berg   mac80211: support...
206
  	if (mac_addr) {
0e5ded5a8   Felix Fietkau   mac80211: allow s...
207
  		sta = sta_info_get_bss(sdata, mac_addr);
62da92fb7   Johannes Berg   mac80211: support...
208
209
  		if (!sta)
  			goto out;
e31b82136   Johannes Berg   cfg80211/mac80211...
210
  		if (pairwise)
a3836e02b   Johannes Berg   mac80211: fix a f...
211
  			key = rcu_dereference(sta->ptk);
e31b82136   Johannes Berg   cfg80211/mac80211...
212
  		else if (key_idx < NUM_DEFAULT_KEYS)
a3836e02b   Johannes Berg   mac80211: fix a f...
213
  			key = rcu_dereference(sta->gtk[key_idx]);
62da92fb7   Johannes Berg   mac80211: support...
214
  	} else
a3836e02b   Johannes Berg   mac80211: fix a f...
215
  		key = rcu_dereference(sdata->keys[key_idx]);
62da92fb7   Johannes Berg   mac80211: support...
216
217
218
219
220
  
  	if (!key)
  		goto out;
  
  	memset(&params, 0, sizeof(params));
97359d123   Johannes Berg   mac80211: use cip...
221
  	params.cipher = key->conf.cipher;
62da92fb7   Johannes Berg   mac80211: support...
222

97359d123   Johannes Berg   mac80211: use cip...
223
224
  	switch (key->conf.cipher) {
  	case WLAN_CIPHER_SUITE_TKIP:
b0f76b335   Harvey Harrison   mac80211: add a s...
225
226
  		iv32 = key->u.tkip.tx.iv32;
  		iv16 = key->u.tkip.tx.iv16;
62da92fb7   Johannes Berg   mac80211: support...
227

244879813   Johannes Berg   mac80211: add dri...
228
229
230
231
  		if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
  			drv_get_tkip_seq(sdata->local,
  					 key->conf.hw_key_idx,
  					 &iv32, &iv16);
62da92fb7   Johannes Berg   mac80211: support...
232
233
234
235
236
237
238
239
240
241
  
  		seq[0] = iv16 & 0xff;
  		seq[1] = (iv16 >> 8) & 0xff;
  		seq[2] = iv32 & 0xff;
  		seq[3] = (iv32 >> 8) & 0xff;
  		seq[4] = (iv32 >> 16) & 0xff;
  		seq[5] = (iv32 >> 24) & 0xff;
  		params.seq = seq;
  		params.seq_len = 6;
  		break;
97359d123   Johannes Berg   mac80211: use cip...
242
  	case WLAN_CIPHER_SUITE_CCMP:
aba83a0b3   Johannes Berg   mac80211: fix CCM...
243
244
245
246
247
248
249
  		pn64 = atomic64_read(&key->u.ccmp.tx_pn);
  		seq[0] = pn64;
  		seq[1] = pn64 >> 8;
  		seq[2] = pn64 >> 16;
  		seq[3] = pn64 >> 24;
  		seq[4] = pn64 >> 32;
  		seq[5] = pn64 >> 40;
62da92fb7   Johannes Berg   mac80211: support...
250
251
252
  		params.seq = seq;
  		params.seq_len = 6;
  		break;
97359d123   Johannes Berg   mac80211: use cip...
253
  	case WLAN_CIPHER_SUITE_AES_CMAC:
75396ae6d   Johannes Berg   mac80211: fix CMA...
254
255
256
257
258
259
260
  		pn64 = atomic64_read(&key->u.aes_cmac.tx_pn);
  		seq[0] = pn64;
  		seq[1] = pn64 >> 8;
  		seq[2] = pn64 >> 16;
  		seq[3] = pn64 >> 24;
  		seq[4] = pn64 >> 32;
  		seq[5] = pn64 >> 40;
3cfcf6ac6   Jouni Malinen   mac80211: 802.11w...
261
262
263
  		params.seq = seq;
  		params.seq_len = 6;
  		break;
62da92fb7   Johannes Berg   mac80211: support...
264
265
266
267
268
269
270
271
272
  	}
  
  	params.key = key->conf.key;
  	params.key_len = key->conf.keylen;
  
  	callback(cookie, &params);
  	err = 0;
  
   out:
3b96766f0   Johannes Berg   mac80211: fix key...
273
  	rcu_read_unlock();
62da92fb7   Johannes Berg   mac80211: support...
274
275
  	return err;
  }
e8cbb4cbe   Johannes Berg   mac80211: support...
276
277
  static int ieee80211_config_default_key(struct wiphy *wiphy,
  					struct net_device *dev,
dbd2fd656   Johannes Berg   cfg80211/nl80211:...
278
279
  					u8 key_idx, bool uni,
  					bool multi)
e8cbb4cbe   Johannes Berg   mac80211: support...
280
  {
ad0e2b5a0   Johannes Berg   mac80211: simplif...
281
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3b96766f0   Johannes Berg   mac80211: fix key...
282

f7e0104c1   Johannes Berg   mac80211: support...
283
  	ieee80211_set_default_key(sdata, key_idx, uni, multi);
e8cbb4cbe   Johannes Berg   mac80211: support...
284
285
286
  
  	return 0;
  }
3cfcf6ac6   Jouni Malinen   mac80211: 802.11w...
287
288
289
290
  static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy,
  					     struct net_device *dev,
  					     u8 key_idx)
  {
66c524210   Johannes Berg   mac80211: remove ...
291
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3cfcf6ac6   Jouni Malinen   mac80211: 802.11w...
292

3cfcf6ac6   Jouni Malinen   mac80211: 802.11w...
293
  	ieee80211_set_default_mgmt_key(sdata, key_idx);
3cfcf6ac6   Jouni Malinen   mac80211: 802.11w...
294
295
  	return 0;
  }
3af6334c9   Felix Fietkau   mac80211: add sup...
296
297
298
299
300
301
302
303
304
305
  static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, int idx)
  {
  	if (!(rate->flags & RATE_INFO_FLAGS_MCS)) {
  		struct ieee80211_supported_band *sband;
  		sband = sta->local->hw.wiphy->bands[
  				sta->local->hw.conf.channel->band];
  		rate->legacy = sband->bitrates[idx].bitrate;
  	} else
  		rate->mcs = idx;
  }
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
306
307
  static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
  {
d0709a651   Johannes Berg   mac80211: RCU-ify...
308
  	struct ieee80211_sub_if_data *sdata = sta->sdata;
ebe27c91a   Mohammed Shafi Shajakhan   {mac|nl}80211: Ad...
309
  	struct timespec uptime;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
310

f5ea9120b   Johannes Berg   nl80211: add gene...
311
  	sinfo->generation = sdata->local->sta_generation;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
312
313
  	sinfo->filled = STATION_INFO_INACTIVE_TIME |
  			STATION_INFO_RX_BYTES |
420e7fabd   Henning Rogge   nl80211: Add sign...
314
  			STATION_INFO_TX_BYTES |
98c8a60a0   Jouni Malinen   nl80211: Provide ...
315
316
  			STATION_INFO_RX_PACKETS |
  			STATION_INFO_TX_PACKETS |
b206b4ef0   Bruno Randolf   nl80211/mac80211:...
317
318
  			STATION_INFO_TX_RETRIES |
  			STATION_INFO_TX_FAILED |
5a5c731aa   Ben Greear   wireless: Set som...
319
  			STATION_INFO_TX_BITRATE |
3af6334c9   Felix Fietkau   mac80211: add sup...
320
  			STATION_INFO_RX_BITRATE |
f4263c985   Paul Stewart   nl80211: Add BSS ...
321
  			STATION_INFO_RX_DROP_MISC |
ebe27c91a   Mohammed Shafi Shajakhan   {mac|nl}80211: Ad...
322
323
324
325
326
  			STATION_INFO_BSS_PARAM |
  			STATION_INFO_CONNECTED_TIME;
  
  	do_posix_clock_monotonic_gettime(&uptime);
  	sinfo->connected_time = uptime.tv_sec - sta->last_connected;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
327
328
329
330
  
  	sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
  	sinfo->rx_bytes = sta->rx_bytes;
  	sinfo->tx_bytes = sta->tx_bytes;
98c8a60a0   Jouni Malinen   nl80211: Provide ...
331
332
  	sinfo->rx_packets = sta->rx_packets;
  	sinfo->tx_packets = sta->tx_packets;
b206b4ef0   Bruno Randolf   nl80211/mac80211:...
333
334
  	sinfo->tx_retries = sta->tx_retry_count;
  	sinfo->tx_failed = sta->tx_retry_failed;
5a5c731aa   Ben Greear   wireless: Set som...
335
  	sinfo->rx_dropped_misc = sta->rx_dropped;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
336

19deffbeb   John W. Linville   wireless: correct...
337
338
  	if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) ||
  	    (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) {
541a45a14   Bruno Randolf   nl80211/mac80211:...
339
  		sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG;
420e7fabd   Henning Rogge   nl80211: Add sign...
340
  		sinfo->signal = (s8)sta->last_signal;
541a45a14   Bruno Randolf   nl80211/mac80211:...
341
  		sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);
420e7fabd   Henning Rogge   nl80211: Add sign...
342
343
344
345
346
347
348
349
350
  	}
  
  	sinfo->txrate.flags = 0;
  	if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)
  		sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
  	if (sta->last_tx_rate.flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
  		sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
  	if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI)
  		sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
3af6334c9   Felix Fietkau   mac80211: add sup...
351
352
353
354
355
356
357
358
359
360
  	rate_idx_to_bitrate(&sinfo->txrate, sta, sta->last_tx_rate.idx);
  
  	sinfo->rxrate.flags = 0;
  	if (sta->last_rx_rate_flag & RX_FLAG_HT)
  		sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS;
  	if (sta->last_rx_rate_flag & RX_FLAG_40MHZ)
  		sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
  	if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI)
  		sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
  	rate_idx_to_bitrate(&sinfo->rxrate, sta, sta->last_rx_rate_idx);
420e7fabd   Henning Rogge   nl80211: Add sign...
361

902acc789   Johannes Berg   mac80211: clean u...
362
  	if (ieee80211_vif_is_mesh(&sdata->vif)) {
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
363
  #ifdef CONFIG_MAC80211_MESH
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
364
365
366
367
368
369
370
  		sinfo->filled |= STATION_INFO_LLID |
  				 STATION_INFO_PLID |
  				 STATION_INFO_PLINK_STATE;
  
  		sinfo->llid = le16_to_cpu(sta->llid);
  		sinfo->plid = le16_to_cpu(sta->plid);
  		sinfo->plink_state = sta->plink_state;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
371
  #endif
902acc789   Johannes Berg   mac80211: clean u...
372
  	}
f4263c985   Paul Stewart   nl80211: Add BSS ...
373
374
375
376
377
378
379
380
381
382
  
  	sinfo->bss_param.flags = 0;
  	if (sdata->vif.bss_conf.use_cts_prot)
  		sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
  	if (sdata->vif.bss_conf.use_short_preamble)
  		sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
  	if (sdata->vif.bss_conf.use_short_slot)
  		sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
  	sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period;
  	sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
383
384
385
386
387
388
  }
  
  
  static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
  				 int idx, u8 *mac, struct station_info *sinfo)
  {
3b53fde8a   Johannes Berg   mac80211: let sta...
389
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
390
  	struct sta_info *sta;
d0709a651   Johannes Berg   mac80211: RCU-ify...
391
392
393
  	int ret = -ENOENT;
  
  	rcu_read_lock();
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
394

3b53fde8a   Johannes Berg   mac80211: let sta...
395
  	sta = sta_info_get_by_idx(sdata, idx);
d0709a651   Johannes Berg   mac80211: RCU-ify...
396
397
  	if (sta) {
  		ret = 0;
17741cdc2   Johannes Berg   mac80211: share S...
398
  		memcpy(mac, sta->sta.addr, ETH_ALEN);
d0709a651   Johannes Berg   mac80211: RCU-ify...
399
400
  		sta_set_sinfo(sta, sinfo);
  	}
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
401

d0709a651   Johannes Berg   mac80211: RCU-ify...
402
  	rcu_read_unlock();
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
403

d0709a651   Johannes Berg   mac80211: RCU-ify...
404
  	return ret;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
405
  }
1289723ef   Holger Schurig   mac80211: sample ...
406
407
408
409
  static int ieee80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
  				 int idx, struct survey_info *survey)
  {
  	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1289723ef   Holger Schurig   mac80211: sample ...
410
411
  	return drv_get_survey(local, idx, survey);
  }
7bbdd2d98   Johannes Berg   mac80211: impleme...
412
  static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
2ec600d67   Luis Carlos Cobo   nl80211/cfg80211:...
413
  				 u8 *mac, struct station_info *sinfo)
7bbdd2d98   Johannes Berg   mac80211: impleme...
414
  {
abe60632f   Johannes Berg   mac80211: make st...
415
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
7bbdd2d98   Johannes Berg   mac80211: impleme...
416
  	struct sta_info *sta;
d0709a651   Johannes Berg   mac80211: RCU-ify...
417
  	int ret = -ENOENT;
7bbdd2d98   Johannes Berg   mac80211: impleme...
418

d0709a651   Johannes Berg   mac80211: RCU-ify...
419
  	rcu_read_lock();
7bbdd2d98   Johannes Berg   mac80211: impleme...
420

0e5ded5a8   Felix Fietkau   mac80211: allow s...
421
  	sta = sta_info_get_bss(sdata, mac);
d0709a651   Johannes Berg   mac80211: RCU-ify...
422
423
424
425
426
427
428
429
  	if (sta) {
  		ret = 0;
  		sta_set_sinfo(sta, sinfo);
  	}
  
  	rcu_read_unlock();
  
  	return ret;
7bbdd2d98   Johannes Berg   mac80211: impleme...
430
  }
5dfdaf58d   Johannes Berg   mac80211: add bea...
431
432
433
434
435
436
437
438
439
440
  /*
   * This handles both adding a beacon and setting new beacon info
   */
  static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
  				   struct beacon_parameters *params)
  {
  	struct beacon_data *new, *old;
  	int new_head_len, new_tail_len;
  	int size;
  	int err = -EINVAL;
40b275b69   Johannes Berg   mac80211: sparse ...
441
  	old = rtnl_dereference(sdata->u.ap.beacon);
5dfdaf58d   Johannes Berg   mac80211: add bea...
442
443
444
445
446
447
448
449
450
  
  	/* head must not be zero-length */
  	if (params->head && !params->head_len)
  		return -EINVAL;
  
  	/*
  	 * This is a kludge. beacon interval should really be part
  	 * of the beacon information.
  	 */
57c4d7b4c   Johannes Berg   mac80211: clean u...
451
452
453
454
455
  	if (params->interval &&
  	    (sdata->vif.bss_conf.beacon_int != params->interval)) {
  		sdata->vif.bss_conf.beacon_int = params->interval;
  		ieee80211_bss_info_change_notify(sdata,
  						 BSS_CHANGED_BEACON_INT);
5dfdaf58d   Johannes Berg   mac80211: add bea...
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
  	}
  
  	/* Need to have a beacon head if we don't have one yet */
  	if (!params->head && !old)
  		return err;
  
  	/* sorry, no way to start beaconing without dtim period */
  	if (!params->dtim_period && !old)
  		return err;
  
  	/* new or old head? */
  	if (params->head)
  		new_head_len = params->head_len;
  	else
  		new_head_len = old->head_len;
  
  	/* new or old tail? */
  	if (params->tail || !old)
  		/* params->tail_len will be zero for !params->tail */
  		new_tail_len = params->tail_len;
  	else
  		new_tail_len = old->tail_len;
  
  	size = sizeof(*new) + new_head_len + new_tail_len;
  
  	new = kzalloc(size, GFP_KERNEL);
  	if (!new)
  		return -ENOMEM;
  
  	/* start filling the new info now */
  
  	/* new or old dtim period? */
  	if (params->dtim_period)
  		new->dtim_period = params->dtim_period;
  	else
  		new->dtim_period = old->dtim_period;
  
  	/*
  	 * pointers go into the block we allocated,
  	 * memory is | beacon_data | head | tail |
  	 */
  	new->head = ((u8 *) new) + sizeof(*new);
  	new->tail = new->head + new_head_len;
  	new->head_len = new_head_len;
  	new->tail_len = new_tail_len;
  
  	/* copy in head */
  	if (params->head)
  		memcpy(new->head, params->head, new_head_len);
  	else
  		memcpy(new->head, old->head, new_head_len);
  
  	/* copy in optional tail */
  	if (params->tail)
  		memcpy(new->tail, params->tail, new_tail_len);
  	else
  		if (old)
  			memcpy(new->tail, old->tail, new_tail_len);
19885c4fb   Johannes Berg   mac80211: fix bss...
514
  	sdata->vif.bss_conf.dtim_period = new->dtim_period;
5dfdaf58d   Johannes Berg   mac80211: add bea...
515
516
517
518
519
  	rcu_assign_pointer(sdata->u.ap.beacon, new);
  
  	synchronize_rcu();
  
  	kfree(old);
2d0ddec5b   Johannes Berg   mac80211: unify c...
520
521
522
  	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
  						BSS_CHANGED_BEACON);
  	return 0;
5dfdaf58d   Johannes Berg   mac80211: add bea...
523
524
525
526
527
  }
  
  static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
  				struct beacon_parameters *params)
  {
14db74bcc   Johannes Berg   mac80211: fix cfg...
528
  	struct ieee80211_sub_if_data *sdata;
5dfdaf58d   Johannes Berg   mac80211: add bea...
529
  	struct beacon_data *old;
14db74bcc   Johannes Berg   mac80211: fix cfg...
530
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
40b275b69   Johannes Berg   mac80211: sparse ...
531
  	old = rtnl_dereference(sdata->u.ap.beacon);
5dfdaf58d   Johannes Berg   mac80211: add bea...
532
533
534
535
536
537
538
539
540
  	if (old)
  		return -EALREADY;
  
  	return ieee80211_config_beacon(sdata, params);
  }
  
  static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
  				struct beacon_parameters *params)
  {
14db74bcc   Johannes Berg   mac80211: fix cfg...
541
  	struct ieee80211_sub_if_data *sdata;
5dfdaf58d   Johannes Berg   mac80211: add bea...
542
  	struct beacon_data *old;
14db74bcc   Johannes Berg   mac80211: fix cfg...
543
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
40b275b69   Johannes Berg   mac80211: sparse ...
544
  	old = rtnl_dereference(sdata->u.ap.beacon);
5dfdaf58d   Johannes Berg   mac80211: add bea...
545
546
547
548
549
550
551
552
  	if (!old)
  		return -ENOENT;
  
  	return ieee80211_config_beacon(sdata, params);
  }
  
  static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
  {
14db74bcc   Johannes Berg   mac80211: fix cfg...
553
  	struct ieee80211_sub_if_data *sdata;
5dfdaf58d   Johannes Berg   mac80211: add bea...
554
  	struct beacon_data *old;
14db74bcc   Johannes Berg   mac80211: fix cfg...
555
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
40b275b69   Johannes Berg   mac80211: sparse ...
556
  	old = rtnl_dereference(sdata->u.ap.beacon);
5dfdaf58d   Johannes Berg   mac80211: add bea...
557
558
559
560
561
562
  	if (!old)
  		return -ENOENT;
  
  	rcu_assign_pointer(sdata->u.ap.beacon, NULL);
  	synchronize_rcu();
  	kfree(old);
2d0ddec5b   Johannes Berg   mac80211: unify c...
563
564
  	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
  	return 0;
5dfdaf58d   Johannes Berg   mac80211: add bea...
565
  }
4fd6931eb   Johannes Berg   mac80211: impleme...
566
567
568
569
570
571
572
573
574
  /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
  struct iapp_layer2_update {
  	u8 da[ETH_ALEN];	/* broadcast */
  	u8 sa[ETH_ALEN];	/* STA addr */
  	__be16 len;		/* 6 */
  	u8 dsap;		/* 0 */
  	u8 ssap;		/* 0 */
  	u8 control;
  	u8 xid_info[3];
bc10502db   Eric Dumazet   net: use __packed...
575
  } __packed;
4fd6931eb   Johannes Berg   mac80211: impleme...
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
  
  static void ieee80211_send_layer2_update(struct sta_info *sta)
  {
  	struct iapp_layer2_update *msg;
  	struct sk_buff *skb;
  
  	/* Send Level 2 Update Frame to update forwarding tables in layer 2
  	 * bridge devices */
  
  	skb = dev_alloc_skb(sizeof(*msg));
  	if (!skb)
  		return;
  	msg = (struct iapp_layer2_update *)skb_put(skb, sizeof(*msg));
  
  	/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
  	 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
  
  	memset(msg->da, 0xff, ETH_ALEN);
17741cdc2   Johannes Berg   mac80211: share S...
594
  	memcpy(msg->sa, sta->sta.addr, ETH_ALEN);
4fd6931eb   Johannes Berg   mac80211: impleme...
595
596
597
598
599
600
601
602
  	msg->len = htons(6);
  	msg->dsap = 0;
  	msg->ssap = 0x01;	/* NULL LSAP, CR Bit: Response */
  	msg->control = 0xaf;	/* XID response lsb.1111F101.
  				 * F=0 (no poll command; unsolicited frame) */
  	msg->xid_info[0] = 0x81;	/* XID format identifier */
  	msg->xid_info[1] = 1;	/* LLC types/classes: Type 1 LLC */
  	msg->xid_info[2] = 0;	/* XID sender's receive window size (RW) */
d0709a651   Johannes Berg   mac80211: RCU-ify...
603
604
  	skb->dev = sta->sdata->dev;
  	skb->protocol = eth_type_trans(skb, sta->sdata->dev);
4fd6931eb   Johannes Berg   mac80211: impleme...
605
  	memset(skb->cb, 0, sizeof(skb->cb));
06ee1c261   John W. Linville   wireless: use net...
606
  	netif_rx_ni(skb);
4fd6931eb   Johannes Berg   mac80211: impleme...
607
608
609
610
611
612
  }
  
  static void sta_apply_parameters(struct ieee80211_local *local,
  				 struct sta_info *sta,
  				 struct station_parameters *params)
  {
f5521b138   Johannes Berg   mac80211: use cor...
613
  	unsigned long flags;
4fd6931eb   Johannes Berg   mac80211: impleme...
614
615
  	u32 rates;
  	int i, j;
8318d78a4   Johannes Berg   cfg80211 API for ...
616
  	struct ieee80211_supported_band *sband;
d0709a651   Johannes Berg   mac80211: RCU-ify...
617
  	struct ieee80211_sub_if_data *sdata = sta->sdata;
eccb8e8f0   Johannes Berg   nl80211: improve ...
618
  	u32 mask, set;
4fd6931eb   Johannes Berg   mac80211: impleme...
619

ae5eb0264   Johannes Berg   mac80211: rewrite...
620
  	sband = local->hw.wiphy->bands[local->oper_channel->band];
f5521b138   Johannes Berg   mac80211: use cor...
621
  	spin_lock_irqsave(&sta->flaglock, flags);
eccb8e8f0   Johannes Berg   nl80211: improve ...
622
623
  	mask = params->sta_flags_mask;
  	set = params->sta_flags_set;
73651ee63   Johannes Berg   mac80211: split s...
624

eccb8e8f0   Johannes Berg   nl80211: improve ...
625
  	if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
4fd6931eb   Johannes Berg   mac80211: impleme...
626
  		sta->flags &= ~WLAN_STA_AUTHORIZED;
eccb8e8f0   Johannes Berg   nl80211: improve ...
627
  		if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
4fd6931eb   Johannes Berg   mac80211: impleme...
628
  			sta->flags |= WLAN_STA_AUTHORIZED;
eccb8e8f0   Johannes Berg   nl80211: improve ...
629
  	}
4fd6931eb   Johannes Berg   mac80211: impleme...
630

eccb8e8f0   Johannes Berg   nl80211: improve ...
631
  	if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
4fd6931eb   Johannes Berg   mac80211: impleme...
632
  		sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
eccb8e8f0   Johannes Berg   nl80211: improve ...
633
  		if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE))
4fd6931eb   Johannes Berg   mac80211: impleme...
634
  			sta->flags |= WLAN_STA_SHORT_PREAMBLE;
eccb8e8f0   Johannes Berg   nl80211: improve ...
635
  	}
4fd6931eb   Johannes Berg   mac80211: impleme...
636

eccb8e8f0   Johannes Berg   nl80211: improve ...
637
  	if (mask & BIT(NL80211_STA_FLAG_WME)) {
4fd6931eb   Johannes Berg   mac80211: impleme...
638
  		sta->flags &= ~WLAN_STA_WME;
39df600aa   Arik Nemtsov   mac80211: propaga...
639
640
  		sta->sta.wme = false;
  		if (set & BIT(NL80211_STA_FLAG_WME)) {
4fd6931eb   Johannes Berg   mac80211: impleme...
641
  			sta->flags |= WLAN_STA_WME;
39df600aa   Arik Nemtsov   mac80211: propaga...
642
643
  			sta->sta.wme = true;
  		}
eccb8e8f0   Johannes Berg   nl80211: improve ...
644
  	}
5394af4d8   Jouni Malinen   mac80211: 802.11w...
645

eccb8e8f0   Johannes Berg   nl80211: improve ...
646
  	if (mask & BIT(NL80211_STA_FLAG_MFP)) {
5394af4d8   Jouni Malinen   mac80211: 802.11w...
647
  		sta->flags &= ~WLAN_STA_MFP;
eccb8e8f0   Johannes Berg   nl80211: improve ...
648
  		if (set & BIT(NL80211_STA_FLAG_MFP))
5394af4d8   Jouni Malinen   mac80211: 802.11w...
649
  			sta->flags |= WLAN_STA_MFP;
4fd6931eb   Johannes Berg   mac80211: impleme...
650
  	}
b39c48fac   Javier Cardona   nl80211/mac80211:...
651
652
653
654
655
656
  
  	if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
  		sta->flags &= ~WLAN_STA_AUTH;
  		if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
  			sta->flags |= WLAN_STA_AUTH;
  	}
f5521b138   Johannes Berg   mac80211: use cor...
657
  	spin_unlock_irqrestore(&sta->flaglock, flags);
4fd6931eb   Johannes Berg   mac80211: impleme...
658

73651ee63   Johannes Berg   mac80211: split s...
659
  	/*
51b50fbeb   Johannes Berg   cfg80211: validat...
660
661
662
663
664
665
666
  	 * cfg80211 validates this (1-2007) and allows setting the AID
  	 * only when creating a new station entry
  	 */
  	if (params->aid)
  		sta->sta.aid = params->aid;
  
  	/*
73651ee63   Johannes Berg   mac80211: split s...
667
668
669
670
671
  	 * FIXME: updating the following information is racy when this
  	 *	  function is called from ieee80211_change_station().
  	 *	  However, all this information should be static so
  	 *	  maybe we should just reject attemps to change it.
  	 */
4fd6931eb   Johannes Berg   mac80211: impleme...
672
673
674
675
676
  	if (params->listen_interval >= 0)
  		sta->listen_interval = params->listen_interval;
  
  	if (params->supported_rates) {
  		rates = 0;
8318d78a4   Johannes Berg   cfg80211 API for ...
677

4fd6931eb   Johannes Berg   mac80211: impleme...
678
679
  		for (i = 0; i < params->supported_rates_len; i++) {
  			int rate = (params->supported_rates[i] & 0x7f) * 5;
8318d78a4   Johannes Berg   cfg80211 API for ...
680
681
  			for (j = 0; j < sband->n_bitrates; j++) {
  				if (sband->bitrates[j].bitrate == rate)
4fd6931eb   Johannes Berg   mac80211: impleme...
682
683
684
  					rates |= BIT(j);
  			}
  		}
323ce79a9   Johannes Berg   mac80211: share s...
685
  		sta->sta.supp_rates[local->oper_channel->band] = rates;
4fd6931eb   Johannes Berg   mac80211: impleme...
686
  	}
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
687

d9fe60dea   Johannes Berg   802.11: clean up/...
688
  	if (params->ht_capa)
ae5eb0264   Johannes Berg   mac80211: rewrite...
689
690
  		ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
  						  params->ht_capa,
d9fe60dea   Johannes Berg   802.11: clean up/...
691
  						  &sta->sta.ht_cap);
36aedc903   Jouni Malinen   mac80211/cfg80211...
692

9c3990aae   Javier Cardona   nl80211: Let user...
693
  	if (ieee80211_vif_is_mesh(&sdata->vif)) {
4daf50f20   Yogesh Ashok Powar   mac80211: Fix mes...
694
  #ifdef CONFIG_MAC80211_MESH
9c3990aae   Javier Cardona   nl80211: Let user...
695
696
  		if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED)
  			switch (params->plink_state) {
57cf8043a   Javier Cardona   nl80211: Move pee...
697
698
699
  			case NL80211_PLINK_LISTEN:
  			case NL80211_PLINK_ESTAB:
  			case NL80211_PLINK_BLOCKED:
9c3990aae   Javier Cardona   nl80211: Let user...
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
  				sta->plink_state = params->plink_state;
  				break;
  			default:
  				/*  nothing  */
  				break;
  			}
  		else
  			switch (params->plink_action) {
  			case PLINK_ACTION_OPEN:
  				mesh_plink_open(sta);
  				break;
  			case PLINK_ACTION_BLOCK:
  				mesh_plink_block(sta);
  				break;
  			}
4daf50f20   Yogesh Ashok Powar   mac80211: Fix mes...
715
  #endif
902acc789   Johannes Berg   mac80211: clean u...
716
  	}
4fd6931eb   Johannes Berg   mac80211: impleme...
717
718
719
720
721
  }
  
  static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
  				 u8 *mac, struct station_parameters *params)
  {
14db74bcc   Johannes Berg   mac80211: fix cfg...
722
  	struct ieee80211_local *local = wiphy_priv(wiphy);
4fd6931eb   Johannes Berg   mac80211: impleme...
723
724
  	struct sta_info *sta;
  	struct ieee80211_sub_if_data *sdata;
73651ee63   Johannes Berg   mac80211: split s...
725
  	int err;
b8d476c8c   Jouni Malinen   mac80211: Send La...
726
  	int layer2_update;
4fd6931eb   Johannes Berg   mac80211: impleme...
727

4fd6931eb   Johannes Berg   mac80211: impleme...
728
729
  	if (params->vlan) {
  		sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
05c914fe3   Johannes Berg   mac80211: use nl8...
730
731
  		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
  		    sdata->vif.type != NL80211_IFTYPE_AP)
4fd6931eb   Johannes Berg   mac80211: impleme...
732
733
734
  			return -EINVAL;
  	} else
  		sdata = IEEE80211_DEV_TO_SUB_IF(dev);
47846c9b0   Johannes Berg   mac80211: reduce ...
735
  	if (compare_ether_addr(mac, sdata->vif.addr) == 0)
03e4497eb   Johannes Berg   mac80211: fix sta...
736
737
738
739
740
741
  		return -EINVAL;
  
  	if (is_multicast_ether_addr(mac))
  		return -EINVAL;
  
  	sta = sta_info_alloc(sdata, mac, GFP_KERNEL);
73651ee63   Johannes Berg   mac80211: split s...
742
743
  	if (!sta)
  		return -ENOMEM;
4fd6931eb   Johannes Berg   mac80211: impleme...
744
745
746
747
  
  	sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
  
  	sta_apply_parameters(local, sta, params);
4b7679a56   Johannes Berg   mac80211: clean u...
748
  	rate_control_rate_init(sta);
4fd6931eb   Johannes Berg   mac80211: impleme...
749

b8d476c8c   Jouni Malinen   mac80211: Send La...
750
751
  	layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
  		sdata->vif.type == NL80211_IFTYPE_AP;
34e895075   Johannes Berg   mac80211: allow s...
752
  	err = sta_info_insert_rcu(sta);
73651ee63   Johannes Berg   mac80211: split s...
753
  	if (err) {
73651ee63   Johannes Berg   mac80211: split s...
754
755
756
  		rcu_read_unlock();
  		return err;
  	}
b8d476c8c   Jouni Malinen   mac80211: Send La...
757
  	if (layer2_update)
73651ee63   Johannes Berg   mac80211: split s...
758
759
760
  		ieee80211_send_layer2_update(sta);
  
  	rcu_read_unlock();
4fd6931eb   Johannes Berg   mac80211: impleme...
761
762
763
764
765
766
  	return 0;
  }
  
  static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
  				 u8 *mac)
  {
14db74bcc   Johannes Berg   mac80211: fix cfg...
767
768
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  	struct ieee80211_sub_if_data *sdata;
4fd6931eb   Johannes Berg   mac80211: impleme...
769

14db74bcc   Johannes Berg   mac80211: fix cfg...
770
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
34e895075   Johannes Berg   mac80211: allow s...
771
772
  	if (mac)
  		return sta_info_destroy_addr_bss(sdata, mac);
4fd6931eb   Johannes Berg   mac80211: impleme...
773

34e895075   Johannes Berg   mac80211: allow s...
774
  	sta_info_flush(local, sdata);
4fd6931eb   Johannes Berg   mac80211: impleme...
775
776
777
778
779
780
781
782
  	return 0;
  }
  
  static int ieee80211_change_station(struct wiphy *wiphy,
  				    struct net_device *dev,
  				    u8 *mac,
  				    struct station_parameters *params)
  {
abe60632f   Johannes Berg   mac80211: make st...
783
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
14db74bcc   Johannes Berg   mac80211: fix cfg...
784
  	struct ieee80211_local *local = wiphy_priv(wiphy);
4fd6931eb   Johannes Berg   mac80211: impleme...
785
786
  	struct sta_info *sta;
  	struct ieee80211_sub_if_data *vlansdata;
98dd6a575   Johannes Berg   mac80211: further...
787
  	rcu_read_lock();
0e5ded5a8   Felix Fietkau   mac80211: allow s...
788
  	sta = sta_info_get_bss(sdata, mac);
98dd6a575   Johannes Berg   mac80211: further...
789
790
  	if (!sta) {
  		rcu_read_unlock();
4fd6931eb   Johannes Berg   mac80211: impleme...
791
  		return -ENOENT;
98dd6a575   Johannes Berg   mac80211: further...
792
  	}
4fd6931eb   Johannes Berg   mac80211: impleme...
793

d0709a651   Johannes Berg   mac80211: RCU-ify...
794
  	if (params->vlan && params->vlan != sta->sdata->dev) {
4fd6931eb   Johannes Berg   mac80211: impleme...
795
  		vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
05c914fe3   Johannes Berg   mac80211: use nl8...
796
797
  		if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
  		    vlansdata->vif.type != NL80211_IFTYPE_AP) {
98dd6a575   Johannes Berg   mac80211: further...
798
  			rcu_read_unlock();
4fd6931eb   Johannes Berg   mac80211: impleme...
799
  			return -EINVAL;
98dd6a575   Johannes Berg   mac80211: further...
800
  		}
4fd6931eb   Johannes Berg   mac80211: impleme...
801

9bc383de3   Johannes Berg   cfg80211: introdu...
802
  		if (params->vlan->ieee80211_ptr->use_4addr) {
3305443c9   Johannes Berg   mac80211: fix rcu...
803
804
  			if (vlansdata->u.vlan.sta) {
  				rcu_read_unlock();
f14543ee4   Felix Fietkau   mac80211: impleme...
805
  				return -EBUSY;
3305443c9   Johannes Berg   mac80211: fix rcu...
806
  			}
f14543ee4   Felix Fietkau   mac80211: impleme...
807
808
809
  
  			rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
  		}
14db74bcc   Johannes Berg   mac80211: fix cfg...
810
  		sta->sdata = vlansdata;
4fd6931eb   Johannes Berg   mac80211: impleme...
811
812
813
814
  		ieee80211_send_layer2_update(sta);
  	}
  
  	sta_apply_parameters(local, sta, params);
98dd6a575   Johannes Berg   mac80211: further...
815
  	rcu_read_unlock();
808118cb4   Jason Young   mac80211: do not ...
816
817
818
  	if (sdata->vif.type == NL80211_IFTYPE_STATION &&
  	    params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))
  		ieee80211_recalc_ps(local, -1);
4fd6931eb   Johannes Berg   mac80211: impleme...
819
820
  	return 0;
  }
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
821
822
823
824
  #ifdef CONFIG_MAC80211_MESH
  static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
  				 u8 *dst, u8 *next_hop)
  {
14db74bcc   Johannes Berg   mac80211: fix cfg...
825
  	struct ieee80211_sub_if_data *sdata;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
826
827
828
  	struct mesh_path *mpath;
  	struct sta_info *sta;
  	int err;
14db74bcc   Johannes Berg   mac80211: fix cfg...
829
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
d0709a651   Johannes Berg   mac80211: RCU-ify...
830
  	rcu_read_lock();
abe60632f   Johannes Berg   mac80211: make st...
831
  	sta = sta_info_get(sdata, next_hop);
d0709a651   Johannes Berg   mac80211: RCU-ify...
832
833
  	if (!sta) {
  		rcu_read_unlock();
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
834
  		return -ENOENT;
d0709a651   Johannes Berg   mac80211: RCU-ify...
835
  	}
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
836

f698d856f   Jasper Bryant-Greene   replace net_devic...
837
  	err = mesh_path_add(dst, sdata);
d0709a651   Johannes Berg   mac80211: RCU-ify...
838
839
  	if (err) {
  		rcu_read_unlock();
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
840
  		return err;
d0709a651   Johannes Berg   mac80211: RCU-ify...
841
  	}
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
842

f698d856f   Jasper Bryant-Greene   replace net_devic...
843
  	mpath = mesh_path_lookup(dst, sdata);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
844
845
  	if (!mpath) {
  		rcu_read_unlock();
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
846
847
848
  		return -ENXIO;
  	}
  	mesh_path_fix_nexthop(mpath, sta);
d0709a651   Johannes Berg   mac80211: RCU-ify...
849

c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
850
851
852
853
854
855
856
  	rcu_read_unlock();
  	return 0;
  }
  
  static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
  				 u8 *dst)
  {
f698d856f   Jasper Bryant-Greene   replace net_devic...
857
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
858
  	if (dst)
f698d856f   Jasper Bryant-Greene   replace net_devic...
859
  		return mesh_path_del(dst, sdata);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
860

f698d856f   Jasper Bryant-Greene   replace net_devic...
861
  	mesh_path_flush(sdata);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
862
863
864
865
866
867
868
  	return 0;
  }
  
  static int ieee80211_change_mpath(struct wiphy *wiphy,
  				    struct net_device *dev,
  				    u8 *dst, u8 *next_hop)
  {
14db74bcc   Johannes Berg   mac80211: fix cfg...
869
  	struct ieee80211_sub_if_data *sdata;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
870
871
  	struct mesh_path *mpath;
  	struct sta_info *sta;
14db74bcc   Johannes Berg   mac80211: fix cfg...
872
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
d0709a651   Johannes Berg   mac80211: RCU-ify...
873
  	rcu_read_lock();
abe60632f   Johannes Berg   mac80211: make st...
874
  	sta = sta_info_get(sdata, next_hop);
d0709a651   Johannes Berg   mac80211: RCU-ify...
875
876
  	if (!sta) {
  		rcu_read_unlock();
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
877
  		return -ENOENT;
d0709a651   Johannes Berg   mac80211: RCU-ify...
878
  	}
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
879

f698d856f   Jasper Bryant-Greene   replace net_devic...
880
  	mpath = mesh_path_lookup(dst, sdata);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
881
882
  	if (!mpath) {
  		rcu_read_unlock();
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
883
884
885
886
  		return -ENOENT;
  	}
  
  	mesh_path_fix_nexthop(mpath, sta);
d0709a651   Johannes Berg   mac80211: RCU-ify...
887

c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
888
889
890
891
892
893
894
  	rcu_read_unlock();
  	return 0;
  }
  
  static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop,
  			    struct mpath_info *pinfo)
  {
a3836e02b   Johannes Berg   mac80211: fix a f...
895
896
897
898
  	struct sta_info *next_hop_sta = rcu_dereference(mpath->next_hop);
  
  	if (next_hop_sta)
  		memcpy(next_hop, next_hop_sta->sta.addr, ETH_ALEN);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
899
900
  	else
  		memset(next_hop, 0, ETH_ALEN);
f5ea9120b   Johannes Berg   nl80211: add gene...
901
  	pinfo->generation = mesh_paths_generation;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
902
  	pinfo->filled = MPATH_INFO_FRAME_QLEN |
d19b3bf63   Rui Paulo   mac80211: replace...
903
  			MPATH_INFO_SN |
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
904
905
906
907
908
909
910
  			MPATH_INFO_METRIC |
  			MPATH_INFO_EXPTIME |
  			MPATH_INFO_DISCOVERY_TIMEOUT |
  			MPATH_INFO_DISCOVERY_RETRIES |
  			MPATH_INFO_FLAGS;
  
  	pinfo->frame_qlen = mpath->frame_queue.qlen;
d19b3bf63   Rui Paulo   mac80211: replace...
911
  	pinfo->sn = mpath->sn;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
912
913
914
915
916
917
918
919
920
921
922
  	pinfo->metric = mpath->metric;
  	if (time_before(jiffies, mpath->exp_time))
  		pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies);
  	pinfo->discovery_timeout =
  			jiffies_to_msecs(mpath->discovery_timeout);
  	pinfo->discovery_retries = mpath->discovery_retries;
  	pinfo->flags = 0;
  	if (mpath->flags & MESH_PATH_ACTIVE)
  		pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE;
  	if (mpath->flags & MESH_PATH_RESOLVING)
  		pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING;
d19b3bf63   Rui Paulo   mac80211: replace...
923
924
  	if (mpath->flags & MESH_PATH_SN_VALID)
  		pinfo->flags |= NL80211_MPATH_FLAG_SN_VALID;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
925
926
927
928
929
930
931
932
933
934
935
936
  	if (mpath->flags & MESH_PATH_FIXED)
  		pinfo->flags |= NL80211_MPATH_FLAG_FIXED;
  	if (mpath->flags & MESH_PATH_RESOLVING)
  		pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING;
  
  	pinfo->flags = mpath->flags;
  }
  
  static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
  			       u8 *dst, u8 *next_hop, struct mpath_info *pinfo)
  
  {
14db74bcc   Johannes Berg   mac80211: fix cfg...
937
  	struct ieee80211_sub_if_data *sdata;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
938
  	struct mesh_path *mpath;
14db74bcc   Johannes Berg   mac80211: fix cfg...
939
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
940
  	rcu_read_lock();
f698d856f   Jasper Bryant-Greene   replace net_devic...
941
  	mpath = mesh_path_lookup(dst, sdata);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
942
943
944
945
946
947
948
949
950
951
952
953
954
955
  	if (!mpath) {
  		rcu_read_unlock();
  		return -ENOENT;
  	}
  	memcpy(dst, mpath->dst, ETH_ALEN);
  	mpath_set_pinfo(mpath, next_hop, pinfo);
  	rcu_read_unlock();
  	return 0;
  }
  
  static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
  				 int idx, u8 *dst, u8 *next_hop,
  				 struct mpath_info *pinfo)
  {
14db74bcc   Johannes Berg   mac80211: fix cfg...
956
  	struct ieee80211_sub_if_data *sdata;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
957
  	struct mesh_path *mpath;
14db74bcc   Johannes Berg   mac80211: fix cfg...
958
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
959
  	rcu_read_lock();
f698d856f   Jasper Bryant-Greene   replace net_devic...
960
  	mpath = mesh_path_lookup_by_idx(idx, sdata);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
961
962
963
964
965
966
967
968
969
  	if (!mpath) {
  		rcu_read_unlock();
  		return -ENOENT;
  	}
  	memcpy(dst, mpath->dst, ETH_ALEN);
  	mpath_set_pinfo(mpath, next_hop, pinfo);
  	rcu_read_unlock();
  	return 0;
  }
93da9cc17   colin@cozybit.com   Add nl80211 comma...
970

24bdd9f4c   Javier Cardona   mac80211: Rename ...
971
  static int ieee80211_get_mesh_config(struct wiphy *wiphy,
93da9cc17   colin@cozybit.com   Add nl80211 comma...
972
973
974
975
976
  				struct net_device *dev,
  				struct mesh_config *conf)
  {
  	struct ieee80211_sub_if_data *sdata;
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
93da9cc17   colin@cozybit.com   Add nl80211 comma...
977
978
979
980
981
982
983
984
  	memcpy(conf, &(sdata->u.mesh.mshcfg), sizeof(struct mesh_config));
  	return 0;
  }
  
  static inline bool _chg_mesh_attr(enum nl80211_meshconf_params parm, u32 mask)
  {
  	return (mask >> (parm-1)) & 0x1;
  }
c80d545da   Javier Cardona   mac80211: Let use...
985
986
987
988
989
  static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
  		const struct mesh_setup *setup)
  {
  	u8 *new_ie;
  	const u8 *old_ie;
581a8b0fe   Javier Cardona   nl80211: rename N...
990
  	/* allocate information elements */
c80d545da   Javier Cardona   mac80211: Let use...
991
  	new_ie = NULL;
581a8b0fe   Javier Cardona   nl80211: rename N...
992
  	old_ie = ifmsh->ie;
c80d545da   Javier Cardona   mac80211: Let use...
993

581a8b0fe   Javier Cardona   nl80211: rename N...
994
995
  	if (setup->ie_len) {
  		new_ie = kmemdup(setup->ie, setup->ie_len,
c80d545da   Javier Cardona   mac80211: Let use...
996
997
998
999
  				GFP_KERNEL);
  		if (!new_ie)
  			return -ENOMEM;
  	}
581a8b0fe   Javier Cardona   nl80211: rename N...
1000
1001
1002
  	ifmsh->ie_len = setup->ie_len;
  	ifmsh->ie = new_ie;
  	kfree(old_ie);
c80d545da   Javier Cardona   mac80211: Let use...
1003
1004
1005
1006
1007
1008
  
  	/* now copy the rest of the setup parameters */
  	ifmsh->mesh_id_len = setup->mesh_id_len;
  	memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len);
  	ifmsh->mesh_pp_id = setup->path_sel_proto;
  	ifmsh->mesh_pm_id = setup->path_metric;
b130e5cec   Javier Cardona   nl80211: Introduc...
1009
1010
1011
1012
1013
  	ifmsh->security = IEEE80211_MESH_SEC_NONE;
  	if (setup->is_authenticated)
  		ifmsh->security |= IEEE80211_MESH_SEC_AUTHED;
  	if (setup->is_secure)
  		ifmsh->security |= IEEE80211_MESH_SEC_SECURED;
c80d545da   Javier Cardona   mac80211: Let use...
1014
1015
1016
  
  	return 0;
  }
24bdd9f4c   Javier Cardona   mac80211: Rename ...
1017
  static int ieee80211_update_mesh_config(struct wiphy *wiphy,
29cbe68c5   Johannes Berg   cfg80211/mac80211...
1018
1019
  					struct net_device *dev, u32 mask,
  					const struct mesh_config *nconf)
93da9cc17   colin@cozybit.com   Add nl80211 comma...
1020
1021
1022
  {
  	struct mesh_config *conf;
  	struct ieee80211_sub_if_data *sdata;
63c5723bc   Rui Paulo   mac80211: add nl8...
1023
  	struct ieee80211_if_mesh *ifmsh;
93da9cc17   colin@cozybit.com   Add nl80211 comma...
1024
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
63c5723bc   Rui Paulo   mac80211: add nl8...
1025
  	ifmsh = &sdata->u.mesh;
93da9cc17   colin@cozybit.com   Add nl80211 comma...
1026

93da9cc17   colin@cozybit.com   Add nl80211 comma...
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
  	/* Set the config options which we are interested in setting */
  	conf = &(sdata->u.mesh.mshcfg);
  	if (_chg_mesh_attr(NL80211_MESHCONF_RETRY_TIMEOUT, mask))
  		conf->dot11MeshRetryTimeout = nconf->dot11MeshRetryTimeout;
  	if (_chg_mesh_attr(NL80211_MESHCONF_CONFIRM_TIMEOUT, mask))
  		conf->dot11MeshConfirmTimeout = nconf->dot11MeshConfirmTimeout;
  	if (_chg_mesh_attr(NL80211_MESHCONF_HOLDING_TIMEOUT, mask))
  		conf->dot11MeshHoldingTimeout = nconf->dot11MeshHoldingTimeout;
  	if (_chg_mesh_attr(NL80211_MESHCONF_MAX_PEER_LINKS, mask))
  		conf->dot11MeshMaxPeerLinks = nconf->dot11MeshMaxPeerLinks;
  	if (_chg_mesh_attr(NL80211_MESHCONF_MAX_RETRIES, mask))
  		conf->dot11MeshMaxRetries = nconf->dot11MeshMaxRetries;
  	if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask))
  		conf->dot11MeshTTL = nconf->dot11MeshTTL;
45904f216   Javier Cardona   nl80211/mac80211:...
1041
1042
  	if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask))
  		conf->dot11MeshTTL = nconf->element_ttl;
93da9cc17   colin@cozybit.com   Add nl80211 comma...
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
  	if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask))
  		conf->auto_open_plinks = nconf->auto_open_plinks;
  	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask))
  		conf->dot11MeshHWMPmaxPREQretries =
  			nconf->dot11MeshHWMPmaxPREQretries;
  	if (_chg_mesh_attr(NL80211_MESHCONF_PATH_REFRESH_TIME, mask))
  		conf->path_refresh_time = nconf->path_refresh_time;
  	if (_chg_mesh_attr(NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, mask))
  		conf->min_discovery_timeout = nconf->min_discovery_timeout;
  	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, mask))
  		conf->dot11MeshHWMPactivePathTimeout =
  			nconf->dot11MeshHWMPactivePathTimeout;
  	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, mask))
  		conf->dot11MeshHWMPpreqMinInterval =
  			nconf->dot11MeshHWMPpreqMinInterval;
  	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
  			   mask))
  		conf->dot11MeshHWMPnetDiameterTraversalTime =
  			nconf->dot11MeshHWMPnetDiameterTraversalTime;
63c5723bc   Rui Paulo   mac80211: add nl8...
1062
1063
1064
1065
  	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ROOTMODE, mask)) {
  		conf->dot11MeshHWMPRootMode = nconf->dot11MeshHWMPRootMode;
  		ieee80211_mesh_root_setup(ifmsh);
  	}
93da9cc17   colin@cozybit.com   Add nl80211 comma...
1066
1067
  	return 0;
  }
29cbe68c5   Johannes Berg   cfg80211/mac80211...
1068
1069
1070
1071
1072
1073
  static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
  			       const struct mesh_config *conf,
  			       const struct mesh_setup *setup)
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
c80d545da   Javier Cardona   mac80211: Let use...
1074
  	int err;
29cbe68c5   Johannes Berg   cfg80211/mac80211...
1075

c80d545da   Javier Cardona   mac80211: Let use...
1076
1077
1078
1079
  	memcpy(&ifmsh->mshcfg, conf, sizeof(struct mesh_config));
  	err = copy_mesh_setup(ifmsh, setup);
  	if (err)
  		return err;
29cbe68c5   Johannes Berg   cfg80211/mac80211...
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
  	ieee80211_start_mesh(sdata);
  
  	return 0;
  }
  
  static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  
  	ieee80211_stop_mesh(sdata);
  
  	return 0;
  }
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1093
  #endif
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
1094
1095
1096
1097
  static int ieee80211_change_bss(struct wiphy *wiphy,
  				struct net_device *dev,
  				struct bss_parameters *params)
  {
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
1098
1099
  	struct ieee80211_sub_if_data *sdata;
  	u32 changed = 0;
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
1100
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
1101
  	if (params->use_cts_prot >= 0) {
bda3933a8   Johannes Berg   mac80211: move bs...
1102
  		sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
1103
1104
1105
  		changed |= BSS_CHANGED_ERP_CTS_PROT;
  	}
  	if (params->use_short_preamble >= 0) {
bda3933a8   Johannes Berg   mac80211: move bs...
1106
  		sdata->vif.bss_conf.use_short_preamble =
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
1107
1108
1109
  			params->use_short_preamble;
  		changed |= BSS_CHANGED_ERP_PREAMBLE;
  	}
43d353434   Felix Fietkau   mac80211: force u...
1110
1111
1112
1113
1114
1115
  
  	if (!sdata->vif.bss_conf.use_short_slot &&
  	    sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) {
  		sdata->vif.bss_conf.use_short_slot = true;
  		changed |= BSS_CHANGED_ERP_SLOT;
  	}
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
1116
  	if (params->use_short_slot_time >= 0) {
bda3933a8   Johannes Berg   mac80211: move bs...
1117
  		sdata->vif.bss_conf.use_short_slot =
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
1118
1119
1120
  			params->use_short_slot_time;
  		changed |= BSS_CHANGED_ERP_SLOT;
  	}
90c97a040   Jouni Malinen   nl80211: Add basi...
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
  	if (params->basic_rates) {
  		int i, j;
  		u32 rates = 0;
  		struct ieee80211_local *local = wiphy_priv(wiphy);
  		struct ieee80211_supported_band *sband =
  			wiphy->bands[local->oper_channel->band];
  
  		for (i = 0; i < params->basic_rates_len; i++) {
  			int rate = (params->basic_rates[i] & 0x7f) * 5;
  			for (j = 0; j < sband->n_bitrates; j++) {
  				if (sband->bitrates[j].bitrate == rate)
  					rates |= BIT(j);
  			}
  		}
  		sdata->vif.bss_conf.basic_rates = rates;
  		changed |= BSS_CHANGED_BASIC_RATES;
  	}
7b7b5e56d   Felix Fietkau   mac80211: impleme...
1138
1139
1140
1141
1142
1143
  	if (params->ap_isolate >= 0) {
  		if (params->ap_isolate)
  			sdata->flags |= IEEE80211_SDATA_DONT_BRIDGE_PACKETS;
  		else
  			sdata->flags &= ~IEEE80211_SDATA_DONT_BRIDGE_PACKETS;
  	}
80d7e403c   Helmut Schaa   mac80211: Apply h...
1144
1145
1146
1147
1148
  	if (params->ht_opmode >= 0) {
  		sdata->vif.bss_conf.ht_operation_mode =
  			(u16) params->ht_opmode;
  		changed |= BSS_CHANGED_HT;
  	}
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
1149
1150
1151
1152
  	ieee80211_bss_info_change_notify(sdata, changed);
  
  	return 0;
  }
318884875   Jouni Malinen   nl80211: Add TX q...
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
  static int ieee80211_set_txq_params(struct wiphy *wiphy,
  				    struct ieee80211_txq_params *params)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  	struct ieee80211_tx_queue_params p;
  
  	if (!local->ops->conf_tx)
  		return -EOPNOTSUPP;
  
  	memset(&p, 0, sizeof(p));
  	p.aifs = params->aifs;
  	p.cw_max = params->cwmax;
  	p.cw_min = params->cwmin;
  	p.txop = params->txop;
ab13315af   Kalle Valo   mac80211: add U-A...
1167
1168
1169
1170
1171
1172
  
  	/*
  	 * Setting tx queue params disables u-apsd because it's only
  	 * called in master mode.
  	 */
  	p.uapsd = false;
2683d65bb   Eliad Peller   mac80211: reconfi...
1173
1174
1175
1176
  	if (params->queue >= local->hw.queues)
  		return -EINVAL;
  
  	local->tx_conf[params->queue] = p;
244879813   Johannes Berg   mac80211: add dri...
1177
  	if (drv_conf_tx(local, params->queue, &p)) {
0fb9a9ec2   Joe Perches   net/mac80211: Use...
1178
1179
1180
1181
  		wiphy_debug(local->hw.wiphy,
  			    "failed to set TX queue parameters for queue %d
  ",
  			    params->queue);
318884875   Jouni Malinen   nl80211: Add TX q...
1182
1183
1184
1185
1186
  		return -EINVAL;
  	}
  
  	return 0;
  }
72bdcf343   Jouni Malinen   nl80211: Add freq...
1187
  static int ieee80211_set_channel(struct wiphy *wiphy,
f444de05d   Johannes Berg   cfg80211/mac80211...
1188
  				 struct net_device *netdev,
72bdcf343   Jouni Malinen   nl80211: Add freq...
1189
  				 struct ieee80211_channel *chan,
094d05dc3   Sujith   mac80211: Fix HT ...
1190
  				 enum nl80211_channel_type channel_type)
72bdcf343   Jouni Malinen   nl80211: Add freq...
1191
1192
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
0aaffa9b9   Johannes Berg   mac80211: improve...
1193
  	struct ieee80211_sub_if_data *sdata = NULL;
eeabee7e5   Ben Greear   mac80211: Be more...
1194
1195
1196
  	struct ieee80211_channel *old_oper;
  	enum nl80211_channel_type old_oper_type;
  	enum nl80211_channel_type old_vif_oper_type= NL80211_CHAN_NO_HT;
0aaffa9b9   Johannes Berg   mac80211: improve...
1197
1198
1199
  
  	if (netdev)
  		sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
72bdcf343   Jouni Malinen   nl80211: Add freq...
1200

f444de05d   Johannes Berg   cfg80211/mac80211...
1201
1202
1203
1204
  	switch (ieee80211_get_channel_mode(local, NULL)) {
  	case CHAN_MODE_HOPPING:
  		return -EBUSY;
  	case CHAN_MODE_FIXED:
0aaffa9b9   Johannes Berg   mac80211: improve...
1205
1206
1207
  		if (local->oper_channel != chan)
  			return -EBUSY;
  		if (!sdata && local->_oper_channel_type == channel_type)
f444de05d   Johannes Berg   cfg80211/mac80211...
1208
  			return 0;
0aaffa9b9   Johannes Berg   mac80211: improve...
1209
  		break;
f444de05d   Johannes Berg   cfg80211/mac80211...
1210
1211
1212
  	case CHAN_MODE_UNDEFINED:
  		break;
  	}
72bdcf343   Jouni Malinen   nl80211: Add freq...
1213

eeabee7e5   Ben Greear   mac80211: Be more...
1214
1215
1216
  	if (sdata)
  		old_vif_oper_type = sdata->vif.bss_conf.channel_type;
  	old_oper_type = local->_oper_channel_type;
72bdcf343   Jouni Malinen   nl80211: Add freq...
1217

0aaffa9b9   Johannes Berg   mac80211: improve...
1218
1219
  	if (!ieee80211_set_channel_type(local, sdata, channel_type))
  		return -EBUSY;
eeabee7e5   Ben Greear   mac80211: Be more...
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
  	old_oper = local->oper_channel;
  	local->oper_channel = chan;
  
  	/* Update driver if changes were actually made. */
  	if ((old_oper != local->oper_channel) ||
  	    (old_oper_type != local->_oper_channel_type))
  		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
  
  	if ((sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR) &&
  	    old_vif_oper_type != sdata->vif.bss_conf.channel_type)
0aaffa9b9   Johannes Berg   mac80211: improve...
1230
1231
1232
  		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
  
  	return 0;
72bdcf343   Jouni Malinen   nl80211: Add freq...
1233
  }
665af4fc8   Bob Copeland   mac80211: add sus...
1234
  #ifdef CONFIG_PM
ff1b6e69a   Johannes Berg   nl80211/cfg80211:...
1235
1236
  static int ieee80211_suspend(struct wiphy *wiphy,
  			     struct cfg80211_wowlan *wowlan)
665af4fc8   Bob Copeland   mac80211: add sus...
1237
  {
eecc48000   Johannes Berg   mac80211: add bas...
1238
  	return __ieee80211_suspend(wiphy_priv(wiphy), wowlan);
665af4fc8   Bob Copeland   mac80211: add sus...
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
  }
  
  static int ieee80211_resume(struct wiphy *wiphy)
  {
  	return __ieee80211_resume(wiphy_priv(wiphy));
  }
  #else
  #define ieee80211_suspend NULL
  #define ieee80211_resume NULL
  #endif
2a5193119   Johannes Berg   cfg80211/nl80211:...
1249
1250
1251
1252
  static int ieee80211_scan(struct wiphy *wiphy,
  			  struct net_device *dev,
  			  struct cfg80211_scan_request *req)
  {
2ca27bcff   Johannes Berg   mac80211: add p2p...
1253
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2a5193119   Johannes Berg   cfg80211/nl80211:...
1254

2ca27bcff   Johannes Berg   mac80211: add p2p...
1255
1256
1257
1258
1259
1260
1261
1262
1263
  	switch (ieee80211_vif_type_p2p(&sdata->vif)) {
  	case NL80211_IFTYPE_STATION:
  	case NL80211_IFTYPE_ADHOC:
  	case NL80211_IFTYPE_MESH_POINT:
  	case NL80211_IFTYPE_P2P_CLIENT:
  		break;
  	case NL80211_IFTYPE_P2P_GO:
  		if (sdata->local->ops->hw_scan)
  			break;
e9d7732ea   Johannes Berg   mac80211: allow G...
1264
1265
1266
1267
1268
  		/*
  		 * FIXME: implement NoA while scanning in software,
  		 * for now fall through to allow scanning only when
  		 * beaconing hasn't been configured yet
  		 */
2ca27bcff   Johannes Berg   mac80211: add p2p...
1269
1270
1271
1272
1273
1274
1275
  	case NL80211_IFTYPE_AP:
  		if (sdata->u.ap.beacon)
  			return -EOPNOTSUPP;
  		break;
  	default:
  		return -EOPNOTSUPP;
  	}
2a5193119   Johannes Berg   cfg80211/nl80211:...
1276
1277
1278
  
  	return ieee80211_request_scan(sdata, req);
  }
79f460ca4   Luciano Coelho   mac80211: add sup...
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
  static int
  ieee80211_sched_scan_start(struct wiphy *wiphy,
  			   struct net_device *dev,
  			   struct cfg80211_sched_scan_request *req)
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  
  	if (!sdata->local->ops->sched_scan_start)
  		return -EOPNOTSUPP;
  
  	return ieee80211_request_sched_scan_start(sdata, req);
  }
  
  static int
85a9994a0   Luciano Coelho   cfg80211/mac80211...
1293
  ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev)
79f460ca4   Luciano Coelho   mac80211: add sup...
1294
1295
1296
1297
1298
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  
  	if (!sdata->local->ops->sched_scan_stop)
  		return -EOPNOTSUPP;
85a9994a0   Luciano Coelho   cfg80211/mac80211...
1299
  	return ieee80211_request_sched_scan_stop(sdata);
79f460ca4   Luciano Coelho   mac80211: add sup...
1300
  }
636a5d362   Jouni Malinen   nl80211: Add MLME...
1301
1302
1303
  static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
  			  struct cfg80211_auth_request *req)
  {
77fdaa12c   Johannes Berg   mac80211: rework ...
1304
  	return ieee80211_mgd_auth(IEEE80211_DEV_TO_SUB_IF(dev), req);
636a5d362   Jouni Malinen   nl80211: Add MLME...
1305
1306
1307
1308
1309
  }
  
  static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
  			   struct cfg80211_assoc_request *req)
  {
f444de05d   Johannes Berg   cfg80211/mac80211...
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  
  	switch (ieee80211_get_channel_mode(local, sdata)) {
  	case CHAN_MODE_HOPPING:
  		return -EBUSY;
  	case CHAN_MODE_FIXED:
  		if (local->oper_channel == req->bss->channel)
  			break;
  		return -EBUSY;
  	case CHAN_MODE_UNDEFINED:
  		break;
  	}
77fdaa12c   Johannes Berg   mac80211: rework ...
1323
  	return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
636a5d362   Jouni Malinen   nl80211: Add MLME...
1324
1325
1326
  }
  
  static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev,
667503ddc   Johannes Berg   cfg80211: fix loc...
1327
1328
  			    struct cfg80211_deauth_request *req,
  			    void *cookie)
636a5d362   Jouni Malinen   nl80211: Add MLME...
1329
  {
667503ddc   Johannes Berg   cfg80211: fix loc...
1330
1331
  	return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev),
  				    req, cookie);
636a5d362   Jouni Malinen   nl80211: Add MLME...
1332
1333
1334
  }
  
  static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
667503ddc   Johannes Berg   cfg80211: fix loc...
1335
1336
  			      struct cfg80211_disassoc_request *req,
  			      void *cookie)
636a5d362   Jouni Malinen   nl80211: Add MLME...
1337
  {
667503ddc   Johannes Berg   cfg80211: fix loc...
1338
1339
  	return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev),
  				      req, cookie);
636a5d362   Jouni Malinen   nl80211: Add MLME...
1340
  }
af8cdcd82   Johannes Berg   mac80211: convert...
1341
1342
1343
  static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
  			       struct cfg80211_ibss_params *params)
  {
f444de05d   Johannes Berg   cfg80211/mac80211...
1344
  	struct ieee80211_local *local = wiphy_priv(wiphy);
af8cdcd82   Johannes Berg   mac80211: convert...
1345
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
f444de05d   Johannes Berg   cfg80211/mac80211...
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
  	switch (ieee80211_get_channel_mode(local, sdata)) {
  	case CHAN_MODE_HOPPING:
  		return -EBUSY;
  	case CHAN_MODE_FIXED:
  		if (!params->channel_fixed)
  			return -EBUSY;
  		if (local->oper_channel == params->channel)
  			break;
  		return -EBUSY;
  	case CHAN_MODE_UNDEFINED:
  		break;
  	}
af8cdcd82   Johannes Berg   mac80211: convert...
1358
1359
1360
1361
1362
1363
1364
1365
1366
  	return ieee80211_ibss_join(sdata, params);
  }
  
  static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  
  	return ieee80211_ibss_leave(sdata);
  }
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
1367
1368
1369
  static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
244879813   Johannes Berg   mac80211: add dri...
1370
  	int err;
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
1371

f23a47807   Arik Nemtsov   mac80211: support...
1372
1373
1374
1375
1376
1377
  	if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
  		err = drv_set_frag_threshold(local, wiphy->frag_threshold);
  
  		if (err)
  			return err;
  	}
310bc676e   Lukáš Turek   mac80211: Add new...
1378
1379
1380
1381
1382
1383
  	if (changed & WIPHY_PARAM_COVERAGE_CLASS) {
  		err = drv_set_coverage_class(local, wiphy->coverage_class);
  
  		if (err)
  			return err;
  	}
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
1384
  	if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
244879813   Johannes Berg   mac80211: add dri...
1385
  		err = drv_set_rts_threshold(local, wiphy->rts_threshold);
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
1386

244879813   Johannes Berg   mac80211: add dri...
1387
1388
  		if (err)
  			return err;
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
  	}
  
  	if (changed & WIPHY_PARAM_RETRY_SHORT)
  		local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
  	if (changed & WIPHY_PARAM_RETRY_LONG)
  		local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
  	if (changed &
  	    (WIPHY_PARAM_RETRY_SHORT | WIPHY_PARAM_RETRY_LONG))
  		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS);
  
  	return 0;
  }
7643a2c3f   Johannes Berg   cfg80211: move tx...
1401
  static int ieee80211_set_tx_power(struct wiphy *wiphy,
fa61cf70a   Juuso Oikarinen   cfg80211/mac80211...
1402
  				  enum nl80211_tx_power_setting type, int mbm)
7643a2c3f   Johannes Berg   cfg80211: move tx...
1403
1404
1405
1406
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  	struct ieee80211_channel *chan = local->hw.conf.channel;
  	u32 changes = 0;
7643a2c3f   Johannes Berg   cfg80211: move tx...
1407
1408
  
  	switch (type) {
fa61cf70a   Juuso Oikarinen   cfg80211/mac80211...
1409
  	case NL80211_TX_POWER_AUTOMATIC:
7643a2c3f   Johannes Berg   cfg80211: move tx...
1410
1411
  		local->user_power_level = -1;
  		break;
fa61cf70a   Juuso Oikarinen   cfg80211/mac80211...
1412
1413
1414
1415
  	case NL80211_TX_POWER_LIMITED:
  		if (mbm < 0 || (mbm % 100))
  			return -EOPNOTSUPP;
  		local->user_power_level = MBM_TO_DBM(mbm);
7643a2c3f   Johannes Berg   cfg80211: move tx...
1416
  		break;
fa61cf70a   Juuso Oikarinen   cfg80211/mac80211...
1417
1418
1419
  	case NL80211_TX_POWER_FIXED:
  		if (mbm < 0 || (mbm % 100))
  			return -EOPNOTSUPP;
7643a2c3f   Johannes Berg   cfg80211: move tx...
1420
  		/* TODO: move to cfg80211 when it knows the channel */
fa61cf70a   Juuso Oikarinen   cfg80211/mac80211...
1421
  		if (MBM_TO_DBM(mbm) > chan->max_power)
7643a2c3f   Johannes Berg   cfg80211: move tx...
1422
  			return -EINVAL;
fa61cf70a   Juuso Oikarinen   cfg80211/mac80211...
1423
  		local->user_power_level = MBM_TO_DBM(mbm);
7643a2c3f   Johannes Berg   cfg80211: move tx...
1424
  		break;
7643a2c3f   Johannes Berg   cfg80211: move tx...
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
  	}
  
  	ieee80211_hw_config(local, changes);
  
  	return 0;
  }
  
  static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  
  	*dbm = local->hw.conf.power_level;
7643a2c3f   Johannes Berg   cfg80211: move tx...
1437
1438
  	return 0;
  }
ab737a4f7   Johannes Berg   cfg80211: impleme...
1439
  static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
388ac775b   Johannes Berg   cfg80211: constif...
1440
  				  const u8 *addr)
ab737a4f7   Johannes Berg   cfg80211: impleme...
1441
1442
1443
1444
1445
1446
1447
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  
  	memcpy(&sdata->u.wds.remote_addr, addr, ETH_ALEN);
  
  	return 0;
  }
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
1448
1449
1450
1451
1452
1453
  static void ieee80211_rfkill_poll(struct wiphy *wiphy)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  
  	drv_rfkill_poll(local);
  }
aff89a9b9   Johannes Berg   cfg80211: introdu...
1454
  #ifdef CONFIG_NL80211_TESTMODE
99783e2cd   Johannes Berg   mac80211: fix spa...
1455
  static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
aff89a9b9   Johannes Berg   cfg80211: introdu...
1456
1457
1458
1459
1460
1461
1462
1463
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  
  	if (!local->ops->testmode_cmd)
  		return -EOPNOTSUPP;
  
  	return local->ops->testmode_cmd(&local->hw, data, len);
  }
71063f0e8   Wey-Yi Guy   nl80211: add test...
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
  
  static int ieee80211_testmode_dump(struct wiphy *wiphy,
  				   struct sk_buff *skb,
  				   struct netlink_callback *cb,
  				   void *data, int len)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  
  	if (!local->ops->testmode_dump)
  		return -EOPNOTSUPP;
  
  	return local->ops->testmode_dump(&local->hw, skb, cb, data, len);
  }
aff89a9b9   Johannes Berg   cfg80211: introdu...
1477
  #endif
0f78231bf   Johannes Berg   mac80211: enable ...
1478
1479
1480
1481
1482
1483
  int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
  			     enum ieee80211_smps_mode smps_mode)
  {
  	const u8 *ap;
  	enum ieee80211_smps_mode old_req;
  	int err;
243e6df4e   Johannes Berg   mac80211: fix SMP...
1484
  	lockdep_assert_held(&sdata->u.mgd.mtx);
0f78231bf   Johannes Berg   mac80211: enable ...
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
  	old_req = sdata->u.mgd.req_smps;
  	sdata->u.mgd.req_smps = smps_mode;
  
  	if (old_req == smps_mode &&
  	    smps_mode != IEEE80211_SMPS_AUTOMATIC)
  		return 0;
  
  	/*
  	 * If not associated, or current association is not an HT
  	 * association, there's no need to send an action frame.
  	 */
  	if (!sdata->u.mgd.associated ||
0aaffa9b9   Johannes Berg   mac80211: improve...
1497
  	    sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) {
0f78231bf   Johannes Berg   mac80211: enable ...
1498
  		mutex_lock(&sdata->local->iflist_mtx);
025e6be22   Johannes Berg   mac80211: fix dea...
1499
  		ieee80211_recalc_smps(sdata->local);
0f78231bf   Johannes Berg   mac80211: enable ...
1500
1501
1502
  		mutex_unlock(&sdata->local->iflist_mtx);
  		return 0;
  	}
0c1ad2cac   Johannes Berg   mac80211: proper ...
1503
  	ap = sdata->u.mgd.associated->bssid;
0f78231bf   Johannes Berg   mac80211: enable ...
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
  
  	if (smps_mode == IEEE80211_SMPS_AUTOMATIC) {
  		if (sdata->u.mgd.powersave)
  			smps_mode = IEEE80211_SMPS_DYNAMIC;
  		else
  			smps_mode = IEEE80211_SMPS_OFF;
  	}
  
  	/* send SM PS frame to AP */
  	err = ieee80211_send_smps_action(sdata, smps_mode,
  					 ap, ap);
  	if (err)
  		sdata->u.mgd.req_smps = old_req;
  
  	return err;
  }
bc92afd92   Johannes Berg   cfg80211: impleme...
1520
1521
1522
1523
1524
  static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
  				    bool enabled, int timeout)
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
bc92afd92   Johannes Berg   cfg80211: impleme...
1525

e5de30c9b   Benoit Papillault   mac80211: check t...
1526
1527
  	if (sdata->vif.type != NL80211_IFTYPE_STATION)
  		return -EOPNOTSUPP;
bc92afd92   Johannes Berg   cfg80211: impleme...
1528
1529
1530
1531
  	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
  		return -EOPNOTSUPP;
  
  	if (enabled == sdata->u.mgd.powersave &&
ff6163810   Juuso Oikarinen   mac80211: Fix ps-...
1532
  	    timeout == local->dynamic_ps_forced_timeout)
bc92afd92   Johannes Berg   cfg80211: impleme...
1533
1534
1535
  		return 0;
  
  	sdata->u.mgd.powersave = enabled;
ff6163810   Juuso Oikarinen   mac80211: Fix ps-...
1536
  	local->dynamic_ps_forced_timeout = timeout;
bc92afd92   Johannes Berg   cfg80211: impleme...
1537

0f78231bf   Johannes Berg   mac80211: enable ...
1538
1539
1540
1541
  	/* no change, but if automatic follow powersave */
  	mutex_lock(&sdata->u.mgd.mtx);
  	__ieee80211_request_smps(sdata, sdata->u.mgd.req_smps);
  	mutex_unlock(&sdata->u.mgd.mtx);
bc92afd92   Johannes Berg   cfg80211: impleme...
1542
1543
1544
1545
1546
1547
1548
  	if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
  		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
  
  	ieee80211_recalc_ps(local, -1);
  
  	return 0;
  }
a97c13c34   Juuso Oikarinen   mac80211: Add sup...
1549
1550
1551
1552
1553
1554
1555
1556
  static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
  					 struct net_device *dev,
  					 s32 rssi_thold, u32 rssi_hyst)
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
  	struct ieee80211_vif *vif = &sdata->vif;
  	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
a97c13c34   Juuso Oikarinen   mac80211: Add sup...
1557
1558
1559
1560
1561
1562
  	if (rssi_thold == bss_conf->cqm_rssi_thold &&
  	    rssi_hyst == bss_conf->cqm_rssi_hyst)
  		return 0;
  
  	bss_conf->cqm_rssi_thold = rssi_thold;
  	bss_conf->cqm_rssi_hyst = rssi_hyst;
17e4ec147   Jouni Malinen   mac80211: Track B...
1563
1564
1565
1566
1567
  	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
  		if (sdata->vif.type != NL80211_IFTYPE_STATION)
  			return -EOPNOTSUPP;
  		return 0;
  	}
a97c13c34   Juuso Oikarinen   mac80211: Add sup...
1568
1569
1570
1571
1572
1573
  	/* tell the driver upon association, unless already associated */
  	if (sdata->u.mgd.associated)
  		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM);
  
  	return 0;
  }
9930380f0   Johannes Berg   cfg80211: impleme...
1574
1575
1576
1577
1578
1579
1580
  static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
  				      struct net_device *dev,
  				      const u8 *addr,
  				      const struct cfg80211_bitrate_mask *mask)
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
bdbfd6b58   Sujith Manoharan   mac80211: Add new...
1581
  	int i, ret;
2c7e6bc9a   Johannes Berg   mac80211: disallo...
1582

bdbfd6b58   Sujith Manoharan   mac80211: Add new...
1583
1584
1585
1586
1587
  	if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) {
  		ret = drv_set_bitrate_mask(local, sdata, mask);
  		if (ret)
  			return ret;
  	}
9930380f0   Johannes Berg   cfg80211: impleme...
1588

37eb0b164   Jouni Malinen   cfg80211/mac80211...
1589
1590
  	for (i = 0; i < IEEE80211_NUM_BANDS; i++)
  		sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
9930380f0   Johannes Berg   cfg80211: impleme...
1591

37eb0b164   Jouni Malinen   cfg80211/mac80211...
1592
  	return 0;
9930380f0   Johannes Berg   cfg80211: impleme...
1593
  }
21f835896   Johannes Berg   mac80211: impleme...
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
  static int ieee80211_remain_on_channel_hw(struct ieee80211_local *local,
  					  struct net_device *dev,
  					  struct ieee80211_channel *chan,
  					  enum nl80211_channel_type chantype,
  					  unsigned int duration, u64 *cookie)
  {
  	int ret;
  	u32 random_cookie;
  
  	lockdep_assert_held(&local->mtx);
  
  	if (local->hw_roc_cookie)
  		return -EBUSY;
  	/* must be nonzero */
  	random_cookie = random32() | 1;
  
  	*cookie = random_cookie;
  	local->hw_roc_dev = dev;
  	local->hw_roc_cookie = random_cookie;
  	local->hw_roc_channel = chan;
  	local->hw_roc_channel_type = chantype;
  	local->hw_roc_duration = duration;
  	ret = drv_remain_on_channel(local, chan, chantype, duration);
  	if (ret) {
  		local->hw_roc_channel = NULL;
  		local->hw_roc_cookie = 0;
  	}
  
  	return ret;
  }
b8bc4b0aa   Johannes Berg   mac80211: support...
1624
1625
1626
1627
1628
1629
1630
1631
  static int ieee80211_remain_on_channel(struct wiphy *wiphy,
  				       struct net_device *dev,
  				       struct ieee80211_channel *chan,
  				       enum nl80211_channel_type channel_type,
  				       unsigned int duration,
  				       u64 *cookie)
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
21f835896   Johannes Berg   mac80211: impleme...
1632
1633
1634
1635
1636
1637
1638
1639
1640
  	struct ieee80211_local *local = sdata->local;
  
  	if (local->ops->remain_on_channel) {
  		int ret;
  
  		mutex_lock(&local->mtx);
  		ret = ieee80211_remain_on_channel_hw(local, dev,
  						     chan, channel_type,
  						     duration, cookie);
90fc4b3a5   Johannes Berg   mac80211: impleme...
1641
  		local->hw_roc_for_tx = false;
21f835896   Johannes Berg   mac80211: impleme...
1642
1643
1644
1645
  		mutex_unlock(&local->mtx);
  
  		return ret;
  	}
b8bc4b0aa   Johannes Berg   mac80211: support...
1646
1647
1648
1649
  
  	return ieee80211_wk_remain_on_channel(sdata, chan, channel_type,
  					      duration, cookie);
  }
21f835896   Johannes Berg   mac80211: impleme...
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
  static int ieee80211_cancel_remain_on_channel_hw(struct ieee80211_local *local,
  						 u64 cookie)
  {
  	int ret;
  
  	lockdep_assert_held(&local->mtx);
  
  	if (local->hw_roc_cookie != cookie)
  		return -ENOENT;
  
  	ret = drv_cancel_remain_on_channel(local);
  	if (ret)
  		return ret;
  
  	local->hw_roc_cookie = 0;
  	local->hw_roc_channel = NULL;
  
  	ieee80211_recalc_idle(local);
  
  	return 0;
  }
b8bc4b0aa   Johannes Berg   mac80211: support...
1671
1672
1673
1674
1675
  static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
  					      struct net_device *dev,
  					      u64 cookie)
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
21f835896   Johannes Berg   mac80211: impleme...
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
  	struct ieee80211_local *local = sdata->local;
  
  	if (local->ops->cancel_remain_on_channel) {
  		int ret;
  
  		mutex_lock(&local->mtx);
  		ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
  		mutex_unlock(&local->mtx);
  
  		return ret;
  	}
b8bc4b0aa   Johannes Berg   mac80211: support...
1687
1688
1689
  
  	return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
  }
f30221e4e   Johannes Berg   mac80211: impleme...
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
  static enum work_done_result
  ieee80211_offchan_tx_done(struct ieee80211_work *wk, struct sk_buff *skb)
  {
  	/*
  	 * Use the data embedded in the work struct for reporting
  	 * here so if the driver mangled the SKB before dropping
  	 * it (which is the only way we really should get here)
  	 * then we don't report mangled data.
  	 *
  	 * If there was no wait time, then by the time we get here
  	 * the driver will likely not have reported the status yet,
  	 * so in that case userspace will have to deal with it.
  	 */
  
  	if (wk->offchan_tx.wait && wk->offchan_tx.frame)
  		cfg80211_mgmt_tx_status(wk->sdata->dev,
  					(unsigned long) wk->offchan_tx.frame,
  					wk->ie, wk->ie_len, false, GFP_KERNEL);
  
  	return WORK_DONE_DESTROY;
  }
2e161f78e   Johannes Berg   cfg80211/mac80211...
1711
  static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
f7ca38dfe   Johannes Berg   nl80211/cfg80211:...
1712
  			     struct ieee80211_channel *chan, bool offchan,
2e161f78e   Johannes Berg   cfg80211/mac80211...
1713
  			     enum nl80211_channel_type channel_type,
f7ca38dfe   Johannes Berg   nl80211/cfg80211:...
1714
  			     bool channel_type_valid, unsigned int wait,
2e161f78e   Johannes Berg   cfg80211/mac80211...
1715
  			     const u8 *buf, size_t len, u64 *cookie)
026331c4d   Jouni Malinen   cfg80211/mac80211...
1716
  {
9d38d85de   Johannes Berg   cfg80211/mac80211...
1717
1718
1719
1720
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  	struct ieee80211_local *local = sdata->local;
  	struct sk_buff *skb;
  	struct sta_info *sta;
f30221e4e   Johannes Berg   mac80211: impleme...
1721
  	struct ieee80211_work *wk;
9d38d85de   Johannes Berg   cfg80211/mac80211...
1722
1723
1724
  	const struct ieee80211_mgmt *mgmt = (void *)buf;
  	u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
  		    IEEE80211_TX_CTL_REQ_TX_STATUS;
f30221e4e   Johannes Berg   mac80211: impleme...
1725
  	bool is_offchan = false;
f7ca38dfe   Johannes Berg   nl80211/cfg80211:...
1726

9d38d85de   Johannes Berg   cfg80211/mac80211...
1727
1728
1729
  	/* Check that we are on the requested channel for transmission */
  	if (chan != local->tmp_channel &&
  	    chan != local->oper_channel)
f30221e4e   Johannes Berg   mac80211: impleme...
1730
  		is_offchan = true;
9d38d85de   Johannes Berg   cfg80211/mac80211...
1731
1732
1733
  	if (channel_type_valid &&
  	    (channel_type != local->tmp_channel_type &&
  	     channel_type != local->_oper_channel_type))
f30221e4e   Johannes Berg   mac80211: impleme...
1734
  		is_offchan = true;
21f835896   Johannes Berg   mac80211: impleme...
1735
1736
1737
1738
1739
  	if (chan == local->hw_roc_channel) {
  		/* TODO: check channel type? */
  		is_offchan = false;
  		flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
  	}
f30221e4e   Johannes Berg   mac80211: impleme...
1740
  	if (is_offchan && !offchan)
9d38d85de   Johannes Berg   cfg80211/mac80211...
1741
1742
1743
1744
  		return -EBUSY;
  
  	switch (sdata->vif.type) {
  	case NL80211_IFTYPE_ADHOC:
663fcafd9   Johannes Berg   cfg80211/mac80211...
1745
1746
1747
  	case NL80211_IFTYPE_AP:
  	case NL80211_IFTYPE_AP_VLAN:
  	case NL80211_IFTYPE_P2P_GO:
c7108a711   Javier Cardona   mac80211: Send me...
1748
  	case NL80211_IFTYPE_MESH_POINT:
663fcafd9   Johannes Berg   cfg80211/mac80211...
1749
1750
  		if (!ieee80211_is_action(mgmt->frame_control) ||
  		    mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
9d38d85de   Johannes Berg   cfg80211/mac80211...
1751
1752
1753
1754
1755
1756
1757
1758
  			break;
  		rcu_read_lock();
  		sta = sta_info_get(sdata, mgmt->da);
  		rcu_read_unlock();
  		if (!sta)
  			return -ENOLINK;
  		break;
  	case NL80211_IFTYPE_STATION:
663fcafd9   Johannes Berg   cfg80211/mac80211...
1759
  	case NL80211_IFTYPE_P2P_CLIENT:
9d38d85de   Johannes Berg   cfg80211/mac80211...
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
  		break;
  	default:
  		return -EOPNOTSUPP;
  	}
  
  	skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
  	if (!skb)
  		return -ENOMEM;
  	skb_reserve(skb, local->hw.extra_tx_headroom);
  
  	memcpy(skb_put(skb, len), buf, len);
  
  	IEEE80211_SKB_CB(skb)->flags = flags;
  
  	skb->dev = sdata->dev;
9d38d85de   Johannes Berg   cfg80211/mac80211...
1775
1776
  
  	*cookie = (unsigned long) skb;
f30221e4e   Johannes Berg   mac80211: impleme...
1777

5f16a4361   Johannes Berg   mac80211: support...
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
  	if (is_offchan && local->ops->offchannel_tx) {
  		int ret;
  
  		IEEE80211_SKB_CB(skb)->band = chan->band;
  
  		mutex_lock(&local->mtx);
  
  		if (local->hw_offchan_tx_cookie) {
  			mutex_unlock(&local->mtx);
  			return -EBUSY;
  		}
  
  		/* TODO: bitrate control, TX processing? */
  		ret = drv_offchannel_tx(local, skb, chan, channel_type, wait);
  
  		if (ret == 0)
  			local->hw_offchan_tx_cookie = *cookie;
  		mutex_unlock(&local->mtx);
  
  		/*
  		 * Allow driver to return 1 to indicate it wants to have the
  		 * frame transmitted with a remain_on_channel + regular TX.
  		 */
  		if (ret != 1)
  			return ret;
  	}
90fc4b3a5   Johannes Berg   mac80211: impleme...
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
  	if (is_offchan && local->ops->remain_on_channel) {
  		unsigned int duration;
  		int ret;
  
  		mutex_lock(&local->mtx);
  		/*
  		 * If the duration is zero, then the driver
  		 * wouldn't actually do anything. Set it to
  		 * 100 for now.
  		 *
  		 * TODO: cancel the off-channel operation
  		 *       when we get the SKB's TX status and
  		 *       the wait time was zero before.
  		 */
  		duration = 100;
  		if (wait)
  			duration = wait;
  		ret = ieee80211_remain_on_channel_hw(local, dev, chan,
  						     channel_type,
  						     duration, cookie);
  		if (ret) {
  			kfree_skb(skb);
  			mutex_unlock(&local->mtx);
  			return ret;
  		}
  
  		local->hw_roc_for_tx = true;
  		local->hw_roc_duration = wait;
  
  		/*
  		 * queue up frame for transmission after
  		 * ieee80211_ready_on_channel call
  		 */
  
  		/* modify cookie to prevent API mismatches */
  		*cookie ^= 2;
  		IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
  		local->hw_roc_skb = skb;
4334ec851   Johannes Berg   mac80211: fix TX ...
1842
  		local->hw_roc_skb_for_status = skb;
90fc4b3a5   Johannes Berg   mac80211: impleme...
1843
1844
1845
1846
  		mutex_unlock(&local->mtx);
  
  		return 0;
  	}
f30221e4e   Johannes Berg   mac80211: impleme...
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
  	/*
  	 * Can transmit right away if the channel was the
  	 * right one and there's no wait involved... If a
  	 * wait is involved, we might otherwise not be on
  	 * the right channel for long enough!
  	 */
  	if (!is_offchan && !wait && !sdata->vif.bss_conf.idle) {
  		ieee80211_tx_skb(sdata, skb);
  		return 0;
  	}
  
  	wk = kzalloc(sizeof(*wk) + len, GFP_KERNEL);
  	if (!wk) {
  		kfree_skb(skb);
  		return -ENOMEM;
  	}
  
  	wk->type = IEEE80211_WORK_OFFCHANNEL_TX;
  	wk->chan = chan;
4d51e149a   Ben Greear   mac80211: Properl...
1866
  	wk->chan_type = channel_type;
f30221e4e   Johannes Berg   mac80211: impleme...
1867
1868
1869
1870
1871
1872
1873
1874
  	wk->sdata = sdata;
  	wk->done = ieee80211_offchan_tx_done;
  	wk->offchan_tx.frame = skb;
  	wk->offchan_tx.wait = wait;
  	wk->ie_len = len;
  	memcpy(wk->ie, buf, len);
  
  	ieee80211_add_work(wk);
9d38d85de   Johannes Berg   cfg80211/mac80211...
1875
  	return 0;
026331c4d   Jouni Malinen   cfg80211/mac80211...
1876
  }
f30221e4e   Johannes Berg   mac80211: impleme...
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
  static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
  					 struct net_device *dev,
  					 u64 cookie)
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  	struct ieee80211_local *local = sdata->local;
  	struct ieee80211_work *wk;
  	int ret = -ENOENT;
  
  	mutex_lock(&local->mtx);
90fc4b3a5   Johannes Berg   mac80211: impleme...
1887

5f16a4361   Johannes Berg   mac80211: support...
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
  	if (local->ops->offchannel_tx_cancel_wait &&
  	    local->hw_offchan_tx_cookie == cookie) {
  		ret = drv_offchannel_tx_cancel_wait(local);
  
  		if (!ret)
  			local->hw_offchan_tx_cookie = 0;
  
  		mutex_unlock(&local->mtx);
  
  		return ret;
  	}
90fc4b3a5   Johannes Berg   mac80211: impleme...
1899
1900
1901
1902
1903
1904
1905
  	if (local->ops->cancel_remain_on_channel) {
  		cookie ^= 2;
  		ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
  
  		if (ret == 0) {
  			kfree_skb(local->hw_roc_skb);
  			local->hw_roc_skb = NULL;
4334ec851   Johannes Berg   mac80211: fix TX ...
1906
  			local->hw_roc_skb_for_status = NULL;
90fc4b3a5   Johannes Berg   mac80211: impleme...
1907
1908
1909
1910
1911
1912
  		}
  
  		mutex_unlock(&local->mtx);
  
  		return ret;
  	}
f30221e4e   Johannes Berg   mac80211: impleme...
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
  	list_for_each_entry(wk, &local->work_list, list) {
  		if (wk->sdata != sdata)
  			continue;
  
  		if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
  			continue;
  
  		if (cookie != (unsigned long) wk->offchan_tx.frame)
  			continue;
  
  		wk->timeout = jiffies;
  
  		ieee80211_queue_work(&local->hw, &local->work_work);
  		ret = 0;
  		break;
  	}
  	mutex_unlock(&local->mtx);
  
  	return ret;
  }
7be5086d4   Johannes Berg   mac80211: add pro...
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
  static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
  					  struct net_device *dev,
  					  u16 frame_type, bool reg)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  
  	if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
  		return;
  
  	if (reg)
  		local->probe_req_reg++;
  	else
  		local->probe_req_reg--;
  
  	ieee80211_queue_work(&local->hw, &local->reconfig_filter);
  }
15d967532   Bruno Randolf   mac80211: Add ant...
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
  static int ieee80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  
  	if (local->started)
  		return -EOPNOTSUPP;
  
  	return drv_set_antenna(local, tx_ant, rx_ant);
  }
  
  static int ieee80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  
  	return drv_get_antenna(local, tx_ant, rx_ant);
  }
38c091590   John W. Linville   mac80211: impleme...
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
  static int ieee80211_set_ringparam(struct wiphy *wiphy, u32 tx, u32 rx)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  
  	return drv_set_ringparam(local, tx, rx);
  }
  
  static void ieee80211_get_ringparam(struct wiphy *wiphy,
  				    u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  
  	drv_get_ringparam(local, tx, tx_max, rx, rx_max);
  }
c68f4b892   Johannes Berg   mac80211: support...
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
  static int ieee80211_set_rekey_data(struct wiphy *wiphy,
  				    struct net_device *dev,
  				    struct cfg80211_gtk_rekey_data *data)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  
  	if (!local->ops->set_rekey_data)
  		return -EOPNOTSUPP;
  
  	drv_set_rekey_data(local, sdata, data);
  
  	return 0;
  }
f0706e828   Jiri Benc   [MAC80211]: Add m...
1993
1994
1995
  struct cfg80211_ops mac80211_config_ops = {
  	.add_virtual_intf = ieee80211_add_iface,
  	.del_virtual_intf = ieee80211_del_iface,
42613db76   Johannes Berg   [MAC80211]: imple...
1996
  	.change_virtual_intf = ieee80211_change_iface,
e8cbb4cbe   Johannes Berg   mac80211: support...
1997
1998
  	.add_key = ieee80211_add_key,
  	.del_key = ieee80211_del_key,
62da92fb7   Johannes Berg   mac80211: support...
1999
  	.get_key = ieee80211_get_key,
e8cbb4cbe   Johannes Berg   mac80211: support...
2000
  	.set_default_key = ieee80211_config_default_key,
3cfcf6ac6   Jouni Malinen   mac80211: 802.11w...
2001
  	.set_default_mgmt_key = ieee80211_config_default_mgmt_key,
5dfdaf58d   Johannes Berg   mac80211: add bea...
2002
2003
2004
  	.add_beacon = ieee80211_add_beacon,
  	.set_beacon = ieee80211_set_beacon,
  	.del_beacon = ieee80211_del_beacon,
4fd6931eb   Johannes Berg   mac80211: impleme...
2005
2006
2007
  	.add_station = ieee80211_add_station,
  	.del_station = ieee80211_del_station,
  	.change_station = ieee80211_change_station,
7bbdd2d98   Johannes Berg   mac80211: impleme...
2008
  	.get_station = ieee80211_get_station,
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
2009
  	.dump_station = ieee80211_dump_station,
1289723ef   Holger Schurig   mac80211: sample ...
2010
  	.dump_survey = ieee80211_dump_survey,
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
2011
2012
2013
2014
2015
2016
  #ifdef CONFIG_MAC80211_MESH
  	.add_mpath = ieee80211_add_mpath,
  	.del_mpath = ieee80211_del_mpath,
  	.change_mpath = ieee80211_change_mpath,
  	.get_mpath = ieee80211_get_mpath,
  	.dump_mpath = ieee80211_dump_mpath,
24bdd9f4c   Javier Cardona   mac80211: Rename ...
2017
2018
  	.update_mesh_config = ieee80211_update_mesh_config,
  	.get_mesh_config = ieee80211_get_mesh_config,
29cbe68c5   Johannes Berg   cfg80211/mac80211...
2019
2020
  	.join_mesh = ieee80211_join_mesh,
  	.leave_mesh = ieee80211_leave_mesh,
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
2021
  #endif
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
2022
  	.change_bss = ieee80211_change_bss,
318884875   Jouni Malinen   nl80211: Add TX q...
2023
  	.set_txq_params = ieee80211_set_txq_params,
72bdcf343   Jouni Malinen   nl80211: Add freq...
2024
  	.set_channel = ieee80211_set_channel,
665af4fc8   Bob Copeland   mac80211: add sus...
2025
2026
  	.suspend = ieee80211_suspend,
  	.resume = ieee80211_resume,
2a5193119   Johannes Berg   cfg80211/nl80211:...
2027
  	.scan = ieee80211_scan,
79f460ca4   Luciano Coelho   mac80211: add sup...
2028
2029
  	.sched_scan_start = ieee80211_sched_scan_start,
  	.sched_scan_stop = ieee80211_sched_scan_stop,
636a5d362   Jouni Malinen   nl80211: Add MLME...
2030
2031
2032
2033
  	.auth = ieee80211_auth,
  	.assoc = ieee80211_assoc,
  	.deauth = ieee80211_deauth,
  	.disassoc = ieee80211_disassoc,
af8cdcd82   Johannes Berg   mac80211: convert...
2034
2035
  	.join_ibss = ieee80211_join_ibss,
  	.leave_ibss = ieee80211_leave_ibss,
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
2036
  	.set_wiphy_params = ieee80211_set_wiphy_params,
7643a2c3f   Johannes Berg   cfg80211: move tx...
2037
2038
  	.set_tx_power = ieee80211_set_tx_power,
  	.get_tx_power = ieee80211_get_tx_power,
ab737a4f7   Johannes Berg   cfg80211: impleme...
2039
  	.set_wds_peer = ieee80211_set_wds_peer,
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
2040
  	.rfkill_poll = ieee80211_rfkill_poll,
aff89a9b9   Johannes Berg   cfg80211: introdu...
2041
  	CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
71063f0e8   Wey-Yi Guy   nl80211: add test...
2042
  	CFG80211_TESTMODE_DUMP(ieee80211_testmode_dump)
bc92afd92   Johannes Berg   cfg80211: impleme...
2043
  	.set_power_mgmt = ieee80211_set_power_mgmt,
9930380f0   Johannes Berg   cfg80211: impleme...
2044
  	.set_bitrate_mask = ieee80211_set_bitrate_mask,
b8bc4b0aa   Johannes Berg   mac80211: support...
2045
2046
  	.remain_on_channel = ieee80211_remain_on_channel,
  	.cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
2e161f78e   Johannes Berg   cfg80211/mac80211...
2047
  	.mgmt_tx = ieee80211_mgmt_tx,
f30221e4e   Johannes Berg   mac80211: impleme...
2048
  	.mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,
a97c13c34   Juuso Oikarinen   mac80211: Add sup...
2049
  	.set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
7be5086d4   Johannes Berg   mac80211: add pro...
2050
  	.mgmt_frame_register = ieee80211_mgmt_frame_register,
15d967532   Bruno Randolf   mac80211: Add ant...
2051
2052
  	.set_antenna = ieee80211_set_antenna,
  	.get_antenna = ieee80211_get_antenna,
38c091590   John W. Linville   mac80211: impleme...
2053
2054
  	.set_ringparam = ieee80211_set_ringparam,
  	.get_ringparam = ieee80211_get_ringparam,
c68f4b892   Johannes Berg   mac80211: support...
2055
  	.set_rekey_data = ieee80211_set_rekey_data,
f0706e828   Jiri Benc   [MAC80211]: Add m...
2056
  };