Blame view

net/wireless/core.c 35.6 KB
704232c27   Johannes Berg   [WIRELESS] cfg802...
1
2
3
  /*
   * This is the linux wireless configuration interface.
   *
5f2aa25e0   Johannes Berg   cfg80211: rcu-ify...
4
   * Copyright 2006-2010		Johannes Berg <johannes@sipsolutions.net>
2740f0cf8   Johannes Berg   cfg80211: add Int...
5
   * Copyright 2013-2014  Intel Mobile Communications GmbH
53873f134   Johannes Berg   cfg80211: make wd...
6
   * Copyright 2015	Intel Deutschland GmbH
704232c27   Johannes Berg   [WIRELESS] cfg802...
7
   */
e9c0268f0   Joe Perches   net/wireless: Use...
8
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
704232c27   Johannes Berg   [WIRELESS] cfg802...
9
10
11
  #include <linux/if.h>
  #include <linux/module.h>
  #include <linux/err.h>
704232c27   Johannes Berg   [WIRELESS] cfg802...
12
  #include <linux/list.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
13
  #include <linux/slab.h>
704232c27   Johannes Berg   [WIRELESS] cfg802...
14
15
16
17
  #include <linux/nl80211.h>
  #include <linux/debugfs.h>
  #include <linux/notifier.h>
  #include <linux/device.h>
16a832e78   Zhu Yi   cfg80211: allow c...
18
  #include <linux/etherdevice.h>
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
19
  #include <linux/rtnetlink.h>
d43c36dc6   Alexey Dobriyan   headers: remove s...
20
  #include <linux/sched.h>
704232c27   Johannes Berg   [WIRELESS] cfg802...
21
22
  #include <net/genetlink.h>
  #include <net/cfg80211.h>
556829657   Johannes Berg   [NL80211]: add ne...
23
  #include "nl80211.h"
704232c27   Johannes Berg   [WIRELESS] cfg802...
24
25
  #include "core.h"
  #include "sysfs.h"
1ac61302d   Luis R. Rodriguez   mac80211/cfg80211...
26
  #include "debugfs.h"
a9a11622c   Johannes Berg   cfg80211: self-co...
27
  #include "wext-compat.h"
e35e4d28b   Hila Gonen   cfg80211: add wra...
28
  #include "rdev-ops.h"
704232c27   Johannes Berg   [WIRELESS] cfg802...
29
30
31
32
33
34
35
  
  /* name for sysfs, %d is appended */
  #define PHY_NAME "phy"
  
  MODULE_AUTHOR("Johannes Berg");
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("wireless configuration support");
fb4e15688   Marcel Holtmann   nl80211: Add gene...
36
  MODULE_ALIAS_GENL_FAMILY(NL80211_GENL_NAME);
704232c27   Johannes Berg   [WIRELESS] cfg802...
37

5fe231e87   Johannes Berg   cfg80211: vastly ...
38
  /* RCU-protected (and RTNL for writers) */
79c97e97a   Johannes Berg   cfg80211: clean u...
39
  LIST_HEAD(cfg80211_rdev_list);
f5ea9120b   Johannes Berg   nl80211: add gene...
40
  int cfg80211_rdev_list_generation;
a1794390f   Luis R. Rodriguez   cfg80211: rename ...
41

704232c27   Johannes Berg   [WIRELESS] cfg802...
42
43
  /* for debugfs */
  static struct dentry *ieee80211_debugfs_dir;
e60d7443e   Alban Browaeys   wireless : use a ...
44
45
  /* for the cleanup, scan and event works */
  struct workqueue_struct *cfg80211_wq;
40db6c77a   Amitkumar Karwar   cfg80211: module_...
46
47
48
49
  static bool cfg80211_disable_40mhz_24ghz;
  module_param(cfg80211_disable_40mhz_24ghz, bool, 0644);
  MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz,
  		 "Disable 40MHz support in the 2.4GHz band");
79c97e97a   Johannes Berg   cfg80211: clean u...
50
  struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx)
556829657   Johannes Berg   [NL80211]: add ne...
51
  {
79c97e97a   Johannes Berg   cfg80211: clean u...
52
  	struct cfg80211_registered_device *result = NULL, *rdev;
556829657   Johannes Berg   [NL80211]: add ne...
53

5fe231e87   Johannes Berg   cfg80211: vastly ...
54
  	ASSERT_RTNL();
761cf7ecf   Luis R. Rodriguez   cfg80211: add ass...
55

79c97e97a   Johannes Berg   cfg80211: clean u...
56
57
58
  	list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
  		if (rdev->wiphy_idx == wiphy_idx) {
  			result = rdev;
556829657   Johannes Berg   [NL80211]: add ne...
59
60
61
62
63
64
  			break;
  		}
  	}
  
  	return result;
  }
806a9e396   Luis R. Rodriguez   cfg80211: make re...
65
66
  int get_wiphy_idx(struct wiphy *wiphy)
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
67
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
f41737669   Johannes Berg   cfg80211: remove ...
68

79c97e97a   Johannes Berg   cfg80211: clean u...
69
  	return rdev->wiphy_idx;
806a9e396   Luis R. Rodriguez   cfg80211: make re...
70
  }
806a9e396   Luis R. Rodriguez   cfg80211: make re...
71
72
  struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx)
  {
79c97e97a   Johannes Berg   cfg80211: clean u...
73
  	struct cfg80211_registered_device *rdev;
806a9e396   Luis R. Rodriguez   cfg80211: make re...
74

5fe231e87   Johannes Berg   cfg80211: vastly ...
75
  	ASSERT_RTNL();
806a9e396   Luis R. Rodriguez   cfg80211: make re...
76

79c97e97a   Johannes Berg   cfg80211: clean u...
77
78
  	rdev = cfg80211_rdev_by_wiphy_idx(wiphy_idx);
  	if (!rdev)
806a9e396   Luis R. Rodriguez   cfg80211: make re...
79
  		return NULL;
79c97e97a   Johannes Berg   cfg80211: clean u...
80
  	return &rdev->wiphy;
806a9e396   Luis R. Rodriguez   cfg80211: make re...
81
  }
1998d90ad   Ben Greear   cfg80211: support...
82
83
  static int cfg80211_dev_check_name(struct cfg80211_registered_device *rdev,
  				   const char *newname)
556829657   Johannes Berg   [NL80211]: add ne...
84
  {
79c97e97a   Johannes Berg   cfg80211: clean u...
85
  	struct cfg80211_registered_device *rdev2;
1998d90ad   Ben Greear   cfg80211: support...
86
  	int wiphy_idx, taken = -1, digits;
556829657   Johannes Berg   [NL80211]: add ne...
87

5fe231e87   Johannes Berg   cfg80211: vastly ...
88
  	ASSERT_RTNL();
2940bb69f   Eric W. Biederman   wireless: Add mis...
89

9f2c35864   Johannes Berg   cfg80211: limit w...
90
91
  	if (strlen(newname) > NL80211_WIPHY_NAME_MAXLEN)
  		return -EINVAL;
7623225f9   Johannes Berg   Revert "wireless:...
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  	/* prohibit calling the thing phy%d when %d is not its number */
  	sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken);
  	if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) {
  		/* count number of places needed to print wiphy_idx */
  		digits = 1;
  		while (wiphy_idx /= 10)
  			digits++;
  		/*
  		 * deny the name if it is phy<idx> where <idx> is printed
  		 * without leading zeroes. taken == strlen(newname) here
  		 */
  		if (taken == strlen(PHY_NAME) + digits)
  			return -EINVAL;
  	}
1998d90ad   Ben Greear   cfg80211: support...
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  	/* Ensure another device does not already have this name. */
  	list_for_each_entry(rdev2, &cfg80211_rdev_list, list)
  		if (strcmp(newname, wiphy_name(&rdev2->wiphy)) == 0)
  			return -EINVAL;
  
  	return 0;
  }
  
  int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
  			char *newname)
  {
  	int result;
  
  	ASSERT_RTNL();
7623225f9   Johannes Berg   Revert "wireless:...
120

2940bb69f   Eric W. Biederman   wireless: Add mis...
121
  	/* Ignore nop renames */
1998d90ad   Ben Greear   cfg80211: support...
122
  	if (strcmp(newname, wiphy_name(&rdev->wiphy)) == 0)
4bbf4d565   Johannes Berg   cfg80211: fix loc...
123
  		return 0;
2940bb69f   Eric W. Biederman   wireless: Add mis...
124

1998d90ad   Ben Greear   cfg80211: support...
125
126
127
  	result = cfg80211_dev_check_name(rdev, newname);
  	if (result < 0)
  		return result;
556829657   Johannes Berg   [NL80211]: add ne...
128

556829657   Johannes Berg   [NL80211]: add ne...
129
130
  	result = device_rename(&rdev->wiphy.dev, newname);
  	if (result)
4bbf4d565   Johannes Berg   cfg80211: fix loc...
131
  		return result;
556829657   Johannes Berg   [NL80211]: add ne...
132

33c0360bf   Johannes Berg   cfg80211: fix deb...
133
134
  	if (rdev->wiphy.debugfsdir &&
  	    !debugfs_rename(rdev->wiphy.debugfsdir->d_parent,
556829657   Johannes Berg   [NL80211]: add ne...
135
136
137
  			    rdev->wiphy.debugfsdir,
  			    rdev->wiphy.debugfsdir->d_parent,
  			    newname))
e9c0268f0   Joe Perches   net/wireless: Use...
138
139
  		pr_err("failed to rename debugfs dir to %s!
  ", newname);
556829657   Johannes Berg   [NL80211]: add ne...
140

3bb205567   Johannes Berg   cfg80211: send ev...
141
  	nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY);
556829657   Johannes Berg   [NL80211]: add ne...
142

4bbf4d565   Johannes Berg   cfg80211: fix loc...
143
  	return 0;
556829657   Johannes Berg   [NL80211]: add ne...
144
  }
463d01832   Johannes Berg   cfg80211: make aw...
145
146
147
148
149
  int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
  			  struct net *net)
  {
  	struct wireless_dev *wdev;
  	int err = 0;
5be83de54   Johannes Berg   cfg80211: convert...
150
  	if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK))
463d01832   Johannes Berg   cfg80211: make aw...
151
  		return -EOPNOTSUPP;
53873f134   Johannes Berg   cfg80211: make wd...
152
  	list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
ba22fb5b2   Johannes Berg   nl80211: don't as...
153
154
  		if (!wdev->netdev)
  			continue;
463d01832   Johannes Berg   cfg80211: make aw...
155
156
157
158
159
160
161
162
163
164
  		wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
  		err = dev_change_net_namespace(wdev->netdev, net, "wlan%d");
  		if (err)
  			break;
  		wdev->netdev->features |= NETIF_F_NETNS_LOCAL;
  	}
  
  	if (err) {
  		/* failed -- clean up to old netns */
  		net = wiphy_net(&rdev->wiphy);
53873f134   Johannes Berg   cfg80211: make wd...
165
166
  		list_for_each_entry_continue_reverse(wdev,
  						     &rdev->wiphy.wdev_list,
463d01832   Johannes Berg   cfg80211: make aw...
167
  						     list) {
ba22fb5b2   Johannes Berg   nl80211: don't as...
168
169
  			if (!wdev->netdev)
  				continue;
463d01832   Johannes Berg   cfg80211: make aw...
170
171
172
173
174
175
  			wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
  			err = dev_change_net_namespace(wdev->netdev, net,
  							"wlan%d");
  			WARN_ON(err);
  			wdev->netdev->features |= NETIF_F_NETNS_LOCAL;
  		}
046007949   Johannes Berg   cfg80211: support...
176
177
  
  		return err;
463d01832   Johannes Berg   cfg80211: make aw...
178
179
180
  	}
  
  	wiphy_net_set(&rdev->wiphy, net);
046007949   Johannes Berg   cfg80211: support...
181
182
183
184
  	err = device_rename(&rdev->wiphy.dev, dev_name(&rdev->wiphy.dev));
  	WARN_ON(err);
  
  	return 0;
463d01832   Johannes Berg   cfg80211: make aw...
185
  }
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
186
187
  static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
  {
79c97e97a   Johannes Berg   cfg80211: clean u...
188
  	struct cfg80211_registered_device *rdev = data;
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
189

e35e4d28b   Hila Gonen   cfg80211: add wra...
190
  	rdev_rfkill_poll(rdev);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
191
  }
f9f475292   Johannes Berg   cfg80211: always ...
192
193
194
  void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
  			      struct wireless_dev *wdev)
  {
5fe231e87   Johannes Berg   cfg80211: vastly ...
195
  	ASSERT_RTNL();
f9f475292   Johannes Berg   cfg80211: always ...
196
197
198
  
  	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE))
  		return;
73c7da3da   Arend Van Spriel   cfg80211: add gen...
199
  	if (!wdev_running(wdev))
f9f475292   Johannes Berg   cfg80211: always ...
200
201
202
  		return;
  
  	rdev_stop_p2p_device(rdev, wdev);
73c7da3da   Arend Van Spriel   cfg80211: add gen...
203
  	wdev->is_running = false;
f9f475292   Johannes Berg   cfg80211: always ...
204
205
  
  	rdev->opencount--;
a617302c5   Johannes Berg   cfg80211: fix sca...
206
207
  	if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
  		if (WARN_ON(!rdev->scan_req->notified))
1d76250bd   Avraham Stern   nl80211: support ...
208
  			rdev->scan_req->info.aborted = true;
f9d15d162   Johannes Berg   cfg80211: send sc...
209
  		___cfg80211_scan_done(rdev, false);
a617302c5   Johannes Berg   cfg80211: fix sca...
210
  	}
f9f475292   Johannes Berg   cfg80211: always ...
211
  }
cb3b7d876   Ayala Beker   cfg80211: add sta...
212
213
214
215
216
217
218
  void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
  		       struct wireless_dev *wdev)
  {
  	ASSERT_RTNL();
  
  	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_NAN))
  		return;
73c7da3da   Arend Van Spriel   cfg80211: add gen...
219
  	if (!wdev_running(wdev))
cb3b7d876   Ayala Beker   cfg80211: add sta...
220
221
222
  		return;
  
  	rdev_stop_nan(rdev, wdev);
73c7da3da   Arend Van Spriel   cfg80211: add gen...
223
  	wdev->is_running = false;
cb3b7d876   Ayala Beker   cfg80211: add sta...
224
225
226
  
  	rdev->opencount--;
  }
f6837ba8c   Johannes Berg   mac80211: handle ...
227
  void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
228
  {
f6837ba8c   Johannes Berg   mac80211: handle ...
229
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
230
  	struct wireless_dev *wdev;
f6837ba8c   Johannes Berg   mac80211: handle ...
231
  	ASSERT_RTNL();
f9f475292   Johannes Berg   cfg80211: always ...
232

53873f134   Johannes Berg   cfg80211: make wd...
233
  	list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
98104fded   Johannes Berg   cfg80211: add P2P...
234
  		if (wdev->netdev) {
ba22fb5b2   Johannes Berg   nl80211: don't as...
235
  			dev_close(wdev->netdev);
98104fded   Johannes Berg   cfg80211: add P2P...
236
237
238
239
240
  			continue;
  		}
  		/* otherwise, check iftype */
  		switch (wdev->iftype) {
  		case NL80211_IFTYPE_P2P_DEVICE:
f9f475292   Johannes Berg   cfg80211: always ...
241
  			cfg80211_stop_p2p_device(rdev, wdev);
98104fded   Johannes Berg   cfg80211: add P2P...
242
  			break;
cb3b7d876   Ayala Beker   cfg80211: add sta...
243
244
245
  		case NL80211_IFTYPE_NAN:
  			cfg80211_stop_nan(rdev, wdev);
  			break;
98104fded   Johannes Berg   cfg80211: add P2P...
246
247
248
249
  		default:
  			break;
  		}
  	}
f6837ba8c   Johannes Berg   mac80211: handle ...
250
251
  }
  EXPORT_SYMBOL_GPL(cfg80211_shutdown_all_interfaces);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
252

f6837ba8c   Johannes Berg   mac80211: handle ...
253
254
255
256
257
258
259
260
261
  static int cfg80211_rfkill_set_block(void *data, bool blocked)
  {
  	struct cfg80211_registered_device *rdev = data;
  
  	if (!blocked)
  		return 0;
  
  	rtnl_lock();
  	cfg80211_shutdown_all_interfaces(&rdev->wiphy);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
262
263
264
265
266
267
268
  	rtnl_unlock();
  
  	return 0;
  }
  
  static void cfg80211_rfkill_sync_work(struct work_struct *work)
  {
79c97e97a   Johannes Berg   cfg80211: clean u...
269
  	struct cfg80211_registered_device *rdev;
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
270

79c97e97a   Johannes Berg   cfg80211: clean u...
271
272
  	rdev = container_of(work, struct cfg80211_registered_device, rfkill_sync);
  	cfg80211_rfkill_set_block(rdev, rfkill_blocked(rdev->rfkill));
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
273
  }
667503ddc   Johannes Berg   cfg80211: fix loc...
274
275
276
  static void cfg80211_event_work(struct work_struct *work)
  {
  	struct cfg80211_registered_device *rdev;
667503ddc   Johannes Berg   cfg80211: fix loc...
277
278
279
280
281
  
  	rdev = container_of(work, struct cfg80211_registered_device,
  			    event_work);
  
  	rtnl_lock();
3d54d2551   Johannes Berg   cfg80211: clean u...
282
  	cfg80211_process_rdev_events(rdev);
667503ddc   Johannes Berg   cfg80211: fix loc...
283
284
  	rtnl_unlock();
  }
78f22b6a3   Johannes Berg   cfg80211: allow u...
285
286
  void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev)
  {
ab81007a7   Johannes Berg   cfg80211: simplif...
287
  	struct wireless_dev *wdev, *tmp;
78f22b6a3   Johannes Berg   cfg80211: allow u...
288
289
  
  	ASSERT_RTNL();
ab81007a7   Johannes Berg   cfg80211: simplif...
290
291
292
  	list_for_each_entry_safe(wdev, tmp, &rdev->wiphy.wdev_list, list) {
  		if (wdev->nl_owner_dead)
  			rdev_del_virtual_intf(rdev, wdev);
78f22b6a3   Johannes Berg   cfg80211: allow u...
293
  	}
78f22b6a3   Johannes Berg   cfg80211: allow u...
294
295
296
297
298
299
300
301
302
303
304
305
306
  }
  
  static void cfg80211_destroy_iface_wk(struct work_struct *work)
  {
  	struct cfg80211_registered_device *rdev;
  
  	rdev = container_of(work, struct cfg80211_registered_device,
  			    destroy_work);
  
  	rtnl_lock();
  	cfg80211_destroy_ifaces(rdev);
  	rtnl_unlock();
  }
93a1e86ce   Jukka Rissanen   nl80211: Stop sch...
307
308
309
  static void cfg80211_sched_scan_stop_wk(struct work_struct *work)
  {
  	struct cfg80211_registered_device *rdev;
ca986ad9b   Arend Van Spriel   nl80211: allow mu...
310
  	struct cfg80211_sched_scan_request *req, *tmp;
93a1e86ce   Jukka Rissanen   nl80211: Stop sch...
311
312
313
314
315
  
  	rdev = container_of(work, struct cfg80211_registered_device,
  			   sched_scan_stop_wk);
  
  	rtnl_lock();
ca986ad9b   Arend Van Spriel   nl80211: allow mu...
316
317
318
319
  	list_for_each_entry_safe(req, tmp, &rdev->sched_scan_req_list, list) {
  		if (req->nl_owner_dead)
  			cfg80211_stop_sched_scan_req(rdev, req, false);
  	}
93a1e86ce   Jukka Rissanen   nl80211: Stop sch...
320
321
  	rtnl_unlock();
  }
897667273   Vasanthakumar Thiagarajan   cfg80211: Share C...
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
  static void cfg80211_propagate_radar_detect_wk(struct work_struct *work)
  {
  	struct cfg80211_registered_device *rdev;
  
  	rdev = container_of(work, struct cfg80211_registered_device,
  			    propagate_radar_detect_wk);
  
  	rtnl_lock();
  
  	regulatory_propagate_dfs_state(&rdev->wiphy, &rdev->radar_chandef,
  				       NL80211_DFS_UNAVAILABLE,
  				       NL80211_RADAR_DETECTED);
  
  	rtnl_unlock();
  }
  
  static void cfg80211_propagate_cac_done_wk(struct work_struct *work)
  {
  	struct cfg80211_registered_device *rdev;
  
  	rdev = container_of(work, struct cfg80211_registered_device,
  			    propagate_cac_done_wk);
  
  	rtnl_lock();
  
  	regulatory_propagate_dfs_state(&rdev->wiphy, &rdev->cac_done_chandef,
  				       NL80211_DFS_AVAILABLE,
  				       NL80211_RADAR_CAC_FINISHED);
  
  	rtnl_unlock();
  }
704232c27   Johannes Berg   [WIRELESS] cfg802...
353
  /* exported functions */
1998d90ad   Ben Greear   cfg80211: support...
354
355
  struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
  			   const char *requested_name)
704232c27   Johannes Berg   [WIRELESS] cfg802...
356
  {
c539d271c   Andy Duan   MLK-20541 cfg8021...
357
  	static atomic_t wiphy_counter = ATOMIC_INIT(0);
7623225f9   Johannes Berg   Revert "wireless:...
358
  	struct cfg80211_registered_device *rdev;
704232c27   Johannes Berg   [WIRELESS] cfg802...
359
  	int alloc_size;
0b20633d9   Johannes Berg   cfg80211: disallo...
360
361
362
363
364
365
366
  	WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key));
  	WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc));
  	WARN_ON(ops->connect && !ops->disconnect);
  	WARN_ON(ops->join_ibss && !ops->leave_ibss);
  	WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf);
  	WARN_ON(ops->add_station && !ops->del_station);
  	WARN_ON(ops->add_mpath && !ops->del_mpath);
29cbe68c5   Johannes Berg   cfg80211/mac80211...
367
  	WARN_ON(ops->join_mesh && !ops->leave_mesh);
de3bb771f   Ola Olsson   cfg80211: add mor...
368
369
370
371
372
373
374
375
  	WARN_ON(ops->start_p2p_device && !ops->stop_p2p_device);
  	WARN_ON(ops->start_ap && !ops->stop_ap);
  	WARN_ON(ops->join_ocb && !ops->leave_ocb);
  	WARN_ON(ops->suspend && !ops->resume);
  	WARN_ON(ops->sched_scan_start && !ops->sched_scan_stop);
  	WARN_ON(ops->remain_on_channel && !ops->cancel_remain_on_channel);
  	WARN_ON(ops->tdls_channel_switch && !ops->tdls_cancel_channel_switch);
  	WARN_ON(ops->add_tx_ts && !ops->del_tx_ts);
41ade00f2   Johannes Berg   cfg80211/nl80211:...
376

79c97e97a   Johannes Berg   cfg80211: clean u...
377
  	alloc_size = sizeof(*rdev) + sizeof_priv;
704232c27   Johannes Berg   [WIRELESS] cfg802...
378

79c97e97a   Johannes Berg   cfg80211: clean u...
379
380
  	rdev = kzalloc(alloc_size, GFP_KERNEL);
  	if (!rdev)
704232c27   Johannes Berg   [WIRELESS] cfg802...
381
  		return NULL;
79c97e97a   Johannes Berg   cfg80211: clean u...
382
  	rdev->ops = ops;
704232c27   Johannes Berg   [WIRELESS] cfg802...
383

73810b77d   Johannes Berg   cfg80211: use ato...
384
  	rdev->wiphy_idx = atomic_inc_return(&wiphy_counter);
a4d73ee16   Johannes Berg   [WIRELESS] cfg802...
385

f41737669   Johannes Berg   cfg80211: remove ...
386
  	if (unlikely(rdev->wiphy_idx < 0)) {
7623225f9   Johannes Berg   Revert "wireless:...
387
  		/* ugh, wrapped! */
73810b77d   Johannes Berg   cfg80211: use ato...
388
  		atomic_dec(&wiphy_counter);
79c97e97a   Johannes Berg   cfg80211: clean u...
389
  		kfree(rdev);
704232c27   Johannes Berg   [WIRELESS] cfg802...
390
391
  		return NULL;
  	}
704232c27   Johannes Berg   [WIRELESS] cfg802...
392

9b881963c   Johannes Berg   cfg80211: make wi...
393
394
  	/* atomic_inc_return makes it start at 1, make it start at 0 */
  	rdev->wiphy_idx--;
7623225f9   Johannes Berg   Revert "wireless:...
395
  	/* give it a proper name */
1998d90ad   Ben Greear   cfg80211: support...
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
  	if (requested_name && requested_name[0]) {
  		int rv;
  
  		rtnl_lock();
  		rv = cfg80211_dev_check_name(rdev, requested_name);
  
  		if (rv < 0) {
  			rtnl_unlock();
  			goto use_default_name;
  		}
  
  		rv = dev_set_name(&rdev->wiphy.dev, "%s", requested_name);
  		rtnl_unlock();
  		if (rv)
  			goto use_default_name;
  	} else {
b9e441e2e   Johannes Berg   cfg80211: check d...
412
  		int rv;
1998d90ad   Ben Greear   cfg80211: support...
413
414
415
416
417
418
419
  use_default_name:
  		/* NOTE:  This is *probably* safe w/out holding rtnl because of
  		 * the restrictions on phy names.  Probably this call could
  		 * fail if some other part of the kernel (re)named a device
  		 * phyX.  But, might should add some locking and check return
  		 * value, and use a different name if this one exists?
  		 */
b9e441e2e   Johannes Berg   cfg80211: check d...
420
421
422
423
424
  		rv = dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
  		if (rv < 0) {
  			kfree(rdev);
  			return NULL;
  		}
1998d90ad   Ben Greear   cfg80211: support...
425
  	}
7623225f9   Johannes Berg   Revert "wireless:...
426

53873f134   Johannes Berg   cfg80211: make wd...
427
  	INIT_LIST_HEAD(&rdev->wiphy.wdev_list);
37c73b5f3   Ben Greear   cfg80211: allow r...
428
429
  	INIT_LIST_HEAD(&rdev->beacon_registrations);
  	spin_lock_init(&rdev->beacon_registrations_lock);
79c97e97a   Johannes Berg   cfg80211: clean u...
430
431
  	spin_lock_init(&rdev->bss_lock);
  	INIT_LIST_HEAD(&rdev->bss_list);
ca986ad9b   Arend Van Spriel   nl80211: allow mu...
432
  	INIT_LIST_HEAD(&rdev->sched_scan_req_list);
79c97e97a   Johannes Berg   cfg80211: clean u...
433
  	INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
33d8783c5   Johannes Berg   cfg80211: allow m...
434
435
436
  	INIT_LIST_HEAD(&rdev->mlme_unreg);
  	spin_lock_init(&rdev->mlme_unreg_lock);
  	INIT_WORK(&rdev->mlme_unreg_wk, cfg80211_mlme_unreg_wk);
04f39047a   Simon Wunderlich   nl80211/cfg80211:...
437
438
  	INIT_DELAYED_WORK(&rdev->dfs_update_channels_wk,
  			  cfg80211_dfs_channels_update_work);
3d23e349d   Johannes Berg   wext: refactor
439
440
441
  #ifdef CONFIG_CFG80211_WEXT
  	rdev->wiphy.wext = &cfg80211_wext_handler;
  #endif
79c97e97a   Johannes Berg   cfg80211: clean u...
442
443
444
  	device_initialize(&rdev->wiphy.dev);
  	rdev->wiphy.dev.class = &ieee80211_class;
  	rdev->wiphy.dev.platform_data = rdev;
9f0e13546   Fu, Zhonghui   net/wireless: ena...
445
  	device_enable_async_suspend(&rdev->wiphy.dev);
79c97e97a   Johannes Berg   cfg80211: clean u...
446

78f22b6a3   Johannes Berg   cfg80211: allow u...
447
  	INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk);
93a1e86ce   Jukka Rissanen   nl80211: Stop sch...
448
  	INIT_WORK(&rdev->sched_scan_stop_wk, cfg80211_sched_scan_stop_wk);
b34939b98   Arend Van Spriel   cfg80211: add req...
449
  	INIT_WORK(&rdev->sched_scan_res_wk, cfg80211_sched_scan_results_wk);
897667273   Vasanthakumar Thiagarajan   cfg80211: Share C...
450
451
452
  	INIT_WORK(&rdev->propagate_radar_detect_wk,
  		  cfg80211_propagate_radar_detect_wk);
  	INIT_WORK(&rdev->propagate_cac_done_wk, cfg80211_propagate_cac_done_wk);
78f22b6a3   Johannes Berg   cfg80211: allow u...
453

5be83de54   Johannes Berg   cfg80211: convert...
454
455
456
  #ifdef CONFIG_CFG80211_DEFAULT_PS
  	rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
  #endif
16cb9d42b   Johannes Berg   cfg80211: allow d...
457

463d01832   Johannes Berg   cfg80211: make aw...
458
  	wiphy_net_set(&rdev->wiphy, &init_net);
79c97e97a   Johannes Berg   cfg80211: clean u...
459
460
461
462
463
464
465
  	rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block;
  	rdev->rfkill = rfkill_alloc(dev_name(&rdev->wiphy.dev),
  				   &rdev->wiphy.dev, RFKILL_TYPE_WLAN,
  				   &rdev->rfkill_ops, rdev);
  
  	if (!rdev->rfkill) {
  		kfree(rdev);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
466
467
  		return NULL;
  	}
79c97e97a   Johannes Berg   cfg80211: clean u...
468
469
470
  	INIT_WORK(&rdev->rfkill_sync, cfg80211_rfkill_sync_work);
  	INIT_WORK(&rdev->conn_work, cfg80211_conn_work);
  	INIT_WORK(&rdev->event_work, cfg80211_event_work);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
471

ad002395f   Johannes Berg   cfg80211: fix dan...
472
  	init_waitqueue_head(&rdev->dev_wait);
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
473
474
475
476
477
  	/*
  	 * Initialize wiphy parameters to IEEE 802.11 MIB default values.
  	 * Fragmentation and RTS threshold are disabled by default with the
  	 * special -1 value.
  	 */
79c97e97a   Johannes Berg   cfg80211: clean u...
478
479
480
481
  	rdev->wiphy.retry_short = 7;
  	rdev->wiphy.retry_long = 4;
  	rdev->wiphy.frag_threshold = (u32) -1;
  	rdev->wiphy.rts_threshold = (u32) -1;
81077e82c   Lukáš Turek   nl80211: Add new ...
482
  	rdev->wiphy.coverage_class = 0;
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
483

9a774c78e   Andrei Otcheretianski   cfg80211: Support...
484
  	rdev->wiphy.max_num_csa_counters = 1;
3b06d2779   Avraham Stern   cfg80211: Add mul...
485
486
  	rdev->wiphy.max_sched_scan_plans = 1;
  	rdev->wiphy.max_sched_scan_plan_interval = U32_MAX;
79c97e97a   Johannes Berg   cfg80211: clean u...
487
  	return &rdev->wiphy;
704232c27   Johannes Berg   [WIRELESS] cfg802...
488
  }
1998d90ad   Ben Greear   cfg80211: support...
489
  EXPORT_SYMBOL(wiphy_new_nm);
704232c27   Johannes Berg   [WIRELESS] cfg802...
490

7527a782e   Johannes Berg   cfg80211: adverti...
491
492
493
494
  static int wiphy_verify_combinations(struct wiphy *wiphy)
  {
  	const struct ieee80211_iface_combination *c;
  	int i, j;
7527a782e   Johannes Berg   cfg80211: adverti...
495
496
497
498
499
  	for (i = 0; i < wiphy->n_iface_combinations; i++) {
  		u32 cnt = 0;
  		u16 all_iftypes = 0;
  
  		c = &wiphy->iface_combinations[i];
11c4a075d   Simon Wunderlich   cfg80211: check r...
500
501
502
503
504
  		/*
  		 * Combinations with just one interface aren't real,
  		 * however we make an exception for DFS.
  		 */
  		if (WARN_ON((c->max_interfaces < 2) && !c->radar_detect_widths))
7527a782e   Johannes Berg   cfg80211: adverti...
505
506
507
508
509
  			return -EINVAL;
  
  		/* Need at least one channel */
  		if (WARN_ON(!c->num_different_channels))
  			return -EINVAL;
d4e50c591   Michal Kazior   cfg80211: add cha...
510
511
512
513
514
515
516
  		/*
  		 * Put a sane limit on maximum number of different
  		 * channels to simplify channel accounting code.
  		 */
  		if (WARN_ON(c->num_different_channels >
  				CFG80211_MAX_NUM_DIFFERENT_CHANNELS))
  			return -EINVAL;
11c4a075d   Simon Wunderlich   cfg80211: check r...
517
518
519
520
  		/* DFS only works on one channel. */
  		if (WARN_ON(c->radar_detect_widths &&
  			    (c->num_different_channels > 1)))
  			return -EINVAL;
7527a782e   Johannes Berg   cfg80211: adverti...
521
522
523
524
525
  		if (WARN_ON(!c->n_limits))
  			return -EINVAL;
  
  		for (j = 0; j < c->n_limits; j++) {
  			u16 types = c->limits[j].types;
b6a550156   Luciano Coelho   cfg80211/mac80211...
526
  			/* interface types shouldn't overlap */
7527a782e   Johannes Berg   cfg80211: adverti...
527
528
529
530
531
532
533
534
535
536
  			if (WARN_ON(types & all_iftypes))
  				return -EINVAL;
  			all_iftypes |= types;
  
  			if (WARN_ON(!c->limits[j].max))
  				return -EINVAL;
  
  			/* Shouldn't list software iftypes in combinations! */
  			if (WARN_ON(wiphy->software_iftypes & types))
  				return -EINVAL;
98104fded   Johannes Berg   cfg80211: add P2P...
537
538
539
540
  			/* Only a single P2P_DEVICE can be allowed */
  			if (WARN_ON(types & BIT(NL80211_IFTYPE_P2P_DEVICE) &&
  				    c->limits[j].max > 1))
  				return -EINVAL;
cb3b7d876   Ayala Beker   cfg80211: add sta...
541
542
543
544
  			/* Only a single NAN can be allowed */
  			if (WARN_ON(types & BIT(NL80211_IFTYPE_NAN) &&
  				    c->limits[j].max > 1))
  				return -EINVAL;
56271da29   Johannes Berg   cfg80211: disallo...
545
546
547
548
549
550
551
552
553
554
555
556
557
558
  			/*
  			 * This isn't well-defined right now. If you have an
  			 * IBSS interface, then its beacon interval may change
  			 * by joining other networks, and nothing prevents it
  			 * from doing that.
  			 * So technically we probably shouldn't even allow AP
  			 * and IBSS in the same interface, but it seems that
  			 * some drivers support that, possibly only with fixed
  			 * beacon intervals for IBSS.
  			 */
  			if (WARN_ON(types & BIT(NL80211_IFTYPE_ADHOC) &&
  				    c->beacon_int_min_gcd)) {
  				return -EINVAL;
  			}
7527a782e   Johannes Berg   cfg80211: adverti...
559
560
561
562
563
564
565
566
  			cnt += c->limits[j].max;
  			/*
  			 * Don't advertise an unsupported type
  			 * in a combination.
  			 */
  			if (WARN_ON((wiphy->interface_modes & types) != types))
  				return -EINVAL;
  		}
8f2054238   Johannes Berg   wireless: depreca...
567
568
569
570
  #ifndef CONFIG_WIRELESS_WDS
  		if (WARN_ON(all_iftypes & BIT(NL80211_IFTYPE_WDS)))
  			return -EINVAL;
  #endif
7527a782e   Johannes Berg   cfg80211: adverti...
571
572
573
574
575
576
577
  		/* You can't even choose that many! */
  		if (WARN_ON(cnt < c->max_interfaces))
  			return -EINVAL;
  	}
  
  	return 0;
  }
704232c27   Johannes Berg   [WIRELESS] cfg802...
578
579
  int wiphy_register(struct wiphy *wiphy)
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
580
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
704232c27   Johannes Berg   [WIRELESS] cfg802...
581
  	int res;
57fbcce37   Johannes Berg   cfg80211: remove ...
582
  	enum nl80211_band band;
8318d78a4   Johannes Berg   cfg80211 API for ...
583
584
585
  	struct ieee80211_supported_band *sband;
  	bool have_band = false;
  	int i;
f59ac0481   Luis R. Rodriguez   cfg80211: keep tr...
586
  	u16 ifmodes = wiphy->interface_modes;
dfb89c56a   Johannes Berg   cfg80211: don't a...
587
  #ifdef CONFIG_PM
964dc9e2c   Johannes Berg   cfg80211: take Wo...
588
589
590
591
592
593
594
  	if (WARN_ON(wiphy->wowlan &&
  		    (wiphy->wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
  		    !(wiphy->wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY)))
  		return -EINVAL;
  	if (WARN_ON(wiphy->wowlan &&
  		    !wiphy->wowlan->flags && !wiphy->wowlan->n_patterns &&
  		    !wiphy->wowlan->tcp))
77dbbb138   Johannes Berg   nl80211: advertis...
595
  		return -EINVAL;
dfb89c56a   Johannes Berg   cfg80211: don't a...
596
  #endif
1057d35ed   Arik Nemtsov   cfg80211: introdu...
597
598
599
600
  	if (WARN_ON((wiphy->features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) &&
  		    (!rdev->ops->tdls_channel_switch ||
  		     !rdev->ops->tdls_cancel_channel_switch)))
  		return -EINVAL;
77dbbb138   Johannes Berg   nl80211: advertis...
601

cb3b7d876   Ayala Beker   cfg80211: add sta...
602
  	if (WARN_ON((wiphy->interface_modes & BIT(NL80211_IFTYPE_NAN)) &&
a442b761b   Ayala Beker   cfg80211: add add...
603
  		    (!rdev->ops->start_nan || !rdev->ops->stop_nan ||
8585989d1   Luca Coelho   cfg80211: fix NAN...
604
605
  		     !rdev->ops->add_nan_func || !rdev->ops->del_nan_func ||
  		     !(wiphy->nan_supported_bands & BIT(NL80211_BAND_2GHZ)))))
cb3b7d876   Ayala Beker   cfg80211: add sta...
606
  		return -EINVAL;
8f2054238   Johannes Berg   wireless: depreca...
607
608
609
610
  #ifndef CONFIG_WIRELESS_WDS
  	if (WARN_ON(wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)))
  		return -EINVAL;
  #endif
ad932f046   Arik Nemtsov   cfg80211: leave i...
611
612
613
614
615
616
617
618
619
620
  	/*
  	 * if a wiphy has unsupported modes for regulatory channel enforcement,
  	 * opt-out of enforcement checking
  	 */
  	if (wiphy->interface_modes & ~(BIT(NL80211_IFTYPE_STATION) |
  				       BIT(NL80211_IFTYPE_P2P_CLIENT) |
  				       BIT(NL80211_IFTYPE_AP) |
  				       BIT(NL80211_IFTYPE_P2P_GO) |
  				       BIT(NL80211_IFTYPE_ADHOC) |
  				       BIT(NL80211_IFTYPE_P2P_DEVICE) |
cb3b7d876   Ayala Beker   cfg80211: add sta...
621
  				       BIT(NL80211_IFTYPE_NAN) |
ad932f046   Arik Nemtsov   cfg80211: leave i...
622
623
624
  				       BIT(NL80211_IFTYPE_AP_VLAN) |
  				       BIT(NL80211_IFTYPE_MONITOR)))
  		wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF;
b0d7aa595   Jonathan Doron   cfg80211: allow w...
625
626
627
628
629
630
631
  	if (WARN_ON((wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) &&
  		    (wiphy->regulatory_flags &
  					(REGULATORY_CUSTOM_REG |
  					 REGULATORY_STRICT_REG |
  					 REGULATORY_COUNTRY_IE_FOLLOW_POWER |
  					 REGULATORY_COUNTRY_IE_IGNORE))))
  		return -EINVAL;
be29b99a9   Amitkumar Karwar   cfg80211/nl80211:...
632
633
634
635
636
637
638
  	if (WARN_ON(wiphy->coalesce &&
  		    (!wiphy->coalesce->n_rules ||
  		     !wiphy->coalesce->n_patterns) &&
  		    (!wiphy->coalesce->pattern_min_len ||
  		     wiphy->coalesce->pattern_min_len >
  			wiphy->coalesce->pattern_max_len)))
  		return -EINVAL;
562a74803   Johannes Berg   nl80211: advertis...
639
640
641
  	if (WARN_ON(wiphy->ap_sme_capa &&
  		    !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME)))
  		return -EINVAL;
ef15aac60   Johannes Berg   cfg80211: export ...
642
643
644
645
646
647
648
649
  	if (WARN_ON(wiphy->addresses && !wiphy->n_addresses))
  		return -EINVAL;
  
  	if (WARN_ON(wiphy->addresses &&
  		    !is_zero_ether_addr(wiphy->perm_addr) &&
  		    memcmp(wiphy->perm_addr, wiphy->addresses[0].addr,
  			   ETH_ALEN)))
  		return -EINVAL;
77765eaf5   Vasanthakumar Thiagarajan   cfg80211/nl80211:...
650
651
652
653
  	if (WARN_ON(wiphy->max_acl_mac_addrs &&
  		    (!(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME) ||
  		     !rdev->ops->set_mac_acl)))
  		return -EINVAL;
38de03d2a   Arend van Spriel   nl80211: add feat...
654
655
656
657
658
659
  	/* assure only valid behaviours are flagged by driver
  	 * hence subtract 2 as bit 0 is invalid.
  	 */
  	if (WARN_ON(wiphy->bss_select_support &&
  		    (wiphy->bss_select_support & ~(BIT(__NL80211_BSS_SELECT_ATTR_AFTER_LAST) - 2))))
  		return -EINVAL;
3a00df570   Avraham Stern   cfg80211: support...
660
661
662
663
  	if (WARN_ON(wiphy_ext_feature_isset(&rdev->wiphy,
  					    NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X) &&
  		    (!rdev->ops->set_pmk || !rdev->ops->del_pmk)))
  		return -EINVAL;
ef15aac60   Johannes Berg   cfg80211: export ...
664
665
  	if (wiphy->addresses)
  		memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN);
f59ac0481   Luis R. Rodriguez   cfg80211: keep tr...
666
667
  	/* sanity check ifmodes */
  	WARN_ON(!ifmodes);
2e161f78e   Johannes Berg   cfg80211/mac80211...
668
  	ifmodes &= ((1 << NUM_NL80211_IFTYPES) - 1) & ~1;
f59ac0481   Luis R. Rodriguez   cfg80211: keep tr...
669
670
  	if (WARN_ON(ifmodes != wiphy->interface_modes))
  		wiphy->interface_modes = ifmodes;
8318d78a4   Johannes Berg   cfg80211 API for ...
671

7527a782e   Johannes Berg   cfg80211: adverti...
672
673
674
  	res = wiphy_verify_combinations(wiphy);
  	if (res)
  		return res;
8318d78a4   Johannes Berg   cfg80211 API for ...
675
  	/* sanity check supported bands/channels */
57fbcce37   Johannes Berg   cfg80211: remove ...
676
  	for (band = 0; band < NUM_NL80211_BANDS; band++) {
8318d78a4   Johannes Berg   cfg80211 API for ...
677
678
679
680
681
  		sband = wiphy->bands[band];
  		if (!sband)
  			continue;
  
  		sband->band = band;
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
682
683
684
  		if (WARN_ON(!sband->n_channels))
  			return -EINVAL;
  		/*
8047d2616   Johannes Berg   cfg80211: fix gHz...
685
  		 * on 60GHz band, there are no legacy rates, so
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
686
687
  		 * n_bitrates is 0
  		 */
57fbcce37   Johannes Berg   cfg80211: remove ...
688
  		if (WARN_ON(band != NL80211_BAND_60GHZ &&
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
689
  			    !sband->n_bitrates))
881d948c2   Johannes Berg   wireless: restric...
690
691
692
  			return -EINVAL;
  
  		/*
40db6c77a   Amitkumar Karwar   cfg80211: module_...
693
694
695
696
697
  		 * Since cfg80211_disable_40mhz_24ghz is global, we can
  		 * modify the sband's ht data even if the driver uses a
  		 * global structure for that.
  		 */
  		if (cfg80211_disable_40mhz_24ghz &&
57fbcce37   Johannes Berg   cfg80211: remove ...
698
  		    band == NL80211_BAND_2GHZ &&
40db6c77a   Amitkumar Karwar   cfg80211: module_...
699
700
701
702
703
704
  		    sband->ht_cap.ht_supported) {
  			sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
  			sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40;
  		}
  
  		/*
881d948c2   Johannes Berg   wireless: restric...
705
706
707
708
709
  		 * Since we use a u32 for rate bitmaps in
  		 * ieee80211_get_response_rate, we cannot
  		 * have more than 32 legacy rates.
  		 */
  		if (WARN_ON(sband->n_bitrates > 32))
8318d78a4   Johannes Berg   cfg80211 API for ...
710
  			return -EINVAL;
8318d78a4   Johannes Berg   cfg80211 API for ...
711
712
713
714
  
  		for (i = 0; i < sband->n_channels; i++) {
  			sband->channels[i].orig_flags =
  				sband->channels[i].flags;
c4a9fafc7   Felix Fietkau   cfg80211: fix ant...
715
  			sband->channels[i].orig_mag = INT_MAX;
8318d78a4   Johannes Berg   cfg80211 API for ...
716
717
718
719
720
721
722
723
724
725
726
727
  			sband->channels[i].orig_mpwr =
  				sband->channels[i].max_power;
  			sband->channels[i].band = band;
  		}
  
  		have_band = true;
  	}
  
  	if (!have_band) {
  		WARN_ON(1);
  		return -EINVAL;
  	}
dfb89c56a   Johannes Berg   cfg80211: don't a...
728
  #ifdef CONFIG_PM
964dc9e2c   Johannes Berg   cfg80211: take Wo...
729
730
731
732
733
  	if (WARN_ON(rdev->wiphy.wowlan && rdev->wiphy.wowlan->n_patterns &&
  		    (!rdev->wiphy.wowlan->pattern_min_len ||
  		     rdev->wiphy.wowlan->pattern_min_len >
  				rdev->wiphy.wowlan->pattern_max_len)))
  		return -EINVAL;
dfb89c56a   Johannes Berg   cfg80211: don't a...
734
  #endif
ff1b6e69a   Johannes Berg   nl80211/cfg80211:...
735

8318d78a4   Johannes Berg   cfg80211 API for ...
736
737
  	/* check and set up bitrates */
  	ieee80211_set_bitrate_flags(wiphy);
00c3a6ed6   Johannes Berg   cfg80211: don't a...
738
  	rdev->wiphy.features |= NL80211_FEATURE_SCAN_FLUSH;
aa5f66d5a   Johannes Berg   cfg80211: fix sys...
739
  	rtnl_lock();
79c97e97a   Johannes Berg   cfg80211: clean u...
740
  	res = device_add(&rdev->wiphy.dev);
c3d34d5d9   John W. Linville   wireless: registe...
741
  	if (res) {
aa5f66d5a   Johannes Berg   cfg80211: fix sys...
742
  		rtnl_unlock();
c3d34d5d9   John W. Linville   wireless: registe...
743
744
  		return res;
  	}
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
745

2f0accc13   Johannes Berg   cfg80211: fix rfk...
746
  	/* set up regulatory info */
57b5ce072   Luis R. Rodriguez   cfg80211: add cel...
747
  	wiphy_regulatory_register(wiphy);
2f0accc13   Johannes Berg   cfg80211: fix rfk...
748

5f2aa25e0   Johannes Berg   cfg80211: rcu-ify...
749
  	list_add_rcu(&rdev->list, &cfg80211_rdev_list);
f5ea9120b   Johannes Berg   nl80211: add gene...
750
  	cfg80211_rdev_list_generation++;
704232c27   Johannes Berg   [WIRELESS] cfg802...
751
752
  
  	/* add to debugfs */
79c97e97a   Johannes Berg   cfg80211: clean u...
753
754
  	rdev->wiphy.debugfsdir =
  		debugfs_create_dir(wiphy_name(&rdev->wiphy),
704232c27   Johannes Berg   [WIRELESS] cfg802...
755
  				   ieee80211_debugfs_dir);
79c97e97a   Johannes Berg   cfg80211: clean u...
756
757
  	if (IS_ERR(rdev->wiphy.debugfsdir))
  		rdev->wiphy.debugfsdir = NULL;
704232c27   Johannes Berg   [WIRELESS] cfg802...
758

a796dac9a   Tomasz Bursztyka   wireless: core: R...
759
760
  	cfg80211_debugfs_rdev_add(rdev);
  	nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY);
a2f73b6c5   Luis R. Rodriguez   cfg80211: move re...
761
  	if (wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {
73d54c9e7   Luis R. Rodriguez   cfg80211: add reg...
762
763
764
765
766
767
768
769
770
  		struct regulatory_request request;
  
  		request.wiphy_idx = get_wiphy_idx(wiphy);
  		request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
  		request.alpha2[0] = '9';
  		request.alpha2[1] = '9';
  
  		nl80211_send_reg_change_event(&request);
  	}
019ae3a91   Kanchanapally, Vidyullatha   cfg80211: Adverti...
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
  	/* Check that nobody globally advertises any capabilities they do not
  	 * advertise on all possible interface types.
  	 */
  	if (wiphy->extended_capabilities_len &&
  	    wiphy->num_iftype_ext_capab &&
  	    wiphy->iftype_ext_capab) {
  		u8 supported_on_all, j;
  		const struct wiphy_iftype_ext_capab *capab;
  
  		capab = wiphy->iftype_ext_capab;
  		for (j = 0; j < wiphy->extended_capabilities_len; j++) {
  			if (capab[0].extended_capabilities_len > j)
  				supported_on_all =
  					capab[0].extended_capabilities[j];
  			else
  				supported_on_all = 0x00;
  			for (i = 1; i < wiphy->num_iftype_ext_capab; i++) {
  				if (j >= capab[i].extended_capabilities_len) {
  					supported_on_all = 0x00;
  					break;
  				}
  				supported_on_all &=
  					capab[i].extended_capabilities[j];
  			}
  			if (WARN_ON(wiphy->extended_capabilities[j] &
  				    ~supported_on_all))
  				break;
  		}
  	}
ecb443355   Stanislaw Gruszka   mac80211: fix sus...
800
801
  	rdev->wiphy.registered = true;
  	rtnl_unlock();
aa5f66d5a   Johannes Berg   cfg80211: fix sys...
802
803
804
805
806
807
808
809
  
  	res = rfkill_register(rdev->rfkill);
  	if (res) {
  		rfkill_destroy(rdev->rfkill);
  		rdev->rfkill = NULL;
  		wiphy_unregister(&rdev->wiphy);
  		return res;
  	}
2f0accc13   Johannes Berg   cfg80211: fix rfk...
810
  	return 0;
704232c27   Johannes Berg   [WIRELESS] cfg802...
811
812
  }
  EXPORT_SYMBOL(wiphy_register);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
813
814
  void wiphy_rfkill_start_polling(struct wiphy *wiphy)
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
815
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
816

79c97e97a   Johannes Berg   cfg80211: clean u...
817
  	if (!rdev->ops->rfkill_poll)
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
818
  		return;
79c97e97a   Johannes Berg   cfg80211: clean u...
819
820
  	rdev->rfkill_ops.poll = cfg80211_rfkill_poll;
  	rfkill_resume_polling(rdev->rfkill);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
821
822
823
824
825
  }
  EXPORT_SYMBOL(wiphy_rfkill_start_polling);
  
  void wiphy_rfkill_stop_polling(struct wiphy *wiphy)
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
826
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
827

79c97e97a   Johannes Berg   cfg80211: clean u...
828
  	rfkill_pause_polling(rdev->rfkill);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
829
830
  }
  EXPORT_SYMBOL(wiphy_rfkill_stop_polling);
704232c27   Johannes Berg   [WIRELESS] cfg802...
831
832
  void wiphy_unregister(struct wiphy *wiphy)
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
833
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
704232c27   Johannes Berg   [WIRELESS] cfg802...
834

ad002395f   Johannes Berg   cfg80211: fix dan...
835
836
  	wait_event(rdev->dev_wait, ({
  		int __count;
5fe231e87   Johannes Berg   cfg80211: vastly ...
837
  		rtnl_lock();
ad002395f   Johannes Berg   cfg80211: fix dan...
838
  		__count = rdev->opencount;
5fe231e87   Johannes Berg   cfg80211: vastly ...
839
  		rtnl_unlock();
c4f608462   Cristian Chilipirea   Net: wireless: co...
840
  		__count == 0; }));
ad002395f   Johannes Berg   cfg80211: fix dan...
841

aa5f66d5a   Johannes Berg   cfg80211: fix sys...
842
843
  	if (rdev->rfkill)
  		rfkill_unregister(rdev->rfkill);
256c90ded   Johannes Berg   cfg80211: fix pot...
844

5fe231e87   Johannes Berg   cfg80211: vastly ...
845
  	rtnl_lock();
3bb205567   Johannes Berg   cfg80211: send ev...
846
  	nl80211_notify_wiphy(rdev, NL80211_CMD_DEL_WIPHY);
5fe231e87   Johannes Berg   cfg80211: vastly ...
847
  	rdev->wiphy.registered = false;
53873f134   Johannes Berg   cfg80211: make wd...
848
  	WARN_ON(!list_empty(&rdev->wiphy.wdev_list));
ad002395f   Johannes Berg   cfg80211: fix dan...
849
850
851
852
853
  
  	/*
  	 * First remove the hardware from everywhere, this makes
  	 * it impossible to find from userspace.
  	 */
7bcfaf2f4   Johannes Berg   cfg80211/mac80211...
854
  	debugfs_remove_recursive(rdev->wiphy.debugfsdir);
5f2aa25e0   Johannes Berg   cfg80211: rcu-ify...
855
856
  	list_del_rcu(&rdev->list);
  	synchronize_rcu();
f16bfc1c0   Johannes Berg   [WIRELESS] cfg802...
857
858
  
  	/*
bfead0808   Luis R. Rodriguez   cfg80211: rename ...
859
860
861
862
  	 * If this device got a regulatory hint tell core its
  	 * free to listen now to a new shiny device regulatory hint
  	 */
  	wiphy_regulatory_deregister(wiphy);
3f2355cb9   Luis R. Rodriguez   cfg80211/mac80211...
863

f5ea9120b   Johannes Berg   nl80211: add gene...
864
  	cfg80211_rdev_list_generation++;
79c97e97a   Johannes Berg   cfg80211: clean u...
865
  	device_del(&rdev->wiphy.dev);
704232c27   Johannes Berg   [WIRELESS] cfg802...
866

5fe231e87   Johannes Berg   cfg80211: vastly ...
867
  	rtnl_unlock();
6682588a0   Johannes Berg   cfg80211: fix unr...
868

36e6fea84   Johannes Berg   cfg80211: check f...
869
  	flush_work(&rdev->scan_done_wk);
6682588a0   Johannes Berg   cfg80211: fix unr...
870
  	cancel_work_sync(&rdev->conn_work);
6682588a0   Johannes Berg   cfg80211: fix unr...
871
  	flush_work(&rdev->event_work);
04f39047a   Simon Wunderlich   nl80211/cfg80211:...
872
  	cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
78f22b6a3   Johannes Berg   cfg80211: allow u...
873
  	flush_work(&rdev->destroy_work);
93a1e86ce   Jukka Rissanen   nl80211: Stop sch...
874
  	flush_work(&rdev->sched_scan_stop_wk);
33d8783c5   Johannes Berg   cfg80211: allow m...
875
  	flush_work(&rdev->mlme_unreg_wk);
897667273   Vasanthakumar Thiagarajan   cfg80211: Share C...
876
877
  	flush_work(&rdev->propagate_radar_detect_wk);
  	flush_work(&rdev->propagate_cac_done_wk);
6d52563f2   Johannes Berg   cfg80211/mac80211...
878

6abb9cb99   Johannes Berg   cfg80211: make Wo...
879
880
  #ifdef CONFIG_PM
  	if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
e35e4d28b   Hila Gonen   cfg80211: add wra...
881
  		rdev_set_wakeup(rdev, false);
6abb9cb99   Johannes Berg   cfg80211: make Wo...
882
  #endif
6d52563f2   Johannes Berg   cfg80211/mac80211...
883
  	cfg80211_rdev_free_wowlan(rdev);
be29b99a9   Amitkumar Karwar   cfg80211/nl80211:...
884
  	cfg80211_rdev_free_coalesce(rdev);
704232c27   Johannes Berg   [WIRELESS] cfg802...
885
886
  }
  EXPORT_SYMBOL(wiphy_unregister);
79c97e97a   Johannes Berg   cfg80211: clean u...
887
  void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
704232c27   Johannes Berg   [WIRELESS] cfg802...
888
  {
2a5193119   Johannes Berg   cfg80211/nl80211:...
889
  	struct cfg80211_internal_bss *scan, *tmp;
37c73b5f3   Ben Greear   cfg80211: allow r...
890
  	struct cfg80211_beacon_registration *reg, *treg;
79c97e97a   Johannes Berg   cfg80211: clean u...
891
  	rfkill_destroy(rdev->rfkill);
37c73b5f3   Ben Greear   cfg80211: allow r...
892
893
894
895
  	list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) {
  		list_del(&reg->list);
  		kfree(reg);
  	}
79c97e97a   Johannes Berg   cfg80211: clean u...
896
  	list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
5b112d3d0   Johannes Berg   cfg80211: pass wi...
897
  		cfg80211_put_bss(&rdev->wiphy, &scan->pub);
79c97e97a   Johannes Berg   cfg80211: clean u...
898
  	kfree(rdev);
704232c27   Johannes Berg   [WIRELESS] cfg802...
899
900
901
902
903
904
905
  }
  
  void wiphy_free(struct wiphy *wiphy)
  {
  	put_device(&wiphy->dev);
  }
  EXPORT_SYMBOL(wiphy_free);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
906
907
  void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
908
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
909

79c97e97a   Johannes Berg   cfg80211: clean u...
910
911
  	if (rfkill_set_hw_state(rdev->rfkill, blocked))
  		schedule_work(&rdev->rfkill_sync);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
912
913
  }
  EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
4a4b81695   Andrew Zaborowski   cfg80211: Accept ...
914
915
916
917
918
  void cfg80211_cqm_config_free(struct wireless_dev *wdev)
  {
  	kfree(wdev->cqm_config);
  	wdev->cqm_config = NULL;
  }
98104fded   Johannes Berg   cfg80211: add P2P...
919
920
  void cfg80211_unregister_wdev(struct wireless_dev *wdev)
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
921
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
98104fded   Johannes Berg   cfg80211: add P2P...
922
923
924
925
926
  
  	ASSERT_RTNL();
  
  	if (WARN_ON(wdev->netdev))
  		return;
7f8ed01ea   Denis Kenzior   cfg80211: always ...
927
  	nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE);
98104fded   Johannes Berg   cfg80211: add P2P...
928
929
930
931
932
  	list_del_rcu(&wdev->list);
  	rdev->devlist_generation++;
  
  	switch (wdev->iftype) {
  	case NL80211_IFTYPE_P2P_DEVICE:
33d8783c5   Johannes Berg   cfg80211: allow m...
933
  		cfg80211_mlme_purge_registrations(wdev);
f9f475292   Johannes Berg   cfg80211: always ...
934
  		cfg80211_stop_p2p_device(rdev, wdev);
98104fded   Johannes Berg   cfg80211: add P2P...
935
  		break;
cb3b7d876   Ayala Beker   cfg80211: add sta...
936
937
938
  	case NL80211_IFTYPE_NAN:
  		cfg80211_stop_nan(rdev, wdev);
  		break;
98104fded   Johannes Berg   cfg80211: add P2P...
939
940
941
942
  	default:
  		WARN_ON_ONCE(1);
  		break;
  	}
4a4b81695   Andrew Zaborowski   cfg80211: Accept ...
943
944
  
  	cfg80211_cqm_config_free(wdev);
98104fded   Johannes Berg   cfg80211: add P2P...
945
946
  }
  EXPORT_SYMBOL(cfg80211_unregister_wdev);
f1e3d556a   Johannes Berg   cfg80211: make de...
947
  static const struct device_type wiphy_type = {
053a93dd1   Marcel Holtmann   cfg80211: assign ...
948
949
  	.name	= "wlan",
  };
dbbae26af   Michal Kazior   cfg80211: track m...
950
951
952
  void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
  			       enum nl80211_iftype iftype, int num)
  {
c5a7e5824   Johannes Berg   cfg80211: fix loc...
953
  	ASSERT_RTNL();
dbbae26af   Michal Kazior   cfg80211: track m...
954
955
956
957
  
  	rdev->num_running_ifaces += num;
  	if (iftype == NL80211_IFTYPE_MONITOR)
  		rdev->num_running_monitor_ifaces += num;
dbbae26af   Michal Kazior   cfg80211: track m...
958
  }
f04c22033   Michal Kazior   cfg80211: export ...
959
960
  void __cfg80211_leave(struct cfg80211_registered_device *rdev,
  		      struct wireless_dev *wdev)
812569699   Stanislaw Gruszka   cfg80211/mac80211...
961
962
  {
  	struct net_device *dev = wdev->netdev;
ca986ad9b   Arend Van Spriel   nl80211: allow mu...
963
  	struct cfg80211_sched_scan_request *pos, *tmp;
812569699   Stanislaw Gruszka   cfg80211/mac80211...
964

24d584d70   Barak Bercovitz   cfg80211: stop sc...
965
  	ASSERT_RTNL();
f04c22033   Michal Kazior   cfg80211: export ...
966
  	ASSERT_WDEV_LOCK(wdev);
24d584d70   Barak Bercovitz   cfg80211: stop sc...
967

812569699   Stanislaw Gruszka   cfg80211/mac80211...
968
969
  	switch (wdev->iftype) {
  	case NL80211_IFTYPE_ADHOC:
f04c22033   Michal Kazior   cfg80211: export ...
970
  		__cfg80211_leave_ibss(rdev, dev, true);
812569699   Stanislaw Gruszka   cfg80211/mac80211...
971
972
973
  		break;
  	case NL80211_IFTYPE_P2P_CLIENT:
  	case NL80211_IFTYPE_STATION:
ca986ad9b   Arend Van Spriel   nl80211: allow mu...
974
975
976
977
978
  		list_for_each_entry_safe(pos, tmp, &rdev->sched_scan_req_list,
  					 list) {
  			if (dev == pos->dev)
  				cfg80211_stop_sched_scan_req(rdev, pos, false);
  		}
812569699   Stanislaw Gruszka   cfg80211/mac80211...
979

812569699   Stanislaw Gruszka   cfg80211/mac80211...
980
981
982
983
984
985
  #ifdef CONFIG_CFG80211_WEXT
  		kfree(wdev->wext.ie);
  		wdev->wext.ie = NULL;
  		wdev->wext.ie_len = 0;
  		wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
  #endif
83739b03d   Johannes Berg   cfg80211: remove ...
986
987
  		cfg80211_disconnect(rdev, dev,
  				    WLAN_REASON_DEAUTH_LEAVING, true);
812569699   Stanislaw Gruszka   cfg80211/mac80211...
988
989
  		break;
  	case NL80211_IFTYPE_MESH_POINT:
f04c22033   Michal Kazior   cfg80211: export ...
990
  		__cfg80211_leave_mesh(rdev, dev);
812569699   Stanislaw Gruszka   cfg80211/mac80211...
991
992
  		break;
  	case NL80211_IFTYPE_AP:
74418edec   Johannes Berg   cfg80211: fix P2P...
993
  	case NL80211_IFTYPE_P2P_GO:
f04c22033   Michal Kazior   cfg80211: export ...
994
  		__cfg80211_stop_ap(rdev, dev, true);
812569699   Stanislaw Gruszka   cfg80211/mac80211...
995
  		break;
6e0bd6c35   Rostislav Lisovy   cfg80211: 802.11p...
996
997
998
  	case NL80211_IFTYPE_OCB:
  		__cfg80211_leave_ocb(rdev, dev);
  		break;
de4fcbadd   Johannes Berg   cfg80211: avoid u...
999
1000
1001
1002
  	case NL80211_IFTYPE_WDS:
  		/* must be handled by mac80211/driver, has no APIs */
  		break;
  	case NL80211_IFTYPE_P2P_DEVICE:
cb3b7d876   Ayala Beker   cfg80211: add sta...
1003
  	case NL80211_IFTYPE_NAN:
de4fcbadd   Johannes Berg   cfg80211: avoid u...
1004
1005
1006
1007
1008
1009
1010
1011
1012
  		/* cannot happen, has no netdev */
  		break;
  	case NL80211_IFTYPE_AP_VLAN:
  	case NL80211_IFTYPE_MONITOR:
  		/* nothing to do */
  		break;
  	case NL80211_IFTYPE_UNSPECIFIED:
  	case NUM_NL80211_IFTYPES:
  		/* invalid */
812569699   Stanislaw Gruszka   cfg80211/mac80211...
1013
1014
  		break;
  	}
812569699   Stanislaw Gruszka   cfg80211/mac80211...
1015
  }
f04c22033   Michal Kazior   cfg80211: export ...
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
  void cfg80211_leave(struct cfg80211_registered_device *rdev,
  		    struct wireless_dev *wdev)
  {
  	wdev_lock(wdev);
  	__cfg80211_leave(rdev, wdev);
  	wdev_unlock(wdev);
  }
  
  void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev,
  			 gfp_t gfp)
  {
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
  	struct cfg80211_event *ev;
  	unsigned long flags;
  
  	trace_cfg80211_stop_iface(wiphy, wdev);
  
  	ev = kzalloc(sizeof(*ev), gfp);
  	if (!ev)
  		return;
  
  	ev->type = EVENT_STOPPED;
  
  	spin_lock_irqsave(&wdev->event_lock, flags);
  	list_add_tail(&ev->list, &wdev->event_list);
  	spin_unlock_irqrestore(&wdev->event_lock, flags);
  	queue_work(cfg80211_wq, &rdev->event_work);
  }
  EXPORT_SYMBOL(cfg80211_stop_iface);
c4f608462   Cristian Chilipirea   Net: wireless: co...
1045
  static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
351638e7d   Jiri Pirko   net: pass info st...
1046
  					 unsigned long state, void *ptr)
704232c27   Johannes Berg   [WIRELESS] cfg802...
1047
  {
351638e7d   Jiri Pirko   net: pass info st...
1048
  	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
2a783c136   Johannes Berg   cfg80211: move br...
1049
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
704232c27   Johannes Berg   [WIRELESS] cfg802...
1050
  	struct cfg80211_registered_device *rdev;
ca986ad9b   Arend Van Spriel   nl80211: allow mu...
1051
  	struct cfg80211_sched_scan_request *pos, *tmp;
704232c27   Johannes Berg   [WIRELESS] cfg802...
1052

2a783c136   Johannes Berg   cfg80211: move br...
1053
  	if (!wdev)
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
1054
  		return NOTIFY_DONE;
704232c27   Johannes Berg   [WIRELESS] cfg802...
1055

f26cbf401   Zhao, Gang   cfg80211: change ...
1056
  	rdev = wiphy_to_rdev(wdev->wiphy);
704232c27   Johannes Berg   [WIRELESS] cfg802...
1057

2a783c136   Johannes Berg   cfg80211: move br...
1058
  	WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED);
60719ffd7   Johannes Berg   cfg80211: show in...
1059

704232c27   Johannes Berg   [WIRELESS] cfg802...
1060
  	switch (state) {
053a93dd1   Marcel Holtmann   cfg80211: assign ...
1061
1062
1063
  	case NETDEV_POST_INIT:
  		SET_NETDEV_DEVTYPE(dev, &wiphy_type);
  		break;
704232c27   Johannes Berg   [WIRELESS] cfg802...
1064
  	case NETDEV_REGISTER:
0ff6ce7b3   Johannes Berg   cfg80211: fix dea...
1065
1066
1067
1068
1069
  		/*
  		 * NB: cannot take rdev->mtx here because this may be
  		 * called within code protected by it when interfaces
  		 * are added with nl80211.
  		 */
667503ddc   Johannes Berg   cfg80211: fix loc...
1070
1071
1072
  		mutex_init(&wdev->mtx);
  		INIT_LIST_HEAD(&wdev->event_list);
  		spin_lock_init(&wdev->event_lock);
2e161f78e   Johannes Berg   cfg80211/mac80211...
1073
1074
  		INIT_LIST_HEAD(&wdev->mgmt_registrations);
  		spin_lock_init(&wdev->mgmt_registrations_lock);
026331c4d   Jouni Malinen   cfg80211/mac80211...
1075

b6ecfd469   Johannes Berg   cfg80211: preserv...
1076
1077
1078
1079
1080
1081
1082
1083
1084
  		/*
  		 * We get here also when the interface changes network namespaces,
  		 * as it's registered into the new one, but we don't want it to
  		 * change ID in that case. Checking if the ID is already assigned
  		 * works, because 0 isn't considered a valid ID and the memory is
  		 * 0-initialized.
  		 */
  		if (!wdev->identifier)
  			wdev->identifier = ++rdev->wdev_id;
53873f134   Johannes Berg   cfg80211: make wd...
1085
  		list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
f5ea9120b   Johannes Berg   nl80211: add gene...
1086
  		rdev->devlist_generation++;
463d01832   Johannes Berg   cfg80211: make aw...
1087
1088
  		/* can only change netns with wiphy */
  		dev->features |= NETIF_F_NETNS_LOCAL;
704232c27   Johannes Berg   [WIRELESS] cfg802...
1089
1090
  		if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj,
  				      "phy80211")) {
e9c0268f0   Joe Perches   net/wireless: Use...
1091
1092
  			pr_err("failed to add phy80211 symlink to netdev!
  ");
704232c27   Johannes Berg   [WIRELESS] cfg802...
1093
  		}
2a783c136   Johannes Berg   cfg80211: move br...
1094
  		wdev->netdev = dev;
3d23e349d   Johannes Berg   wext: refactor
1095
  #ifdef CONFIG_CFG80211_WEXT
2a783c136   Johannes Berg   cfg80211: move br...
1096
1097
  		wdev->wext.default_key = -1;
  		wdev->wext.default_mgmt_key = -1;
f21293549   Johannes Berg   cfg80211: managed...
1098
  		wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
ffb9eb3d8   Kalle Valo   nl80211: add powe...
1099
  #endif
5be83de54   Johannes Berg   cfg80211: convert...
1100
  		if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT)
ffb9eb3d8   Kalle Valo   nl80211: add powe...
1101
  			wdev->ps = true;
5be83de54   Johannes Berg   cfg80211: convert...
1102
  		else
ffb9eb3d8   Kalle Valo   nl80211: add powe...
1103
  			wdev->ps = false;
9043f3b89   Juuso Oikarinen   cfg80211: Remove ...
1104
1105
  		/* allow mac80211 to determine the timeout */
  		wdev->ps_timeout = -1;
ffb9eb3d8   Kalle Valo   nl80211: add powe...
1106

ad4bb6f88   Johannes Berg   cfg80211: disallo...
1107
  		if ((wdev->iftype == NL80211_IFTYPE_STATION ||
074ac8df9   Johannes Berg   cfg80211/nl80211:...
1108
  		     wdev->iftype == NL80211_IFTYPE_P2P_CLIENT ||
ad4bb6f88   Johannes Berg   cfg80211: disallo...
1109
1110
  		     wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
  			dev->priv_flags |= IFF_DONT_BRIDGE;
896ff0635   Denis Kenzior   cfg80211: always ...
1111

bd2522b16   Andrzej Zaborowski   cfg80211: NL80211...
1112
  		INIT_WORK(&wdev->disconnect_wk, cfg80211_autodisconnect_wk);
896ff0635   Denis Kenzior   cfg80211: always ...
1113
  		nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
704232c27   Johannes Berg   [WIRELESS] cfg802...
1114
  		break;
04a773ade   Johannes Berg   cfg80211/nl80211:...
1115
  	case NETDEV_GOING_DOWN:
812569699   Stanislaw Gruszka   cfg80211/mac80211...
1116
  		cfg80211_leave(rdev, wdev);
01a0ac417   Johannes Berg   cfg80211: check l...
1117
1118
  		break;
  	case NETDEV_DOWN:
dbbae26af   Michal Kazior   cfg80211: track m...
1119
  		cfg80211_update_iface_num(rdev, wdev->iftype, -1);
a617302c5   Johannes Berg   cfg80211: fix sca...
1120
1121
  		if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
  			if (WARN_ON(!rdev->scan_req->notified))
1d76250bd   Avraham Stern   nl80211: support ...
1122
  				rdev->scan_req->info.aborted = true;
f9d15d162   Johannes Berg   cfg80211: send sc...
1123
  			___cfg80211_scan_done(rdev, false);
a617302c5   Johannes Berg   cfg80211: fix sca...
1124
  		}
5fe231e87   Johannes Berg   cfg80211: vastly ...
1125

ca986ad9b   Arend Van Spriel   nl80211: allow mu...
1126
1127
1128
1129
  		list_for_each_entry_safe(pos, tmp,
  					 &rdev->sched_scan_req_list, list) {
  			if (WARN_ON(pos && pos->dev == wdev->netdev))
  				cfg80211_stop_sched_scan_req(rdev, pos, false);
5fe231e87   Johannes Berg   cfg80211: vastly ...
1130
1131
1132
1133
  		}
  
  		rdev->opencount--;
  		wake_up(&rdev->dev_wait);
04a773ade   Johannes Berg   cfg80211/nl80211:...
1134
1135
  		break;
  	case NETDEV_UP:
4290cb4bf   Johannes Berg   cfg80211: reduce ...
1136
  		cfg80211_update_iface_num(rdev, wdev->iftype, 1);
667503ddc   Johannes Berg   cfg80211: fix loc...
1137
  		wdev_lock(wdev);
f21293549   Johannes Berg   cfg80211: managed...
1138
  		switch (wdev->iftype) {
29cbe68c5   Johannes Berg   cfg80211/mac80211...
1139
  #ifdef CONFIG_CFG80211_WEXT
f21293549   Johannes Berg   cfg80211: managed...
1140
  		case NL80211_IFTYPE_ADHOC:
fffd0934b   Johannes Berg   cfg80211: rework ...
1141
  			cfg80211_ibss_wext_join(rdev, wdev);
04a773ade   Johannes Berg   cfg80211/nl80211:...
1142
  			break;
f21293549   Johannes Berg   cfg80211: managed...
1143
  		case NL80211_IFTYPE_STATION:
fffd0934b   Johannes Berg   cfg80211: rework ...
1144
  			cfg80211_mgd_wext_connect(rdev, wdev);
f21293549   Johannes Berg   cfg80211: managed...
1145
  			break;
29cbe68c5   Johannes Berg   cfg80211/mac80211...
1146
  #endif
c80d545da   Javier Cardona   mac80211: Let use...
1147
  #ifdef CONFIG_MAC80211_MESH
29cbe68c5   Johannes Berg   cfg80211/mac80211...
1148
  		case NL80211_IFTYPE_MESH_POINT:
c80d545da   Javier Cardona   mac80211: Let use...
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
  			{
  				/* backward compat code... */
  				struct mesh_setup setup;
  				memcpy(&setup, &default_mesh_setup,
  						sizeof(setup));
  				 /* back compat only needed for mesh_id */
  				setup.mesh_id = wdev->ssid;
  				setup.mesh_id_len = wdev->mesh_id_up_len;
  				if (wdev->mesh_id_up_len)
  					__cfg80211_join_mesh(rdev, dev,
  							&setup,
  							&default_mesh_config);
  				break;
  			}
  #endif
f21293549   Johannes Berg   cfg80211: managed...
1164
  		default:
04a773ade   Johannes Berg   cfg80211/nl80211:...
1165
  			break;
f21293549   Johannes Berg   cfg80211: managed...
1166
  		}
667503ddc   Johannes Berg   cfg80211: fix loc...
1167
  		wdev_unlock(wdev);
ad002395f   Johannes Berg   cfg80211: fix dan...
1168
  		rdev->opencount++;
bf6a0579f   Juuso Oikarinen   cfg80211: Fix pow...
1169
1170
1171
1172
1173
  
  		/*
  		 * Configure power management to the driver here so that its
  		 * correctly set also after interface type changes etc.
  		 */
5966f2ddc   Eliad Peller   cfg80211: enter p...
1174
1175
  		if ((wdev->iftype == NL80211_IFTYPE_STATION ||
  		     wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) &&
d4f299786   Johannes Berg   cfg80211: combine...
1176
1177
1178
1179
1180
1181
  		    rdev->ops->set_power_mgmt &&
  		    rdev_set_power_mgmt(rdev, dev, wdev->ps,
  					wdev->ps_timeout)) {
  			/* assume this means it's off */
  			wdev->ps = false;
  		}
2a783c136   Johannes Berg   cfg80211: move br...
1182
  		break;
704232c27   Johannes Berg   [WIRELESS] cfg802...
1183
  	case NETDEV_UNREGISTER:
0ff6ce7b3   Johannes Berg   cfg80211: fix dea...
1184
  		/*
e40cbdac0   Johannes Berg   cfg80211: fix NET...
1185
1186
1187
1188
1189
1190
  		 * It is possible to get NETDEV_UNREGISTER
  		 * multiple times. To detect that, check
  		 * that the interface is still on the list
  		 * of registered interfaces, and only then
  		 * remove and clean it up.
  		 */
2a783c136   Johannes Berg   cfg80211: move br...
1191
  		if (!list_empty(&wdev->list)) {
7f8ed01ea   Denis Kenzior   cfg80211: always ...
1192
1193
  			nl80211_notify_iface(rdev, wdev,
  					     NL80211_CMD_DEL_INTERFACE);
704232c27   Johannes Berg   [WIRELESS] cfg802...
1194
  			sysfs_remove_link(&dev->dev.kobj, "phy80211");
5f2aa25e0   Johannes Berg   cfg80211: rcu-ify...
1195
  			list_del_rcu(&wdev->list);
f5ea9120b   Johannes Berg   nl80211: add gene...
1196
  			rdev->devlist_generation++;
2e161f78e   Johannes Berg   cfg80211/mac80211...
1197
  			cfg80211_mlme_purge_registrations(wdev);
3d23e349d   Johannes Berg   wext: refactor
1198
  #ifdef CONFIG_CFG80211_WEXT
538c9eb8b   Johannes Berg   cfg80211: clear w...
1199
  			kzfree(wdev->wext.keys);
fffd0934b   Johannes Berg   cfg80211: rework ...
1200
  #endif
bd2522b16   Andrzej Zaborowski   cfg80211: NL80211...
1201
  			flush_work(&wdev->disconnect_wk);
4a4b81695   Andrew Zaborowski   cfg80211: Accept ...
1202
  			cfg80211_cqm_config_free(wdev);
e40cbdac0   Johannes Berg   cfg80211: fix NET...
1203
  		}
5f2aa25e0   Johannes Berg   cfg80211: rcu-ify...
1204
1205
1206
1207
1208
1209
1210
1211
  		/*
  		 * synchronise (so that we won't find this netdev
  		 * from other code any more) and then clear the list
  		 * head so that the above code can safely check for
  		 * !list_empty() to avoid double-cleanup.
  		 */
  		synchronize_rcu();
  		INIT_LIST_HEAD(&wdev->list);
1f6fc43e6   Daniel Drake   cfg80211: process...
1212
1213
1214
1215
1216
  		/*
  		 * Ensure that all events have been processed and
  		 * freed.
  		 */
  		cfg80211_process_wdev_events(wdev);
f9bef3df5   Ben Greear   wireless: check f...
1217
1218
1219
1220
1221
1222
  
  		if (WARN_ON(wdev->current_bss)) {
  			cfg80211_unhold_bss(wdev->current_bss);
  			cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
  			wdev->current_bss = NULL;
  		}
704232c27   Johannes Berg   [WIRELESS] cfg802...
1223
  		break;
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
1224
  	case NETDEV_PRE_UP:
0b20633d9   Johannes Berg   cfg80211: disallo...
1225
1226
  		if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
  			return notifier_from_errno(-EOPNOTSUPP);
b6a550156   Luciano Coelho   cfg80211/mac80211...
1227
1228
  		if (rfkill_blocked(rdev->rfkill))
  			return notifier_from_errno(-ERFKILL);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
1229
  		break;
6784c7db8   Zhao, Gang   cfg80211: change ...
1230
1231
  	default:
  		return NOTIFY_DONE;
704232c27   Johannes Berg   [WIRELESS] cfg802...
1232
  	}
cb150b9d2   Johannes Berg   cfg80211/wext: fi...
1233
  	wireless_nlevent_flush();
6784c7db8   Zhao, Gang   cfg80211: change ...
1234
  	return NOTIFY_OK;
704232c27   Johannes Berg   [WIRELESS] cfg802...
1235
1236
1237
1238
1239
  }
  
  static struct notifier_block cfg80211_netdev_notifier = {
  	.notifier_call = cfg80211_netdev_notifier_call,
  };
463d01832   Johannes Berg   cfg80211: make aw...
1240
1241
1242
1243
1244
  static void __net_exit cfg80211_pernet_exit(struct net *net)
  {
  	struct cfg80211_registered_device *rdev;
  
  	rtnl_lock();
463d01832   Johannes Berg   cfg80211: make aw...
1245
1246
1247
1248
  	list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
  		if (net_eq(wiphy_net(&rdev->wiphy), net))
  			WARN_ON(cfg80211_switch_netns(rdev, &init_net));
  	}
463d01832   Johannes Berg   cfg80211: make aw...
1249
1250
1251
1252
1253
1254
1255
1256
  	rtnl_unlock();
  }
  
  static struct pernet_operations cfg80211_pernet_ops = {
  	.exit = cfg80211_pernet_exit,
  };
  
  static int __init cfg80211_init(void)
704232c27   Johannes Berg   [WIRELESS] cfg802...
1257
  {
b2e1b3029   Luis R. Rodriguez   cfg80211: Add new...
1258
  	int err;
463d01832   Johannes Berg   cfg80211: make aw...
1259
1260
1261
  	err = register_pernet_device(&cfg80211_pernet_ops);
  	if (err)
  		goto out_fail_pernet;
b2e1b3029   Luis R. Rodriguez   cfg80211: Add new...
1262
  	err = wiphy_sysfs_init();
704232c27   Johannes Berg   [WIRELESS] cfg802...
1263
1264
1265
1266
1267
1268
  	if (err)
  		goto out_fail_sysfs;
  
  	err = register_netdevice_notifier(&cfg80211_netdev_notifier);
  	if (err)
  		goto out_fail_notifier;
556829657   Johannes Berg   [NL80211]: add ne...
1269
1270
1271
  	err = nl80211_init();
  	if (err)
  		goto out_fail_nl80211;
704232c27   Johannes Berg   [WIRELESS] cfg802...
1272
  	ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL);
b2e1b3029   Luis R. Rodriguez   cfg80211: Add new...
1273
1274
1275
  	err = regulatory_init();
  	if (err)
  		goto out_fail_reg;
e48190138   Bhaktipriya Shridhar   cfg80211: Remove ...
1276
  	cfg80211_wq = alloc_ordered_workqueue("cfg80211", WQ_MEM_RECLAIM);
f00f188f8   Wei Yongjun   cfg80211: fix err...
1277
1278
  	if (!cfg80211_wq) {
  		err = -ENOMEM;
e60d7443e   Alban Browaeys   wireless : use a ...
1279
  		goto out_fail_wq;
f00f188f8   Wei Yongjun   cfg80211: fix err...
1280
  	}
e60d7443e   Alban Browaeys   wireless : use a ...
1281

704232c27   Johannes Berg   [WIRELESS] cfg802...
1282
  	return 0;
e60d7443e   Alban Browaeys   wireless : use a ...
1283
1284
  out_fail_wq:
  	regulatory_exit();
b2e1b3029   Luis R. Rodriguez   cfg80211: Add new...
1285
1286
  out_fail_reg:
  	debugfs_remove(ieee80211_debugfs_dir);
81daf735f   Junjie Mao   cfg80211: calls n...
1287
  	nl80211_exit();
556829657   Johannes Berg   [NL80211]: add ne...
1288
1289
  out_fail_nl80211:
  	unregister_netdevice_notifier(&cfg80211_netdev_notifier);
704232c27   Johannes Berg   [WIRELESS] cfg802...
1290
1291
1292
  out_fail_notifier:
  	wiphy_sysfs_exit();
  out_fail_sysfs:
463d01832   Johannes Berg   cfg80211: make aw...
1293
1294
  	unregister_pernet_device(&cfg80211_pernet_ops);
  out_fail_pernet:
704232c27   Johannes Berg   [WIRELESS] cfg802...
1295
1296
  	return err;
  }
3a4624652   Johannes Berg   [PATCH] cfg80211:...
1297
  subsys_initcall(cfg80211_init);
704232c27   Johannes Berg   [WIRELESS] cfg802...
1298

f884e3879   Uwe Kleine-König   cfg80211: move cf...
1299
  static void __exit cfg80211_exit(void)
704232c27   Johannes Berg   [WIRELESS] cfg802...
1300
1301
  {
  	debugfs_remove(ieee80211_debugfs_dir);
556829657   Johannes Berg   [NL80211]: add ne...
1302
  	nl80211_exit();
704232c27   Johannes Berg   [WIRELESS] cfg802...
1303
1304
  	unregister_netdevice_notifier(&cfg80211_netdev_notifier);
  	wiphy_sysfs_exit();
b2e1b3029   Luis R. Rodriguez   cfg80211: Add new...
1305
  	regulatory_exit();
463d01832   Johannes Berg   cfg80211: make aw...
1306
  	unregister_pernet_device(&cfg80211_pernet_ops);
e60d7443e   Alban Browaeys   wireless : use a ...
1307
  	destroy_workqueue(cfg80211_wq);
704232c27   Johannes Berg   [WIRELESS] cfg802...
1308
1309
  }
  module_exit(cfg80211_exit);