blob: fe6f402a22af0b404a5b11fbaf689430f4c7753b [file] [log] [blame]
Johannes Berg704232c2007-04-23 12:20:05 -07001/*
2 * This is the linux wireless configuration interface.
3 *
Johannes Berg08645122009-05-11 13:54:58 +02004 * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net>
Johannes Berg704232c2007-04-23 12:20:05 -07005 */
6
7#include <linux/if.h>
8#include <linux/module.h>
9#include <linux/err.h>
Johannes Berg704232c2007-04-23 12:20:05 -070010#include <linux/list.h>
11#include <linux/nl80211.h>
12#include <linux/debugfs.h>
13#include <linux/notifier.h>
14#include <linux/device.h>
Zhu Yi16a832e2009-08-19 16:08:22 +080015#include <linux/etherdevice.h>
Johannes Berg1f87f7d2009-06-02 13:01:41 +020016#include <linux/rtnetlink.h>
Alexey Dobriyand43c36d2009-10-07 17:09:06 +040017#include <linux/sched.h>
Johannes Berg704232c2007-04-23 12:20:05 -070018#include <net/genetlink.h>
19#include <net/cfg80211.h>
Johannes Berg55682962007-09-20 13:09:35 -040020#include "nl80211.h"
Johannes Berg704232c2007-04-23 12:20:05 -070021#include "core.h"
22#include "sysfs.h"
Luis R. Rodriguez1ac61302009-05-02 00:37:21 -040023#include "debugfs.h"
Johannes Berga9a11622009-07-27 12:01:53 +020024#include "wext-compat.h"
John W. Linville4890e3b2009-09-30 14:50:17 -040025#include "ethtool.h"
Johannes Berg704232c2007-04-23 12:20:05 -070026
27/* name for sysfs, %d is appended */
28#define PHY_NAME "phy"
29
30MODULE_AUTHOR("Johannes Berg");
31MODULE_LICENSE("GPL");
32MODULE_DESCRIPTION("wireless configuration support");
33
34/* RCU might be appropriate here since we usually
35 * only read the list, and that can happen quite
36 * often because we need to do it for each command */
Johannes Berg79c97e92009-07-07 03:56:12 +020037LIST_HEAD(cfg80211_rdev_list);
Johannes Bergf5ea9122009-08-07 16:17:38 +020038int cfg80211_rdev_list_generation;
Luis R. Rodrigueza1794392009-02-21 00:04:21 -050039
40/*
Luis R. Rodriguezabc73812009-07-30 17:38:08 -070041 * This is used to protect the cfg80211_rdev_list
Luis R. Rodrigueza1794392009-02-21 00:04:21 -050042 */
43DEFINE_MUTEX(cfg80211_mutex);
Johannes Berg704232c2007-04-23 12:20:05 -070044
45/* for debugfs */
46static struct dentry *ieee80211_debugfs_dir;
47
Luis R. Rodriguez806a9e32009-02-21 00:04:26 -050048/* requires cfg80211_mutex to be held! */
Johannes Berg79c97e92009-07-07 03:56:12 +020049struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx)
Johannes Berg55682962007-09-20 13:09:35 -040050{
Johannes Berg79c97e92009-07-07 03:56:12 +020051 struct cfg80211_registered_device *result = NULL, *rdev;
Johannes Berg55682962007-09-20 13:09:35 -040052
Luis R. Rodriguez85fd1292009-02-21 00:04:20 -050053 if (!wiphy_idx_valid(wiphy_idx))
54 return NULL;
55
Luis R. Rodriguez761cf7e2009-02-21 00:04:25 -050056 assert_cfg80211_lock();
57
Johannes Berg79c97e92009-07-07 03:56:12 +020058 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
59 if (rdev->wiphy_idx == wiphy_idx) {
60 result = rdev;
Johannes Berg55682962007-09-20 13:09:35 -040061 break;
62 }
63 }
64
65 return result;
66}
67
Luis R. Rodriguez806a9e32009-02-21 00:04:26 -050068int get_wiphy_idx(struct wiphy *wiphy)
69{
Johannes Berg79c97e92009-07-07 03:56:12 +020070 struct cfg80211_registered_device *rdev;
Luis R. Rodriguez806a9e32009-02-21 00:04:26 -050071 if (!wiphy)
72 return WIPHY_IDX_STALE;
Johannes Berg79c97e92009-07-07 03:56:12 +020073 rdev = wiphy_to_dev(wiphy);
74 return rdev->wiphy_idx;
Luis R. Rodriguez806a9e32009-02-21 00:04:26 -050075}
76
Johannes Berg79c97e92009-07-07 03:56:12 +020077/* requires cfg80211_rdev_mutex to be held! */
Luis R. Rodriguez806a9e32009-02-21 00:04:26 -050078struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx)
79{
Johannes Berg79c97e92009-07-07 03:56:12 +020080 struct cfg80211_registered_device *rdev;
Luis R. Rodriguez806a9e32009-02-21 00:04:26 -050081
82 if (!wiphy_idx_valid(wiphy_idx))
83 return NULL;
84
85 assert_cfg80211_lock();
86
Johannes Berg79c97e92009-07-07 03:56:12 +020087 rdev = cfg80211_rdev_by_wiphy_idx(wiphy_idx);
88 if (!rdev)
Luis R. Rodriguez806a9e32009-02-21 00:04:26 -050089 return NULL;
Johannes Berg79c97e92009-07-07 03:56:12 +020090 return &rdev->wiphy;
Luis R. Rodriguez806a9e32009-02-21 00:04:26 -050091}
92
Luis R. Rodrigueza1794392009-02-21 00:04:21 -050093/* requires cfg80211_mutex to be held! */
Johannes Berg4bbf4d52009-03-24 09:35:46 +010094struct cfg80211_registered_device *
Johannes Berg79c97e92009-07-07 03:56:12 +020095__cfg80211_rdev_from_info(struct genl_info *info)
Johannes Berg55682962007-09-20 13:09:35 -040096{
97 int ifindex;
Luis R. Rodriguezb5850a72009-02-21 00:04:19 -050098 struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL;
Johannes Berg55682962007-09-20 13:09:35 -040099 struct net_device *dev;
100 int err = -EINVAL;
101
Luis R. Rodriguez761cf7e2009-02-21 00:04:25 -0500102 assert_cfg80211_lock();
103
Johannes Berg55682962007-09-20 13:09:35 -0400104 if (info->attrs[NL80211_ATTR_WIPHY]) {
Johannes Berg79c97e92009-07-07 03:56:12 +0200105 bywiphyidx = cfg80211_rdev_by_wiphy_idx(
Johannes Berg55682962007-09-20 13:09:35 -0400106 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY]));
107 err = -ENODEV;
108 }
109
110 if (info->attrs[NL80211_ATTR_IFINDEX]) {
111 ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
Johannes Berg463d0182009-07-14 00:33:35 +0200112 dev = dev_get_by_index(genl_info_net(info), ifindex);
Johannes Berg55682962007-09-20 13:09:35 -0400113 if (dev) {
114 if (dev->ieee80211_ptr)
115 byifidx =
116 wiphy_to_dev(dev->ieee80211_ptr->wiphy);
117 dev_put(dev);
118 }
119 err = -ENODEV;
120 }
121
Luis R. Rodriguezb5850a72009-02-21 00:04:19 -0500122 if (bywiphyidx && byifidx) {
123 if (bywiphyidx != byifidx)
Johannes Berg55682962007-09-20 13:09:35 -0400124 return ERR_PTR(-EINVAL);
125 else
Luis R. Rodriguezb5850a72009-02-21 00:04:19 -0500126 return bywiphyidx; /* == byifidx */
Johannes Berg55682962007-09-20 13:09:35 -0400127 }
Luis R. Rodriguezb5850a72009-02-21 00:04:19 -0500128 if (bywiphyidx)
129 return bywiphyidx;
Johannes Berg55682962007-09-20 13:09:35 -0400130
131 if (byifidx)
132 return byifidx;
133
134 return ERR_PTR(err);
135}
136
137struct cfg80211_registered_device *
138cfg80211_get_dev_from_info(struct genl_info *info)
139{
Johannes Berg79c97e92009-07-07 03:56:12 +0200140 struct cfg80211_registered_device *rdev;
Johannes Berg55682962007-09-20 13:09:35 -0400141
Luis R. Rodrigueza1794392009-02-21 00:04:21 -0500142 mutex_lock(&cfg80211_mutex);
Johannes Berg79c97e92009-07-07 03:56:12 +0200143 rdev = __cfg80211_rdev_from_info(info);
Johannes Berg55682962007-09-20 13:09:35 -0400144
145 /* if it is not an error we grab the lock on
146 * it to assure it won't be going away while
147 * we operate on it */
Johannes Berg79c97e92009-07-07 03:56:12 +0200148 if (!IS_ERR(rdev))
149 mutex_lock(&rdev->mtx);
Johannes Berg55682962007-09-20 13:09:35 -0400150
Luis R. Rodrigueza1794392009-02-21 00:04:21 -0500151 mutex_unlock(&cfg80211_mutex);
Johannes Berg55682962007-09-20 13:09:35 -0400152
Johannes Berg79c97e92009-07-07 03:56:12 +0200153 return rdev;
Johannes Berg55682962007-09-20 13:09:35 -0400154}
155
156struct cfg80211_registered_device *
Johannes Berg463d0182009-07-14 00:33:35 +0200157cfg80211_get_dev_from_ifindex(struct net *net, int ifindex)
Johannes Berg55682962007-09-20 13:09:35 -0400158{
Johannes Berg79c97e92009-07-07 03:56:12 +0200159 struct cfg80211_registered_device *rdev = ERR_PTR(-ENODEV);
Johannes Berg55682962007-09-20 13:09:35 -0400160 struct net_device *dev;
161
Luis R. Rodrigueza1794392009-02-21 00:04:21 -0500162 mutex_lock(&cfg80211_mutex);
Johannes Berg463d0182009-07-14 00:33:35 +0200163 dev = dev_get_by_index(net, ifindex);
Johannes Berg55682962007-09-20 13:09:35 -0400164 if (!dev)
165 goto out;
166 if (dev->ieee80211_ptr) {
Johannes Berg79c97e92009-07-07 03:56:12 +0200167 rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
168 mutex_lock(&rdev->mtx);
Johannes Berg55682962007-09-20 13:09:35 -0400169 } else
Johannes Berg79c97e92009-07-07 03:56:12 +0200170 rdev = ERR_PTR(-ENODEV);
Johannes Berg55682962007-09-20 13:09:35 -0400171 dev_put(dev);
172 out:
Luis R. Rodrigueza1794392009-02-21 00:04:21 -0500173 mutex_unlock(&cfg80211_mutex);
Johannes Berg79c97e92009-07-07 03:56:12 +0200174 return rdev;
Johannes Berg55682962007-09-20 13:09:35 -0400175}
176
Johannes Berg4bbf4d52009-03-24 09:35:46 +0100177/* requires cfg80211_mutex to be held */
Johannes Berg55682962007-09-20 13:09:35 -0400178int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
179 char *newname)
180{
Johannes Berg79c97e92009-07-07 03:56:12 +0200181 struct cfg80211_registered_device *rdev2;
Luis R. Rodriguezb5850a72009-02-21 00:04:19 -0500182 int wiphy_idx, taken = -1, result, digits;
Johannes Berg55682962007-09-20 13:09:35 -0400183
Johannes Berg4bbf4d52009-03-24 09:35:46 +0100184 assert_cfg80211_lock();
Eric W. Biederman2940bb62008-05-08 14:30:18 -0700185
Johannes Berg55682962007-09-20 13:09:35 -0400186 /* prohibit calling the thing phy%d when %d is not its number */
Luis R. Rodriguezb5850a72009-02-21 00:04:19 -0500187 sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken);
188 if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) {
189 /* count number of places needed to print wiphy_idx */
Johannes Berg55682962007-09-20 13:09:35 -0400190 digits = 1;
Luis R. Rodriguezb5850a72009-02-21 00:04:19 -0500191 while (wiphy_idx /= 10)
Johannes Berg55682962007-09-20 13:09:35 -0400192 digits++;
193 /*
194 * deny the name if it is phy<idx> where <idx> is printed
195 * without leading zeroes. taken == strlen(newname) here
196 */
197 if (taken == strlen(PHY_NAME) + digits)
Johannes Berg4bbf4d52009-03-24 09:35:46 +0100198 return -EINVAL;
Johannes Berg55682962007-09-20 13:09:35 -0400199 }
200
Eric W. Biederman2940bb62008-05-08 14:30:18 -0700201
202 /* Ignore nop renames */
Eric W. Biederman2940bb62008-05-08 14:30:18 -0700203 if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0)
Johannes Berg4bbf4d52009-03-24 09:35:46 +0100204 return 0;
Eric W. Biederman2940bb62008-05-08 14:30:18 -0700205
206 /* Ensure another device does not already have this name. */
Johannes Berg79c97e92009-07-07 03:56:12 +0200207 list_for_each_entry(rdev2, &cfg80211_rdev_list, list)
208 if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0)
Johannes Berg4bbf4d52009-03-24 09:35:46 +0100209 return -EINVAL;
Eric W. Biederman2940bb62008-05-08 14:30:18 -0700210
Johannes Berg55682962007-09-20 13:09:35 -0400211 result = device_rename(&rdev->wiphy.dev, newname);
212 if (result)
Johannes Berg4bbf4d52009-03-24 09:35:46 +0100213 return result;
Johannes Berg55682962007-09-20 13:09:35 -0400214
Johannes Berg33c03602008-10-08 10:23:48 +0200215 if (rdev->wiphy.debugfsdir &&
216 !debugfs_rename(rdev->wiphy.debugfsdir->d_parent,
Johannes Berg55682962007-09-20 13:09:35 -0400217 rdev->wiphy.debugfsdir,
218 rdev->wiphy.debugfsdir->d_parent,
219 newname))
220 printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n",
221 newname);
222
Johannes Berg4bbf4d52009-03-24 09:35:46 +0100223 nl80211_notify_dev_rename(rdev);
Johannes Berg55682962007-09-20 13:09:35 -0400224
Johannes Berg4bbf4d52009-03-24 09:35:46 +0100225 return 0;
Johannes Berg55682962007-09-20 13:09:35 -0400226}
227
Johannes Berg463d0182009-07-14 00:33:35 +0200228int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
229 struct net *net)
230{
231 struct wireless_dev *wdev;
232 int err = 0;
233
Johannes Berg5be83de2009-11-19 00:56:28 +0100234 if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK))
Johannes Berg463d0182009-07-14 00:33:35 +0200235 return -EOPNOTSUPP;
236
237 list_for_each_entry(wdev, &rdev->netdev_list, list) {
238 wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
239 err = dev_change_net_namespace(wdev->netdev, net, "wlan%d");
240 if (err)
241 break;
242 wdev->netdev->features |= NETIF_F_NETNS_LOCAL;
243 }
244
245 if (err) {
246 /* failed -- clean up to old netns */
247 net = wiphy_net(&rdev->wiphy);
248
249 list_for_each_entry_continue_reverse(wdev, &rdev->netdev_list,
250 list) {
251 wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
252 err = dev_change_net_namespace(wdev->netdev, net,
253 "wlan%d");
254 WARN_ON(err);
255 wdev->netdev->features |= NETIF_F_NETNS_LOCAL;
256 }
257 }
258
259 wiphy_net_set(&rdev->wiphy, net);
260
261 return err;
262}
263
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200264static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
265{
Johannes Berg79c97e92009-07-07 03:56:12 +0200266 struct cfg80211_registered_device *rdev = data;
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200267
Johannes Berg79c97e92009-07-07 03:56:12 +0200268 rdev->ops->rfkill_poll(&rdev->wiphy);
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200269}
270
271static int cfg80211_rfkill_set_block(void *data, bool blocked)
272{
Johannes Berg79c97e92009-07-07 03:56:12 +0200273 struct cfg80211_registered_device *rdev = data;
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200274 struct wireless_dev *wdev;
275
276 if (!blocked)
277 return 0;
278
279 rtnl_lock();
Johannes Berg79c97e92009-07-07 03:56:12 +0200280 mutex_lock(&rdev->devlist_mtx);
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200281
Johannes Berg79c97e92009-07-07 03:56:12 +0200282 list_for_each_entry(wdev, &rdev->netdev_list, list)
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200283 dev_close(wdev->netdev);
284
Johannes Berg79c97e92009-07-07 03:56:12 +0200285 mutex_unlock(&rdev->devlist_mtx);
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200286 rtnl_unlock();
287
288 return 0;
289}
290
291static void cfg80211_rfkill_sync_work(struct work_struct *work)
292{
Johannes Berg79c97e92009-07-07 03:56:12 +0200293 struct cfg80211_registered_device *rdev;
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200294
Johannes Berg79c97e92009-07-07 03:56:12 +0200295 rdev = container_of(work, struct cfg80211_registered_device, rfkill_sync);
296 cfg80211_rfkill_set_block(rdev, rfkill_blocked(rdev->rfkill));
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200297}
298
Johannes Berg667503dd2009-07-07 03:56:11 +0200299static void cfg80211_event_work(struct work_struct *work)
300{
301 struct cfg80211_registered_device *rdev;
Johannes Berg667503dd2009-07-07 03:56:11 +0200302
303 rdev = container_of(work, struct cfg80211_registered_device,
304 event_work);
305
306 rtnl_lock();
307 cfg80211_lock_rdev(rdev);
Johannes Berg667503dd2009-07-07 03:56:11 +0200308
Johannes Berg3d54d252009-08-21 14:51:05 +0200309 cfg80211_process_rdev_events(rdev);
Johannes Berg667503dd2009-07-07 03:56:11 +0200310 cfg80211_unlock_rdev(rdev);
311 rtnl_unlock();
312}
313
Johannes Berg704232c2007-04-23 12:20:05 -0700314/* exported functions */
315
David Kilroy3dcf6702009-05-16 23:13:46 +0100316struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
Johannes Berg704232c2007-04-23 12:20:05 -0700317{
Denis ChengRq638af072008-09-23 02:35:37 +0800318 static int wiphy_counter;
319
Johannes Berg79c97e92009-07-07 03:56:12 +0200320 struct cfg80211_registered_device *rdev;
Johannes Berg704232c2007-04-23 12:20:05 -0700321 int alloc_size;
322
Johannes Berg0b20633d2009-07-07 03:56:13 +0200323 WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key));
324 WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc));
325 WARN_ON(ops->connect && !ops->disconnect);
326 WARN_ON(ops->join_ibss && !ops->leave_ibss);
327 WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf);
328 WARN_ON(ops->add_station && !ops->del_station);
329 WARN_ON(ops->add_mpath && !ops->del_mpath);
Johannes Berg41ade002007-12-19 02:03:29 +0100330
Johannes Berg79c97e92009-07-07 03:56:12 +0200331 alloc_size = sizeof(*rdev) + sizeof_priv;
Johannes Berg704232c2007-04-23 12:20:05 -0700332
Johannes Berg79c97e92009-07-07 03:56:12 +0200333 rdev = kzalloc(alloc_size, GFP_KERNEL);
334 if (!rdev)
Johannes Berg704232c2007-04-23 12:20:05 -0700335 return NULL;
336
Johannes Berg79c97e92009-07-07 03:56:12 +0200337 rdev->ops = ops;
Johannes Berg704232c2007-04-23 12:20:05 -0700338
Luis R. Rodrigueza1794392009-02-21 00:04:21 -0500339 mutex_lock(&cfg80211_mutex);
Johannes Berg704232c2007-04-23 12:20:05 -0700340
Johannes Berg79c97e92009-07-07 03:56:12 +0200341 rdev->wiphy_idx = wiphy_counter++;
Johannes Berga4d73ee2007-04-26 20:50:35 -0700342
Johannes Berg79c97e92009-07-07 03:56:12 +0200343 if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) {
Denis ChengRq638af072008-09-23 02:35:37 +0800344 wiphy_counter--;
Luis R. Rodrigueza1794392009-02-21 00:04:21 -0500345 mutex_unlock(&cfg80211_mutex);
Johannes Berg704232c2007-04-23 12:20:05 -0700346 /* ugh, wrapped! */
Johannes Berg79c97e92009-07-07 03:56:12 +0200347 kfree(rdev);
Johannes Berg704232c2007-04-23 12:20:05 -0700348 return NULL;
349 }
Johannes Berg704232c2007-04-23 12:20:05 -0700350
Luis R. Rodrigueza1794392009-02-21 00:04:21 -0500351 mutex_unlock(&cfg80211_mutex);
Denis ChengRq638af072008-09-23 02:35:37 +0800352
Johannes Berg704232c2007-04-23 12:20:05 -0700353 /* give it a proper name */
Johannes Berg79c97e92009-07-07 03:56:12 +0200354 dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
Johannes Berg704232c2007-04-23 12:20:05 -0700355
Johannes Berg79c97e92009-07-07 03:56:12 +0200356 mutex_init(&rdev->mtx);
357 mutex_init(&rdev->devlist_mtx);
358 INIT_LIST_HEAD(&rdev->netdev_list);
359 spin_lock_init(&rdev->bss_lock);
360 INIT_LIST_HEAD(&rdev->bss_list);
361 INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
Johannes Berg704232c2007-04-23 12:20:05 -0700362
Johannes Berg3d23e342009-09-29 23:27:28 +0200363#ifdef CONFIG_CFG80211_WEXT
364 rdev->wiphy.wext = &cfg80211_wext_handler;
365#endif
366
Johannes Berg79c97e92009-07-07 03:56:12 +0200367 device_initialize(&rdev->wiphy.dev);
368 rdev->wiphy.dev.class = &ieee80211_class;
369 rdev->wiphy.dev.platform_data = rdev;
Johannes Berg704232c2007-04-23 12:20:05 -0700370
Johannes Berg5be83de2009-11-19 00:56:28 +0100371#ifdef CONFIG_CFG80211_DEFAULT_PS
372 rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
373#endif
Johannes Berg16cb9d42009-08-12 23:33:20 +0200374
Johannes Berg463d0182009-07-14 00:33:35 +0200375 wiphy_net_set(&rdev->wiphy, &init_net);
376
Johannes Berg79c97e92009-07-07 03:56:12 +0200377 rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block;
378 rdev->rfkill = rfkill_alloc(dev_name(&rdev->wiphy.dev),
379 &rdev->wiphy.dev, RFKILL_TYPE_WLAN,
380 &rdev->rfkill_ops, rdev);
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200381
Johannes Berg79c97e92009-07-07 03:56:12 +0200382 if (!rdev->rfkill) {
383 kfree(rdev);
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200384 return NULL;
385 }
386
Johannes Berg79c97e92009-07-07 03:56:12 +0200387 INIT_WORK(&rdev->rfkill_sync, cfg80211_rfkill_sync_work);
388 INIT_WORK(&rdev->conn_work, cfg80211_conn_work);
389 INIT_WORK(&rdev->event_work, cfg80211_event_work);
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200390
Johannes Bergad002392009-08-18 19:51:57 +0200391 init_waitqueue_head(&rdev->dev_wait);
392
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +0200393 /*
394 * Initialize wiphy parameters to IEEE 802.11 MIB default values.
395 * Fragmentation and RTS threshold are disabled by default with the
396 * special -1 value.
397 */
Johannes Berg79c97e92009-07-07 03:56:12 +0200398 rdev->wiphy.retry_short = 7;
399 rdev->wiphy.retry_long = 4;
400 rdev->wiphy.frag_threshold = (u32) -1;
401 rdev->wiphy.rts_threshold = (u32) -1;
Jouni Malinenb9a5f8ca2009-04-20 18:39:05 +0200402
Johannes Berg79c97e92009-07-07 03:56:12 +0200403 return &rdev->wiphy;
Johannes Berg704232c2007-04-23 12:20:05 -0700404}
405EXPORT_SYMBOL(wiphy_new);
406
407int wiphy_register(struct wiphy *wiphy)
408{
Johannes Berg79c97e92009-07-07 03:56:12 +0200409 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
Johannes Berg704232c2007-04-23 12:20:05 -0700410 int res;
Johannes Berg8318d782008-01-24 19:38:38 +0100411 enum ieee80211_band band;
412 struct ieee80211_supported_band *sband;
413 bool have_band = false;
414 int i;
Luis R. Rodriguezf59ac042008-08-29 16:26:43 -0700415 u16 ifmodes = wiphy->interface_modes;
416
417 /* sanity check ifmodes */
418 WARN_ON(!ifmodes);
419 ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1;
420 if (WARN_ON(ifmodes != wiphy->interface_modes))
421 wiphy->interface_modes = ifmodes;
Johannes Berg8318d782008-01-24 19:38:38 +0100422
423 /* sanity check supported bands/channels */
424 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
425 sband = wiphy->bands[band];
426 if (!sband)
427 continue;
428
429 sband->band = band;
430
Johannes Berg881d9482009-01-21 15:13:48 +0100431 if (WARN_ON(!sband->n_channels || !sband->n_bitrates))
Johannes Berg8318d782008-01-24 19:38:38 +0100432 return -EINVAL;
Johannes Berg881d9482009-01-21 15:13:48 +0100433
434 /*
435 * Since we use a u32 for rate bitmaps in
436 * ieee80211_get_response_rate, we cannot
437 * have more than 32 legacy rates.
438 */
439 if (WARN_ON(sband->n_bitrates > 32))
440 return -EINVAL;
Johannes Berg8318d782008-01-24 19:38:38 +0100441
442 for (i = 0; i < sband->n_channels; i++) {
443 sband->channels[i].orig_flags =
444 sband->channels[i].flags;
445 sband->channels[i].orig_mag =
446 sband->channels[i].max_antenna_gain;
447 sband->channels[i].orig_mpwr =
448 sband->channels[i].max_power;
449 sband->channels[i].band = band;
450 }
451
452 have_band = true;
453 }
454
455 if (!have_band) {
456 WARN_ON(1);
457 return -EINVAL;
458 }
459
460 /* check and set up bitrates */
461 ieee80211_set_bitrate_flags(wiphy);
462
Johannes Berg79c97e92009-07-07 03:56:12 +0200463 res = device_add(&rdev->wiphy.dev);
Johannes Berg704232c2007-04-23 12:20:05 -0700464 if (res)
Johannes Berg2f0accc2009-06-10 16:50:29 +0200465 return res;
Johannes Berg704232c2007-04-23 12:20:05 -0700466
Johannes Berg79c97e92009-07-07 03:56:12 +0200467 res = rfkill_register(rdev->rfkill);
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200468 if (res)
469 goto out_rm_dev;
470
Johannes Berg2f0accc2009-06-10 16:50:29 +0200471 mutex_lock(&cfg80211_mutex);
472
473 /* set up regulatory info */
474 wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
475
Johannes Berg79c97e92009-07-07 03:56:12 +0200476 list_add(&rdev->list, &cfg80211_rdev_list);
Johannes Bergf5ea9122009-08-07 16:17:38 +0200477 cfg80211_rdev_list_generation++;
Johannes Berg704232c2007-04-23 12:20:05 -0700478
Johannes Berg2f0accc2009-06-10 16:50:29 +0200479 mutex_unlock(&cfg80211_mutex);
480
Johannes Berg704232c2007-04-23 12:20:05 -0700481 /* add to debugfs */
Johannes Berg79c97e92009-07-07 03:56:12 +0200482 rdev->wiphy.debugfsdir =
483 debugfs_create_dir(wiphy_name(&rdev->wiphy),
Johannes Berg704232c2007-04-23 12:20:05 -0700484 ieee80211_debugfs_dir);
Johannes Berg79c97e92009-07-07 03:56:12 +0200485 if (IS_ERR(rdev->wiphy.debugfsdir))
486 rdev->wiphy.debugfsdir = NULL;
Johannes Berg704232c2007-04-23 12:20:05 -0700487
Johannes Berg5be83de2009-11-19 00:56:28 +0100488 if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) {
Luis R. Rodriguez73d54c92009-03-09 22:07:42 -0400489 struct regulatory_request request;
490
491 request.wiphy_idx = get_wiphy_idx(wiphy);
492 request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
493 request.alpha2[0] = '9';
494 request.alpha2[1] = '9';
495
496 nl80211_send_reg_change_event(&request);
497 }
498
Johannes Berg79c97e92009-07-07 03:56:12 +0200499 cfg80211_debugfs_rdev_add(rdev);
Luis R. Rodriguez1ac61302009-05-02 00:37:21 -0400500
Johannes Berg2f0accc2009-06-10 16:50:29 +0200501 return 0;
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200502
503 out_rm_dev:
Johannes Berg79c97e92009-07-07 03:56:12 +0200504 device_del(&rdev->wiphy.dev);
Johannes Berg704232c2007-04-23 12:20:05 -0700505 return res;
506}
507EXPORT_SYMBOL(wiphy_register);
508
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200509void wiphy_rfkill_start_polling(struct wiphy *wiphy)
510{
Johannes Berg79c97e92009-07-07 03:56:12 +0200511 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200512
Johannes Berg79c97e92009-07-07 03:56:12 +0200513 if (!rdev->ops->rfkill_poll)
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200514 return;
Johannes Berg79c97e92009-07-07 03:56:12 +0200515 rdev->rfkill_ops.poll = cfg80211_rfkill_poll;
516 rfkill_resume_polling(rdev->rfkill);
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200517}
518EXPORT_SYMBOL(wiphy_rfkill_start_polling);
519
520void wiphy_rfkill_stop_polling(struct wiphy *wiphy)
521{
Johannes Berg79c97e92009-07-07 03:56:12 +0200522 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200523
Johannes Berg79c97e92009-07-07 03:56:12 +0200524 rfkill_pause_polling(rdev->rfkill);
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200525}
526EXPORT_SYMBOL(wiphy_rfkill_stop_polling);
527
Johannes Berg704232c2007-04-23 12:20:05 -0700528void wiphy_unregister(struct wiphy *wiphy)
529{
Johannes Berg79c97e92009-07-07 03:56:12 +0200530 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
Johannes Berg704232c2007-04-23 12:20:05 -0700531
Johannes Berg79c97e92009-07-07 03:56:12 +0200532 rfkill_unregister(rdev->rfkill);
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200533
Johannes Bergf16bfc12007-04-26 20:51:12 -0700534 /* protect the device list */
Luis R. Rodrigueza1794392009-02-21 00:04:21 -0500535 mutex_lock(&cfg80211_mutex);
Johannes Berg704232c2007-04-23 12:20:05 -0700536
Johannes Bergad002392009-08-18 19:51:57 +0200537 wait_event(rdev->dev_wait, ({
538 int __count;
539 mutex_lock(&rdev->devlist_mtx);
540 __count = rdev->opencount;
541 mutex_unlock(&rdev->devlist_mtx);
542 __count == 0;}));
543
544 mutex_lock(&rdev->devlist_mtx);
Johannes Berg79c97e92009-07-07 03:56:12 +0200545 BUG_ON(!list_empty(&rdev->netdev_list));
Johannes Bergad002392009-08-18 19:51:57 +0200546 mutex_unlock(&rdev->devlist_mtx);
547
548 /*
549 * First remove the hardware from everywhere, this makes
550 * it impossible to find from userspace.
551 */
Johannes Berg7bcfaf22009-10-27 12:59:03 +0100552 debugfs_remove_recursive(rdev->wiphy.debugfsdir);
Johannes Bergad002392009-08-18 19:51:57 +0200553 list_del(&rdev->list);
Johannes Bergf16bfc12007-04-26 20:51:12 -0700554
555 /*
Johannes Berg79c97e92009-07-07 03:56:12 +0200556 * Try to grab rdev->mtx. If a command is still in progress,
Johannes Bergf16bfc12007-04-26 20:51:12 -0700557 * hopefully the driver will refuse it since it's tearing
558 * down the device already. We wait for this command to complete
559 * before unlinking the item from the list.
560 * Note: as codified by the BUG_ON above we cannot get here if
Johannes Bergad002392009-08-18 19:51:57 +0200561 * a virtual interface is still present. Hence, we can only get
562 * to lock contention here if userspace issues a command that
563 * identified the hardware by wiphy index.
Johannes Bergf16bfc12007-04-26 20:51:12 -0700564 */
Johannes Berg0ff6ce72009-08-17 12:25:37 +0200565 cfg80211_lock_rdev(rdev);
Johannes Bergad002392009-08-18 19:51:57 +0200566 /* nothing */
Johannes Berg0ff6ce72009-08-17 12:25:37 +0200567 cfg80211_unlock_rdev(rdev);
Johannes Berg704232c2007-04-23 12:20:05 -0700568
Luis R. Rodriguez3f2355c2008-11-12 14:22:02 -0800569 /* If this device got a regulatory hint tell core its
570 * free to listen now to a new shiny device regulatory hint */
571 reg_device_remove(wiphy);
572
Johannes Bergf5ea9122009-08-07 16:17:38 +0200573 cfg80211_rdev_list_generation++;
Johannes Berg79c97e92009-07-07 03:56:12 +0200574 device_del(&rdev->wiphy.dev);
Johannes Berg704232c2007-04-23 12:20:05 -0700575
Luis R. Rodrigueza1794392009-02-21 00:04:21 -0500576 mutex_unlock(&cfg80211_mutex);
Johannes Berg66825882009-07-13 13:24:44 +0200577
Johannes Berg36e6fea2009-08-12 22:21:21 +0200578 flush_work(&rdev->scan_done_wk);
Johannes Berg66825882009-07-13 13:24:44 +0200579 cancel_work_sync(&rdev->conn_work);
Johannes Berg66825882009-07-13 13:24:44 +0200580 flush_work(&rdev->event_work);
Johannes Berg704232c2007-04-23 12:20:05 -0700581}
582EXPORT_SYMBOL(wiphy_unregister);
583
Johannes Berg79c97e92009-07-07 03:56:12 +0200584void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
Johannes Berg704232c2007-04-23 12:20:05 -0700585{
Johannes Berg2a519312009-02-10 21:25:55 +0100586 struct cfg80211_internal_bss *scan, *tmp;
Johannes Berg79c97e92009-07-07 03:56:12 +0200587 rfkill_destroy(rdev->rfkill);
588 mutex_destroy(&rdev->mtx);
589 mutex_destroy(&rdev->devlist_mtx);
590 list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
Johannes Berg78c1c7e2009-02-10 21:25:57 +0100591 cfg80211_put_bss(&scan->pub);
Johannes Berg79c97e92009-07-07 03:56:12 +0200592 kfree(rdev);
Johannes Berg704232c2007-04-23 12:20:05 -0700593}
594
595void wiphy_free(struct wiphy *wiphy)
596{
597 put_device(&wiphy->dev);
598}
599EXPORT_SYMBOL(wiphy_free);
600
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200601void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
602{
Johannes Berg79c97e92009-07-07 03:56:12 +0200603 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200604
Johannes Berg79c97e92009-07-07 03:56:12 +0200605 if (rfkill_set_hw_state(rdev->rfkill, blocked))
606 schedule_work(&rdev->rfkill_sync);
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200607}
608EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
609
Johannes Bergad002392009-08-18 19:51:57 +0200610static void wdev_cleanup_work(struct work_struct *work)
611{
612 struct wireless_dev *wdev;
613 struct cfg80211_registered_device *rdev;
614
615 wdev = container_of(work, struct wireless_dev, cleanup_work);
616 rdev = wiphy_to_dev(wdev->wiphy);
617
618 cfg80211_lock_rdev(rdev);
619
620 if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) {
621 rdev->scan_req->aborted = true;
Johannes Berg01a0ac42009-08-20 21:36:16 +0200622 ___cfg80211_scan_done(rdev, true);
Johannes Bergad002392009-08-18 19:51:57 +0200623 }
624
625 cfg80211_unlock_rdev(rdev);
626
627 mutex_lock(&rdev->devlist_mtx);
628 rdev->opencount--;
629 mutex_unlock(&rdev->devlist_mtx);
630 wake_up(&rdev->dev_wait);
631
632 dev_put(wdev->netdev);
633}
634
Marcel Holtmann053a93d2009-10-02 05:15:28 +0000635static struct device_type wiphy_type = {
636 .name = "wlan",
637};
638
Johannes Berg704232c2007-04-23 12:20:05 -0700639static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
640 unsigned long state,
641 void *ndev)
642{
643 struct net_device *dev = ndev;
Johannes Berg2a783c12009-07-01 21:26:45 +0200644 struct wireless_dev *wdev = dev->ieee80211_ptr;
Johannes Berg704232c2007-04-23 12:20:05 -0700645 struct cfg80211_registered_device *rdev;
646
Johannes Berg2a783c12009-07-01 21:26:45 +0200647 if (!wdev)
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200648 return NOTIFY_DONE;
Johannes Berg704232c2007-04-23 12:20:05 -0700649
Johannes Berg2a783c12009-07-01 21:26:45 +0200650 rdev = wiphy_to_dev(wdev->wiphy);
Johannes Berg704232c2007-04-23 12:20:05 -0700651
Johannes Berg2a783c12009-07-01 21:26:45 +0200652 WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED);
Johannes Berg60719ff2008-09-16 14:55:09 +0200653
Johannes Berg704232c2007-04-23 12:20:05 -0700654 switch (state) {
Marcel Holtmann053a93d2009-10-02 05:15:28 +0000655 case NETDEV_POST_INIT:
656 SET_NETDEV_DEVTYPE(dev, &wiphy_type);
657 break;
Johannes Berg704232c2007-04-23 12:20:05 -0700658 case NETDEV_REGISTER:
Johannes Berg0ff6ce72009-08-17 12:25:37 +0200659 /*
660 * NB: cannot take rdev->mtx here because this may be
661 * called within code protected by it when interfaces
662 * are added with nl80211.
663 */
Johannes Berg667503dd2009-07-07 03:56:11 +0200664 mutex_init(&wdev->mtx);
Johannes Bergad002392009-08-18 19:51:57 +0200665 INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work);
Johannes Berg667503dd2009-07-07 03:56:11 +0200666 INIT_LIST_HEAD(&wdev->event_list);
667 spin_lock_init(&wdev->event_lock);
Johannes Berg704232c2007-04-23 12:20:05 -0700668 mutex_lock(&rdev->devlist_mtx);
Johannes Berg2a783c12009-07-01 21:26:45 +0200669 list_add(&wdev->list, &rdev->netdev_list);
Johannes Bergf5ea9122009-08-07 16:17:38 +0200670 rdev->devlist_generation++;
Johannes Berg463d0182009-07-14 00:33:35 +0200671 /* can only change netns with wiphy */
672 dev->features |= NETIF_F_NETNS_LOCAL;
673
Johannes Berg704232c2007-04-23 12:20:05 -0700674 if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj,
675 "phy80211")) {
676 printk(KERN_ERR "wireless: failed to add phy80211 "
677 "symlink to netdev!\n");
678 }
Johannes Berg2a783c12009-07-01 21:26:45 +0200679 wdev->netdev = dev;
Samuel Ortizb23aa672009-07-01 21:26:54 +0200680 wdev->sme_state = CFG80211_SME_IDLE;
Johannes Bergbc92afd2009-07-01 21:26:57 +0200681 mutex_unlock(&rdev->devlist_mtx);
Johannes Berg3d23e342009-09-29 23:27:28 +0200682#ifdef CONFIG_CFG80211_WEXT
Johannes Berg2a783c12009-07-01 21:26:45 +0200683 wdev->wext.default_key = -1;
684 wdev->wext.default_mgmt_key = -1;
Johannes Bergf2129352009-07-01 21:26:56 +0200685 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
Johannes Berg5be83de2009-11-19 00:56:28 +0100686 if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT)
687 wdev->wext.ps = true;
688 else
689 wdev->wext.ps = false;
Johannes Berg75e6c3b2009-07-31 11:18:13 +0200690 wdev->wext.ps_timeout = 100;
Johannes Bergbc92afd2009-07-01 21:26:57 +0200691 if (rdev->ops->set_power_mgmt)
692 if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
693 wdev->wext.ps,
694 wdev->wext.ps_timeout)) {
695 /* assume this means it's off */
696 wdev->wext.ps = false;
697 }
Johannes Berg08645122009-05-11 13:54:58 +0200698#endif
John W. Linville4890e3b2009-09-30 14:50:17 -0400699 if (!dev->ethtool_ops)
700 dev->ethtool_ops = &cfg80211_ethtool_ops;
Johannes Bergad4bb6f2009-11-19 00:56:30 +0100701
702 if ((wdev->iftype == NL80211_IFTYPE_STATION ||
703 wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
704 dev->priv_flags |= IFF_DONT_BRIDGE;
Johannes Berg704232c2007-04-23 12:20:05 -0700705 break;
Johannes Berg04a773a2009-04-19 21:24:32 +0200706 case NETDEV_GOING_DOWN:
Samuel Ortizb23aa672009-07-01 21:26:54 +0200707 switch (wdev->iftype) {
708 case NL80211_IFTYPE_ADHOC:
709 cfg80211_leave_ibss(rdev, dev, true);
710 break;
711 case NL80211_IFTYPE_STATION:
Johannes Berg667503dd2009-07-07 03:56:11 +0200712 wdev_lock(wdev);
Johannes Berg3d23e342009-09-29 23:27:28 +0200713#ifdef CONFIG_CFG80211_WEXT
Johannes Bergf2129352009-07-01 21:26:56 +0200714 kfree(wdev->wext.ie);
715 wdev->wext.ie = NULL;
716 wdev->wext.ie_len = 0;
Johannes Berg0eb14642009-07-02 15:49:03 +0200717 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
Johannes Bergf2129352009-07-01 21:26:56 +0200718#endif
Johannes Berg667503dd2009-07-07 03:56:11 +0200719 __cfg80211_disconnect(rdev, dev,
720 WLAN_REASON_DEAUTH_LEAVING, true);
Johannes Berg19957bb2009-07-02 17:20:43 +0200721 cfg80211_mlme_down(rdev, dev);
Johannes Berg667503dd2009-07-07 03:56:11 +0200722 wdev_unlock(wdev);
Samuel Ortizb23aa672009-07-01 21:26:54 +0200723 break;
724 default:
725 break;
726 }
Johannes Berg01a0ac42009-08-20 21:36:16 +0200727 break;
728 case NETDEV_DOWN:
Johannes Bergad002392009-08-18 19:51:57 +0200729 dev_hold(dev);
730 schedule_work(&wdev->cleanup_work);
Johannes Berg04a773a2009-04-19 21:24:32 +0200731 break;
732 case NETDEV_UP:
Johannes Bergad002392009-08-18 19:51:57 +0200733 /*
734 * If we have a really quick DOWN/UP succession we may
735 * have this work still pending ... cancel it and see
736 * if it was pending, in which case we need to account
737 * for some of the work it would have done.
738 */
739 if (cancel_work_sync(&wdev->cleanup_work)) {
740 mutex_lock(&rdev->devlist_mtx);
741 rdev->opencount--;
742 mutex_unlock(&rdev->devlist_mtx);
743 dev_put(dev);
744 }
Johannes Berg3d23e342009-09-29 23:27:28 +0200745#ifdef CONFIG_CFG80211_WEXT
Johannes Berg667503dd2009-07-07 03:56:11 +0200746 cfg80211_lock_rdev(rdev);
Johannes Bergaee83ea2009-08-09 11:51:29 +0200747 mutex_lock(&rdev->devlist_mtx);
Johannes Berg667503dd2009-07-07 03:56:11 +0200748 wdev_lock(wdev);
Johannes Bergf2129352009-07-01 21:26:56 +0200749 switch (wdev->iftype) {
750 case NL80211_IFTYPE_ADHOC:
Johannes Bergfffd0932009-07-08 14:22:54 +0200751 cfg80211_ibss_wext_join(rdev, wdev);
Johannes Berg04a773a2009-04-19 21:24:32 +0200752 break;
Johannes Bergf2129352009-07-01 21:26:56 +0200753 case NL80211_IFTYPE_STATION:
Johannes Bergfffd0932009-07-08 14:22:54 +0200754 cfg80211_mgd_wext_connect(rdev, wdev);
Johannes Berg04a773a2009-04-19 21:24:32 +0200755 break;
Johannes Bergf2129352009-07-01 21:26:56 +0200756 default:
757 break;
758 }
Johannes Berg667503dd2009-07-07 03:56:11 +0200759 wdev_unlock(wdev);
Johannes Bergad002392009-08-18 19:51:57 +0200760 rdev->opencount++;
Johannes Bergaee83ea2009-08-09 11:51:29 +0200761 mutex_unlock(&rdev->devlist_mtx);
Johannes Berg667503dd2009-07-07 03:56:11 +0200762 cfg80211_unlock_rdev(rdev);
Johannes Berg04a773a2009-04-19 21:24:32 +0200763#endif
Johannes Berg2a783c12009-07-01 21:26:45 +0200764 break;
Johannes Berg704232c2007-04-23 12:20:05 -0700765 case NETDEV_UNREGISTER:
Johannes Berg0ff6ce72009-08-17 12:25:37 +0200766 /*
767 * NB: cannot take rdev->mtx here because this may be
768 * called within code protected by it when interfaces
769 * are removed with nl80211.
770 */
Johannes Berg704232c2007-04-23 12:20:05 -0700771 mutex_lock(&rdev->devlist_mtx);
Johannes Berge40cbdac2009-07-30 14:04:01 +0200772 /*
773 * It is possible to get NETDEV_UNREGISTER
774 * multiple times. To detect that, check
775 * that the interface is still on the list
776 * of registered interfaces, and only then
777 * remove and clean it up.
778 */
Johannes Berg2a783c12009-07-01 21:26:45 +0200779 if (!list_empty(&wdev->list)) {
Johannes Berg704232c2007-04-23 12:20:05 -0700780 sysfs_remove_link(&dev->dev.kobj, "phy80211");
Johannes Berg2a783c12009-07-01 21:26:45 +0200781 list_del_init(&wdev->list);
Johannes Bergf5ea9122009-08-07 16:17:38 +0200782 rdev->devlist_generation++;
Johannes Berg3d23e342009-09-29 23:27:28 +0200783#ifdef CONFIG_CFG80211_WEXT
Johannes Berge40cbdac2009-07-30 14:04:01 +0200784 kfree(wdev->wext.keys);
785#endif
Johannes Berg704232c2007-04-23 12:20:05 -0700786 }
787 mutex_unlock(&rdev->devlist_mtx);
788 break;
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200789 case NETDEV_PRE_UP:
Johannes Berg0b20633d2009-07-07 03:56:13 +0200790 if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
791 return notifier_from_errno(-EOPNOTSUPP);
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200792 if (rfkill_blocked(rdev->rfkill))
793 return notifier_from_errno(-ERFKILL);
794 break;
Johannes Berg704232c2007-04-23 12:20:05 -0700795 }
796
Johannes Berg1f87f7d2009-06-02 13:01:41 +0200797 return NOTIFY_DONE;
Johannes Berg704232c2007-04-23 12:20:05 -0700798}
799
800static struct notifier_block cfg80211_netdev_notifier = {
801 .notifier_call = cfg80211_netdev_notifier_call,
802};
803
Johannes Berg463d0182009-07-14 00:33:35 +0200804static void __net_exit cfg80211_pernet_exit(struct net *net)
805{
806 struct cfg80211_registered_device *rdev;
807
808 rtnl_lock();
809 mutex_lock(&cfg80211_mutex);
810 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
811 if (net_eq(wiphy_net(&rdev->wiphy), net))
812 WARN_ON(cfg80211_switch_netns(rdev, &init_net));
813 }
814 mutex_unlock(&cfg80211_mutex);
815 rtnl_unlock();
816}
817
818static struct pernet_operations cfg80211_pernet_ops = {
819 .exit = cfg80211_pernet_exit,
820};
821
822static int __init cfg80211_init(void)
Johannes Berg704232c2007-04-23 12:20:05 -0700823{
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700824 int err;
825
Johannes Berg463d0182009-07-14 00:33:35 +0200826 err = register_pernet_device(&cfg80211_pernet_ops);
827 if (err)
828 goto out_fail_pernet;
829
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700830 err = wiphy_sysfs_init();
Johannes Berg704232c2007-04-23 12:20:05 -0700831 if (err)
832 goto out_fail_sysfs;
833
834 err = register_netdevice_notifier(&cfg80211_netdev_notifier);
835 if (err)
836 goto out_fail_notifier;
837
Johannes Berg55682962007-09-20 13:09:35 -0400838 err = nl80211_init();
839 if (err)
840 goto out_fail_nl80211;
841
Johannes Berg704232c2007-04-23 12:20:05 -0700842 ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL);
843
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700844 err = regulatory_init();
845 if (err)
846 goto out_fail_reg;
847
Johannes Berg704232c2007-04-23 12:20:05 -0700848 return 0;
849
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700850out_fail_reg:
851 debugfs_remove(ieee80211_debugfs_dir);
Johannes Berg55682962007-09-20 13:09:35 -0400852out_fail_nl80211:
853 unregister_netdevice_notifier(&cfg80211_netdev_notifier);
Johannes Berg704232c2007-04-23 12:20:05 -0700854out_fail_notifier:
855 wiphy_sysfs_exit();
856out_fail_sysfs:
Johannes Berg463d0182009-07-14 00:33:35 +0200857 unregister_pernet_device(&cfg80211_pernet_ops);
858out_fail_pernet:
Johannes Berg704232c2007-04-23 12:20:05 -0700859 return err;
860}
Johannes Berg3a462462007-09-10 13:44:45 +0200861subsys_initcall(cfg80211_init);
Johannes Berg704232c2007-04-23 12:20:05 -0700862
863static void cfg80211_exit(void)
864{
865 debugfs_remove(ieee80211_debugfs_dir);
Johannes Berg55682962007-09-20 13:09:35 -0400866 nl80211_exit();
Johannes Berg704232c2007-04-23 12:20:05 -0700867 unregister_netdevice_notifier(&cfg80211_netdev_notifier);
868 wiphy_sysfs_exit();
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700869 regulatory_exit();
Johannes Berg463d0182009-07-14 00:33:35 +0200870 unregister_pernet_device(&cfg80211_pernet_ops);
Johannes Berg704232c2007-04-23 12:20:05 -0700871}
872module_exit(cfg80211_exit);