Blame view

net/mac80211/cfg.c 70.7 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>
dfe018bf9   Arik Nemtsov   mac80211: handle ...
14
  #include <linux/if_ether.h>
f0706e828   Jiri Benc   [MAC80211]: Add m...
15
16
  #include <net/cfg80211.h>
  #include "ieee80211_i.h"
244879813   Johannes Berg   mac80211: add dri...
17
  #include "driver-ops.h"
e0eb68596   Michael Wu   [MAC80211]: renam...
18
  #include "cfg.h"
2c8dccc77   Johannes Berg   mac80211: rename ...
19
  #include "rate.h"
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
20
  #include "mesh.h"
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
21

f9e10ce4c   Johannes Berg   cfg80211: require...
22
23
24
25
  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...
26
27
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
8cc9a7391   Michael Wu   mac80211: Use mon...
28
29
30
  	struct net_device *dev;
  	struct ieee80211_sub_if_data *sdata;
  	int err;
f0706e828   Jiri Benc   [MAC80211]: Add m...
31

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

f9e10ce4c   Johannes Berg   cfg80211: require...
36
37
38
39
40
41
  	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...
42
  }
463d01832   Johannes Berg   cfg80211: make aw...
43
  static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev)
f0706e828   Jiri Benc   [MAC80211]: Add m...
44
  {
463d01832   Johannes Berg   cfg80211: make aw...
45
  	ieee80211_if_remove(IEEE80211_DEV_TO_SUB_IF(dev));
f0706e828   Jiri Benc   [MAC80211]: Add m...
46

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

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

9bc383de3   Johannes Berg   cfg80211: introdu...
61
62
  	if (type == NL80211_IFTYPE_AP_VLAN &&
  	    params && params->use_4addr == 0)
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
63
  		RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
9bc383de3   Johannes Berg   cfg80211: introdu...
64
65
66
  	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 ...
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
96
  	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...
97

42613db76   Johannes Berg   [MAC80211]: imple...
98
99
  	return 0;
  }
b53be7920   Simon Wunderlich   mac80211: Add NoA...
100
101
102
103
104
105
106
107
108
  static int ieee80211_set_noack_map(struct wiphy *wiphy,
  				  struct net_device *dev,
  				  u16 noack_map)
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  
  	sdata->noack_map = noack_map;
  	return 0;
  }
e8cbb4cbe   Johannes Berg   mac80211: support...
109
  static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
e31b82136   Johannes Berg   cfg80211/mac80211...
110
  			     u8 key_idx, bool pairwise, const u8 *mac_addr,
e8cbb4cbe   Johannes Berg   mac80211: support...
111
112
  			     struct key_params *params)
  {
26a58456b   Johannes Berg   mac80211: switch ...
113
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
e8cbb4cbe   Johannes Berg   mac80211: support...
114
  	struct sta_info *sta = NULL;
db4d1169d   Johannes Berg   mac80211: split i...
115
  	struct ieee80211_key *key;
3b96766f0   Johannes Berg   mac80211: fix key...
116
  	int err;
e8cbb4cbe   Johannes Berg   mac80211: support...
117

26a58456b   Johannes Berg   mac80211: switch ...
118
  	if (!ieee80211_sdata_running(sdata))
ad0e2b5a0   Johannes Berg   mac80211: simplif...
119
  		return -ENETDOWN;
97359d123   Johannes Berg   mac80211: use cip...
120
  	/* reject WEP and TKIP keys if WEP failed to initialize */
e8cbb4cbe   Johannes Berg   mac80211: support...
121
122
  	switch (params->cipher) {
  	case WLAN_CIPHER_SUITE_WEP40:
e8cbb4cbe   Johannes Berg   mac80211: support...
123
  	case WLAN_CIPHER_SUITE_TKIP:
97359d123   Johannes Berg   mac80211: use cip...
124
125
126
  	case WLAN_CIPHER_SUITE_WEP104:
  		if (IS_ERR(sdata->local->wep_tx_tfm))
  			return -EINVAL;
3cfcf6ac6   Jouni Malinen   mac80211: 802.11w...
127
  		break;
e8cbb4cbe   Johannes Berg   mac80211: support...
128
  	default:
97359d123   Johannes Berg   mac80211: use cip...
129
  		break;
e8cbb4cbe   Johannes Berg   mac80211: support...
130
  	}
97359d123   Johannes Berg   mac80211: use cip...
131
132
  	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...
133
134
  	if (IS_ERR(key))
  		return PTR_ERR(key);
db4d1169d   Johannes Berg   mac80211: split i...
135

e31b82136   Johannes Berg   cfg80211/mac80211...
136
137
  	if (pairwise)
  		key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
ad0e2b5a0   Johannes Berg   mac80211: simplif...
138
  	mutex_lock(&sdata->local->sta_mtx);
3b96766f0   Johannes Berg   mac80211: fix key...
139

e8cbb4cbe   Johannes Berg   mac80211: support...
140
  	if (mac_addr) {
ff973af74   Thomas Pedersen   nl80211: allow in...
141
142
143
144
  		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...
145
  		if (!sta) {
32162a4da   Jouni Malinen   mac80211: Fix key...
146
  			ieee80211_key_free(sdata->local, key);
3b96766f0   Johannes Berg   mac80211: fix key...
147
148
  			err = -ENOENT;
  			goto out_unlock;
db4d1169d   Johannes Berg   mac80211: split i...
149
  		}
e8cbb4cbe   Johannes Berg   mac80211: support...
150
  	}
3ffc2a905   Johannes Berg   mac80211: allow v...
151
152
153
  	err = ieee80211_key_link(key, sdata, sta);
  	if (err)
  		ieee80211_key_free(sdata->local, key);
db4d1169d   Johannes Berg   mac80211: split i...
154

3b96766f0   Johannes Berg   mac80211: fix key...
155
   out_unlock:
ad0e2b5a0   Johannes Berg   mac80211: simplif...
156
  	mutex_unlock(&sdata->local->sta_mtx);
3b96766f0   Johannes Berg   mac80211: fix key...
157
158
  
  	return err;
e8cbb4cbe   Johannes Berg   mac80211: support...
159
160
161
  }
  
  static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
e31b82136   Johannes Berg   cfg80211/mac80211...
162
  			     u8 key_idx, bool pairwise, const u8 *mac_addr)
e8cbb4cbe   Johannes Berg   mac80211: support...
163
  {
5c0c36412   Johannes Berg   mac80211: make ke...
164
165
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  	struct ieee80211_local *local = sdata->local;
e8cbb4cbe   Johannes Berg   mac80211: support...
166
  	struct sta_info *sta;
5c0c36412   Johannes Berg   mac80211: make ke...
167
  	struct ieee80211_key *key = NULL;
e8cbb4cbe   Johannes Berg   mac80211: support...
168
  	int ret;
5c0c36412   Johannes Berg   mac80211: make ke...
169
170
  	mutex_lock(&local->sta_mtx);
  	mutex_lock(&local->key_mtx);
3b96766f0   Johannes Berg   mac80211: fix key...
171

e8cbb4cbe   Johannes Berg   mac80211: support...
172
  	if (mac_addr) {
3b96766f0   Johannes Berg   mac80211: fix key...
173
  		ret = -ENOENT;
0e5ded5a8   Felix Fietkau   mac80211: allow s...
174
  		sta = sta_info_get_bss(sdata, mac_addr);
e8cbb4cbe   Johannes Berg   mac80211: support...
175
  		if (!sta)
3b96766f0   Johannes Berg   mac80211: fix key...
176
  			goto out_unlock;
e8cbb4cbe   Johannes Berg   mac80211: support...
177

5c0c36412   Johannes Berg   mac80211: make ke...
178
  		if (pairwise)
40b275b69   Johannes Berg   mac80211: sparse ...
179
  			key = key_mtx_dereference(local, sta->ptk);
5c0c36412   Johannes Berg   mac80211: make ke...
180
  		else
40b275b69   Johannes Berg   mac80211: sparse ...
181
  			key = key_mtx_dereference(local, sta->gtk[key_idx]);
5c0c36412   Johannes Berg   mac80211: make ke...
182
  	} else
40b275b69   Johannes Berg   mac80211: sparse ...
183
  		key = key_mtx_dereference(local, sdata->keys[key_idx]);
e8cbb4cbe   Johannes Berg   mac80211: support...
184

5c0c36412   Johannes Berg   mac80211: make ke...
185
  	if (!key) {
3b96766f0   Johannes Berg   mac80211: fix key...
186
187
188
  		ret = -ENOENT;
  		goto out_unlock;
  	}
e8cbb4cbe   Johannes Berg   mac80211: support...
189

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

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

97359d123   Johannes Berg   mac80211: use cip...
233
234
  	switch (key->conf.cipher) {
  	case WLAN_CIPHER_SUITE_TKIP:
b0f76b335   Harvey Harrison   mac80211: add a s...
235
236
  		iv32 = key->u.tkip.tx.iv32;
  		iv16 = key->u.tkip.tx.iv16;
62da92fb7   Johannes Berg   mac80211: support...
237

244879813   Johannes Berg   mac80211: add dri...
238
239
240
241
  		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...
242
243
244
245
246
247
248
249
250
251
  
  		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...
252
  	case WLAN_CIPHER_SUITE_CCMP:
aba83a0b3   Johannes Berg   mac80211: fix CCM...
253
254
255
256
257
258
259
  		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...
260
261
262
  		params.seq = seq;
  		params.seq_len = 6;
  		break;
97359d123   Johannes Berg   mac80211: use cip...
263
  	case WLAN_CIPHER_SUITE_AES_CMAC:
75396ae6d   Johannes Berg   mac80211: fix CMA...
264
265
266
267
268
269
270
  		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...
271
272
273
  		params.seq = seq;
  		params.seq_len = 6;
  		break;
62da92fb7   Johannes Berg   mac80211: support...
274
275
276
277
278
279
280
281
282
  	}
  
  	params.key = key->conf.key;
  	params.key_len = key->conf.keylen;
  
  	callback(cookie, &params);
  	err = 0;
  
   out:
3b96766f0   Johannes Berg   mac80211: fix key...
283
  	rcu_read_unlock();
62da92fb7   Johannes Berg   mac80211: support...
284
285
  	return err;
  }
e8cbb4cbe   Johannes Berg   mac80211: support...
286
287
  static int ieee80211_config_default_key(struct wiphy *wiphy,
  					struct net_device *dev,
dbd2fd656   Johannes Berg   cfg80211/nl80211:...
288
289
  					u8 key_idx, bool uni,
  					bool multi)
e8cbb4cbe   Johannes Berg   mac80211: support...
290
  {
ad0e2b5a0   Johannes Berg   mac80211: simplif...
291
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3b96766f0   Johannes Berg   mac80211: fix key...
292

f7e0104c1   Johannes Berg   mac80211: support...
293
  	ieee80211_set_default_key(sdata, key_idx, uni, multi);
e8cbb4cbe   Johannes Berg   mac80211: support...
294
295
296
  
  	return 0;
  }
3cfcf6ac6   Jouni Malinen   mac80211: 802.11w...
297
298
299
300
  static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy,
  					     struct net_device *dev,
  					     u8 key_idx)
  {
66c524210   Johannes Berg   mac80211: remove ...
301
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3cfcf6ac6   Jouni Malinen   mac80211: 802.11w...
302

3cfcf6ac6   Jouni Malinen   mac80211: 802.11w...
303
  	ieee80211_set_default_mgmt_key(sdata, key_idx);
3cfcf6ac6   Jouni Malinen   mac80211: 802.11w...
304
305
  	return 0;
  }
3af6334c9   Felix Fietkau   mac80211: add sup...
306
307
308
309
310
311
312
313
314
315
  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...
316
317
  static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
  {
d0709a651   Johannes Berg   mac80211: RCU-ify...
318
  	struct ieee80211_sub_if_data *sdata = sta->sdata;
ebe27c91a   Mohammed Shafi Shajakhan   {mac|nl}80211: Ad...
319
  	struct timespec uptime;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
320

f5ea9120b   Johannes Berg   nl80211: add gene...
321
  	sinfo->generation = sdata->local->sta_generation;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
322
323
  	sinfo->filled = STATION_INFO_INACTIVE_TIME |
  			STATION_INFO_RX_BYTES |
420e7fabd   Henning Rogge   nl80211: Add sign...
324
  			STATION_INFO_TX_BYTES |
98c8a60a0   Jouni Malinen   nl80211: Provide ...
325
326
  			STATION_INFO_RX_PACKETS |
  			STATION_INFO_TX_PACKETS |
b206b4ef0   Bruno Randolf   nl80211/mac80211:...
327
328
  			STATION_INFO_TX_RETRIES |
  			STATION_INFO_TX_FAILED |
5a5c731aa   Ben Greear   wireless: Set som...
329
  			STATION_INFO_TX_BITRATE |
3af6334c9   Felix Fietkau   mac80211: add sup...
330
  			STATION_INFO_RX_BITRATE |
f4263c985   Paul Stewart   nl80211: Add BSS ...
331
  			STATION_INFO_RX_DROP_MISC |
ebe27c91a   Mohammed Shafi Shajakhan   {mac|nl}80211: Ad...
332
  			STATION_INFO_BSS_PARAM |
7a7247676   Helmut Schaa   mac80211: Provide...
333
  			STATION_INFO_CONNECTED_TIME |
a85e1d559   Paul Stewart   cfg80211: Return ...
334
335
  			STATION_INFO_STA_FLAGS |
  			STATION_INFO_BEACON_LOSS_COUNT;
ebe27c91a   Mohammed Shafi Shajakhan   {mac|nl}80211: Ad...
336
337
338
  
  	do_posix_clock_monotonic_gettime(&uptime);
  	sinfo->connected_time = uptime.tv_sec - sta->last_connected;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
339
340
341
342
  
  	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 ...
343
344
  	sinfo->rx_packets = sta->rx_packets;
  	sinfo->tx_packets = sta->tx_packets;
b206b4ef0   Bruno Randolf   nl80211/mac80211:...
345
346
  	sinfo->tx_retries = sta->tx_retry_count;
  	sinfo->tx_failed = sta->tx_retry_failed;
5a5c731aa   Ben Greear   wireless: Set som...
347
  	sinfo->rx_dropped_misc = sta->rx_dropped;
a85e1d559   Paul Stewart   cfg80211: Return ...
348
  	sinfo->beacon_loss_count = sta->beacon_loss_count;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
349

19deffbeb   John W. Linville   wireless: correct...
350
351
  	if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) ||
  	    (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) {
541a45a14   Bruno Randolf   nl80211/mac80211:...
352
  		sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG;
420e7fabd   Henning Rogge   nl80211: Add sign...
353
  		sinfo->signal = (s8)sta->last_signal;
541a45a14   Bruno Randolf   nl80211/mac80211:...
354
  		sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);
420e7fabd   Henning Rogge   nl80211: Add sign...
355
356
357
358
359
360
361
362
363
  	}
  
  	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...
364
365
366
367
368
369
370
371
372
373
  	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...
374

902acc789   Johannes Berg   mac80211: clean u...
375
  	if (ieee80211_vif_is_mesh(&sdata->vif)) {
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
376
  #ifdef CONFIG_MAC80211_MESH
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
377
378
379
380
381
382
383
  		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...
384
  #endif
902acc789   Johannes Berg   mac80211: clean u...
385
  	}
f4263c985   Paul Stewart   nl80211: Add BSS ...
386
387
388
389
390
391
392
393
394
395
  
  	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;
7a7247676   Helmut Schaa   mac80211: Provide...
396
397
398
399
400
401
  
  	sinfo->sta_flags.set = 0;
  	sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
  				BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
  				BIT(NL80211_STA_FLAG_WME) |
  				BIT(NL80211_STA_FLAG_MFP) |
e41215626   Helmut Schaa   mac80211: Also re...
402
403
  				BIT(NL80211_STA_FLAG_AUTHENTICATED) |
  				BIT(NL80211_STA_FLAG_TDLS_PEER);
7a7247676   Helmut Schaa   mac80211: Provide...
404
405
406
407
408
409
410
411
412
413
  	if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
  		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
  	if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE))
  		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
  	if (test_sta_flag(sta, WLAN_STA_WME))
  		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME);
  	if (test_sta_flag(sta, WLAN_STA_MFP))
  		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP);
  	if (test_sta_flag(sta, WLAN_STA_AUTH))
  		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
e41215626   Helmut Schaa   mac80211: Also re...
414
415
  	if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
  		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
416
417
418
419
420
421
  }
  
  
  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...
422
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
423
  	struct sta_info *sta;
d0709a651   Johannes Berg   mac80211: RCU-ify...
424
425
426
  	int ret = -ENOENT;
  
  	rcu_read_lock();
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
427

3b53fde8a   Johannes Berg   mac80211: let sta...
428
  	sta = sta_info_get_by_idx(sdata, idx);
d0709a651   Johannes Berg   mac80211: RCU-ify...
429
430
  	if (sta) {
  		ret = 0;
17741cdc2   Johannes Berg   mac80211: share S...
431
  		memcpy(mac, sta->sta.addr, ETH_ALEN);
d0709a651   Johannes Berg   mac80211: RCU-ify...
432
433
  		sta_set_sinfo(sta, sinfo);
  	}
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
434

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

d0709a651   Johannes Berg   mac80211: RCU-ify...
437
  	return ret;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
438
  }
1289723ef   Holger Schurig   mac80211: sample ...
439
440
441
442
  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 ...
443
444
  	return drv_get_survey(local, idx, survey);
  }
7bbdd2d98   Johannes Berg   mac80211: impleme...
445
  static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
2ec600d67   Luis Carlos Cobo   nl80211/cfg80211:...
446
  				 u8 *mac, struct station_info *sinfo)
7bbdd2d98   Johannes Berg   mac80211: impleme...
447
  {
abe60632f   Johannes Berg   mac80211: make st...
448
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
7bbdd2d98   Johannes Berg   mac80211: impleme...
449
  	struct sta_info *sta;
d0709a651   Johannes Berg   mac80211: RCU-ify...
450
  	int ret = -ENOENT;
7bbdd2d98   Johannes Berg   mac80211: impleme...
451

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

0e5ded5a8   Felix Fietkau   mac80211: allow s...
454
  	sta = sta_info_get_bss(sdata, mac);
d0709a651   Johannes Berg   mac80211: RCU-ify...
455
456
457
458
459
460
461
462
  	if (sta) {
  		ret = 0;
  		sta_set_sinfo(sta, sinfo);
  	}
  
  	rcu_read_unlock();
  
  	return ret;
7bbdd2d98   Johannes Berg   mac80211: impleme...
463
  }
7827493b8   Arik Nemtsov   mac80211: add ssi...
464
465
466
467
468
469
470
471
472
473
474
475
476
  static void ieee80211_config_ap_ssid(struct ieee80211_sub_if_data *sdata,
  				     struct beacon_parameters *params)
  {
  	struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
  
  	bss_conf->ssid_len = params->ssid_len;
  
  	if (params->ssid_len)
  		memcpy(bss_conf->ssid, params->ssid, params->ssid_len);
  
  	bss_conf->hidden_ssid =
  		(params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
  }
029458212   Arik Nemtsov   mac80211: Save pr...
477
478
479
480
481
482
483
  static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
  				    u8 *resp, size_t resp_len)
  {
  	struct sk_buff *new, *old;
  
  	if (!resp || !resp_len)
  		return -EINVAL;
f724828bd   Arik Nemtsov   mac80211: derefer...
484
  	old = rtnl_dereference(sdata->u.ap.probe_resp);
029458212   Arik Nemtsov   mac80211: Save pr...
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
  
  	new = dev_alloc_skb(resp_len);
  	if (!new)
  		return -ENOMEM;
  
  	memcpy(skb_put(new, resp_len), resp, resp_len);
  
  	rcu_assign_pointer(sdata->u.ap.probe_resp, new);
  	synchronize_rcu();
  
  	if (old)
  		dev_kfree_skb(old);
  
  	return 0;
  }
5dfdaf58d   Johannes Berg   mac80211: add bea...
500
501
502
503
504
505
506
507
508
509
  /*
   * 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;
029458212   Arik Nemtsov   mac80211: Save pr...
510
  	u32 changed = 0;
5dfdaf58d   Johannes Berg   mac80211: add bea...
511

40b275b69   Johannes Berg   mac80211: sparse ...
512
  	old = rtnl_dereference(sdata->u.ap.beacon);
5dfdaf58d   Johannes Berg   mac80211: add bea...
513
514
515
516
517
518
519
520
521
  
  	/* 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...
522
523
524
525
526
  	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...
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
  	}
  
  	/* 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...
585
  	sdata->vif.bss_conf.dtim_period = new->dtim_period;
cf778b00e   Eric Dumazet   net: reintroduce ...
586
  	rcu_assign_pointer(sdata->u.ap.beacon, new);
5dfdaf58d   Johannes Berg   mac80211: add bea...
587
588
589
590
  
  	synchronize_rcu();
  
  	kfree(old);
029458212   Arik Nemtsov   mac80211: Save pr...
591
592
593
594
  	err = ieee80211_set_probe_resp(sdata, params->probe_resp,
  				       params->probe_resp_len);
  	if (!err)
  		changed |= BSS_CHANGED_AP_PROBE_RESP;
7827493b8   Arik Nemtsov   mac80211: add ssi...
595
  	ieee80211_config_ap_ssid(sdata, params);
029458212   Arik Nemtsov   mac80211: Save pr...
596
597
598
  	changed |= BSS_CHANGED_BEACON_ENABLED |
  		   BSS_CHANGED_BEACON |
  		   BSS_CHANGED_SSID;
7827493b8   Arik Nemtsov   mac80211: add ssi...
599

029458212   Arik Nemtsov   mac80211: Save pr...
600
  	ieee80211_bss_info_change_notify(sdata, changed);
2d0ddec5b   Johannes Berg   mac80211: unify c...
601
  	return 0;
5dfdaf58d   Johannes Berg   mac80211: add bea...
602
603
604
605
606
  }
  
  static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
  				struct beacon_parameters *params)
  {
14db74bcc   Johannes Berg   mac80211: fix cfg...
607
  	struct ieee80211_sub_if_data *sdata;
5dfdaf58d   Johannes Berg   mac80211: add bea...
608
  	struct beacon_data *old;
665c93a93   Johannes Berg   mac80211: add sup...
609
610
  	struct ieee80211_sub_if_data *vlan;
  	int ret;
5dfdaf58d   Johannes Berg   mac80211: add bea...
611

14db74bcc   Johannes Berg   mac80211: fix cfg...
612
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
40b275b69   Johannes Berg   mac80211: sparse ...
613
  	old = rtnl_dereference(sdata->u.ap.beacon);
5dfdaf58d   Johannes Berg   mac80211: add bea...
614
615
  	if (old)
  		return -EALREADY;
665c93a93   Johannes Berg   mac80211: add sup...
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
  	ret = ieee80211_config_beacon(sdata, params);
  	if (ret)
  		return ret;
  
  	/*
  	 * Apply control port protocol, this allows us to
  	 * not encrypt dynamic WEP control frames.
  	 */
  	sdata->control_port_protocol = params->crypto.control_port_ethertype;
  	sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt;
  	list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
  		vlan->control_port_protocol =
  			params->crypto.control_port_ethertype;
  		vlan->control_port_no_encrypt =
  			params->crypto.control_port_no_encrypt;
  	}
  
  	return 0;
5dfdaf58d   Johannes Berg   mac80211: add bea...
634
635
636
637
638
  }
  
  static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
  				struct beacon_parameters *params)
  {
14db74bcc   Johannes Berg   mac80211: fix cfg...
639
  	struct ieee80211_sub_if_data *sdata;
5dfdaf58d   Johannes Berg   mac80211: add bea...
640
  	struct beacon_data *old;
14db74bcc   Johannes Berg   mac80211: fix cfg...
641
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
40b275b69   Johannes Berg   mac80211: sparse ...
642
  	old = rtnl_dereference(sdata->u.ap.beacon);
5dfdaf58d   Johannes Berg   mac80211: add bea...
643
644
645
646
647
648
649
650
  	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...
651
  	struct ieee80211_sub_if_data *sdata;
5dfdaf58d   Johannes Berg   mac80211: add bea...
652
  	struct beacon_data *old;
14db74bcc   Johannes Berg   mac80211: fix cfg...
653
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
40b275b69   Johannes Berg   mac80211: sparse ...
654
  	old = rtnl_dereference(sdata->u.ap.beacon);
5dfdaf58d   Johannes Berg   mac80211: add bea...
655
656
  	if (!old)
  		return -ENOENT;
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
657
  	RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
5dfdaf58d   Johannes Berg   mac80211: add bea...
658
659
  	synchronize_rcu();
  	kfree(old);
2d0ddec5b   Johannes Berg   mac80211: unify c...
660
661
  	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
  	return 0;
5dfdaf58d   Johannes Berg   mac80211: add bea...
662
  }
4fd6931eb   Johannes Berg   mac80211: impleme...
663
664
665
666
667
668
669
670
671
  /* 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...
672
  } __packed;
4fd6931eb   Johannes Berg   mac80211: impleme...
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
  
  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...
691
  	memcpy(msg->sa, sta->sta.addr, ETH_ALEN);
4fd6931eb   Johannes Berg   mac80211: impleme...
692
693
694
695
696
697
698
699
  	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...
700
701
  	skb->dev = sta->sdata->dev;
  	skb->protocol = eth_type_trans(skb, sta->sdata->dev);
4fd6931eb   Johannes Berg   mac80211: impleme...
702
  	memset(skb->cb, 0, sizeof(skb->cb));
06ee1c261   John W. Linville   wireless: use net...
703
  	netif_rx_ni(skb);
4fd6931eb   Johannes Berg   mac80211: impleme...
704
  }
d9a7ddb05   Johannes Berg   mac80211: refacto...
705
706
707
  static int sta_apply_parameters(struct ieee80211_local *local,
  				struct sta_info *sta,
  				struct station_parameters *params)
4fd6931eb   Johannes Berg   mac80211: impleme...
708
  {
d9a7ddb05   Johannes Berg   mac80211: refacto...
709
  	int ret = 0;
4fd6931eb   Johannes Berg   mac80211: impleme...
710
711
  	u32 rates;
  	int i, j;
8318d78a4   Johannes Berg   cfg80211 API for ...
712
  	struct ieee80211_supported_band *sband;
d0709a651   Johannes Berg   mac80211: RCU-ify...
713
  	struct ieee80211_sub_if_data *sdata = sta->sdata;
eccb8e8f0   Johannes Berg   nl80211: improve ...
714
  	u32 mask, set;
4fd6931eb   Johannes Berg   mac80211: impleme...
715

ae5eb0264   Johannes Berg   mac80211: rewrite...
716
  	sband = local->hw.wiphy->bands[local->oper_channel->band];
eccb8e8f0   Johannes Berg   nl80211: improve ...
717
718
  	mask = params->sta_flags_mask;
  	set = params->sta_flags_set;
73651ee63   Johannes Berg   mac80211: split s...
719

d9a7ddb05   Johannes Berg   mac80211: refacto...
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
  	/*
  	 * In mesh mode, we can clear AUTHENTICATED flag but must
  	 * also make ASSOCIATED follow appropriately for the driver
  	 * API. See also below, after AUTHORIZED changes.
  	 */
  	if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
  		/* cfg80211 should not allow this in non-mesh modes */
  		if (WARN_ON(!ieee80211_vif_is_mesh(&sdata->vif)))
  			return -EINVAL;
  
  		if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
  		    !test_sta_flag(sta, WLAN_STA_AUTH)) {
  			ret = sta_info_move_state_checked(sta,
  					IEEE80211_STA_AUTH);
  			if (ret)
  				return ret;
  			ret = sta_info_move_state_checked(sta,
  					IEEE80211_STA_ASSOC);
  			if (ret)
  				return ret;
  		}
  	}
eccb8e8f0   Johannes Berg   nl80211: improve ...
742
  	if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
eccb8e8f0   Johannes Berg   nl80211: improve ...
743
  		if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
d9a7ddb05   Johannes Berg   mac80211: refacto...
744
745
  			ret = sta_info_move_state_checked(sta,
  					IEEE80211_STA_AUTHORIZED);
c2c98fdeb   Johannes Berg   mac80211: optimis...
746
  		else
d9a7ddb05   Johannes Berg   mac80211: refacto...
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
  			ret = sta_info_move_state_checked(sta,
  					IEEE80211_STA_ASSOC);
  		if (ret)
  			return ret;
  	}
  
  	if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
  		/* cfg80211 should not allow this in non-mesh modes */
  		if (WARN_ON(!ieee80211_vif_is_mesh(&sdata->vif)))
  			return -EINVAL;
  
  		if (!(set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) &&
  		    test_sta_flag(sta, WLAN_STA_AUTH)) {
  			ret = sta_info_move_state_checked(sta,
  					IEEE80211_STA_AUTH);
  			if (ret)
  				return ret;
  			ret = sta_info_move_state_checked(sta,
  					IEEE80211_STA_NONE);
  			if (ret)
  				return ret;
  		}
eccb8e8f0   Johannes Berg   nl80211: improve ...
769
  	}
4fd6931eb   Johannes Berg   mac80211: impleme...
770

d9a7ddb05   Johannes Berg   mac80211: refacto...
771

eccb8e8f0   Johannes Berg   nl80211: improve ...
772
  	if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
eccb8e8f0   Johannes Berg   nl80211: improve ...
773
  		if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE))
c2c98fdeb   Johannes Berg   mac80211: optimis...
774
775
776
  			set_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE);
  		else
  			clear_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE);
eccb8e8f0   Johannes Berg   nl80211: improve ...
777
  	}
4fd6931eb   Johannes Berg   mac80211: impleme...
778

eccb8e8f0   Johannes Berg   nl80211: improve ...
779
  	if (mask & BIT(NL80211_STA_FLAG_WME)) {
39df600aa   Arik Nemtsov   mac80211: propaga...
780
  		if (set & BIT(NL80211_STA_FLAG_WME)) {
c2c98fdeb   Johannes Berg   mac80211: optimis...
781
  			set_sta_flag(sta, WLAN_STA_WME);
39df600aa   Arik Nemtsov   mac80211: propaga...
782
  			sta->sta.wme = true;
c2c98fdeb   Johannes Berg   mac80211: optimis...
783
784
785
  		} else {
  			clear_sta_flag(sta, WLAN_STA_WME);
  			sta->sta.wme = false;
39df600aa   Arik Nemtsov   mac80211: propaga...
786
  		}
eccb8e8f0   Johannes Berg   nl80211: improve ...
787
  	}
5394af4d8   Jouni Malinen   mac80211: 802.11w...
788

eccb8e8f0   Johannes Berg   nl80211: improve ...
789
  	if (mask & BIT(NL80211_STA_FLAG_MFP)) {
eccb8e8f0   Johannes Berg   nl80211: improve ...
790
  		if (set & BIT(NL80211_STA_FLAG_MFP))
c2c98fdeb   Johannes Berg   mac80211: optimis...
791
792
793
  			set_sta_flag(sta, WLAN_STA_MFP);
  		else
  			clear_sta_flag(sta, WLAN_STA_MFP);
4fd6931eb   Johannes Berg   mac80211: impleme...
794
  	}
b39c48fac   Javier Cardona   nl80211/mac80211:...
795

07ba55d7f   Arik Nemtsov   nl80211/mac80211:...
796
  	if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
07ba55d7f   Arik Nemtsov   nl80211/mac80211:...
797
  		if (set & BIT(NL80211_STA_FLAG_TDLS_PEER))
c2c98fdeb   Johannes Berg   mac80211: optimis...
798
799
800
  			set_sta_flag(sta, WLAN_STA_TDLS_PEER);
  		else
  			clear_sta_flag(sta, WLAN_STA_TDLS_PEER);
07ba55d7f   Arik Nemtsov   nl80211/mac80211:...
801
  	}
4fd6931eb   Johannes Berg   mac80211: impleme...
802

3b9ce80ce   Johannes Berg   cfg80211/mac80211...
803
804
805
806
  	if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) {
  		sta->sta.uapsd_queues = params->uapsd_queues;
  		sta->sta.max_sp = params->max_sp;
  	}
9533b4ac8   Eliad Peller   mac80211: add uap...
807

73651ee63   Johannes Berg   mac80211: split s...
808
  	/*
51b50fbeb   Johannes Berg   cfg80211: validat...
809
810
811
812
813
814
815
  	 * 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...
816
817
818
819
820
  	 * 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...
821
822
823
824
825
  	if (params->listen_interval >= 0)
  		sta->listen_interval = params->listen_interval;
  
  	if (params->supported_rates) {
  		rates = 0;
8318d78a4   Johannes Berg   cfg80211 API for ...
826

4fd6931eb   Johannes Berg   mac80211: impleme...
827
828
  		for (i = 0; i < params->supported_rates_len; i++) {
  			int rate = (params->supported_rates[i] & 0x7f) * 5;
8318d78a4   Johannes Berg   cfg80211 API for ...
829
830
  			for (j = 0; j < sband->n_bitrates; j++) {
  				if (sband->bitrates[j].bitrate == rate)
4fd6931eb   Johannes Berg   mac80211: impleme...
831
832
833
  					rates |= BIT(j);
  			}
  		}
323ce79a9   Johannes Berg   mac80211: share s...
834
  		sta->sta.supp_rates[local->oper_channel->band] = rates;
4fd6931eb   Johannes Berg   mac80211: impleme...
835
  	}
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
836

d9fe60dea   Johannes Berg   802.11: clean up/...
837
  	if (params->ht_capa)
ef96a8420   Ben Greear   mac80211: Support...
838
  		ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
ae5eb0264   Johannes Berg   mac80211: rewrite...
839
  						  params->ht_capa,
d9fe60dea   Johannes Berg   802.11: clean up/...
840
  						  &sta->sta.ht_cap);
36aedc903   Jouni Malinen   mac80211/cfg80211...
841

9c3990aae   Javier Cardona   nl80211: Let user...
842
  	if (ieee80211_vif_is_mesh(&sdata->vif)) {
4daf50f20   Yogesh Ashok Powar   mac80211: Fix mes...
843
  #ifdef CONFIG_MAC80211_MESH
9c3990aae   Javier Cardona   nl80211: Let user...
844
845
  		if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED)
  			switch (params->plink_state) {
57cf8043a   Javier Cardona   nl80211: Move pee...
846
847
848
  			case NL80211_PLINK_LISTEN:
  			case NL80211_PLINK_ESTAB:
  			case NL80211_PLINK_BLOCKED:
9c3990aae   Javier Cardona   nl80211: Let user...
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
  				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...
864
  #endif
902acc789   Johannes Berg   mac80211: clean u...
865
  	}
d9a7ddb05   Johannes Berg   mac80211: refacto...
866
867
  
  	return 0;
4fd6931eb   Johannes Berg   mac80211: impleme...
868
869
870
871
872
  }
  
  static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
  				 u8 *mac, struct station_parameters *params)
  {
14db74bcc   Johannes Berg   mac80211: fix cfg...
873
  	struct ieee80211_local *local = wiphy_priv(wiphy);
4fd6931eb   Johannes Berg   mac80211: impleme...
874
875
  	struct sta_info *sta;
  	struct ieee80211_sub_if_data *sdata;
73651ee63   Johannes Berg   mac80211: split s...
876
  	int err;
b8d476c8c   Jouni Malinen   mac80211: Send La...
877
  	int layer2_update;
4fd6931eb   Johannes Berg   mac80211: impleme...
878

4fd6931eb   Johannes Berg   mac80211: impleme...
879
880
  	if (params->vlan) {
  		sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
05c914fe3   Johannes Berg   mac80211: use nl8...
881
882
  		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
  		    sdata->vif.type != NL80211_IFTYPE_AP)
4fd6931eb   Johannes Berg   mac80211: impleme...
883
884
885
  			return -EINVAL;
  	} else
  		sdata = IEEE80211_DEV_TO_SUB_IF(dev);
47846c9b0   Johannes Berg   mac80211: reduce ...
886
  	if (compare_ether_addr(mac, sdata->vif.addr) == 0)
03e4497eb   Johannes Berg   mac80211: fix sta...
887
888
889
890
891
892
  		return -EINVAL;
  
  	if (is_multicast_ether_addr(mac))
  		return -EINVAL;
  
  	sta = sta_info_alloc(sdata, mac, GFP_KERNEL);
73651ee63   Johannes Berg   mac80211: split s...
893
894
  	if (!sta)
  		return -ENOMEM;
4fd6931eb   Johannes Berg   mac80211: impleme...
895

d9a7ddb05   Johannes Berg   mac80211: refacto...
896
897
  	sta_info_move_state(sta, IEEE80211_STA_AUTH);
  	sta_info_move_state(sta, IEEE80211_STA_ASSOC);
4fd6931eb   Johannes Berg   mac80211: impleme...
898

d9a7ddb05   Johannes Berg   mac80211: refacto...
899
900
901
902
903
  	err = sta_apply_parameters(local, sta, params);
  	if (err) {
  		sta_info_free(local, sta);
  		return err;
  	}
4fd6931eb   Johannes Berg   mac80211: impleme...
904

d64cf63e0   Arik Nemtsov   mac80211: init ra...
905
906
907
908
909
910
  	/*
  	 * for TDLS, rate control should be initialized only when supported
  	 * rates are known.
  	 */
  	if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER))
  		rate_control_rate_init(sta);
4fd6931eb   Johannes Berg   mac80211: impleme...
911

b8d476c8c   Jouni Malinen   mac80211: Send La...
912
913
  	layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
  		sdata->vif.type == NL80211_IFTYPE_AP;
34e895075   Johannes Berg   mac80211: allow s...
914
  	err = sta_info_insert_rcu(sta);
73651ee63   Johannes Berg   mac80211: split s...
915
  	if (err) {
73651ee63   Johannes Berg   mac80211: split s...
916
917
918
  		rcu_read_unlock();
  		return err;
  	}
b8d476c8c   Jouni Malinen   mac80211: Send La...
919
  	if (layer2_update)
73651ee63   Johannes Berg   mac80211: split s...
920
921
922
  		ieee80211_send_layer2_update(sta);
  
  	rcu_read_unlock();
4fd6931eb   Johannes Berg   mac80211: impleme...
923
924
925
926
927
928
  	return 0;
  }
  
  static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
  				 u8 *mac)
  {
14db74bcc   Johannes Berg   mac80211: fix cfg...
929
930
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  	struct ieee80211_sub_if_data *sdata;
4fd6931eb   Johannes Berg   mac80211: impleme...
931

14db74bcc   Johannes Berg   mac80211: fix cfg...
932
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
34e895075   Johannes Berg   mac80211: allow s...
933
934
  	if (mac)
  		return sta_info_destroy_addr_bss(sdata, mac);
4fd6931eb   Johannes Berg   mac80211: impleme...
935

34e895075   Johannes Berg   mac80211: allow s...
936
  	sta_info_flush(local, sdata);
4fd6931eb   Johannes Berg   mac80211: impleme...
937
938
939
940
941
942
943
944
  	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...
945
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
14db74bcc   Johannes Berg   mac80211: fix cfg...
946
  	struct ieee80211_local *local = wiphy_priv(wiphy);
4fd6931eb   Johannes Berg   mac80211: impleme...
947
948
  	struct sta_info *sta;
  	struct ieee80211_sub_if_data *vlansdata;
87be1e1e0   Johannes Berg   mac80211: use sta...
949
  	mutex_lock(&local->sta_mtx);
98dd6a575   Johannes Berg   mac80211: further...
950

0e5ded5a8   Felix Fietkau   mac80211: allow s...
951
  	sta = sta_info_get_bss(sdata, mac);
98dd6a575   Johannes Berg   mac80211: further...
952
  	if (!sta) {
87be1e1e0   Johannes Berg   mac80211: use sta...
953
  		mutex_unlock(&local->sta_mtx);
4fd6931eb   Johannes Berg   mac80211: impleme...
954
  		return -ENOENT;
98dd6a575   Johannes Berg   mac80211: further...
955
  	}
4fd6931eb   Johannes Berg   mac80211: impleme...
956

bdd90d5e3   Johannes Berg   cfg80211: validat...
957
958
959
960
  	/* in station mode, supported rates are only valid with TDLS */
  	if (sdata->vif.type == NL80211_IFTYPE_STATION &&
  	    params->supported_rates &&
  	    !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
87be1e1e0   Johannes Berg   mac80211: use sta...
961
  		mutex_unlock(&local->sta_mtx);
bdd90d5e3   Johannes Berg   cfg80211: validat...
962
963
  		return -EINVAL;
  	}
d0709a651   Johannes Berg   mac80211: RCU-ify...
964
  	if (params->vlan && params->vlan != sta->sdata->dev) {
4fd6931eb   Johannes Berg   mac80211: impleme...
965
  		vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
05c914fe3   Johannes Berg   mac80211: use nl8...
966
967
  		if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
  		    vlansdata->vif.type != NL80211_IFTYPE_AP) {
87be1e1e0   Johannes Berg   mac80211: use sta...
968
  			mutex_unlock(&local->sta_mtx);
4fd6931eb   Johannes Berg   mac80211: impleme...
969
  			return -EINVAL;
98dd6a575   Johannes Berg   mac80211: further...
970
  		}
4fd6931eb   Johannes Berg   mac80211: impleme...
971

9bc383de3   Johannes Berg   cfg80211: introdu...
972
  		if (params->vlan->ieee80211_ptr->use_4addr) {
3305443c9   Johannes Berg   mac80211: fix rcu...
973
  			if (vlansdata->u.vlan.sta) {
87be1e1e0   Johannes Berg   mac80211: use sta...
974
  				mutex_unlock(&local->sta_mtx);
f14543ee4   Felix Fietkau   mac80211: impleme...
975
  				return -EBUSY;
3305443c9   Johannes Berg   mac80211: fix rcu...
976
  			}
f14543ee4   Felix Fietkau   mac80211: impleme...
977

cf778b00e   Eric Dumazet   net: reintroduce ...
978
  			rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
f14543ee4   Felix Fietkau   mac80211: impleme...
979
  		}
14db74bcc   Johannes Berg   mac80211: fix cfg...
980
  		sta->sdata = vlansdata;
4fd6931eb   Johannes Berg   mac80211: impleme...
981
982
983
984
  		ieee80211_send_layer2_update(sta);
  	}
  
  	sta_apply_parameters(local, sta, params);
d64cf63e0   Arik Nemtsov   mac80211: init ra...
985
986
  	if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && params->supported_rates)
  		rate_control_rate_init(sta);
87be1e1e0   Johannes Berg   mac80211: use sta...
987
  	mutex_unlock(&local->sta_mtx);
98dd6a575   Johannes Berg   mac80211: further...
988

808118cb4   Jason Young   mac80211: do not ...
989
990
991
  	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...
992
993
  	return 0;
  }
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
994
995
996
997
  #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...
998
  	struct ieee80211_sub_if_data *sdata;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
999
1000
1001
  	struct mesh_path *mpath;
  	struct sta_info *sta;
  	int err;
14db74bcc   Johannes Berg   mac80211: fix cfg...
1002
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
d0709a651   Johannes Berg   mac80211: RCU-ify...
1003
  	rcu_read_lock();
abe60632f   Johannes Berg   mac80211: make st...
1004
  	sta = sta_info_get(sdata, next_hop);
d0709a651   Johannes Berg   mac80211: RCU-ify...
1005
1006
  	if (!sta) {
  		rcu_read_unlock();
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1007
  		return -ENOENT;
d0709a651   Johannes Berg   mac80211: RCU-ify...
1008
  	}
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1009

f698d856f   Jasper Bryant-Greene   replace net_devic...
1010
  	err = mesh_path_add(dst, sdata);
d0709a651   Johannes Berg   mac80211: RCU-ify...
1011
1012
  	if (err) {
  		rcu_read_unlock();
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1013
  		return err;
d0709a651   Johannes Berg   mac80211: RCU-ify...
1014
  	}
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1015

f698d856f   Jasper Bryant-Greene   replace net_devic...
1016
  	mpath = mesh_path_lookup(dst, sdata);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1017
1018
  	if (!mpath) {
  		rcu_read_unlock();
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1019
1020
1021
  		return -ENXIO;
  	}
  	mesh_path_fix_nexthop(mpath, sta);
d0709a651   Johannes Berg   mac80211: RCU-ify...
1022

c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1023
1024
1025
1026
1027
1028
1029
  	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...
1030
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1031
  	if (dst)
f698d856f   Jasper Bryant-Greene   replace net_devic...
1032
  		return mesh_path_del(dst, sdata);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1033

ece1a2e7e   Javier Cardona   mac80211: Remove ...
1034
  	mesh_path_flush_by_iface(sdata);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1035
1036
1037
1038
1039
1040
1041
  	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...
1042
  	struct ieee80211_sub_if_data *sdata;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1043
1044
  	struct mesh_path *mpath;
  	struct sta_info *sta;
14db74bcc   Johannes Berg   mac80211: fix cfg...
1045
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
d0709a651   Johannes Berg   mac80211: RCU-ify...
1046
  	rcu_read_lock();
abe60632f   Johannes Berg   mac80211: make st...
1047
  	sta = sta_info_get(sdata, next_hop);
d0709a651   Johannes Berg   mac80211: RCU-ify...
1048
1049
  	if (!sta) {
  		rcu_read_unlock();
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1050
  		return -ENOENT;
d0709a651   Johannes Berg   mac80211: RCU-ify...
1051
  	}
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1052

f698d856f   Jasper Bryant-Greene   replace net_devic...
1053
  	mpath = mesh_path_lookup(dst, sdata);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1054
1055
  	if (!mpath) {
  		rcu_read_unlock();
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1056
1057
1058
1059
  		return -ENOENT;
  	}
  
  	mesh_path_fix_nexthop(mpath, sta);
d0709a651   Johannes Berg   mac80211: RCU-ify...
1060

c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1061
1062
1063
1064
1065
1066
1067
  	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...
1068
1069
1070
1071
  	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...
1072
1073
  	else
  		memset(next_hop, 0, ETH_ALEN);
f5ea9120b   Johannes Berg   nl80211: add gene...
1074
  	pinfo->generation = mesh_paths_generation;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1075
  	pinfo->filled = MPATH_INFO_FRAME_QLEN |
d19b3bf63   Rui Paulo   mac80211: replace...
1076
  			MPATH_INFO_SN |
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1077
1078
1079
1080
1081
1082
1083
  			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...
1084
  	pinfo->sn = mpath->sn;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
  	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...
1096
1097
  	if (mpath->flags & MESH_PATH_SN_VALID)
  		pinfo->flags |= NL80211_MPATH_FLAG_SN_VALID;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
  	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...
1110
  	struct ieee80211_sub_if_data *sdata;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1111
  	struct mesh_path *mpath;
14db74bcc   Johannes Berg   mac80211: fix cfg...
1112
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1113
  	rcu_read_lock();
f698d856f   Jasper Bryant-Greene   replace net_devic...
1114
  	mpath = mesh_path_lookup(dst, sdata);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
  	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...
1129
  	struct ieee80211_sub_if_data *sdata;
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1130
  	struct mesh_path *mpath;
14db74bcc   Johannes Berg   mac80211: fix cfg...
1131
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1132
  	rcu_read_lock();
f698d856f   Jasper Bryant-Greene   replace net_devic...
1133
  	mpath = mesh_path_lookup_by_idx(idx, sdata);
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
1134
1135
1136
1137
1138
1139
1140
1141
1142
  	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...
1143

24bdd9f4c   Javier Cardona   mac80211: Rename ...
1144
  static int ieee80211_get_mesh_config(struct wiphy *wiphy,
93da9cc17   colin@cozybit.com   Add nl80211 comma...
1145
1146
1147
1148
1149
  				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...
1150
1151
1152
1153
1154
1155
1156
1157
  	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...
1158
1159
1160
1161
1162
  static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
  		const struct mesh_setup *setup)
  {
  	u8 *new_ie;
  	const u8 *old_ie;
4bb62344e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1163
1164
  	struct ieee80211_sub_if_data *sdata = container_of(ifmsh,
  					struct ieee80211_sub_if_data, u.mesh);
c80d545da   Javier Cardona   mac80211: Let use...
1165

581a8b0fe   Javier Cardona   nl80211: rename N...
1166
  	/* allocate information elements */
c80d545da   Javier Cardona   mac80211: Let use...
1167
  	new_ie = NULL;
581a8b0fe   Javier Cardona   nl80211: rename N...
1168
  	old_ie = ifmsh->ie;
c80d545da   Javier Cardona   mac80211: Let use...
1169

581a8b0fe   Javier Cardona   nl80211: rename N...
1170
1171
  	if (setup->ie_len) {
  		new_ie = kmemdup(setup->ie, setup->ie_len,
c80d545da   Javier Cardona   mac80211: Let use...
1172
1173
1174
1175
  				GFP_KERNEL);
  		if (!new_ie)
  			return -ENOMEM;
  	}
581a8b0fe   Javier Cardona   nl80211: rename N...
1176
1177
1178
  	ifmsh->ie_len = setup->ie_len;
  	ifmsh->ie = new_ie;
  	kfree(old_ie);
c80d545da   Javier Cardona   mac80211: Let use...
1179
1180
1181
1182
1183
1184
  
  	/* 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...
1185
1186
1187
1188
1189
  	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...
1190

4bb62344e   Chun-Yeow Yeoh   {nl,cfg,mac}80211...
1191
1192
1193
  	/* mcast rate setting in Mesh Node */
  	memcpy(sdata->vif.bss_conf.mcast_rate, setup->mcast_rate,
  						sizeof(setup->mcast_rate));
c80d545da   Javier Cardona   mac80211: Let use...
1194
1195
  	return 0;
  }
24bdd9f4c   Javier Cardona   mac80211: Rename ...
1196
  static int ieee80211_update_mesh_config(struct wiphy *wiphy,
29cbe68c5   Johannes Berg   cfg80211/mac80211...
1197
1198
  					struct net_device *dev, u32 mask,
  					const struct mesh_config *nconf)
93da9cc17   colin@cozybit.com   Add nl80211 comma...
1199
1200
1201
  {
  	struct mesh_config *conf;
  	struct ieee80211_sub_if_data *sdata;
63c5723bc   Rui Paulo   mac80211: add nl8...
1202
  	struct ieee80211_if_mesh *ifmsh;
93da9cc17   colin@cozybit.com   Add nl80211 comma...
1203
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
63c5723bc   Rui Paulo   mac80211: add nl8...
1204
  	ifmsh = &sdata->u.mesh;
93da9cc17   colin@cozybit.com   Add nl80211 comma...
1205

93da9cc17   colin@cozybit.com   Add nl80211 comma...
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
  	/* 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:...
1220
1221
  	if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask))
  		conf->dot11MeshTTL = nconf->element_ttl;
93da9cc17   colin@cozybit.com   Add nl80211 comma...
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
  	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;
dca7e9430   Thomas Pedersen   {nl,cfg,mac}80211...
1237
1238
1239
  	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, mask))
  		conf->dot11MeshHWMPperrMinInterval =
  			nconf->dot11MeshHWMPperrMinInterval;
93da9cc17   colin@cozybit.com   Add nl80211 comma...
1240
1241
1242
1243
  	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
  			   mask))
  		conf->dot11MeshHWMPnetDiameterTraversalTime =
  			nconf->dot11MeshHWMPnetDiameterTraversalTime;
63c5723bc   Rui Paulo   mac80211: add nl8...
1244
1245
1246
1247
  	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ROOTMODE, mask)) {
  		conf->dot11MeshHWMPRootMode = nconf->dot11MeshHWMPRootMode;
  		ieee80211_mesh_root_setup(ifmsh);
  	}
16dd7267f   Javier Cardona   {nl,cfg,mac}80211...
1248
  	if (_chg_mesh_attr(NL80211_MESHCONF_GATE_ANNOUNCEMENTS, mask)) {
c61336611   Thomas Pedersen   mac80211: mesh ga...
1249
1250
1251
1252
1253
1254
1255
1256
  		/* our current gate announcement implementation rides on root
  		 * announcements, so require this ifmsh to also be a root node
  		 * */
  		if (nconf->dot11MeshGateAnnouncementProtocol &&
  		    !conf->dot11MeshHWMPRootMode) {
  			conf->dot11MeshHWMPRootMode = 1;
  			ieee80211_mesh_root_setup(ifmsh);
  		}
16dd7267f   Javier Cardona   {nl,cfg,mac}80211...
1257
1258
1259
  		conf->dot11MeshGateAnnouncementProtocol =
  			nconf->dot11MeshGateAnnouncementProtocol;
  	}
0507e159a   Javier Cardona   {nl,cfg,mac}80211...
1260
1261
1262
1263
  	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask)) {
  		conf->dot11MeshHWMPRannInterval =
  			nconf->dot11MeshHWMPRannInterval;
  	}
93da9cc17   colin@cozybit.com   Add nl80211 comma...
1264
1265
  	return 0;
  }
29cbe68c5   Johannes Berg   cfg80211/mac80211...
1266
1267
1268
1269
1270
1271
  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...
1272
  	int err;
29cbe68c5   Johannes Berg   cfg80211/mac80211...
1273

c80d545da   Javier Cardona   mac80211: Let use...
1274
1275
1276
1277
  	memcpy(&ifmsh->mshcfg, conf, sizeof(struct mesh_config));
  	err = copy_mesh_setup(ifmsh, setup);
  	if (err)
  		return err;
29cbe68c5   Johannes Berg   cfg80211/mac80211...
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
  	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...
1291
  #endif
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
1292
1293
1294
1295
  static int ieee80211_change_bss(struct wiphy *wiphy,
  				struct net_device *dev,
  				struct bss_parameters *params)
  {
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
1296
1297
  	struct ieee80211_sub_if_data *sdata;
  	u32 changed = 0;
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
1298
  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
1299
  	if (params->use_cts_prot >= 0) {
bda3933a8   Johannes Berg   mac80211: move bs...
1300
  		sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
1301
1302
1303
  		changed |= BSS_CHANGED_ERP_CTS_PROT;
  	}
  	if (params->use_short_preamble >= 0) {
bda3933a8   Johannes Berg   mac80211: move bs...
1304
  		sdata->vif.bss_conf.use_short_preamble =
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
1305
1306
1307
  			params->use_short_preamble;
  		changed |= BSS_CHANGED_ERP_PREAMBLE;
  	}
43d353434   Felix Fietkau   mac80211: force u...
1308
1309
1310
1311
1312
1313
  
  	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...
1314
  	if (params->use_short_slot_time >= 0) {
bda3933a8   Johannes Berg   mac80211: move bs...
1315
  		sdata->vif.bss_conf.use_short_slot =
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
1316
1317
1318
  			params->use_short_slot_time;
  		changed |= BSS_CHANGED_ERP_SLOT;
  	}
90c97a040   Jouni Malinen   nl80211: Add basi...
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
  	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...
1336
1337
1338
1339
1340
1341
  	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...
1342
1343
1344
1345
1346
  	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...
1347
1348
1349
1350
  	ieee80211_bss_info_change_notify(sdata, changed);
  
  	return 0;
  }
318884875   Jouni Malinen   nl80211: Add TX q...
1351
  static int ieee80211_set_txq_params(struct wiphy *wiphy,
f70f01c2e   Eliad Peller   cfg80211/mac80211...
1352
  				    struct net_device *dev,
318884875   Jouni Malinen   nl80211: Add TX q...
1353
1354
1355
  				    struct ieee80211_txq_params *params)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
f6f3def32   Eliad Peller   mac80211: save tx...
1356
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
318884875   Jouni Malinen   nl80211: Add TX q...
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
  	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...
1367
1368
1369
1370
1371
1372
  
  	/*
  	 * Setting tx queue params disables u-apsd because it's only
  	 * called in master mode.
  	 */
  	p.uapsd = false;
2683d65bb   Eliad Peller   mac80211: reconfi...
1373
1374
  	if (params->queue >= local->hw.queues)
  		return -EINVAL;
f6f3def32   Eliad Peller   mac80211: save tx...
1375
1376
  	sdata->tx_conf[params->queue] = p;
  	if (drv_conf_tx(local, sdata, params->queue, &p)) {
0fb9a9ec2   Joe Perches   net/mac80211: Use...
1377
1378
1379
1380
  		wiphy_debug(local->hw.wiphy,
  			    "failed to set TX queue parameters for queue %d
  ",
  			    params->queue);
318884875   Jouni Malinen   nl80211: Add TX q...
1381
1382
1383
1384
1385
  		return -EINVAL;
  	}
  
  	return 0;
  }
72bdcf343   Jouni Malinen   nl80211: Add freq...
1386
  static int ieee80211_set_channel(struct wiphy *wiphy,
f444de05d   Johannes Berg   cfg80211/mac80211...
1387
  				 struct net_device *netdev,
72bdcf343   Jouni Malinen   nl80211: Add freq...
1388
  				 struct ieee80211_channel *chan,
094d05dc3   Sujith   mac80211: Fix HT ...
1389
  				 enum nl80211_channel_type channel_type)
72bdcf343   Jouni Malinen   nl80211: Add freq...
1390
1391
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
0aaffa9b9   Johannes Berg   mac80211: improve...
1392
  	struct ieee80211_sub_if_data *sdata = NULL;
eeabee7e5   Ben Greear   mac80211: Be more...
1393
1394
1395
  	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...
1396
1397
1398
  
  	if (netdev)
  		sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
72bdcf343   Jouni Malinen   nl80211: Add freq...
1399

f444de05d   Johannes Berg   cfg80211/mac80211...
1400
1401
1402
1403
  	switch (ieee80211_get_channel_mode(local, NULL)) {
  	case CHAN_MODE_HOPPING:
  		return -EBUSY;
  	case CHAN_MODE_FIXED:
0aaffa9b9   Johannes Berg   mac80211: improve...
1404
1405
1406
  		if (local->oper_channel != chan)
  			return -EBUSY;
  		if (!sdata && local->_oper_channel_type == channel_type)
f444de05d   Johannes Berg   cfg80211/mac80211...
1407
  			return 0;
0aaffa9b9   Johannes Berg   mac80211: improve...
1408
  		break;
f444de05d   Johannes Berg   cfg80211/mac80211...
1409
1410
1411
  	case CHAN_MODE_UNDEFINED:
  		break;
  	}
72bdcf343   Jouni Malinen   nl80211: Add freq...
1412

eeabee7e5   Ben Greear   mac80211: Be more...
1413
1414
1415
  	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...
1416

0aaffa9b9   Johannes Berg   mac80211: improve...
1417
1418
  	if (!ieee80211_set_channel_type(local, sdata, channel_type))
  		return -EBUSY;
eeabee7e5   Ben Greear   mac80211: Be more...
1419
1420
1421
1422
1423
1424
1425
  	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);
ef5af7470   Johannes Berg   mac80211: fix con...
1426
  	if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR &&
eeabee7e5   Ben Greear   mac80211: Be more...
1427
  	    old_vif_oper_type != sdata->vif.bss_conf.channel_type)
0aaffa9b9   Johannes Berg   mac80211: improve...
1428
1429
1430
  		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
  
  	return 0;
72bdcf343   Jouni Malinen   nl80211: Add freq...
1431
  }
665af4fc8   Bob Copeland   mac80211: add sus...
1432
  #ifdef CONFIG_PM
ff1b6e69a   Johannes Berg   nl80211/cfg80211:...
1433
1434
  static int ieee80211_suspend(struct wiphy *wiphy,
  			     struct cfg80211_wowlan *wowlan)
665af4fc8   Bob Copeland   mac80211: add sus...
1435
  {
eecc48000   Johannes Berg   mac80211: add bas...
1436
  	return __ieee80211_suspend(wiphy_priv(wiphy), wowlan);
665af4fc8   Bob Copeland   mac80211: add sus...
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
  }
  
  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:...
1447
1448
1449
1450
  static int ieee80211_scan(struct wiphy *wiphy,
  			  struct net_device *dev,
  			  struct cfg80211_scan_request *req)
  {
2ca27bcff   Johannes Berg   mac80211: add p2p...
1451
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2a5193119   Johannes Berg   cfg80211/nl80211:...
1452

2ca27bcff   Johannes Berg   mac80211: add p2p...
1453
1454
1455
1456
1457
1458
1459
1460
1461
  	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...
1462
1463
1464
1465
1466
  		/*
  		 * 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...
1467
1468
1469
1470
1471
1472
1473
  	case NL80211_IFTYPE_AP:
  		if (sdata->u.ap.beacon)
  			return -EOPNOTSUPP;
  		break;
  	default:
  		return -EOPNOTSUPP;
  	}
2a5193119   Johannes Berg   cfg80211/nl80211:...
1474
1475
1476
  
  	return ieee80211_request_scan(sdata, req);
  }
79f460ca4   Luciano Coelho   mac80211: add sup...
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
  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...
1491
  ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev)
79f460ca4   Luciano Coelho   mac80211: add sup...
1492
1493
1494
1495
1496
  {
  	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...
1497
  	return ieee80211_request_sched_scan_stop(sdata);
79f460ca4   Luciano Coelho   mac80211: add sup...
1498
  }
636a5d362   Jouni Malinen   nl80211: Add MLME...
1499
1500
1501
  static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
  			  struct cfg80211_auth_request *req)
  {
77fdaa12c   Johannes Berg   mac80211: rework ...
1502
  	return ieee80211_mgd_auth(IEEE80211_DEV_TO_SUB_IF(dev), req);
636a5d362   Jouni Malinen   nl80211: Add MLME...
1503
1504
1505
1506
1507
  }
  
  static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
  			   struct cfg80211_assoc_request *req)
  {
f444de05d   Johannes Berg   cfg80211/mac80211...
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
  	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 ...
1521
  	return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
636a5d362   Jouni Malinen   nl80211: Add MLME...
1522
1523
1524
  }
  
  static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev,
667503ddc   Johannes Berg   cfg80211: fix loc...
1525
1526
  			    struct cfg80211_deauth_request *req,
  			    void *cookie)
636a5d362   Jouni Malinen   nl80211: Add MLME...
1527
  {
667503ddc   Johannes Berg   cfg80211: fix loc...
1528
1529
  	return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev),
  				    req, cookie);
636a5d362   Jouni Malinen   nl80211: Add MLME...
1530
1531
1532
  }
  
  static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
667503ddc   Johannes Berg   cfg80211: fix loc...
1533
1534
  			      struct cfg80211_disassoc_request *req,
  			      void *cookie)
636a5d362   Jouni Malinen   nl80211: Add MLME...
1535
  {
667503ddc   Johannes Berg   cfg80211: fix loc...
1536
1537
  	return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev),
  				      req, cookie);
636a5d362   Jouni Malinen   nl80211: Add MLME...
1538
  }
af8cdcd82   Johannes Berg   mac80211: convert...
1539
1540
1541
  static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
  			       struct cfg80211_ibss_params *params)
  {
f444de05d   Johannes Berg   cfg80211/mac80211...
1542
  	struct ieee80211_local *local = wiphy_priv(wiphy);
af8cdcd82   Johannes Berg   mac80211: convert...
1543
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
f444de05d   Johannes Berg   cfg80211/mac80211...
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
  	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...
1556
1557
1558
1559
1560
1561
1562
1563
1564
  	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/...
1565
1566
1567
  static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
244879813   Johannes Berg   mac80211: add dri...
1568
  	int err;
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
1569

f23a47807   Arik Nemtsov   mac80211: support...
1570
1571
1572
1573
1574
1575
  	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...
1576
1577
1578
1579
1580
1581
  	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/...
1582
  	if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
244879813   Johannes Berg   mac80211: add dri...
1583
  		err = drv_set_rts_threshold(local, wiphy->rts_threshold);
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
1584

244879813   Johannes Berg   mac80211: add dri...
1585
1586
  		if (err)
  			return err;
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
  	}
  
  	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...
1599
  static int ieee80211_set_tx_power(struct wiphy *wiphy,
fa61cf70a   Juuso Oikarinen   cfg80211/mac80211...
1600
  				  enum nl80211_tx_power_setting type, int mbm)
7643a2c3f   Johannes Berg   cfg80211: move tx...
1601
1602
1603
1604
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  	struct ieee80211_channel *chan = local->hw.conf.channel;
  	u32 changes = 0;
7643a2c3f   Johannes Berg   cfg80211: move tx...
1605
1606
  
  	switch (type) {
fa61cf70a   Juuso Oikarinen   cfg80211/mac80211...
1607
  	case NL80211_TX_POWER_AUTOMATIC:
7643a2c3f   Johannes Berg   cfg80211: move tx...
1608
1609
  		local->user_power_level = -1;
  		break;
fa61cf70a   Juuso Oikarinen   cfg80211/mac80211...
1610
1611
1612
1613
  	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...
1614
  		break;
fa61cf70a   Juuso Oikarinen   cfg80211/mac80211...
1615
1616
1617
  	case NL80211_TX_POWER_FIXED:
  		if (mbm < 0 || (mbm % 100))
  			return -EOPNOTSUPP;
7643a2c3f   Johannes Berg   cfg80211: move tx...
1618
  		/* TODO: move to cfg80211 when it knows the channel */
fa61cf70a   Juuso Oikarinen   cfg80211/mac80211...
1619
  		if (MBM_TO_DBM(mbm) > chan->max_power)
7643a2c3f   Johannes Berg   cfg80211: move tx...
1620
  			return -EINVAL;
fa61cf70a   Juuso Oikarinen   cfg80211/mac80211...
1621
  		local->user_power_level = MBM_TO_DBM(mbm);
7643a2c3f   Johannes Berg   cfg80211: move tx...
1622
  		break;
7643a2c3f   Johannes Berg   cfg80211: move tx...
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
  	}
  
  	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...
1635
1636
  	return 0;
  }
ab737a4f7   Johannes Berg   cfg80211: impleme...
1637
  static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
388ac775b   Johannes Berg   cfg80211: constif...
1638
  				  const u8 *addr)
ab737a4f7   Johannes Berg   cfg80211: impleme...
1639
1640
1641
1642
1643
1644
1645
  {
  	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...
1646
1647
1648
1649
1650
1651
  static void ieee80211_rfkill_poll(struct wiphy *wiphy)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  
  	drv_rfkill_poll(local);
  }
aff89a9b9   Johannes Berg   cfg80211: introdu...
1652
  #ifdef CONFIG_NL80211_TESTMODE
99783e2cd   Johannes Berg   mac80211: fix spa...
1653
  static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
aff89a9b9   Johannes Berg   cfg80211: introdu...
1654
1655
1656
1657
1658
1659
1660
1661
  {
  	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...
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
  
  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...
1675
  #endif
0f78231bf   Johannes Berg   mac80211: enable ...
1676
1677
1678
1679
1680
1681
  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...
1682
  	lockdep_assert_held(&sdata->u.mgd.mtx);
0f78231bf   Johannes Berg   mac80211: enable ...
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
  	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...
1695
  	    sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) {
0f78231bf   Johannes Berg   mac80211: enable ...
1696
  		mutex_lock(&sdata->local->iflist_mtx);
025e6be22   Johannes Berg   mac80211: fix dea...
1697
  		ieee80211_recalc_smps(sdata->local);
0f78231bf   Johannes Berg   mac80211: enable ...
1698
1699
1700
  		mutex_unlock(&sdata->local->iflist_mtx);
  		return 0;
  	}
0c1ad2cac   Johannes Berg   mac80211: proper ...
1701
  	ap = sdata->u.mgd.associated->bssid;
0f78231bf   Johannes Berg   mac80211: enable ...
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
  
  	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...
1718
1719
1720
1721
1722
  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...
1723

e5de30c9b   Benoit Papillault   mac80211: check t...
1724
1725
  	if (sdata->vif.type != NL80211_IFTYPE_STATION)
  		return -EOPNOTSUPP;
bc92afd92   Johannes Berg   cfg80211: impleme...
1726
1727
1728
1729
  	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
  		return -EOPNOTSUPP;
  
  	if (enabled == sdata->u.mgd.powersave &&
ff6163810   Juuso Oikarinen   mac80211: Fix ps-...
1730
  	    timeout == local->dynamic_ps_forced_timeout)
bc92afd92   Johannes Berg   cfg80211: impleme...
1731
1732
1733
  		return 0;
  
  	sdata->u.mgd.powersave = enabled;
ff6163810   Juuso Oikarinen   mac80211: Fix ps-...
1734
  	local->dynamic_ps_forced_timeout = timeout;
bc92afd92   Johannes Berg   cfg80211: impleme...
1735

0f78231bf   Johannes Berg   mac80211: enable ...
1736
1737
1738
1739
  	/* 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...
1740
1741
1742
1743
1744
1745
1746
  	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...
1747
1748
1749
1750
1751
1752
1753
1754
  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...
1755
1756
1757
1758
1759
1760
  	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...
1761
1762
1763
1764
1765
  	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...
1766
1767
1768
1769
1770
1771
  	/* 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...
1772
1773
1774
1775
1776
1777
1778
  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...
1779
  	int i, ret;
2c7e6bc9a   Johannes Berg   mac80211: disallo...
1780

bdbfd6b58   Sujith Manoharan   mac80211: Add new...
1781
1782
1783
1784
1785
  	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...
1786

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

37eb0b164   Jouni Malinen   cfg80211/mac80211...
1790
  	return 0;
9930380f0   Johannes Berg   cfg80211: impleme...
1791
  }
21f835896   Johannes Berg   mac80211: impleme...
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
  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...
1822
1823
1824
1825
1826
1827
1828
1829
  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...
1830
1831
1832
1833
1834
1835
1836
1837
1838
  	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...
1839
  		local->hw_roc_for_tx = false;
21f835896   Johannes Berg   mac80211: impleme...
1840
1841
1842
1843
  		mutex_unlock(&local->mtx);
  
  		return ret;
  	}
b8bc4b0aa   Johannes Berg   mac80211: support...
1844
1845
1846
1847
  
  	return ieee80211_wk_remain_on_channel(sdata, chan, channel_type,
  					      duration, cookie);
  }
21f835896   Johannes Berg   mac80211: impleme...
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
  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...
1869
1870
1871
1872
1873
  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...
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
  	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...
1885
1886
1887
  
  	return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
  }
f30221e4e   Johannes Berg   mac80211: impleme...
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
  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.
  	 */
28a1bcdb5   Johannes Berg   mac80211: fix off...
1901
  	if (wk->offchan_tx.wait && !wk->offchan_tx.status)
f30221e4e   Johannes Berg   mac80211: impleme...
1902
1903
1904
1905
1906
1907
  		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...
1908
  static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
f7ca38dfe   Johannes Berg   nl80211/cfg80211:...
1909
  			     struct ieee80211_channel *chan, bool offchan,
2e161f78e   Johannes Berg   cfg80211/mac80211...
1910
  			     enum nl80211_channel_type channel_type,
f7ca38dfe   Johannes Berg   nl80211/cfg80211:...
1911
  			     bool channel_type_valid, unsigned int wait,
e9f935e3e   Rajkumar Manoharan   nl80211/cfg80211:...
1912
  			     const u8 *buf, size_t len, bool no_cck,
e247bd906   Johannes Berg   cfg80211/mac80211...
1913
  			     bool dont_wait_for_ack, u64 *cookie)
026331c4d   Jouni Malinen   cfg80211/mac80211...
1914
  {
9d38d85de   Johannes Berg   cfg80211/mac80211...
1915
1916
1917
1918
  	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...
1919
  	struct ieee80211_work *wk;
9d38d85de   Johannes Berg   cfg80211/mac80211...
1920
  	const struct ieee80211_mgmt *mgmt = (void *)buf;
e247bd906   Johannes Berg   cfg80211/mac80211...
1921
  	u32 flags;
f30221e4e   Johannes Berg   mac80211: impleme...
1922
  	bool is_offchan = false;
f7ca38dfe   Johannes Berg   nl80211/cfg80211:...
1923

e247bd906   Johannes Berg   cfg80211/mac80211...
1924
1925
1926
1927
1928
  	if (dont_wait_for_ack)
  		flags = IEEE80211_TX_CTL_NO_ACK;
  	else
  		flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
  			IEEE80211_TX_CTL_REQ_TX_STATUS;
9d38d85de   Johannes Berg   cfg80211/mac80211...
1929
1930
1931
  	/* Check that we are on the requested channel for transmission */
  	if (chan != local->tmp_channel &&
  	    chan != local->oper_channel)
f30221e4e   Johannes Berg   mac80211: impleme...
1932
  		is_offchan = true;
9d38d85de   Johannes Berg   cfg80211/mac80211...
1933
1934
1935
  	if (channel_type_valid &&
  	    (channel_type != local->tmp_channel_type &&
  	     channel_type != local->_oper_channel_type))
f30221e4e   Johannes Berg   mac80211: impleme...
1936
  		is_offchan = true;
21f835896   Johannes Berg   mac80211: impleme...
1937
1938
1939
1940
1941
  	if (chan == local->hw_roc_channel) {
  		/* TODO: check channel type? */
  		is_offchan = false;
  		flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
  	}
aad14ceb4   Rajkumar Manoharan   mac80211: Send th...
1942
1943
  	if (no_cck)
  		flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
f30221e4e   Johannes Berg   mac80211: impleme...
1944
  	if (is_offchan && !offchan)
9d38d85de   Johannes Berg   cfg80211/mac80211...
1945
1946
1947
1948
  		return -EBUSY;
  
  	switch (sdata->vif.type) {
  	case NL80211_IFTYPE_ADHOC:
663fcafd9   Johannes Berg   cfg80211/mac80211...
1949
1950
1951
  	case NL80211_IFTYPE_AP:
  	case NL80211_IFTYPE_AP_VLAN:
  	case NL80211_IFTYPE_P2P_GO:
c7108a711   Javier Cardona   mac80211: Send me...
1952
  	case NL80211_IFTYPE_MESH_POINT:
663fcafd9   Johannes Berg   cfg80211/mac80211...
1953
1954
  		if (!ieee80211_is_action(mgmt->frame_control) ||
  		    mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
9d38d85de   Johannes Berg   cfg80211/mac80211...
1955
1956
1957
1958
1959
1960
1961
1962
  			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...
1963
  	case NL80211_IFTYPE_P2P_CLIENT:
9d38d85de   Johannes Berg   cfg80211/mac80211...
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
  		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...
1979
1980
  
  	*cookie = (unsigned long) skb;
f30221e4e   Johannes Berg   mac80211: impleme...
1981

90fc4b3a5   Johannes Berg   mac80211: impleme...
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
  	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 ...
2020
  		local->hw_roc_skb_for_status = skb;
90fc4b3a5   Johannes Berg   mac80211: impleme...
2021
2022
2023
2024
  		mutex_unlock(&local->mtx);
  
  		return 0;
  	}
f30221e4e   Johannes Berg   mac80211: impleme...
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
  	/*
  	 * 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...
2044
  	wk->chan_type = channel_type;
f30221e4e   Johannes Berg   mac80211: impleme...
2045
2046
2047
2048
2049
2050
2051
2052
  	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...
2053
  	return 0;
026331c4d   Jouni Malinen   cfg80211/mac80211...
2054
  }
f30221e4e   Johannes Berg   mac80211: impleme...
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
  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...
2065
2066
2067
2068
2069
2070
2071
2072
  
  	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 ...
2073
  			local->hw_roc_skb_for_status = NULL;
90fc4b3a5   Johannes Berg   mac80211: impleme...
2074
2075
2076
2077
2078
2079
  		}
  
  		mutex_unlock(&local->mtx);
  
  		return ret;
  	}
f30221e4e   Johannes Berg   mac80211: impleme...
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
  	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...
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
  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...
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
  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...
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
  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...
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
  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;
  }
dfe018bf9   Arik Nemtsov   mac80211: handle ...
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
  static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb)
  {
  	u8 *pos = (void *)skb_put(skb, 7);
  
  	*pos++ = WLAN_EID_EXT_CAPABILITY;
  	*pos++ = 5; /* len */
  	*pos++ = 0x0;
  	*pos++ = 0x0;
  	*pos++ = 0x0;
  	*pos++ = 0x0;
  	*pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED;
  }
  
  static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata)
  {
  	struct ieee80211_local *local = sdata->local;
  	u16 capab;
  
  	capab = 0;
  	if (local->oper_channel->band != IEEE80211_BAND_2GHZ)
  		return capab;
  
  	if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
  		capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
  	if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
  		capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
  
  	return capab;
  }
  
  static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, u8 *src_addr,
  				       u8 *peer, u8 *bssid)
  {
  	struct ieee80211_tdls_lnkie *lnkid;
  
  	lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
  
  	lnkid->ie_type = WLAN_EID_LINK_ID;
  	lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
  
  	memcpy(lnkid->bssid, bssid, ETH_ALEN);
  	memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
  	memcpy(lnkid->resp_sta, peer, ETH_ALEN);
  }
  
  static int
  ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
  			       u8 *peer, u8 action_code, u8 dialog_token,
  			       u16 status_code, struct sk_buff *skb)
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  	struct ieee80211_tdls_data *tf;
  
  	tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
  
  	memcpy(tf->da, peer, ETH_ALEN);
  	memcpy(tf->sa, sdata->vif.addr, ETH_ALEN);
  	tf->ether_type = cpu_to_be16(ETH_P_TDLS);
  	tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
  
  	switch (action_code) {
  	case WLAN_TDLS_SETUP_REQUEST:
  		tf->category = WLAN_CATEGORY_TDLS;
  		tf->action_code = WLAN_TDLS_SETUP_REQUEST;
  
  		skb_put(skb, sizeof(tf->u.setup_req));
  		tf->u.setup_req.dialog_token = dialog_token;
  		tf->u.setup_req.capability =
  			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
  
  		ieee80211_add_srates_ie(&sdata->vif, skb);
  		ieee80211_add_ext_srates_ie(&sdata->vif, skb);
  		ieee80211_tdls_add_ext_capab(skb);
  		break;
  	case WLAN_TDLS_SETUP_RESPONSE:
  		tf->category = WLAN_CATEGORY_TDLS;
  		tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
  
  		skb_put(skb, sizeof(tf->u.setup_resp));
  		tf->u.setup_resp.status_code = cpu_to_le16(status_code);
  		tf->u.setup_resp.dialog_token = dialog_token;
  		tf->u.setup_resp.capability =
  			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
  
  		ieee80211_add_srates_ie(&sdata->vif, skb);
  		ieee80211_add_ext_srates_ie(&sdata->vif, skb);
  		ieee80211_tdls_add_ext_capab(skb);
  		break;
  	case WLAN_TDLS_SETUP_CONFIRM:
  		tf->category = WLAN_CATEGORY_TDLS;
  		tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
  
  		skb_put(skb, sizeof(tf->u.setup_cfm));
  		tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
  		tf->u.setup_cfm.dialog_token = dialog_token;
  		break;
  	case WLAN_TDLS_TEARDOWN:
  		tf->category = WLAN_CATEGORY_TDLS;
  		tf->action_code = WLAN_TDLS_TEARDOWN;
  
  		skb_put(skb, sizeof(tf->u.teardown));
  		tf->u.teardown.reason_code = cpu_to_le16(status_code);
  		break;
  	case WLAN_TDLS_DISCOVERY_REQUEST:
  		tf->category = WLAN_CATEGORY_TDLS;
  		tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
  
  		skb_put(skb, sizeof(tf->u.discover_req));
  		tf->u.discover_req.dialog_token = dialog_token;
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	return 0;
  }
  
  static int
  ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
  			   u8 *peer, u8 action_code, u8 dialog_token,
  			   u16 status_code, struct sk_buff *skb)
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  	struct ieee80211_mgmt *mgmt;
  
  	mgmt = (void *)skb_put(skb, 24);
  	memset(mgmt, 0, 24);
  	memcpy(mgmt->da, peer, ETH_ALEN);
  	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
  	memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
  
  	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
  					  IEEE80211_STYPE_ACTION);
  
  	switch (action_code) {
  	case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
  		skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
  		mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
  		mgmt->u.action.u.tdls_discover_resp.action_code =
  			WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
  		mgmt->u.action.u.tdls_discover_resp.dialog_token =
  			dialog_token;
  		mgmt->u.action.u.tdls_discover_resp.capability =
  			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
  
  		ieee80211_add_srates_ie(&sdata->vif, skb);
  		ieee80211_add_ext_srates_ie(&sdata->vif, skb);
  		ieee80211_tdls_add_ext_capab(skb);
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	return 0;
  }
  
  static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
  			       u8 *peer, u8 action_code, u8 dialog_token,
  			       u16 status_code, const u8 *extra_ies,
  			       size_t extra_ies_len)
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  	struct ieee80211_local *local = sdata->local;
  	struct ieee80211_tx_info *info;
  	struct sk_buff *skb = NULL;
  	bool send_direct;
  	int ret;
  
  	if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
  		return -ENOTSUPP;
  
  	/* make sure we are in managed mode, and associated */
  	if (sdata->vif.type != NL80211_IFTYPE_STATION ||
  	    !sdata->u.mgd.associated)
  		return -EINVAL;
  
  #ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
  	printk(KERN_DEBUG "TDLS mgmt action %d peer %pM
  ", action_code, peer);
  #endif
  
  	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
  			    max(sizeof(struct ieee80211_mgmt),
  				sizeof(struct ieee80211_tdls_data)) +
  			    50 + /* supported rates */
  			    7 + /* ext capab */
  			    extra_ies_len +
  			    sizeof(struct ieee80211_tdls_lnkie));
  	if (!skb)
  		return -ENOMEM;
  
  	info = IEEE80211_SKB_CB(skb);
  	skb_reserve(skb, local->hw.extra_tx_headroom);
  
  	switch (action_code) {
  	case WLAN_TDLS_SETUP_REQUEST:
  	case WLAN_TDLS_SETUP_RESPONSE:
  	case WLAN_TDLS_SETUP_CONFIRM:
  	case WLAN_TDLS_TEARDOWN:
  	case WLAN_TDLS_DISCOVERY_REQUEST:
  		ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer,
  						     action_code, dialog_token,
  						     status_code, skb);
  		send_direct = false;
  		break;
  	case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
  		ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code,
  						 dialog_token, status_code,
  						 skb);
  		send_direct = true;
  		break;
  	default:
  		ret = -ENOTSUPP;
  		break;
  	}
  
  	if (ret < 0)
  		goto fail;
  
  	if (extra_ies_len)
  		memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
  
  	/* the TDLS link IE is always added last */
  	switch (action_code) {
  	case WLAN_TDLS_SETUP_REQUEST:
  	case WLAN_TDLS_SETUP_CONFIRM:
  	case WLAN_TDLS_TEARDOWN:
  	case WLAN_TDLS_DISCOVERY_REQUEST:
  		/* we are the initiator */
  		ieee80211_tdls_add_link_ie(skb, sdata->vif.addr, peer,
  					   sdata->u.mgd.bssid);
  		break;
  	case WLAN_TDLS_SETUP_RESPONSE:
  	case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
  		/* we are the responder */
  		ieee80211_tdls_add_link_ie(skb, peer, sdata->vif.addr,
  					   sdata->u.mgd.bssid);
  		break;
  	default:
  		ret = -ENOTSUPP;
  		goto fail;
  	}
  
  	if (send_direct) {
  		ieee80211_tx_skb(sdata, skb);
  		return 0;
  	}
  
  	/*
  	 * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
  	 * we should default to AC_VI.
  	 */
  	switch (action_code) {
  	case WLAN_TDLS_SETUP_REQUEST:
  	case WLAN_TDLS_SETUP_RESPONSE:
  		skb_set_queue_mapping(skb, IEEE80211_AC_BK);
  		skb->priority = 2;
  		break;
  	default:
  		skb_set_queue_mapping(skb, IEEE80211_AC_VI);
  		skb->priority = 5;
  		break;
  	}
  
  	/* disable bottom halves when entering the Tx path */
  	local_bh_disable();
  	ret = ieee80211_subif_start_xmit(skb, dev);
  	local_bh_enable();
  
  	return ret;
  
  fail:
  	dev_kfree_skb(skb);
  	return ret;
  }
  
  static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
  			       u8 *peer, enum nl80211_tdls_operation oper)
  {
941c93cd0   Arik Nemtsov   mac80211: data pa...
2439
  	struct sta_info *sta;
dfe018bf9   Arik Nemtsov   mac80211: handle ...
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  
  	if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
  		return -ENOTSUPP;
  
  	if (sdata->vif.type != NL80211_IFTYPE_STATION)
  		return -EINVAL;
  
  #ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
  	printk(KERN_DEBUG "TDLS oper %d peer %pM
  ", oper, peer);
  #endif
  
  	switch (oper) {
  	case NL80211_TDLS_ENABLE_LINK:
941c93cd0   Arik Nemtsov   mac80211: data pa...
2455
2456
2457
2458
2459
2460
  		rcu_read_lock();
  		sta = sta_info_get(sdata, peer);
  		if (!sta) {
  			rcu_read_unlock();
  			return -ENOLINK;
  		}
c2c98fdeb   Johannes Berg   mac80211: optimis...
2461
  		set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
941c93cd0   Arik Nemtsov   mac80211: data pa...
2462
  		rcu_read_unlock();
dfe018bf9   Arik Nemtsov   mac80211: handle ...
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
  		break;
  	case NL80211_TDLS_DISABLE_LINK:
  		return sta_info_destroy_addr(sdata, peer);
  	case NL80211_TDLS_TEARDOWN:
  	case NL80211_TDLS_SETUP:
  	case NL80211_TDLS_DISCOVERY_REQ:
  		/* We don't support in-driver setup/teardown/discovery */
  		return -ENOTSUPP;
  	default:
  		return -ENOTSUPP;
  	}
  
  	return 0;
  }
06500736c   Johannes Berg   mac80211: support...
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
  static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
  				  const u8 *peer, u64 *cookie)
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  	struct ieee80211_local *local = sdata->local;
  	struct ieee80211_qos_hdr *nullfunc;
  	struct sk_buff *skb;
  	int size = sizeof(*nullfunc);
  	__le16 fc;
  	bool qos;
  	struct ieee80211_tx_info *info;
  	struct sta_info *sta;
  
  	rcu_read_lock();
  	sta = sta_info_get(sdata, peer);
b4487c2d0   Johannes Berg   mac80211: fix war...
2492
  	if (sta) {
06500736c   Johannes Berg   mac80211: support...
2493
  		qos = test_sta_flag(sta, WLAN_STA_WME);
b4487c2d0   Johannes Berg   mac80211: fix war...
2494
2495
2496
  		rcu_read_unlock();
  	} else {
  		rcu_read_unlock();
06500736c   Johannes Berg   mac80211: support...
2497
  		return -ENOLINK;
b4487c2d0   Johannes Berg   mac80211: fix war...
2498
  	}
06500736c   Johannes Berg   mac80211: support...
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
  
  	if (qos) {
  		fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
  				 IEEE80211_STYPE_QOS_NULLFUNC |
  				 IEEE80211_FCTL_FROMDS);
  	} else {
  		size -= 2;
  		fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
  				 IEEE80211_STYPE_NULLFUNC |
  				 IEEE80211_FCTL_FROMDS);
  	}
  
  	skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
  	if (!skb)
  		return -ENOMEM;
  
  	skb->dev = dev;
  
  	skb_reserve(skb, local->hw.extra_tx_headroom);
  
  	nullfunc = (void *) skb_put(skb, size);
  	nullfunc->frame_control = fc;
  	nullfunc->duration_id = 0;
  	memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
  	memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
  	memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
  	nullfunc->seq_ctrl = 0;
  
  	info = IEEE80211_SKB_CB(skb);
  
  	info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
  		       IEEE80211_TX_INTFL_NL80211_FRAME_TX;
  
  	skb_set_queue_mapping(skb, IEEE80211_AC_VO);
  	skb->priority = 7;
  	if (qos)
  		nullfunc->qos_ctrl = cpu_to_le16(7);
  
  	local_bh_disable();
  	ieee80211_xmit(sdata, skb);
  	local_bh_enable();
  
  	*cookie = (unsigned long) skb;
  	return 0;
  }
e999882a0   Johannes Berg   mac80211/cfg80211...
2544
2545
2546
2547
2548
2549
2550
  static struct ieee80211_channel *
  ieee80211_wiphy_get_channel(struct wiphy *wiphy)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  
  	return local->oper_channel;
  }
f0706e828   Jiri Benc   [MAC80211]: Add m...
2551
2552
2553
  struct cfg80211_ops mac80211_config_ops = {
  	.add_virtual_intf = ieee80211_add_iface,
  	.del_virtual_intf = ieee80211_del_iface,
42613db76   Johannes Berg   [MAC80211]: imple...
2554
  	.change_virtual_intf = ieee80211_change_iface,
e8cbb4cbe   Johannes Berg   mac80211: support...
2555
2556
  	.add_key = ieee80211_add_key,
  	.del_key = ieee80211_del_key,
62da92fb7   Johannes Berg   mac80211: support...
2557
  	.get_key = ieee80211_get_key,
e8cbb4cbe   Johannes Berg   mac80211: support...
2558
  	.set_default_key = ieee80211_config_default_key,
3cfcf6ac6   Jouni Malinen   mac80211: 802.11w...
2559
  	.set_default_mgmt_key = ieee80211_config_default_mgmt_key,
5dfdaf58d   Johannes Berg   mac80211: add bea...
2560
2561
2562
  	.add_beacon = ieee80211_add_beacon,
  	.set_beacon = ieee80211_set_beacon,
  	.del_beacon = ieee80211_del_beacon,
4fd6931eb   Johannes Berg   mac80211: impleme...
2563
2564
2565
  	.add_station = ieee80211_add_station,
  	.del_station = ieee80211_del_station,
  	.change_station = ieee80211_change_station,
7bbdd2d98   Johannes Berg   mac80211: impleme...
2566
  	.get_station = ieee80211_get_station,
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
2567
  	.dump_station = ieee80211_dump_station,
1289723ef   Holger Schurig   mac80211: sample ...
2568
  	.dump_survey = ieee80211_dump_survey,
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
2569
2570
2571
2572
2573
2574
  #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 ...
2575
2576
  	.update_mesh_config = ieee80211_update_mesh_config,
  	.get_mesh_config = ieee80211_get_mesh_config,
29cbe68c5   Johannes Berg   cfg80211/mac80211...
2577
2578
  	.join_mesh = ieee80211_join_mesh,
  	.leave_mesh = ieee80211_leave_mesh,
c5dd9c2bd   Luis Carlos Cobo   mac80211: mesh pa...
2579
  #endif
9f1ba9062   Jouni Malinen   mac80211/cfg80211...
2580
  	.change_bss = ieee80211_change_bss,
318884875   Jouni Malinen   nl80211: Add TX q...
2581
  	.set_txq_params = ieee80211_set_txq_params,
72bdcf343   Jouni Malinen   nl80211: Add freq...
2582
  	.set_channel = ieee80211_set_channel,
665af4fc8   Bob Copeland   mac80211: add sus...
2583
2584
  	.suspend = ieee80211_suspend,
  	.resume = ieee80211_resume,
2a5193119   Johannes Berg   cfg80211/nl80211:...
2585
  	.scan = ieee80211_scan,
79f460ca4   Luciano Coelho   mac80211: add sup...
2586
2587
  	.sched_scan_start = ieee80211_sched_scan_start,
  	.sched_scan_stop = ieee80211_sched_scan_stop,
636a5d362   Jouni Malinen   nl80211: Add MLME...
2588
2589
2590
2591
  	.auth = ieee80211_auth,
  	.assoc = ieee80211_assoc,
  	.deauth = ieee80211_deauth,
  	.disassoc = ieee80211_disassoc,
af8cdcd82   Johannes Berg   mac80211: convert...
2592
2593
  	.join_ibss = ieee80211_join_ibss,
  	.leave_ibss = ieee80211_leave_ibss,
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
2594
  	.set_wiphy_params = ieee80211_set_wiphy_params,
7643a2c3f   Johannes Berg   cfg80211: move tx...
2595
2596
  	.set_tx_power = ieee80211_set_tx_power,
  	.get_tx_power = ieee80211_get_tx_power,
ab737a4f7   Johannes Berg   cfg80211: impleme...
2597
  	.set_wds_peer = ieee80211_set_wds_peer,
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
2598
  	.rfkill_poll = ieee80211_rfkill_poll,
aff89a9b9   Johannes Berg   cfg80211: introdu...
2599
  	CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
71063f0e8   Wey-Yi Guy   nl80211: add test...
2600
  	CFG80211_TESTMODE_DUMP(ieee80211_testmode_dump)
bc92afd92   Johannes Berg   cfg80211: impleme...
2601
  	.set_power_mgmt = ieee80211_set_power_mgmt,
9930380f0   Johannes Berg   cfg80211: impleme...
2602
  	.set_bitrate_mask = ieee80211_set_bitrate_mask,
b8bc4b0aa   Johannes Berg   mac80211: support...
2603
2604
  	.remain_on_channel = ieee80211_remain_on_channel,
  	.cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
2e161f78e   Johannes Berg   cfg80211/mac80211...
2605
  	.mgmt_tx = ieee80211_mgmt_tx,
f30221e4e   Johannes Berg   mac80211: impleme...
2606
  	.mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,
a97c13c34   Juuso Oikarinen   mac80211: Add sup...
2607
  	.set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
7be5086d4   Johannes Berg   mac80211: add pro...
2608
  	.mgmt_frame_register = ieee80211_mgmt_frame_register,
15d967532   Bruno Randolf   mac80211: Add ant...
2609
2610
  	.set_antenna = ieee80211_set_antenna,
  	.get_antenna = ieee80211_get_antenna,
38c091590   John W. Linville   mac80211: impleme...
2611
2612
  	.set_ringparam = ieee80211_set_ringparam,
  	.get_ringparam = ieee80211_get_ringparam,
c68f4b892   Johannes Berg   mac80211: support...
2613
  	.set_rekey_data = ieee80211_set_rekey_data,
dfe018bf9   Arik Nemtsov   mac80211: handle ...
2614
2615
  	.tdls_oper = ieee80211_tdls_oper,
  	.tdls_mgmt = ieee80211_tdls_mgmt,
06500736c   Johannes Berg   mac80211: support...
2616
  	.probe_client = ieee80211_probe_client,
e999882a0   Johannes Berg   mac80211/cfg80211...
2617
  	.get_channel = ieee80211_wiphy_get_channel,
b53be7920   Simon Wunderlich   mac80211: Add NoA...
2618
  	.set_noack_map = ieee80211_set_noack_map,
f0706e828   Jiri Benc   [MAC80211]: Add m...
2619
  };