Root/
1 | /* |
2 | * This is the linux wireless configuration interface. |
3 | * |
4 | * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> |
5 | */ |
6 | |
7 | #include <linux/if.h> |
8 | #include <linux/module.h> |
9 | #include <linux/err.h> |
10 | #include <linux/list.h> |
11 | #include <linux/nl80211.h> |
12 | #include <linux/debugfs.h> |
13 | #include <linux/notifier.h> |
14 | #include <linux/device.h> |
15 | #include <linux/etherdevice.h> |
16 | #include <linux/rtnetlink.h> |
17 | #include <linux/sched.h> |
18 | #include <net/genetlink.h> |
19 | #include <net/cfg80211.h> |
20 | #include "nl80211.h" |
21 | #include "core.h" |
22 | #include "sysfs.h" |
23 | #include "debugfs.h" |
24 | #include "wext-compat.h" |
25 | |
26 | /* name for sysfs, %d is appended */ |
27 | #define PHY_NAME "phy" |
28 | |
29 | MODULE_AUTHOR("Johannes Berg"); |
30 | MODULE_LICENSE("GPL"); |
31 | MODULE_DESCRIPTION("wireless configuration support"); |
32 | |
33 | /* RCU might be appropriate here since we usually |
34 | * only read the list, and that can happen quite |
35 | * often because we need to do it for each command */ |
36 | LIST_HEAD(cfg80211_rdev_list); |
37 | int cfg80211_rdev_list_generation; |
38 | |
39 | /* |
40 | * This is used to protect the cfg80211_rdev_list |
41 | */ |
42 | DEFINE_MUTEX(cfg80211_mutex); |
43 | |
44 | /* for debugfs */ |
45 | static struct dentry *ieee80211_debugfs_dir; |
46 | |
47 | /* requires cfg80211_mutex to be held! */ |
48 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) |
49 | { |
50 | struct cfg80211_registered_device *result = NULL, *rdev; |
51 | |
52 | if (!wiphy_idx_valid(wiphy_idx)) |
53 | return NULL; |
54 | |
55 | assert_cfg80211_lock(); |
56 | |
57 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
58 | if (rdev->wiphy_idx == wiphy_idx) { |
59 | result = rdev; |
60 | break; |
61 | } |
62 | } |
63 | |
64 | return result; |
65 | } |
66 | |
67 | int get_wiphy_idx(struct wiphy *wiphy) |
68 | { |
69 | struct cfg80211_registered_device *rdev; |
70 | if (!wiphy) |
71 | return WIPHY_IDX_STALE; |
72 | rdev = wiphy_to_dev(wiphy); |
73 | return rdev->wiphy_idx; |
74 | } |
75 | |
76 | /* requires cfg80211_rdev_mutex to be held! */ |
77 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) |
78 | { |
79 | struct cfg80211_registered_device *rdev; |
80 | |
81 | if (!wiphy_idx_valid(wiphy_idx)) |
82 | return NULL; |
83 | |
84 | assert_cfg80211_lock(); |
85 | |
86 | rdev = cfg80211_rdev_by_wiphy_idx(wiphy_idx); |
87 | if (!rdev) |
88 | return NULL; |
89 | return &rdev->wiphy; |
90 | } |
91 | |
92 | /* requires cfg80211_mutex to be held! */ |
93 | struct cfg80211_registered_device * |
94 | __cfg80211_rdev_from_info(struct genl_info *info) |
95 | { |
96 | int ifindex; |
97 | struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL; |
98 | struct net_device *dev; |
99 | int err = -EINVAL; |
100 | |
101 | assert_cfg80211_lock(); |
102 | |
103 | if (info->attrs[NL80211_ATTR_WIPHY]) { |
104 | bywiphyidx = cfg80211_rdev_by_wiphy_idx( |
105 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY])); |
106 | err = -ENODEV; |
107 | } |
108 | |
109 | if (info->attrs[NL80211_ATTR_IFINDEX]) { |
110 | ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); |
111 | dev = dev_get_by_index(genl_info_net(info), ifindex); |
112 | if (dev) { |
113 | if (dev->ieee80211_ptr) |
114 | byifidx = |
115 | wiphy_to_dev(dev->ieee80211_ptr->wiphy); |
116 | dev_put(dev); |
117 | } |
118 | err = -ENODEV; |
119 | } |
120 | |
121 | if (bywiphyidx && byifidx) { |
122 | if (bywiphyidx != byifidx) |
123 | return ERR_PTR(-EINVAL); |
124 | else |
125 | return bywiphyidx; /* == byifidx */ |
126 | } |
127 | if (bywiphyidx) |
128 | return bywiphyidx; |
129 | |
130 | if (byifidx) |
131 | return byifidx; |
132 | |
133 | return ERR_PTR(err); |
134 | } |
135 | |
136 | struct cfg80211_registered_device * |
137 | cfg80211_get_dev_from_info(struct genl_info *info) |
138 | { |
139 | struct cfg80211_registered_device *rdev; |
140 | |
141 | mutex_lock(&cfg80211_mutex); |
142 | rdev = __cfg80211_rdev_from_info(info); |
143 | |
144 | /* if it is not an error we grab the lock on |
145 | * it to assure it won't be going away while |
146 | * we operate on it */ |
147 | if (!IS_ERR(rdev)) |
148 | mutex_lock(&rdev->mtx); |
149 | |
150 | mutex_unlock(&cfg80211_mutex); |
151 | |
152 | return rdev; |
153 | } |
154 | |
155 | struct cfg80211_registered_device * |
156 | cfg80211_get_dev_from_ifindex(struct net *net, int ifindex) |
157 | { |
158 | struct cfg80211_registered_device *rdev = ERR_PTR(-ENODEV); |
159 | struct net_device *dev; |
160 | |
161 | mutex_lock(&cfg80211_mutex); |
162 | dev = dev_get_by_index(net, ifindex); |
163 | if (!dev) |
164 | goto out; |
165 | if (dev->ieee80211_ptr) { |
166 | rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy); |
167 | mutex_lock(&rdev->mtx); |
168 | } else |
169 | rdev = ERR_PTR(-ENODEV); |
170 | dev_put(dev); |
171 | out: |
172 | mutex_unlock(&cfg80211_mutex); |
173 | return rdev; |
174 | } |
175 | |
176 | /* requires cfg80211_mutex to be held */ |
177 | int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, |
178 | char *newname) |
179 | { |
180 | struct cfg80211_registered_device *rdev2; |
181 | int wiphy_idx, taken = -1, result, digits; |
182 | |
183 | assert_cfg80211_lock(); |
184 | |
185 | /* prohibit calling the thing phy%d when %d is not its number */ |
186 | sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); |
187 | if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) { |
188 | /* count number of places needed to print wiphy_idx */ |
189 | digits = 1; |
190 | while (wiphy_idx /= 10) |
191 | digits++; |
192 | /* |
193 | * deny the name if it is phy<idx> where <idx> is printed |
194 | * without leading zeroes. taken == strlen(newname) here |
195 | */ |
196 | if (taken == strlen(PHY_NAME) + digits) |
197 | return -EINVAL; |
198 | } |
199 | |
200 | |
201 | /* Ignore nop renames */ |
202 | if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0) |
203 | return 0; |
204 | |
205 | /* Ensure another device does not already have this name. */ |
206 | list_for_each_entry(rdev2, &cfg80211_rdev_list, list) |
207 | if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0) |
208 | return -EINVAL; |
209 | |
210 | result = device_rename(&rdev->wiphy.dev, newname); |
211 | if (result) |
212 | return result; |
213 | |
214 | if (rdev->wiphy.debugfsdir && |
215 | !debugfs_rename(rdev->wiphy.debugfsdir->d_parent, |
216 | rdev->wiphy.debugfsdir, |
217 | rdev->wiphy.debugfsdir->d_parent, |
218 | newname)) |
219 | printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n", |
220 | newname); |
221 | |
222 | nl80211_notify_dev_rename(rdev); |
223 | |
224 | return 0; |
225 | } |
226 | |
227 | int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, |
228 | struct net *net) |
229 | { |
230 | struct wireless_dev *wdev; |
231 | int err = 0; |
232 | |
233 | if (!rdev->wiphy.netnsok) |
234 | return -EOPNOTSUPP; |
235 | |
236 | list_for_each_entry(wdev, &rdev->netdev_list, list) { |
237 | wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; |
238 | err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); |
239 | if (err) |
240 | break; |
241 | wdev->netdev->features |= NETIF_F_NETNS_LOCAL; |
242 | } |
243 | |
244 | if (err) { |
245 | /* failed -- clean up to old netns */ |
246 | net = wiphy_net(&rdev->wiphy); |
247 | |
248 | list_for_each_entry_continue_reverse(wdev, &rdev->netdev_list, |
249 | list) { |
250 | wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; |
251 | err = dev_change_net_namespace(wdev->netdev, net, |
252 | "wlan%d"); |
253 | WARN_ON(err); |
254 | wdev->netdev->features |= NETIF_F_NETNS_LOCAL; |
255 | } |
256 | } |
257 | |
258 | wiphy_net_set(&rdev->wiphy, net); |
259 | |
260 | return err; |
261 | } |
262 | |
263 | static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) |
264 | { |
265 | struct cfg80211_registered_device *rdev = data; |
266 | |
267 | rdev->ops->rfkill_poll(&rdev->wiphy); |
268 | } |
269 | |
270 | static int cfg80211_rfkill_set_block(void *data, bool blocked) |
271 | { |
272 | struct cfg80211_registered_device *rdev = data; |
273 | struct wireless_dev *wdev; |
274 | |
275 | if (!blocked) |
276 | return 0; |
277 | |
278 | rtnl_lock(); |
279 | mutex_lock(&rdev->devlist_mtx); |
280 | |
281 | list_for_each_entry(wdev, &rdev->netdev_list, list) |
282 | dev_close(wdev->netdev); |
283 | |
284 | mutex_unlock(&rdev->devlist_mtx); |
285 | rtnl_unlock(); |
286 | |
287 | return 0; |
288 | } |
289 | |
290 | static void cfg80211_rfkill_sync_work(struct work_struct *work) |
291 | { |
292 | struct cfg80211_registered_device *rdev; |
293 | |
294 | rdev = container_of(work, struct cfg80211_registered_device, rfkill_sync); |
295 | cfg80211_rfkill_set_block(rdev, rfkill_blocked(rdev->rfkill)); |
296 | } |
297 | |
298 | static void cfg80211_event_work(struct work_struct *work) |
299 | { |
300 | struct cfg80211_registered_device *rdev; |
301 | |
302 | rdev = container_of(work, struct cfg80211_registered_device, |
303 | event_work); |
304 | |
305 | rtnl_lock(); |
306 | cfg80211_lock_rdev(rdev); |
307 | |
308 | cfg80211_process_rdev_events(rdev); |
309 | cfg80211_unlock_rdev(rdev); |
310 | rtnl_unlock(); |
311 | } |
312 | |
313 | /* exported functions */ |
314 | |
315 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) |
316 | { |
317 | static int wiphy_counter; |
318 | |
319 | struct cfg80211_registered_device *rdev; |
320 | int alloc_size; |
321 | |
322 | WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key)); |
323 | WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc)); |
324 | WARN_ON(ops->connect && !ops->disconnect); |
325 | WARN_ON(ops->join_ibss && !ops->leave_ibss); |
326 | WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf); |
327 | WARN_ON(ops->add_station && !ops->del_station); |
328 | WARN_ON(ops->add_mpath && !ops->del_mpath); |
329 | |
330 | alloc_size = sizeof(*rdev) + sizeof_priv; |
331 | |
332 | rdev = kzalloc(alloc_size, GFP_KERNEL); |
333 | if (!rdev) |
334 | return NULL; |
335 | |
336 | rdev->ops = ops; |
337 | |
338 | mutex_lock(&cfg80211_mutex); |
339 | |
340 | rdev->wiphy_idx = wiphy_counter++; |
341 | |
342 | if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) { |
343 | wiphy_counter--; |
344 | mutex_unlock(&cfg80211_mutex); |
345 | /* ugh, wrapped! */ |
346 | kfree(rdev); |
347 | return NULL; |
348 | } |
349 | |
350 | mutex_unlock(&cfg80211_mutex); |
351 | |
352 | /* give it a proper name */ |
353 | dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); |
354 | |
355 | mutex_init(&rdev->mtx); |
356 | mutex_init(&rdev->devlist_mtx); |
357 | INIT_LIST_HEAD(&rdev->netdev_list); |
358 | spin_lock_init(&rdev->bss_lock); |
359 | INIT_LIST_HEAD(&rdev->bss_list); |
360 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); |
361 | |
362 | device_initialize(&rdev->wiphy.dev); |
363 | rdev->wiphy.dev.class = &ieee80211_class; |
364 | rdev->wiphy.dev.platform_data = rdev; |
365 | |
366 | rdev->wiphy.ps_default = CONFIG_CFG80211_DEFAULT_PS_VALUE; |
367 | |
368 | wiphy_net_set(&rdev->wiphy, &init_net); |
369 | |
370 | rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block; |
371 | rdev->rfkill = rfkill_alloc(dev_name(&rdev->wiphy.dev), |
372 | &rdev->wiphy.dev, RFKILL_TYPE_WLAN, |
373 | &rdev->rfkill_ops, rdev); |
374 | |
375 | if (!rdev->rfkill) { |
376 | kfree(rdev); |
377 | return NULL; |
378 | } |
379 | |
380 | INIT_WORK(&rdev->rfkill_sync, cfg80211_rfkill_sync_work); |
381 | INIT_WORK(&rdev->conn_work, cfg80211_conn_work); |
382 | INIT_WORK(&rdev->event_work, cfg80211_event_work); |
383 | |
384 | init_waitqueue_head(&rdev->dev_wait); |
385 | |
386 | /* |
387 | * Initialize wiphy parameters to IEEE 802.11 MIB default values. |
388 | * Fragmentation and RTS threshold are disabled by default with the |
389 | * special -1 value. |
390 | */ |
391 | rdev->wiphy.retry_short = 7; |
392 | rdev->wiphy.retry_long = 4; |
393 | rdev->wiphy.frag_threshold = (u32) -1; |
394 | rdev->wiphy.rts_threshold = (u32) -1; |
395 | |
396 | return &rdev->wiphy; |
397 | } |
398 | EXPORT_SYMBOL(wiphy_new); |
399 | |
400 | int wiphy_register(struct wiphy *wiphy) |
401 | { |
402 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
403 | int res; |
404 | enum ieee80211_band band; |
405 | struct ieee80211_supported_band *sband; |
406 | bool have_band = false; |
407 | int i; |
408 | u16 ifmodes = wiphy->interface_modes; |
409 | |
410 | /* sanity check ifmodes */ |
411 | WARN_ON(!ifmodes); |
412 | ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; |
413 | if (WARN_ON(ifmodes != wiphy->interface_modes)) |
414 | wiphy->interface_modes = ifmodes; |
415 | |
416 | /* sanity check supported bands/channels */ |
417 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
418 | sband = wiphy->bands[band]; |
419 | if (!sband) |
420 | continue; |
421 | |
422 | sband->band = band; |
423 | |
424 | if (WARN_ON(!sband->n_channels || !sband->n_bitrates)) |
425 | return -EINVAL; |
426 | |
427 | /* |
428 | * Since we use a u32 for rate bitmaps in |
429 | * ieee80211_get_response_rate, we cannot |
430 | * have more than 32 legacy rates. |
431 | */ |
432 | if (WARN_ON(sband->n_bitrates > 32)) |
433 | return -EINVAL; |
434 | |
435 | for (i = 0; i < sband->n_channels; i++) { |
436 | sband->channels[i].orig_flags = |
437 | sband->channels[i].flags; |
438 | sband->channels[i].orig_mag = |
439 | sband->channels[i].max_antenna_gain; |
440 | sband->channels[i].orig_mpwr = |
441 | sband->channels[i].max_power; |
442 | sband->channels[i].band = band; |
443 | } |
444 | |
445 | have_band = true; |
446 | } |
447 | |
448 | if (!have_band) { |
449 | WARN_ON(1); |
450 | return -EINVAL; |
451 | } |
452 | |
453 | /* check and set up bitrates */ |
454 | ieee80211_set_bitrate_flags(wiphy); |
455 | |
456 | res = device_add(&rdev->wiphy.dev); |
457 | if (res) |
458 | return res; |
459 | |
460 | res = rfkill_register(rdev->rfkill); |
461 | if (res) |
462 | goto out_rm_dev; |
463 | |
464 | mutex_lock(&cfg80211_mutex); |
465 | |
466 | /* set up regulatory info */ |
467 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); |
468 | |
469 | list_add(&rdev->list, &cfg80211_rdev_list); |
470 | cfg80211_rdev_list_generation++; |
471 | |
472 | mutex_unlock(&cfg80211_mutex); |
473 | |
474 | /* add to debugfs */ |
475 | rdev->wiphy.debugfsdir = |
476 | debugfs_create_dir(wiphy_name(&rdev->wiphy), |
477 | ieee80211_debugfs_dir); |
478 | if (IS_ERR(rdev->wiphy.debugfsdir)) |
479 | rdev->wiphy.debugfsdir = NULL; |
480 | |
481 | if (wiphy->custom_regulatory) { |
482 | struct regulatory_request request; |
483 | |
484 | request.wiphy_idx = get_wiphy_idx(wiphy); |
485 | request.initiator = NL80211_REGDOM_SET_BY_DRIVER; |
486 | request.alpha2[0] = '9'; |
487 | request.alpha2[1] = '9'; |
488 | |
489 | nl80211_send_reg_change_event(&request); |
490 | } |
491 | |
492 | cfg80211_debugfs_rdev_add(rdev); |
493 | |
494 | return 0; |
495 | |
496 | out_rm_dev: |
497 | device_del(&rdev->wiphy.dev); |
498 | return res; |
499 | } |
500 | EXPORT_SYMBOL(wiphy_register); |
501 | |
502 | void wiphy_rfkill_start_polling(struct wiphy *wiphy) |
503 | { |
504 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
505 | |
506 | if (!rdev->ops->rfkill_poll) |
507 | return; |
508 | rdev->rfkill_ops.poll = cfg80211_rfkill_poll; |
509 | rfkill_resume_polling(rdev->rfkill); |
510 | } |
511 | EXPORT_SYMBOL(wiphy_rfkill_start_polling); |
512 | |
513 | void wiphy_rfkill_stop_polling(struct wiphy *wiphy) |
514 | { |
515 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
516 | |
517 | rfkill_pause_polling(rdev->rfkill); |
518 | } |
519 | EXPORT_SYMBOL(wiphy_rfkill_stop_polling); |
520 | |
521 | void wiphy_unregister(struct wiphy *wiphy) |
522 | { |
523 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
524 | |
525 | rfkill_unregister(rdev->rfkill); |
526 | |
527 | /* protect the device list */ |
528 | mutex_lock(&cfg80211_mutex); |
529 | |
530 | wait_event(rdev->dev_wait, ({ |
531 | int __count; |
532 | mutex_lock(&rdev->devlist_mtx); |
533 | __count = rdev->opencount; |
534 | mutex_unlock(&rdev->devlist_mtx); |
535 | __count == 0;})); |
536 | |
537 | mutex_lock(&rdev->devlist_mtx); |
538 | BUG_ON(!list_empty(&rdev->netdev_list)); |
539 | mutex_unlock(&rdev->devlist_mtx); |
540 | |
541 | /* |
542 | * First remove the hardware from everywhere, this makes |
543 | * it impossible to find from userspace. |
544 | */ |
545 | cfg80211_debugfs_rdev_del(rdev); |
546 | list_del(&rdev->list); |
547 | |
548 | /* |
549 | * Try to grab rdev->mtx. If a command is still in progress, |
550 | * hopefully the driver will refuse it since it's tearing |
551 | * down the device already. We wait for this command to complete |
552 | * before unlinking the item from the list. |
553 | * Note: as codified by the BUG_ON above we cannot get here if |
554 | * a virtual interface is still present. Hence, we can only get |
555 | * to lock contention here if userspace issues a command that |
556 | * identified the hardware by wiphy index. |
557 | */ |
558 | cfg80211_lock_rdev(rdev); |
559 | /* nothing */ |
560 | cfg80211_unlock_rdev(rdev); |
561 | |
562 | /* If this device got a regulatory hint tell core its |
563 | * free to listen now to a new shiny device regulatory hint */ |
564 | reg_device_remove(wiphy); |
565 | |
566 | cfg80211_rdev_list_generation++; |
567 | device_del(&rdev->wiphy.dev); |
568 | debugfs_remove(rdev->wiphy.debugfsdir); |
569 | |
570 | mutex_unlock(&cfg80211_mutex); |
571 | |
572 | flush_work(&rdev->scan_done_wk); |
573 | cancel_work_sync(&rdev->conn_work); |
574 | flush_work(&rdev->event_work); |
575 | } |
576 | EXPORT_SYMBOL(wiphy_unregister); |
577 | |
578 | void cfg80211_dev_free(struct cfg80211_registered_device *rdev) |
579 | { |
580 | struct cfg80211_internal_bss *scan, *tmp; |
581 | rfkill_destroy(rdev->rfkill); |
582 | mutex_destroy(&rdev->mtx); |
583 | mutex_destroy(&rdev->devlist_mtx); |
584 | list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) |
585 | cfg80211_put_bss(&scan->pub); |
586 | kfree(rdev); |
587 | } |
588 | |
589 | void wiphy_free(struct wiphy *wiphy) |
590 | { |
591 | put_device(&wiphy->dev); |
592 | } |
593 | EXPORT_SYMBOL(wiphy_free); |
594 | |
595 | void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked) |
596 | { |
597 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
598 | |
599 | if (rfkill_set_hw_state(rdev->rfkill, blocked)) |
600 | schedule_work(&rdev->rfkill_sync); |
601 | } |
602 | EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); |
603 | |
604 | static void wdev_cleanup_work(struct work_struct *work) |
605 | { |
606 | struct wireless_dev *wdev; |
607 | struct cfg80211_registered_device *rdev; |
608 | |
609 | wdev = container_of(work, struct wireless_dev, cleanup_work); |
610 | rdev = wiphy_to_dev(wdev->wiphy); |
611 | |
612 | cfg80211_lock_rdev(rdev); |
613 | |
614 | if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) { |
615 | rdev->scan_req->aborted = true; |
616 | ___cfg80211_scan_done(rdev, true); |
617 | } |
618 | |
619 | cfg80211_unlock_rdev(rdev); |
620 | |
621 | mutex_lock(&rdev->devlist_mtx); |
622 | rdev->opencount--; |
623 | mutex_unlock(&rdev->devlist_mtx); |
624 | wake_up(&rdev->dev_wait); |
625 | |
626 | dev_put(wdev->netdev); |
627 | } |
628 | |
629 | static int cfg80211_netdev_notifier_call(struct notifier_block * nb, |
630 | unsigned long state, |
631 | void *ndev) |
632 | { |
633 | struct net_device *dev = ndev; |
634 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
635 | struct cfg80211_registered_device *rdev; |
636 | |
637 | if (!wdev) |
638 | return NOTIFY_DONE; |
639 | |
640 | rdev = wiphy_to_dev(wdev->wiphy); |
641 | |
642 | WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED); |
643 | |
644 | switch (state) { |
645 | case NETDEV_REGISTER: |
646 | /* |
647 | * NB: cannot take rdev->mtx here because this may be |
648 | * called within code protected by it when interfaces |
649 | * are added with nl80211. |
650 | */ |
651 | mutex_init(&wdev->mtx); |
652 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); |
653 | INIT_LIST_HEAD(&wdev->event_list); |
654 | spin_lock_init(&wdev->event_lock); |
655 | mutex_lock(&rdev->devlist_mtx); |
656 | list_add(&wdev->list, &rdev->netdev_list); |
657 | rdev->devlist_generation++; |
658 | /* can only change netns with wiphy */ |
659 | dev->features |= NETIF_F_NETNS_LOCAL; |
660 | |
661 | if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj, |
662 | "phy80211")) { |
663 | printk(KERN_ERR "wireless: failed to add phy80211 " |
664 | "symlink to netdev!\n"); |
665 | } |
666 | wdev->netdev = dev; |
667 | wdev->sme_state = CFG80211_SME_IDLE; |
668 | mutex_unlock(&rdev->devlist_mtx); |
669 | #ifdef CONFIG_WIRELESS_EXT |
670 | if (!dev->wireless_handlers) |
671 | dev->wireless_handlers = &cfg80211_wext_handler; |
672 | wdev->wext.default_key = -1; |
673 | wdev->wext.default_mgmt_key = -1; |
674 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; |
675 | wdev->wext.ps = wdev->wiphy->ps_default; |
676 | wdev->wext.ps_timeout = 100; |
677 | if (rdev->ops->set_power_mgmt) |
678 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, |
679 | wdev->wext.ps, |
680 | wdev->wext.ps_timeout)) { |
681 | /* assume this means it's off */ |
682 | wdev->wext.ps = false; |
683 | } |
684 | #endif |
685 | break; |
686 | case NETDEV_GOING_DOWN: |
687 | switch (wdev->iftype) { |
688 | case NL80211_IFTYPE_ADHOC: |
689 | cfg80211_leave_ibss(rdev, dev, true); |
690 | break; |
691 | case NL80211_IFTYPE_STATION: |
692 | wdev_lock(wdev); |
693 | #ifdef CONFIG_WIRELESS_EXT |
694 | kfree(wdev->wext.ie); |
695 | wdev->wext.ie = NULL; |
696 | wdev->wext.ie_len = 0; |
697 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; |
698 | #endif |
699 | __cfg80211_disconnect(rdev, dev, |
700 | WLAN_REASON_DEAUTH_LEAVING, true); |
701 | cfg80211_mlme_down(rdev, dev); |
702 | wdev_unlock(wdev); |
703 | break; |
704 | default: |
705 | break; |
706 | } |
707 | break; |
708 | case NETDEV_DOWN: |
709 | dev_hold(dev); |
710 | schedule_work(&wdev->cleanup_work); |
711 | break; |
712 | case NETDEV_UP: |
713 | /* |
714 | * If we have a really quick DOWN/UP succession we may |
715 | * have this work still pending ... cancel it and see |
716 | * if it was pending, in which case we need to account |
717 | * for some of the work it would have done. |
718 | */ |
719 | if (cancel_work_sync(&wdev->cleanup_work)) { |
720 | mutex_lock(&rdev->devlist_mtx); |
721 | rdev->opencount--; |
722 | mutex_unlock(&rdev->devlist_mtx); |
723 | dev_put(dev); |
724 | } |
725 | #ifdef CONFIG_WIRELESS_EXT |
726 | cfg80211_lock_rdev(rdev); |
727 | mutex_lock(&rdev->devlist_mtx); |
728 | wdev_lock(wdev); |
729 | switch (wdev->iftype) { |
730 | case NL80211_IFTYPE_ADHOC: |
731 | cfg80211_ibss_wext_join(rdev, wdev); |
732 | break; |
733 | case NL80211_IFTYPE_STATION: |
734 | cfg80211_mgd_wext_connect(rdev, wdev); |
735 | break; |
736 | default: |
737 | break; |
738 | } |
739 | wdev_unlock(wdev); |
740 | rdev->opencount++; |
741 | mutex_unlock(&rdev->devlist_mtx); |
742 | cfg80211_unlock_rdev(rdev); |
743 | #endif |
744 | break; |
745 | case NETDEV_UNREGISTER: |
746 | /* |
747 | * NB: cannot take rdev->mtx here because this may be |
748 | * called within code protected by it when interfaces |
749 | * are removed with nl80211. |
750 | */ |
751 | mutex_lock(&rdev->devlist_mtx); |
752 | /* |
753 | * It is possible to get NETDEV_UNREGISTER |
754 | * multiple times. To detect that, check |
755 | * that the interface is still on the list |
756 | * of registered interfaces, and only then |
757 | * remove and clean it up. |
758 | */ |
759 | if (!list_empty(&wdev->list)) { |
760 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); |
761 | list_del_init(&wdev->list); |
762 | rdev->devlist_generation++; |
763 | #ifdef CONFIG_WIRELESS_EXT |
764 | kfree(wdev->wext.keys); |
765 | #endif |
766 | } |
767 | mutex_unlock(&rdev->devlist_mtx); |
768 | break; |
769 | case NETDEV_PRE_UP: |
770 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) |
771 | return notifier_from_errno(-EOPNOTSUPP); |
772 | if (rfkill_blocked(rdev->rfkill)) |
773 | return notifier_from_errno(-ERFKILL); |
774 | break; |
775 | } |
776 | |
777 | return NOTIFY_DONE; |
778 | } |
779 | |
780 | static struct notifier_block cfg80211_netdev_notifier = { |
781 | .notifier_call = cfg80211_netdev_notifier_call, |
782 | }; |
783 | |
784 | static void __net_exit cfg80211_pernet_exit(struct net *net) |
785 | { |
786 | struct cfg80211_registered_device *rdev; |
787 | |
788 | rtnl_lock(); |
789 | mutex_lock(&cfg80211_mutex); |
790 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
791 | if (net_eq(wiphy_net(&rdev->wiphy), net)) |
792 | WARN_ON(cfg80211_switch_netns(rdev, &init_net)); |
793 | } |
794 | mutex_unlock(&cfg80211_mutex); |
795 | rtnl_unlock(); |
796 | } |
797 | |
798 | static struct pernet_operations cfg80211_pernet_ops = { |
799 | .exit = cfg80211_pernet_exit, |
800 | }; |
801 | |
802 | static int __init cfg80211_init(void) |
803 | { |
804 | int err; |
805 | |
806 | err = register_pernet_device(&cfg80211_pernet_ops); |
807 | if (err) |
808 | goto out_fail_pernet; |
809 | |
810 | err = wiphy_sysfs_init(); |
811 | if (err) |
812 | goto out_fail_sysfs; |
813 | |
814 | err = register_netdevice_notifier(&cfg80211_netdev_notifier); |
815 | if (err) |
816 | goto out_fail_notifier; |
817 | |
818 | err = nl80211_init(); |
819 | if (err) |
820 | goto out_fail_nl80211; |
821 | |
822 | ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL); |
823 | |
824 | err = regulatory_init(); |
825 | if (err) |
826 | goto out_fail_reg; |
827 | |
828 | return 0; |
829 | |
830 | out_fail_reg: |
831 | debugfs_remove(ieee80211_debugfs_dir); |
832 | out_fail_nl80211: |
833 | unregister_netdevice_notifier(&cfg80211_netdev_notifier); |
834 | out_fail_notifier: |
835 | wiphy_sysfs_exit(); |
836 | out_fail_sysfs: |
837 | unregister_pernet_device(&cfg80211_pernet_ops); |
838 | out_fail_pernet: |
839 | return err; |
840 | } |
841 | subsys_initcall(cfg80211_init); |
842 | |
843 | static void cfg80211_exit(void) |
844 | { |
845 | debugfs_remove(ieee80211_debugfs_dir); |
846 | nl80211_exit(); |
847 | unregister_netdevice_notifier(&cfg80211_netdev_notifier); |
848 | wiphy_sysfs_exit(); |
849 | regulatory_exit(); |
850 | unregister_pernet_device(&cfg80211_pernet_ops); |
851 | } |
852 | module_exit(cfg80211_exit); |
853 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9