aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-12-08 10:55:01 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-08 10:55:01 -0500
commitd7fc02c7bae7b1cf69269992cf880a43a350cdaa (patch)
treea43d56fa72913a1cc98a0bbebe054d08581b3a7c /net/wireless
parentee1262dbc65ce0b6234a915d8432171e8d77f518 (diff)
parent28b4d5cc17c20786848cdc07b7ea237a309776bb (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1815 commits) mac80211: fix reorder buffer release iwmc3200wifi: Enable wimax core through module parameter iwmc3200wifi: Add wifi-wimax coexistence mode as a module parameter iwmc3200wifi: Coex table command does not expect a response iwmc3200wifi: Update wiwi priority table iwlwifi: driver version track kernel version iwlwifi: indicate uCode type when fail dump error/event log iwl3945: remove duplicated event logging code b43: fix two warnings ipw2100: fix rebooting hang with driver loaded cfg80211: indent regulatory messages with spaces iwmc3200wifi: fix NULL pointer dereference in pmkid update mac80211: Fix TX status reporting for injected data frames ath9k: enable 2GHz band only if the device supports it airo: Fix integer overflow warning rt2x00: Fix padding bug on L2PAD devices. WE: Fix set events not propagated b43legacy: avoid PPC fault during resume b43: avoid PPC fault during resume tcp: fix a timewait refcnt race ... Fix up conflicts due to sysctl cleanups (dead sysctl_check code and CTL_UNNUMBERED removed) in kernel/sysctl_check.c net/ipv4/sysctl_net_ipv4.c net/ipv6/addrconf.c net/sctp/sysctl.c
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/Kconfig44
-rw-r--r--net/wireless/Makefile10
-rw-r--r--net/wireless/core.c56
-rw-r--r--net/wireless/core.h15
-rw-r--r--net/wireless/debugfs.c15
-rw-r--r--net/wireless/debugfs.h3
-rw-r--r--net/wireless/ethtool.c45
-rw-r--r--net/wireless/ethtool.h6
-rw-r--r--net/wireless/ibss.c16
-rw-r--r--net/wireless/mlme.c105
-rw-r--r--net/wireless/nl80211.c406
-rw-r--r--net/wireless/reg.c19
-rw-r--r--net/wireless/scan.c58
-rw-r--r--net/wireless/sme.c18
-rw-r--r--net/wireless/util.c40
-rw-r--r--net/wireless/wext-compat.c97
-rw-r--r--net/wireless/wext-core.c (renamed from net/wireless/wext.c)1464
-rw-r--r--net/wireless/wext-priv.c248
-rw-r--r--net/wireless/wext-proc.c155
-rw-r--r--net/wireless/wext-spy.c231
20 files changed, 1736 insertions, 1315 deletions
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index abf7ca3f9ff9..90e93a5701aa 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -1,3 +1,21 @@
1config WIRELESS_EXT
2 bool
3
4config WEXT_CORE
5 def_bool y
6 depends on CFG80211_WEXT || WIRELESS_EXT
7
8config WEXT_PROC
9 def_bool y
10 depends on PROC_FS
11 depends on WEXT_CORE
12
13config WEXT_SPY
14 bool
15
16config WEXT_PRIV
17 bool
18
1config CFG80211 19config CFG80211
2 tristate "cfg80211 - wireless configuration API" 20 tristate "cfg80211 - wireless configuration API"
3 depends on RFKILL || !RFKILL 21 depends on RFKILL || !RFKILL
@@ -67,14 +85,10 @@ config CFG80211_DEFAULT_PS
67 applications instead -- they need to register their network 85 applications instead -- they need to register their network
68 latency requirement, see Documentation/power/pm_qos_interface.txt. 86 latency requirement, see Documentation/power/pm_qos_interface.txt.
69 87
70config CFG80211_DEFAULT_PS_VALUE
71 int
72 default 1 if CFG80211_DEFAULT_PS
73 default 0
74
75config CFG80211_DEBUGFS 88config CFG80211_DEBUGFS
76 bool "cfg80211 DebugFS entries" 89 bool "cfg80211 DebugFS entries"
77 depends on CFG80211 && DEBUG_FS 90 depends on CFG80211
91 depends on DEBUG_FS
78 ---help--- 92 ---help---
79 You can enable this if you want to debugfs entries for cfg80211. 93 You can enable this if you want to debugfs entries for cfg80211.
80 94
@@ -83,6 +97,7 @@ config CFG80211_DEBUGFS
83config WIRELESS_OLD_REGULATORY 97config WIRELESS_OLD_REGULATORY
84 bool "Old wireless static regulatory definitions" 98 bool "Old wireless static regulatory definitions"
85 default n 99 default n
100 depends on CFG80211
86 ---help--- 101 ---help---
87 This option enables the old static regulatory information 102 This option enables the old static regulatory information
88 and uses it within the new framework. This option is available 103 and uses it within the new framework. This option is available
@@ -94,20 +109,19 @@ config WIRELESS_OLD_REGULATORY
94 109
95 Say N and if you say Y, please tell us why. The default is N. 110 Say N and if you say Y, please tell us why. The default is N.
96 111
97config WIRELESS_EXT 112config CFG80211_WEXT
98 bool "Wireless extensions" 113 bool "cfg80211 wireless extensions compatibility"
114 depends on CFG80211
115 select WEXT_CORE
99 default y 116 default y
100 ---help--- 117 help
101 This option enables the legacy wireless extensions 118 Enable this option if you need old userspace for wireless
102 (wireless network interface configuration via ioctls.) 119 extensions with cfg80211-based drivers.
103
104 Say Y unless you've upgraded all your userspace to use
105 nl80211 instead of wireless extensions.
106 120
107config WIRELESS_EXT_SYSFS 121config WIRELESS_EXT_SYSFS
108 bool "Wireless extensions sysfs files" 122 bool "Wireless extensions sysfs files"
109 default y 123 default y
110 depends on WIRELESS_EXT && SYSFS 124 depends on WEXT_CORE && SYSFS
111 help 125 help
112 This option enables the deprecated wireless statistics 126 This option enables the deprecated wireless statistics
113 files in /sys/class/net/*/wireless/. The same information 127 files in /sys/class/net/*/wireless/. The same information
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 3ecaa9179977..f07c8dc7aab2 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -1,13 +1,17 @@
1obj-$(CONFIG_WIRELESS_EXT) += wext.o
2obj-$(CONFIG_CFG80211) += cfg80211.o 1obj-$(CONFIG_CFG80211) += cfg80211.o
3obj-$(CONFIG_LIB80211) += lib80211.o 2obj-$(CONFIG_LIB80211) += lib80211.o
4obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o 3obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o
5obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o 4obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
6obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o 5obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
7 6
7obj-$(CONFIG_WEXT_CORE) += wext-core.o
8obj-$(CONFIG_WEXT_PROC) += wext-proc.o
9obj-$(CONFIG_WEXT_SPY) += wext-spy.o
10obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
11
8cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o 12cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
9cfg80211-y += mlme.o ibss.o sme.o chan.o 13cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o
10cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o 14cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
11cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o 15cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
12 16
13ccflags-y += -D__CHECK_ENDIAN__ 17ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/wireless/core.c b/net/wireless/core.c
index a595f712b5bf..c2a2c563d21a 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -22,6 +22,7 @@
22#include "sysfs.h" 22#include "sysfs.h"
23#include "debugfs.h" 23#include "debugfs.h"
24#include "wext-compat.h" 24#include "wext-compat.h"
25#include "ethtool.h"
25 26
26/* name for sysfs, %d is appended */ 27/* name for sysfs, %d is appended */
27#define PHY_NAME "phy" 28#define PHY_NAME "phy"
@@ -44,6 +45,9 @@ DEFINE_MUTEX(cfg80211_mutex);
44/* for debugfs */ 45/* for debugfs */
45static struct dentry *ieee80211_debugfs_dir; 46static struct dentry *ieee80211_debugfs_dir;
46 47
48/* for the cleanup, scan and event works */
49struct workqueue_struct *cfg80211_wq;
50
47/* requires cfg80211_mutex to be held! */ 51/* requires cfg80211_mutex to be held! */
48struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) 52struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx)
49{ 53{
@@ -230,7 +234,7 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
230 struct wireless_dev *wdev; 234 struct wireless_dev *wdev;
231 int err = 0; 235 int err = 0;
232 236
233 if (!rdev->wiphy.netnsok) 237 if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK))
234 return -EOPNOTSUPP; 238 return -EOPNOTSUPP;
235 239
236 list_for_each_entry(wdev, &rdev->netdev_list, list) { 240 list_for_each_entry(wdev, &rdev->netdev_list, list) {
@@ -359,11 +363,17 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
359 INIT_LIST_HEAD(&rdev->bss_list); 363 INIT_LIST_HEAD(&rdev->bss_list);
360 INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); 364 INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
361 365
366#ifdef CONFIG_CFG80211_WEXT
367 rdev->wiphy.wext = &cfg80211_wext_handler;
368#endif
369
362 device_initialize(&rdev->wiphy.dev); 370 device_initialize(&rdev->wiphy.dev);
363 rdev->wiphy.dev.class = &ieee80211_class; 371 rdev->wiphy.dev.class = &ieee80211_class;
364 rdev->wiphy.dev.platform_data = rdev; 372 rdev->wiphy.dev.platform_data = rdev;
365 373
366 rdev->wiphy.ps_default = CONFIG_CFG80211_DEFAULT_PS_VALUE; 374#ifdef CONFIG_CFG80211_DEFAULT_PS
375 rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
376#endif
367 377
368 wiphy_net_set(&rdev->wiphy, &init_net); 378 wiphy_net_set(&rdev->wiphy, &init_net);
369 379
@@ -478,7 +488,7 @@ int wiphy_register(struct wiphy *wiphy)
478 if (IS_ERR(rdev->wiphy.debugfsdir)) 488 if (IS_ERR(rdev->wiphy.debugfsdir))
479 rdev->wiphy.debugfsdir = NULL; 489 rdev->wiphy.debugfsdir = NULL;
480 490
481 if (wiphy->custom_regulatory) { 491 if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) {
482 struct regulatory_request request; 492 struct regulatory_request request;
483 493
484 request.wiphy_idx = get_wiphy_idx(wiphy); 494 request.wiphy_idx = get_wiphy_idx(wiphy);
@@ -542,7 +552,7 @@ void wiphy_unregister(struct wiphy *wiphy)
542 * First remove the hardware from everywhere, this makes 552 * First remove the hardware from everywhere, this makes
543 * it impossible to find from userspace. 553 * it impossible to find from userspace.
544 */ 554 */
545 cfg80211_debugfs_rdev_del(rdev); 555 debugfs_remove_recursive(rdev->wiphy.debugfsdir);
546 list_del(&rdev->list); 556 list_del(&rdev->list);
547 557
548 /* 558 /*
@@ -565,7 +575,6 @@ void wiphy_unregister(struct wiphy *wiphy)
565 575
566 cfg80211_rdev_list_generation++; 576 cfg80211_rdev_list_generation++;
567 device_del(&rdev->wiphy.dev); 577 device_del(&rdev->wiphy.dev);
568 debugfs_remove(rdev->wiphy.debugfsdir);
569 578
570 mutex_unlock(&cfg80211_mutex); 579 mutex_unlock(&cfg80211_mutex);
571 580
@@ -626,6 +635,10 @@ static void wdev_cleanup_work(struct work_struct *work)
626 dev_put(wdev->netdev); 635 dev_put(wdev->netdev);
627} 636}
628 637
638static struct device_type wiphy_type = {
639 .name = "wlan",
640};
641
629static int cfg80211_netdev_notifier_call(struct notifier_block * nb, 642static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
630 unsigned long state, 643 unsigned long state,
631 void *ndev) 644 void *ndev)
@@ -642,6 +655,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
642 WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED); 655 WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED);
643 656
644 switch (state) { 657 switch (state) {
658 case NETDEV_POST_INIT:
659 SET_NETDEV_DEVTYPE(dev, &wiphy_type);
660 break;
645 case NETDEV_REGISTER: 661 case NETDEV_REGISTER:
646 /* 662 /*
647 * NB: cannot take rdev->mtx here because this may be 663 * NB: cannot take rdev->mtx here because this may be
@@ -666,13 +682,14 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
666 wdev->netdev = dev; 682 wdev->netdev = dev;
667 wdev->sme_state = CFG80211_SME_IDLE; 683 wdev->sme_state = CFG80211_SME_IDLE;
668 mutex_unlock(&rdev->devlist_mtx); 684 mutex_unlock(&rdev->devlist_mtx);
669#ifdef CONFIG_WIRELESS_EXT 685#ifdef CONFIG_CFG80211_WEXT
670 if (!dev->wireless_handlers)
671 dev->wireless_handlers = &cfg80211_wext_handler;
672 wdev->wext.default_key = -1; 686 wdev->wext.default_key = -1;
673 wdev->wext.default_mgmt_key = -1; 687 wdev->wext.default_mgmt_key = -1;
674 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; 688 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
675 wdev->wext.ps = wdev->wiphy->ps_default; 689 if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT)
690 wdev->wext.ps = true;
691 else
692 wdev->wext.ps = false;
676 wdev->wext.ps_timeout = 100; 693 wdev->wext.ps_timeout = 100;
677 if (rdev->ops->set_power_mgmt) 694 if (rdev->ops->set_power_mgmt)
678 if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, 695 if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
@@ -682,6 +699,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
682 wdev->wext.ps = false; 699 wdev->wext.ps = false;
683 } 700 }
684#endif 701#endif
702 if (!dev->ethtool_ops)
703 dev->ethtool_ops = &cfg80211_ethtool_ops;
704
705 if ((wdev->iftype == NL80211_IFTYPE_STATION ||
706 wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
707 dev->priv_flags |= IFF_DONT_BRIDGE;
685 break; 708 break;
686 case NETDEV_GOING_DOWN: 709 case NETDEV_GOING_DOWN:
687 switch (wdev->iftype) { 710 switch (wdev->iftype) {
@@ -690,7 +713,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
690 break; 713 break;
691 case NL80211_IFTYPE_STATION: 714 case NL80211_IFTYPE_STATION:
692 wdev_lock(wdev); 715 wdev_lock(wdev);
693#ifdef CONFIG_WIRELESS_EXT 716#ifdef CONFIG_CFG80211_WEXT
694 kfree(wdev->wext.ie); 717 kfree(wdev->wext.ie);
695 wdev->wext.ie = NULL; 718 wdev->wext.ie = NULL;
696 wdev->wext.ie_len = 0; 719 wdev->wext.ie_len = 0;
@@ -707,7 +730,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
707 break; 730 break;
708 case NETDEV_DOWN: 731 case NETDEV_DOWN:
709 dev_hold(dev); 732 dev_hold(dev);
710 schedule_work(&wdev->cleanup_work); 733 queue_work(cfg80211_wq, &wdev->cleanup_work);
711 break; 734 break;
712 case NETDEV_UP: 735 case NETDEV_UP:
713 /* 736 /*
@@ -722,7 +745,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
722 mutex_unlock(&rdev->devlist_mtx); 745 mutex_unlock(&rdev->devlist_mtx);
723 dev_put(dev); 746 dev_put(dev);
724 } 747 }
725#ifdef CONFIG_WIRELESS_EXT 748#ifdef CONFIG_CFG80211_WEXT
726 cfg80211_lock_rdev(rdev); 749 cfg80211_lock_rdev(rdev);
727 mutex_lock(&rdev->devlist_mtx); 750 mutex_lock(&rdev->devlist_mtx);
728 wdev_lock(wdev); 751 wdev_lock(wdev);
@@ -760,7 +783,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
760 sysfs_remove_link(&dev->dev.kobj, "phy80211"); 783 sysfs_remove_link(&dev->dev.kobj, "phy80211");
761 list_del_init(&wdev->list); 784 list_del_init(&wdev->list);
762 rdev->devlist_generation++; 785 rdev->devlist_generation++;
763#ifdef CONFIG_WIRELESS_EXT 786#ifdef CONFIG_CFG80211_WEXT
764 kfree(wdev->wext.keys); 787 kfree(wdev->wext.keys);
765#endif 788#endif
766 } 789 }
@@ -825,8 +848,14 @@ static int __init cfg80211_init(void)
825 if (err) 848 if (err)
826 goto out_fail_reg; 849 goto out_fail_reg;
827 850
851 cfg80211_wq = create_singlethread_workqueue("cfg80211");
852 if (!cfg80211_wq)
853 goto out_fail_wq;
854
828 return 0; 855 return 0;
829 856
857out_fail_wq:
858 regulatory_exit();
830out_fail_reg: 859out_fail_reg:
831 debugfs_remove(ieee80211_debugfs_dir); 860 debugfs_remove(ieee80211_debugfs_dir);
832out_fail_nl80211: 861out_fail_nl80211:
@@ -848,5 +877,6 @@ static void cfg80211_exit(void)
848 wiphy_sysfs_exit(); 877 wiphy_sysfs_exit();
849 regulatory_exit(); 878 regulatory_exit();
850 unregister_pernet_device(&cfg80211_pernet_ops); 879 unregister_pernet_device(&cfg80211_pernet_ops);
880 destroy_workqueue(cfg80211_wq);
851} 881}
852module_exit(cfg80211_exit); 882module_exit(cfg80211_exit);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 68b321997d4c..4ef3efc94106 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -72,17 +72,6 @@ struct cfg80211_registered_device {
72 /* current channel */ 72 /* current channel */
73 struct ieee80211_channel *channel; 73 struct ieee80211_channel *channel;
74 74
75#ifdef CONFIG_CFG80211_DEBUGFS
76 /* Debugfs entries */
77 struct wiphy_debugfsdentries {
78 struct dentry *rts_threshold;
79 struct dentry *fragmentation_threshold;
80 struct dentry *short_retry_limit;
81 struct dentry *long_retry_limit;
82 struct dentry *ht40allow_map;
83 } debugfs;
84#endif
85
86 /* must be last because of the way we do wiphy_priv(), 75 /* must be last because of the way we do wiphy_priv(),
87 * and it should at least be aligned to NETDEV_ALIGN */ 76 * and it should at least be aligned to NETDEV_ALIGN */
88 struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); 77 struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
@@ -102,6 +91,8 @@ bool wiphy_idx_valid(int wiphy_idx)
102 return (wiphy_idx >= 0); 91 return (wiphy_idx >= 0);
103} 92}
104 93
94
95extern struct workqueue_struct *cfg80211_wq;
105extern struct mutex cfg80211_mutex; 96extern struct mutex cfg80211_mutex;
106extern struct list_head cfg80211_rdev_list; 97extern struct list_head cfg80211_rdev_list;
107extern int cfg80211_rdev_list_generation; 98extern int cfg80211_rdev_list_generation;
@@ -284,6 +275,8 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
284 struct cfg80211_ibss_params *params, 275 struct cfg80211_ibss_params *params,
285 struct cfg80211_cached_keys *connkeys); 276 struct cfg80211_cached_keys *connkeys);
286void cfg80211_clear_ibss(struct net_device *dev, bool nowext); 277void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
278int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
279 struct net_device *dev, bool nowext);
287int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, 280int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
288 struct net_device *dev, bool nowext); 281 struct net_device *dev, bool nowext);
289void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); 282void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid);
diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c
index 13d93d84f902..2e4895615037 100644
--- a/net/wireless/debugfs.c
+++ b/net/wireless/debugfs.c
@@ -104,11 +104,7 @@ static const struct file_operations ht40allow_map_ops = {
104}; 104};
105 105
106#define DEBUGFS_ADD(name) \ 106#define DEBUGFS_ADD(name) \
107 rdev->debugfs.name = debugfs_create_file(#name, S_IRUGO, phyd, \ 107 debugfs_create_file(#name, S_IRUGO, phyd, &rdev->wiphy, &name## _ops);
108 &rdev->wiphy, &name## _ops);
109#define DEBUGFS_DEL(name) \
110 debugfs_remove(rdev->debugfs.name); \
111 rdev->debugfs.name = NULL;
112 108
113void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev) 109void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev)
114{ 110{
@@ -120,12 +116,3 @@ void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev)
120 DEBUGFS_ADD(long_retry_limit); 116 DEBUGFS_ADD(long_retry_limit);
121 DEBUGFS_ADD(ht40allow_map); 117 DEBUGFS_ADD(ht40allow_map);
122} 118}
123
124void cfg80211_debugfs_rdev_del(struct cfg80211_registered_device *rdev)
125{
126 DEBUGFS_DEL(rts_threshold);
127 DEBUGFS_DEL(fragmentation_threshold);
128 DEBUGFS_DEL(short_retry_limit);
129 DEBUGFS_DEL(long_retry_limit);
130 DEBUGFS_DEL(ht40allow_map);
131}
diff --git a/net/wireless/debugfs.h b/net/wireless/debugfs.h
index 6419b6d6ce3e..74fdd3811427 100644
--- a/net/wireless/debugfs.h
+++ b/net/wireless/debugfs.h
@@ -3,12 +3,9 @@
3 3
4#ifdef CONFIG_CFG80211_DEBUGFS 4#ifdef CONFIG_CFG80211_DEBUGFS
5void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev); 5void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev);
6void cfg80211_debugfs_rdev_del(struct cfg80211_registered_device *rdev);
7#else 6#else
8static inline 7static inline
9void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev) {} 8void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev) {}
10static inline
11void cfg80211_debugfs_rdev_del(struct cfg80211_registered_device *rdev) {}
12#endif 9#endif
13 10
14#endif /* __CFG80211_DEBUGFS_H */ 11#endif /* __CFG80211_DEBUGFS_H */
diff --git a/net/wireless/ethtool.c b/net/wireless/ethtool.c
new file mode 100644
index 000000000000..ca4c825be93d
--- /dev/null
+++ b/net/wireless/ethtool.c
@@ -0,0 +1,45 @@
1#include <linux/utsname.h>
2#include <net/cfg80211.h>
3#include "ethtool.h"
4
5static void cfg80211_get_drvinfo(struct net_device *dev,
6 struct ethtool_drvinfo *info)
7{
8 struct wireless_dev *wdev = dev->ieee80211_ptr;
9
10 strlcpy(info->driver, wiphy_dev(wdev->wiphy)->driver->name,
11 sizeof(info->driver));
12
13 strlcpy(info->version, init_utsname()->release, sizeof(info->version));
14
15 if (wdev->wiphy->fw_version[0])
16 strncpy(info->fw_version, wdev->wiphy->fw_version,
17 sizeof(info->fw_version));
18 else
19 strncpy(info->fw_version, "N/A", sizeof(info->fw_version));
20
21 strlcpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)),
22 sizeof(info->bus_info));
23}
24
25static int cfg80211_get_regs_len(struct net_device *dev)
26{
27 /* For now, return 0... */
28 return 0;
29}
30
31static void cfg80211_get_regs(struct net_device *dev, struct ethtool_regs *regs,
32 void *data)
33{
34 struct wireless_dev *wdev = dev->ieee80211_ptr;
35
36 regs->version = wdev->wiphy->hw_version;
37 regs->len = 0;
38}
39
40const struct ethtool_ops cfg80211_ethtool_ops = {
41 .get_drvinfo = cfg80211_get_drvinfo,
42 .get_regs_len = cfg80211_get_regs_len,
43 .get_regs = cfg80211_get_regs,
44 .get_link = ethtool_op_get_link,
45};
diff --git a/net/wireless/ethtool.h b/net/wireless/ethtool.h
new file mode 100644
index 000000000000..695ecad20bd6
--- /dev/null
+++ b/net/wireless/ethtool.h
@@ -0,0 +1,6 @@
1#ifndef __CFG80211_ETHTOOL__
2#define __CFG80211_ETHTOOL__
3
4extern const struct ethtool_ops cfg80211_ethtool_ops;
5
6#endif /* __CFG80211_ETHTOOL__ */
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index c88338911979..6ef5a491fb4b 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -15,7 +15,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
15{ 15{
16 struct wireless_dev *wdev = dev->ieee80211_ptr; 16 struct wireless_dev *wdev = dev->ieee80211_ptr;
17 struct cfg80211_bss *bss; 17 struct cfg80211_bss *bss;
18#ifdef CONFIG_WIRELESS_EXT 18#ifdef CONFIG_CFG80211_WEXT
19 union iwreq_data wrqu; 19 union iwreq_data wrqu;
20#endif 20#endif
21 21
@@ -44,7 +44,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
44 44
45 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, 45 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
46 GFP_KERNEL); 46 GFP_KERNEL);
47#ifdef CONFIG_WIRELESS_EXT 47#ifdef CONFIG_CFG80211_WEXT
48 memset(&wrqu, 0, sizeof(wrqu)); 48 memset(&wrqu, 0, sizeof(wrqu));
49 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); 49 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
50 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); 50 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
@@ -70,7 +70,7 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
70 spin_lock_irqsave(&wdev->event_lock, flags); 70 spin_lock_irqsave(&wdev->event_lock, flags);
71 list_add_tail(&ev->list, &wdev->event_list); 71 list_add_tail(&ev->list, &wdev->event_list);
72 spin_unlock_irqrestore(&wdev->event_lock, flags); 72 spin_unlock_irqrestore(&wdev->event_lock, flags);
73 schedule_work(&rdev->event_work); 73 queue_work(cfg80211_wq, &rdev->event_work);
74} 74}
75EXPORT_SYMBOL(cfg80211_ibss_joined); 75EXPORT_SYMBOL(cfg80211_ibss_joined);
76 76
@@ -96,7 +96,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
96 kfree(wdev->connect_keys); 96 kfree(wdev->connect_keys);
97 wdev->connect_keys = connkeys; 97 wdev->connect_keys = connkeys;
98 98
99#ifdef CONFIG_WIRELESS_EXT 99#ifdef CONFIG_CFG80211_WEXT
100 wdev->wext.ibss.channel = params->channel; 100 wdev->wext.ibss.channel = params->channel;
101#endif 101#endif
102 err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); 102 err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
@@ -154,7 +154,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
154 154
155 wdev->current_bss = NULL; 155 wdev->current_bss = NULL;
156 wdev->ssid_len = 0; 156 wdev->ssid_len = 0;
157#ifdef CONFIG_WIRELESS_EXT 157#ifdef CONFIG_CFG80211_WEXT
158 if (!nowext) 158 if (!nowext)
159 wdev->wext.ibss.ssid_len = 0; 159 wdev->wext.ibss.ssid_len = 0;
160#endif 160#endif
@@ -169,8 +169,8 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
169 wdev_unlock(wdev); 169 wdev_unlock(wdev);
170} 170}
171 171
172static int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, 172int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
173 struct net_device *dev, bool nowext) 173 struct net_device *dev, bool nowext)
174{ 174{
175 struct wireless_dev *wdev = dev->ieee80211_ptr; 175 struct wireless_dev *wdev = dev->ieee80211_ptr;
176 int err; 176 int err;
@@ -203,7 +203,7 @@ int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
203 return err; 203 return err;
204} 204}
205 205
206#ifdef CONFIG_WIRELESS_EXT 206#ifdef CONFIG_CFG80211_WEXT
207int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, 207int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
208 struct wireless_dev *wdev) 208 struct wireless_dev *wdev)
209{ 209{
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 0a6b7a0eca6b..1001db4912f7 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -62,7 +62,6 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
62 u8 *ie = mgmt->u.assoc_resp.variable; 62 u8 *ie = mgmt->u.assoc_resp.variable;
63 int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); 63 int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
64 struct cfg80211_internal_bss *bss = NULL; 64 struct cfg80211_internal_bss *bss = NULL;
65 bool need_connect_result = true;
66 65
67 wdev_lock(wdev); 66 wdev_lock(wdev);
68 67
@@ -97,7 +96,6 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
97 WARN_ON(!bss); 96 WARN_ON(!bss);
98 } else if (wdev->conn) { 97 } else if (wdev->conn) {
99 cfg80211_sme_failed_assoc(wdev); 98 cfg80211_sme_failed_assoc(wdev);
100 need_connect_result = false;
101 /* 99 /*
102 * do not call connect_result() now because the 100 * do not call connect_result() now because the
103 * sme will schedule work that does it later. 101 * sme will schedule work that does it later.
@@ -130,7 +128,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
130} 128}
131EXPORT_SYMBOL(cfg80211_send_rx_assoc); 129EXPORT_SYMBOL(cfg80211_send_rx_assoc);
132 130
133static void __cfg80211_send_deauth(struct net_device *dev, 131void __cfg80211_send_deauth(struct net_device *dev,
134 const u8 *buf, size_t len) 132 const u8 *buf, size_t len)
135{ 133{
136 struct wireless_dev *wdev = dev->ieee80211_ptr; 134 struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -139,7 +137,6 @@ static void __cfg80211_send_deauth(struct net_device *dev,
139 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 137 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
140 const u8 *bssid = mgmt->bssid; 138 const u8 *bssid = mgmt->bssid;
141 int i; 139 int i;
142 bool done = false;
143 140
144 ASSERT_WDEV_LOCK(wdev); 141 ASSERT_WDEV_LOCK(wdev);
145 142
@@ -147,7 +144,6 @@ static void __cfg80211_send_deauth(struct net_device *dev,
147 144
148 if (wdev->current_bss && 145 if (wdev->current_bss &&
149 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { 146 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
150 done = true;
151 cfg80211_unhold_bss(wdev->current_bss); 147 cfg80211_unhold_bss(wdev->current_bss);
152 cfg80211_put_bss(&wdev->current_bss->pub); 148 cfg80211_put_bss(&wdev->current_bss->pub);
153 wdev->current_bss = NULL; 149 wdev->current_bss = NULL;
@@ -157,7 +153,6 @@ static void __cfg80211_send_deauth(struct net_device *dev,
157 cfg80211_unhold_bss(wdev->auth_bsses[i]); 153 cfg80211_unhold_bss(wdev->auth_bsses[i]);
158 cfg80211_put_bss(&wdev->auth_bsses[i]->pub); 154 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
159 wdev->auth_bsses[i] = NULL; 155 wdev->auth_bsses[i] = NULL;
160 done = true;
161 break; 156 break;
162 } 157 }
163 if (wdev->authtry_bsses[i] && 158 if (wdev->authtry_bsses[i] &&
@@ -165,13 +160,10 @@ static void __cfg80211_send_deauth(struct net_device *dev,
165 cfg80211_unhold_bss(wdev->authtry_bsses[i]); 160 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
166 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); 161 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
167 wdev->authtry_bsses[i] = NULL; 162 wdev->authtry_bsses[i] = NULL;
168 done = true;
169 break; 163 break;
170 } 164 }
171 } 165 }
172 166
173 WARN_ON(!done);
174
175 if (wdev->sme_state == CFG80211_SME_CONNECTED) { 167 if (wdev->sme_state == CFG80211_SME_CONNECTED) {
176 u16 reason_code; 168 u16 reason_code;
177 bool from_ap; 169 bool from_ap;
@@ -186,27 +178,19 @@ static void __cfg80211_send_deauth(struct net_device *dev,
186 false, NULL); 178 false, NULL);
187 } 179 }
188} 180}
181EXPORT_SYMBOL(__cfg80211_send_deauth);
189 182
190 183void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len)
191void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
192 void *cookie)
193{ 184{
194 struct wireless_dev *wdev = dev->ieee80211_ptr; 185 struct wireless_dev *wdev = dev->ieee80211_ptr;
195 186
196 BUG_ON(cookie && wdev != cookie); 187 wdev_lock(wdev);
197 188 __cfg80211_send_deauth(dev, buf, len);
198 if (cookie) { 189 wdev_unlock(wdev);
199 /* called within callback */
200 __cfg80211_send_deauth(dev, buf, len);
201 } else {
202 wdev_lock(wdev);
203 __cfg80211_send_deauth(dev, buf, len);
204 wdev_unlock(wdev);
205 }
206} 190}
207EXPORT_SYMBOL(cfg80211_send_deauth); 191EXPORT_SYMBOL(cfg80211_send_deauth);
208 192
209static void __cfg80211_send_disassoc(struct net_device *dev, 193void __cfg80211_send_disassoc(struct net_device *dev,
210 const u8 *buf, size_t len) 194 const u8 *buf, size_t len)
211{ 195{
212 struct wireless_dev *wdev = dev->ieee80211_ptr; 196 struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -247,40 +231,24 @@ static void __cfg80211_send_disassoc(struct net_device *dev,
247 from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; 231 from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
248 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); 232 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
249} 233}
234EXPORT_SYMBOL(__cfg80211_send_disassoc);
250 235
251void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, 236void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
252 void *cookie)
253{ 237{
254 struct wireless_dev *wdev = dev->ieee80211_ptr; 238 struct wireless_dev *wdev = dev->ieee80211_ptr;
255 239
256 BUG_ON(cookie && wdev != cookie); 240 wdev_lock(wdev);
257 241 __cfg80211_send_disassoc(dev, buf, len);
258 if (cookie) { 242 wdev_unlock(wdev);
259 /* called within callback */
260 __cfg80211_send_disassoc(dev, buf, len);
261 } else {
262 wdev_lock(wdev);
263 __cfg80211_send_disassoc(dev, buf, len);
264 wdev_unlock(wdev);
265 }
266} 243}
267EXPORT_SYMBOL(cfg80211_send_disassoc); 244EXPORT_SYMBOL(cfg80211_send_disassoc);
268 245
269void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) 246static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr)
270{ 247{
271 struct wireless_dev *wdev = dev->ieee80211_ptr;
272 struct wiphy *wiphy = wdev->wiphy;
273 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
274 int i; 248 int i;
275 bool done = false; 249 bool done = false;
276 250
277 wdev_lock(wdev); 251 ASSERT_WDEV_LOCK(wdev);
278
279 nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
280 if (wdev->sme_state == CFG80211_SME_CONNECTING)
281 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
282 WLAN_STATUS_UNSPECIFIED_FAILURE,
283 false, NULL);
284 252
285 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { 253 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
286 if (wdev->authtry_bsses[i] && 254 if (wdev->authtry_bsses[i] &&
@@ -295,6 +263,29 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
295 } 263 }
296 264
297 WARN_ON(!done); 265 WARN_ON(!done);
266}
267
268void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr)
269{
270 __cfg80211_auth_remove(dev->ieee80211_ptr, addr);
271}
272EXPORT_SYMBOL(__cfg80211_auth_canceled);
273
274void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
275{
276 struct wireless_dev *wdev = dev->ieee80211_ptr;
277 struct wiphy *wiphy = wdev->wiphy;
278 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
279
280 wdev_lock(wdev);
281
282 nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
283 if (wdev->sme_state == CFG80211_SME_CONNECTING)
284 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
285 WLAN_STATUS_UNSPECIFIED_FAILURE,
286 false, NULL);
287
288 __cfg80211_auth_remove(wdev, addr);
298 289
299 wdev_unlock(wdev); 290 wdev_unlock(wdev);
300} 291}
@@ -340,7 +331,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
340{ 331{
341 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; 332 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
342 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 333 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
343#ifdef CONFIG_WIRELESS_EXT 334#ifdef CONFIG_CFG80211_WEXT
344 union iwreq_data wrqu; 335 union iwreq_data wrqu;
345 char *buf = kmalloc(128, gfp); 336 char *buf = kmalloc(128, gfp);
346 337
@@ -469,12 +460,23 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
469 struct cfg80211_assoc_request req; 460 struct cfg80211_assoc_request req;
470 struct cfg80211_internal_bss *bss; 461 struct cfg80211_internal_bss *bss;
471 int i, err, slot = -1; 462 int i, err, slot = -1;
463 bool was_connected = false;
472 464
473 ASSERT_WDEV_LOCK(wdev); 465 ASSERT_WDEV_LOCK(wdev);
474 466
475 memset(&req, 0, sizeof(req)); 467 memset(&req, 0, sizeof(req));
476 468
477 if (wdev->current_bss) 469 if (wdev->current_bss && prev_bssid &&
470 memcmp(wdev->current_bss->pub.bssid, prev_bssid, ETH_ALEN) == 0) {
471 /*
472 * Trying to reassociate: Allow this to proceed and let the old
473 * association to be dropped when the new one is completed.
474 */
475 if (wdev->sme_state == CFG80211_SME_CONNECTED) {
476 was_connected = true;
477 wdev->sme_state = CFG80211_SME_CONNECTING;
478 }
479 } else if (wdev->current_bss)
478 return -EALREADY; 480 return -EALREADY;
479 481
480 req.ie = ie; 482 req.ie = ie;
@@ -484,8 +486,11 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
484 req.prev_bssid = prev_bssid; 486 req.prev_bssid = prev_bssid;
485 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, 487 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
486 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); 488 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
487 if (!req.bss) 489 if (!req.bss) {
490 if (was_connected)
491 wdev->sme_state = CFG80211_SME_CONNECTED;
488 return -ENOENT; 492 return -ENOENT;
493 }
489 494
490 bss = bss_from_pub(req.bss); 495 bss = bss_from_pub(req.bss);
491 496
@@ -503,6 +508,8 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
503 508
504 err = rdev->ops->assoc(&rdev->wiphy, dev, &req); 509 err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
505 out: 510 out:
511 if (err && was_connected)
512 wdev->sme_state = CFG80211_SME_CONNECTED;
506 /* still a reference in wdev->auth_bsses[slot] */ 513 /* still a reference in wdev->auth_bsses[slot] */
507 cfg80211_put_bss(req.bss); 514 cfg80211_put_bss(req.bss);
508 return err; 515 return err;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ca3c92a0a14f..a6028433e3a0 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -138,6 +138,9 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
138 [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, 138 [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
139 [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, 139 [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
140 [NL80211_ATTR_PID] = { .type = NLA_U32 }, 140 [NL80211_ATTR_PID] = { .type = NLA_U32 },
141 [NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
142 [NL80211_ATTR_PMKID] = { .type = NLA_BINARY,
143 .len = WLAN_PMKID_LEN },
141}; 144};
142 145
143/* policy for the attributes */ 146/* policy for the attributes */
@@ -151,6 +154,26 @@ nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = {
151 [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, 154 [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
152}; 155};
153 156
157/* ifidx get helper */
158static int nl80211_get_ifidx(struct netlink_callback *cb)
159{
160 int res;
161
162 res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
163 nl80211_fam.attrbuf, nl80211_fam.maxattr,
164 nl80211_policy);
165 if (res)
166 return res;
167
168 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
169 return -EINVAL;
170
171 res = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
172 if (!res)
173 return -EINVAL;
174 return res;
175}
176
154/* IE validation */ 177/* IE validation */
155static bool is_valid_ie_attr(const struct nlattr *attr) 178static bool is_valid_ie_attr(const struct nlattr *attr)
156{ 179{
@@ -429,6 +452,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
429 sizeof(u32) * dev->wiphy.n_cipher_suites, 452 sizeof(u32) * dev->wiphy.n_cipher_suites,
430 dev->wiphy.cipher_suites); 453 dev->wiphy.cipher_suites);
431 454
455 NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
456 dev->wiphy.max_num_pmkids);
457
432 nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); 458 nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
433 if (!nl_modes) 459 if (!nl_modes)
434 goto nla_put_failure; 460 goto nla_put_failure;
@@ -540,7 +566,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
540 CMD(deauth, DEAUTHENTICATE); 566 CMD(deauth, DEAUTHENTICATE);
541 CMD(disassoc, DISASSOCIATE); 567 CMD(disassoc, DISASSOCIATE);
542 CMD(join_ibss, JOIN_IBSS); 568 CMD(join_ibss, JOIN_IBSS);
543 if (dev->wiphy.netnsok) { 569 CMD(set_pmksa, SET_PMKSA);
570 CMD(del_pmksa, DEL_PMKSA);
571 CMD(flush_pmksa, FLUSH_PMKSA);
572 if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
544 i++; 573 i++;
545 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); 574 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
546 } 575 }
@@ -947,6 +976,32 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
947 return 0; 976 return 0;
948} 977}
949 978
979static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
980 struct net_device *netdev, u8 use_4addr,
981 enum nl80211_iftype iftype)
982{
983 if (!use_4addr) {
984 if (netdev && netdev->br_port)
985 return -EBUSY;
986 return 0;
987 }
988
989 switch (iftype) {
990 case NL80211_IFTYPE_AP_VLAN:
991 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
992 return 0;
993 break;
994 case NL80211_IFTYPE_STATION:
995 if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
996 return 0;
997 break;
998 default:
999 break;
1000 }
1001
1002 return -EOPNOTSUPP;
1003}
1004
950static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) 1005static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
951{ 1006{
952 struct cfg80211_registered_device *rdev; 1007 struct cfg80211_registered_device *rdev;
@@ -987,6 +1042,16 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
987 change = true; 1042 change = true;
988 } 1043 }
989 1044
1045 if (info->attrs[NL80211_ATTR_4ADDR]) {
1046 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
1047 change = true;
1048 err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
1049 if (err)
1050 goto unlock;
1051 } else {
1052 params.use_4addr = -1;
1053 }
1054
990 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { 1055 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
991 if (ntype != NL80211_IFTYPE_MONITOR) { 1056 if (ntype != NL80211_IFTYPE_MONITOR) {
992 err = -EINVAL; 1057 err = -EINVAL;
@@ -1006,6 +1071,9 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
1006 else 1071 else
1007 err = 0; 1072 err = 0;
1008 1073
1074 if (!err && params.use_4addr != -1)
1075 dev->ieee80211_ptr->use_4addr = params.use_4addr;
1076
1009 unlock: 1077 unlock:
1010 dev_put(dev); 1078 dev_put(dev);
1011 cfg80211_unlock_rdev(rdev); 1079 cfg80211_unlock_rdev(rdev);
@@ -1053,6 +1121,13 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
1053 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); 1121 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
1054 } 1122 }
1055 1123
1124 if (info->attrs[NL80211_ATTR_4ADDR]) {
1125 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
1126 err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
1127 if (err)
1128 goto unlock;
1129 }
1130
1056 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? 1131 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
1057 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, 1132 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
1058 &flags); 1133 &flags);
@@ -1264,7 +1339,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
1264 if (!err) 1339 if (!err)
1265 err = func(&rdev->wiphy, dev, key.idx); 1340 err = func(&rdev->wiphy, dev, key.idx);
1266 1341
1267#ifdef CONFIG_WIRELESS_EXT 1342#ifdef CONFIG_CFG80211_WEXT
1268 if (!err) { 1343 if (!err) {
1269 if (func == rdev->ops->set_default_key) 1344 if (func == rdev->ops->set_default_key)
1270 dev->ieee80211_ptr->wext.default_key = key.idx; 1345 dev->ieee80211_ptr->wext.default_key = key.idx;
@@ -1365,7 +1440,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
1365 if (!err) 1440 if (!err)
1366 err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); 1441 err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
1367 1442
1368#ifdef CONFIG_WIRELESS_EXT 1443#ifdef CONFIG_CFG80211_WEXT
1369 if (!err) { 1444 if (!err) {
1370 if (key.idx == dev->ieee80211_ptr->wext.default_key) 1445 if (key.idx == dev->ieee80211_ptr->wext.default_key)
1371 dev->ieee80211_ptr->wext.default_key = -1; 1446 dev->ieee80211_ptr->wext.default_key = -1;
@@ -1682,20 +1757,10 @@ static int nl80211_dump_station(struct sk_buff *skb,
1682 int sta_idx = cb->args[1]; 1757 int sta_idx = cb->args[1];
1683 int err; 1758 int err;
1684 1759
1685 if (!ifidx) { 1760 if (!ifidx)
1686 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, 1761 ifidx = nl80211_get_ifidx(cb);
1687 nl80211_fam.attrbuf, nl80211_fam.maxattr, 1762 if (ifidx < 0)
1688 nl80211_policy); 1763 return ifidx;
1689 if (err)
1690 return err;
1691
1692 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
1693 return -EINVAL;
1694
1695 ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
1696 if (!ifidx)
1697 return -EINVAL;
1698 }
1699 1764
1700 rtnl_lock(); 1765 rtnl_lock();
1701 1766
@@ -1800,7 +1865,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
1800} 1865}
1801 1866
1802/* 1867/*
1803 * Get vlan interface making sure it is on the right wiphy. 1868 * Get vlan interface making sure it is running and on the right wiphy.
1804 */ 1869 */
1805static int get_vlan(struct genl_info *info, 1870static int get_vlan(struct genl_info *info,
1806 struct cfg80211_registered_device *rdev, 1871 struct cfg80211_registered_device *rdev,
@@ -1818,6 +1883,8 @@ static int get_vlan(struct genl_info *info,
1818 return -EINVAL; 1883 return -EINVAL;
1819 if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) 1884 if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
1820 return -EINVAL; 1885 return -EINVAL;
1886 if (!netif_running(*vlan))
1887 return -ENETDOWN;
1821 } 1888 }
1822 return 0; 1889 return 0;
1823} 1890}
@@ -2105,9 +2172,9 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq,
2105 if (pinfo->filled & MPATH_INFO_FRAME_QLEN) 2172 if (pinfo->filled & MPATH_INFO_FRAME_QLEN)
2106 NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, 2173 NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
2107 pinfo->frame_qlen); 2174 pinfo->frame_qlen);
2108 if (pinfo->filled & MPATH_INFO_DSN) 2175 if (pinfo->filled & MPATH_INFO_SN)
2109 NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN, 2176 NLA_PUT_U32(msg, NL80211_MPATH_INFO_SN,
2110 pinfo->dsn); 2177 pinfo->sn);
2111 if (pinfo->filled & MPATH_INFO_METRIC) 2178 if (pinfo->filled & MPATH_INFO_METRIC)
2112 NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, 2179 NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC,
2113 pinfo->metric); 2180 pinfo->metric);
@@ -2145,20 +2212,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
2145 int path_idx = cb->args[1]; 2212 int path_idx = cb->args[1];
2146 int err; 2213 int err;
2147 2214
2148 if (!ifidx) { 2215 if (!ifidx)
2149 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, 2216 ifidx = nl80211_get_ifidx(cb);
2150 nl80211_fam.attrbuf, nl80211_fam.maxattr, 2217 if (ifidx < 0)
2151 nl80211_policy); 2218 return ifidx;
2152 if (err)
2153 return err;
2154
2155 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
2156 return -EINVAL;
2157
2158 ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
2159 if (!ifidx)
2160 return -EINVAL;
2161 }
2162 2219
2163 rtnl_lock(); 2220 rtnl_lock();
2164 2221
@@ -2605,6 +2662,8 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
2605 cur_params.dot11MeshHWMPpreqMinInterval); 2662 cur_params.dot11MeshHWMPpreqMinInterval);
2606 NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, 2663 NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
2607 cur_params.dot11MeshHWMPnetDiameterTraversalTime); 2664 cur_params.dot11MeshHWMPnetDiameterTraversalTime);
2665 NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
2666 cur_params.dot11MeshHWMPRootMode);
2608 nla_nest_end(msg, pinfoattr); 2667 nla_nest_end(msg, pinfoattr);
2609 genlmsg_end(msg, hdr); 2668 genlmsg_end(msg, hdr);
2610 err = genlmsg_reply(msg, info); 2669 err = genlmsg_reply(msg, info);
@@ -2715,6 +2774,10 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
2715 dot11MeshHWMPnetDiameterTraversalTime, 2774 dot11MeshHWMPnetDiameterTraversalTime,
2716 mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, 2775 mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
2717 nla_get_u16); 2776 nla_get_u16);
2777 FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
2778 dot11MeshHWMPRootMode, mask,
2779 NL80211_MESHCONF_HWMP_ROOTMODE,
2780 nla_get_u8);
2718 2781
2719 /* Apply changes */ 2782 /* Apply changes */
2720 err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); 2783 err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
@@ -2988,7 +3051,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
2988 goto out; 3051 goto out;
2989 } 3052 }
2990 3053
2991 request->n_channels = n_channels;
2992 if (n_ssids) 3054 if (n_ssids)
2993 request->ssids = (void *)&request->channels[n_channels]; 3055 request->ssids = (void *)&request->channels[n_channels];
2994 request->n_ssids = n_ssids; 3056 request->n_ssids = n_ssids;
@@ -2999,32 +3061,53 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
2999 request->ie = (void *)(request->channels + n_channels); 3061 request->ie = (void *)(request->channels + n_channels);
3000 } 3062 }
3001 3063
3064 i = 0;
3002 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { 3065 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
3003 /* user specified, bail out if channel not found */ 3066 /* user specified, bail out if channel not found */
3004 request->n_channels = n_channels;
3005 i = 0;
3006 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) { 3067 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
3007 request->channels[i] = ieee80211_get_channel(wiphy, nla_get_u32(attr)); 3068 struct ieee80211_channel *chan;
3008 if (!request->channels[i]) { 3069
3070 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
3071
3072 if (!chan) {
3009 err = -EINVAL; 3073 err = -EINVAL;
3010 goto out_free; 3074 goto out_free;
3011 } 3075 }
3076
3077 /* ignore disabled channels */
3078 if (chan->flags & IEEE80211_CHAN_DISABLED)
3079 continue;
3080
3081 request->channels[i] = chan;
3012 i++; 3082 i++;
3013 } 3083 }
3014 } else { 3084 } else {
3015 /* all channels */ 3085 /* all channels */
3016 i = 0;
3017 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 3086 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
3018 int j; 3087 int j;
3019 if (!wiphy->bands[band]) 3088 if (!wiphy->bands[band])
3020 continue; 3089 continue;
3021 for (j = 0; j < wiphy->bands[band]->n_channels; j++) { 3090 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
3022 request->channels[i] = &wiphy->bands[band]->channels[j]; 3091 struct ieee80211_channel *chan;
3092
3093 chan = &wiphy->bands[band]->channels[j];
3094
3095 if (chan->flags & IEEE80211_CHAN_DISABLED)
3096 continue;
3097
3098 request->channels[i] = chan;
3023 i++; 3099 i++;
3024 } 3100 }
3025 } 3101 }
3026 } 3102 }
3027 3103
3104 if (!i) {
3105 err = -EINVAL;
3106 goto out_free;
3107 }
3108
3109 request->n_channels = i;
3110
3028 i = 0; 3111 i = 0;
3029 if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) { 3112 if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) {
3030 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) { 3113 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
@@ -3105,6 +3188,8 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
3105 NLA_PUT_U16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval); 3188 NLA_PUT_U16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval);
3106 NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability); 3189 NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability);
3107 NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq); 3190 NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq);
3191 NLA_PUT_U32(msg, NL80211_BSS_SEEN_MS_AGO,
3192 jiffies_to_msecs(jiffies - intbss->ts));
3108 3193
3109 switch (rdev->wiphy.signal_type) { 3194 switch (rdev->wiphy.signal_type) {
3110 case CFG80211_SIGNAL_TYPE_MBM: 3195 case CFG80211_SIGNAL_TYPE_MBM:
@@ -3159,21 +3244,11 @@ static int nl80211_dump_scan(struct sk_buff *skb,
3159 int start = cb->args[1], idx = 0; 3244 int start = cb->args[1], idx = 0;
3160 int err; 3245 int err;
3161 3246
3162 if (!ifidx) { 3247 if (!ifidx)
3163 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, 3248 ifidx = nl80211_get_ifidx(cb);
3164 nl80211_fam.attrbuf, nl80211_fam.maxattr, 3249 if (ifidx < 0)
3165 nl80211_policy); 3250 return ifidx;
3166 if (err) 3251 cb->args[0] = ifidx;
3167 return err;
3168
3169 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
3170 return -EINVAL;
3171
3172 ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
3173 if (!ifidx)
3174 return -EINVAL;
3175 cb->args[0] = ifidx;
3176 }
3177 3252
3178 dev = dev_get_by_index(sock_net(skb->sk), ifidx); 3253 dev = dev_get_by_index(sock_net(skb->sk), ifidx);
3179 if (!dev) 3254 if (!dev)
@@ -3216,6 +3291,106 @@ static int nl80211_dump_scan(struct sk_buff *skb,
3216 return err; 3291 return err;
3217} 3292}
3218 3293
3294static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq,
3295 int flags, struct net_device *dev,
3296 struct survey_info *survey)
3297{
3298 void *hdr;
3299 struct nlattr *infoattr;
3300
3301 /* Survey without a channel doesn't make sense */
3302 if (!survey->channel)
3303 return -EINVAL;
3304
3305 hdr = nl80211hdr_put(msg, pid, seq, flags,
3306 NL80211_CMD_NEW_SURVEY_RESULTS);
3307 if (!hdr)
3308 return -ENOMEM;
3309
3310 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
3311
3312 infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO);
3313 if (!infoattr)
3314 goto nla_put_failure;
3315
3316 NLA_PUT_U32(msg, NL80211_SURVEY_INFO_FREQUENCY,
3317 survey->channel->center_freq);
3318 if (survey->filled & SURVEY_INFO_NOISE_DBM)
3319 NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE,
3320 survey->noise);
3321
3322 nla_nest_end(msg, infoattr);
3323
3324 return genlmsg_end(msg, hdr);
3325
3326 nla_put_failure:
3327 genlmsg_cancel(msg, hdr);
3328 return -EMSGSIZE;
3329}
3330
3331static int nl80211_dump_survey(struct sk_buff *skb,
3332 struct netlink_callback *cb)
3333{
3334 struct survey_info survey;
3335 struct cfg80211_registered_device *dev;
3336 struct net_device *netdev;
3337 int ifidx = cb->args[0];
3338 int survey_idx = cb->args[1];
3339 int res;
3340
3341 if (!ifidx)
3342 ifidx = nl80211_get_ifidx(cb);
3343 if (ifidx < 0)
3344 return ifidx;
3345 cb->args[0] = ifidx;
3346
3347 rtnl_lock();
3348
3349 netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
3350 if (!netdev) {
3351 res = -ENODEV;
3352 goto out_rtnl;
3353 }
3354
3355 dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
3356 if (IS_ERR(dev)) {
3357 res = PTR_ERR(dev);
3358 goto out_rtnl;
3359 }
3360
3361 if (!dev->ops->dump_survey) {
3362 res = -EOPNOTSUPP;
3363 goto out_err;
3364 }
3365
3366 while (1) {
3367 res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx,
3368 &survey);
3369 if (res == -ENOENT)
3370 break;
3371 if (res)
3372 goto out_err;
3373
3374 if (nl80211_send_survey(skb,
3375 NETLINK_CB(cb->skb).pid,
3376 cb->nlh->nlmsg_seq, NLM_F_MULTI,
3377 netdev,
3378 &survey) < 0)
3379 goto out;
3380 survey_idx++;
3381 }
3382
3383 out:
3384 cb->args[1] = survey_idx;
3385 res = skb->len;
3386 out_err:
3387 cfg80211_unlock_rdev(dev);
3388 out_rtnl:
3389 rtnl_unlock();
3390
3391 return res;
3392}
3393
3219static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) 3394static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type)
3220{ 3395{
3221 return auth_type <= NL80211_AUTHTYPE_MAX; 3396 return auth_type <= NL80211_AUTHTYPE_MAX;
@@ -4054,6 +4229,99 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
4054 return err; 4229 return err;
4055} 4230}
4056 4231
4232static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
4233{
4234 struct cfg80211_registered_device *rdev;
4235 int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev,
4236 struct cfg80211_pmksa *pmksa) = NULL;
4237 int err;
4238 struct net_device *dev;
4239 struct cfg80211_pmksa pmksa;
4240
4241 memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
4242
4243 if (!info->attrs[NL80211_ATTR_MAC])
4244 return -EINVAL;
4245
4246 if (!info->attrs[NL80211_ATTR_PMKID])
4247 return -EINVAL;
4248
4249 rtnl_lock();
4250
4251 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4252 if (err)
4253 goto out_rtnl;
4254
4255 pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
4256 pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
4257
4258 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
4259 err = -EOPNOTSUPP;
4260 goto out;
4261 }
4262
4263 switch (info->genlhdr->cmd) {
4264 case NL80211_CMD_SET_PMKSA:
4265 rdev_ops = rdev->ops->set_pmksa;
4266 break;
4267 case NL80211_CMD_DEL_PMKSA:
4268 rdev_ops = rdev->ops->del_pmksa;
4269 break;
4270 default:
4271 WARN_ON(1);
4272 break;
4273 }
4274
4275 if (!rdev_ops) {
4276 err = -EOPNOTSUPP;
4277 goto out;
4278 }
4279
4280 err = rdev_ops(&rdev->wiphy, dev, &pmksa);
4281
4282 out:
4283 cfg80211_unlock_rdev(rdev);
4284 dev_put(dev);
4285 out_rtnl:
4286 rtnl_unlock();
4287
4288 return err;
4289}
4290
4291static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
4292{
4293 struct cfg80211_registered_device *rdev;
4294 int err;
4295 struct net_device *dev;
4296
4297 rtnl_lock();
4298
4299 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4300 if (err)
4301 goto out_rtnl;
4302
4303 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
4304 err = -EOPNOTSUPP;
4305 goto out;
4306 }
4307
4308 if (!rdev->ops->flush_pmksa) {
4309 err = -EOPNOTSUPP;
4310 goto out;
4311 }
4312
4313 err = rdev->ops->flush_pmksa(&rdev->wiphy, dev);
4314
4315 out:
4316 cfg80211_unlock_rdev(rdev);
4317 dev_put(dev);
4318 out_rtnl:
4319 rtnl_unlock();
4320
4321 return err;
4322
4323}
4324
4057static struct genl_ops nl80211_ops[] = { 4325static struct genl_ops nl80211_ops[] = {
4058 { 4326 {
4059 .cmd = NL80211_CMD_GET_WIPHY, 4327 .cmd = NL80211_CMD_GET_WIPHY,
@@ -4293,6 +4561,30 @@ static struct genl_ops nl80211_ops[] = {
4293 .policy = nl80211_policy, 4561 .policy = nl80211_policy,
4294 .flags = GENL_ADMIN_PERM, 4562 .flags = GENL_ADMIN_PERM,
4295 }, 4563 },
4564 {
4565 .cmd = NL80211_CMD_GET_SURVEY,
4566 .policy = nl80211_policy,
4567 .dumpit = nl80211_dump_survey,
4568 },
4569 {
4570 .cmd = NL80211_CMD_SET_PMKSA,
4571 .doit = nl80211_setdel_pmksa,
4572 .policy = nl80211_policy,
4573 .flags = GENL_ADMIN_PERM,
4574 },
4575 {
4576 .cmd = NL80211_CMD_DEL_PMKSA,
4577 .doit = nl80211_setdel_pmksa,
4578 .policy = nl80211_policy,
4579 .flags = GENL_ADMIN_PERM,
4580 },
4581 {
4582 .cmd = NL80211_CMD_FLUSH_PMKSA,
4583 .doit = nl80211_flush_pmksa,
4584 .policy = nl80211_policy,
4585 .flags = GENL_ADMIN_PERM,
4586 },
4587
4296}; 4588};
4297static struct genl_multicast_group nl80211_mlme_mcgrp = { 4589static struct genl_multicast_group nl80211_mlme_mcgrp = {
4298 .name = "mlme", 4590 .name = "mlme",
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index f256dfffbf46..c01470e7de15 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1008,7 +1008,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
1008 1008
1009 if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && 1009 if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
1010 request_wiphy && request_wiphy == wiphy && 1010 request_wiphy && request_wiphy == wiphy &&
1011 request_wiphy->strict_regulatory) { 1011 request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
1012 /* 1012 /*
1013 * This gaurantees the driver's requested regulatory domain 1013 * This gaurantees the driver's requested regulatory domain
1014 * will always be used as a base for further regulatory 1014 * will always be used as a base for further regulatory
@@ -1051,13 +1051,13 @@ static bool ignore_reg_update(struct wiphy *wiphy,
1051 if (!last_request) 1051 if (!last_request)
1052 return true; 1052 return true;
1053 if (initiator == NL80211_REGDOM_SET_BY_CORE && 1053 if (initiator == NL80211_REGDOM_SET_BY_CORE &&
1054 wiphy->custom_regulatory) 1054 wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)
1055 return true; 1055 return true;
1056 /* 1056 /*
1057 * wiphy->regd will be set once the device has its own 1057 * wiphy->regd will be set once the device has its own
1058 * desired regulatory domain set 1058 * desired regulatory domain set
1059 */ 1059 */
1060 if (wiphy->strict_regulatory && !wiphy->regd && 1060 if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd &&
1061 !is_world_regdom(last_request->alpha2)) 1061 !is_world_regdom(last_request->alpha2))
1062 return true; 1062 return true;
1063 return false; 1063 return false;
@@ -1093,7 +1093,7 @@ static void handle_reg_beacon(struct wiphy *wiphy,
1093 1093
1094 chan->beacon_found = true; 1094 chan->beacon_found = true;
1095 1095
1096 if (wiphy->disable_beacon_hints) 1096 if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS)
1097 return; 1097 return;
1098 1098
1099 chan_before.center_freq = chan->center_freq; 1099 chan_before.center_freq = chan->center_freq;
@@ -1164,7 +1164,7 @@ static bool reg_is_world_roaming(struct wiphy *wiphy)
1164 return true; 1164 return true;
1165 if (last_request && 1165 if (last_request &&
1166 last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && 1166 last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
1167 wiphy->custom_regulatory) 1167 wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)
1168 return true; 1168 return true;
1169 return false; 1169 return false;
1170} 1170}
@@ -1591,7 +1591,8 @@ static void reg_process_hint(struct regulatory_request *reg_request)
1591 1591
1592 r = __regulatory_hint(wiphy, reg_request); 1592 r = __regulatory_hint(wiphy, reg_request);
1593 /* This is required so that the orig_* parameters are saved */ 1593 /* This is required so that the orig_* parameters are saved */
1594 if (r == -EALREADY && wiphy && wiphy->strict_regulatory) 1594 if (r == -EALREADY && wiphy &&
1595 wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
1595 wiphy_update_regulatory(wiphy, reg_request->initiator); 1596 wiphy_update_regulatory(wiphy, reg_request->initiator);
1596out: 1597out:
1597 mutex_unlock(&reg_mutex); 1598 mutex_unlock(&reg_mutex);
@@ -1930,7 +1931,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
1930 const struct ieee80211_freq_range *freq_range = NULL; 1931 const struct ieee80211_freq_range *freq_range = NULL;
1931 const struct ieee80211_power_rule *power_rule = NULL; 1932 const struct ieee80211_power_rule *power_rule = NULL;
1932 1933
1933 printk(KERN_INFO "\t(start_freq - end_freq @ bandwidth), " 1934 printk(KERN_INFO " (start_freq - end_freq @ bandwidth), "
1934 "(max_antenna_gain, max_eirp)\n"); 1935 "(max_antenna_gain, max_eirp)\n");
1935 1936
1936 for (i = 0; i < rd->n_reg_rules; i++) { 1937 for (i = 0; i < rd->n_reg_rules; i++) {
@@ -1943,7 +1944,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
1943 * in certain regions 1944 * in certain regions
1944 */ 1945 */
1945 if (power_rule->max_antenna_gain) 1946 if (power_rule->max_antenna_gain)
1946 printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), " 1947 printk(KERN_INFO " (%d KHz - %d KHz @ %d KHz), "
1947 "(%d mBi, %d mBm)\n", 1948 "(%d mBi, %d mBm)\n",
1948 freq_range->start_freq_khz, 1949 freq_range->start_freq_khz,
1949 freq_range->end_freq_khz, 1950 freq_range->end_freq_khz,
@@ -1951,7 +1952,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
1951 power_rule->max_antenna_gain, 1952 power_rule->max_antenna_gain,
1952 power_rule->max_eirp); 1953 power_rule->max_eirp);
1953 else 1954 else
1954 printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), " 1955 printk(KERN_INFO " (%d KHz - %d KHz @ %d KHz), "
1955 "(N/A, %d mBm)\n", 1956 "(N/A, %d mBm)\n",
1956 freq_range->start_freq_khz, 1957 freq_range->start_freq_khz,
1957 freq_range->end_freq_khz, 1958 freq_range->end_freq_khz,
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index e5f92ee758f4..12dfa62aad18 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -22,7 +22,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
22{ 22{
23 struct cfg80211_scan_request *request; 23 struct cfg80211_scan_request *request;
24 struct net_device *dev; 24 struct net_device *dev;
25#ifdef CONFIG_WIRELESS_EXT 25#ifdef CONFIG_CFG80211_WEXT
26 union iwreq_data wrqu; 26 union iwreq_data wrqu;
27#endif 27#endif
28 28
@@ -47,7 +47,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
47 else 47 else
48 nl80211_send_scan_done(rdev, dev); 48 nl80211_send_scan_done(rdev, dev);
49 49
50#ifdef CONFIG_WIRELESS_EXT 50#ifdef CONFIG_CFG80211_WEXT
51 if (!request->aborted) { 51 if (!request->aborted) {
52 memset(&wrqu, 0, sizeof(wrqu)); 52 memset(&wrqu, 0, sizeof(wrqu));
53 53
@@ -88,7 +88,7 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
88 WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); 88 WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
89 89
90 request->aborted = aborted; 90 request->aborted = aborted;
91 schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk); 91 queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk);
92} 92}
93EXPORT_SYMBOL(cfg80211_scan_done); 93EXPORT_SYMBOL(cfg80211_scan_done);
94 94
@@ -217,7 +217,7 @@ static bool is_mesh(struct cfg80211_bss *a,
217 a->len_information_elements); 217 a->len_information_elements);
218 if (!ie) 218 if (!ie)
219 return false; 219 return false;
220 if (ie[1] != IEEE80211_MESH_CONFIG_LEN) 220 if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
221 return false; 221 return false;
222 222
223 /* 223 /*
@@ -225,7 +225,8 @@ static bool is_mesh(struct cfg80211_bss *a,
225 * comparing since that may differ between stations taking 225 * comparing since that may differ between stations taking
226 * part in the same mesh. 226 * part in the same mesh.
227 */ 227 */
228 return memcmp(ie + 2, meshcfg, IEEE80211_MESH_CONFIG_LEN - 2) == 0; 228 return memcmp(ie + 2, meshcfg,
229 sizeof(struct ieee80211_meshconf_ie) - 2) == 0;
229} 230}
230 231
231static int cmp_bss(struct cfg80211_bss *a, 232static int cmp_bss(struct cfg80211_bss *a,
@@ -399,7 +400,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
399 res->pub.information_elements, 400 res->pub.information_elements,
400 res->pub.len_information_elements); 401 res->pub.len_information_elements);
401 if (!meshid || !meshcfg || 402 if (!meshid || !meshcfg ||
402 meshcfg[1] != IEEE80211_MESH_CONFIG_LEN) { 403 meshcfg[1] != sizeof(struct ieee80211_meshconf_ie)) {
403 /* bogus mesh */ 404 /* bogus mesh */
404 kref_put(&res->ref, bss_release); 405 kref_put(&res->ref, bss_release);
405 return NULL; 406 return NULL;
@@ -592,7 +593,7 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
592} 593}
593EXPORT_SYMBOL(cfg80211_unlink_bss); 594EXPORT_SYMBOL(cfg80211_unlink_bss);
594 595
595#ifdef CONFIG_WIRELESS_EXT 596#ifdef CONFIG_CFG80211_WEXT
596int cfg80211_wext_siwscan(struct net_device *dev, 597int cfg80211_wext_siwscan(struct net_device *dev,
597 struct iw_request_info *info, 598 struct iw_request_info *info,
598 union iwreq_data *wrqu, char *extra) 599 union iwreq_data *wrqu, char *extra)
@@ -650,9 +651,15 @@ int cfg80211_wext_siwscan(struct net_device *dev,
650 i = 0; 651 i = 0;
651 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 652 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
652 int j; 653 int j;
654
653 if (!wiphy->bands[band]) 655 if (!wiphy->bands[band])
654 continue; 656 continue;
657
655 for (j = 0; j < wiphy->bands[band]->n_channels; j++) { 658 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
659 /* ignore disabled channels */
660 if (wiphy->bands[band]->channels[j].flags &
661 IEEE80211_CHAN_DISABLED)
662 continue;
656 663
657 /* If we have a wireless request structure and the 664 /* If we have a wireless request structure and the
658 * wireless request specifies frequencies, then search 665 * wireless request specifies frequencies, then search
@@ -859,7 +866,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
859 break; 866 break;
860 case WLAN_EID_MESH_CONFIG: 867 case WLAN_EID_MESH_CONFIG:
861 ismesh = true; 868 ismesh = true;
862 if (ie[1] != IEEE80211_MESH_CONFIG_LEN) 869 if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
863 break; 870 break;
864 buf = kmalloc(50, GFP_ATOMIC); 871 buf = kmalloc(50, GFP_ATOMIC);
865 if (!buf) 872 if (!buf)
@@ -867,35 +874,40 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
867 cfg = ie + 2; 874 cfg = ie + 2;
868 memset(&iwe, 0, sizeof(iwe)); 875 memset(&iwe, 0, sizeof(iwe));
869 iwe.cmd = IWEVCUSTOM; 876 iwe.cmd = IWEVCUSTOM;
870 sprintf(buf, "Mesh network (version %d)", cfg[0]); 877 sprintf(buf, "Mesh Network Path Selection Protocol ID: "
878 "0x%02X", cfg[0]);
879 iwe.u.data.length = strlen(buf);
880 current_ev = iwe_stream_add_point(info, current_ev,
881 end_buf,
882 &iwe, buf);
883 sprintf(buf, "Path Selection Metric ID: 0x%02X",
884 cfg[1]);
885 iwe.u.data.length = strlen(buf);
886 current_ev = iwe_stream_add_point(info, current_ev,
887 end_buf,
888 &iwe, buf);
889 sprintf(buf, "Congestion Control Mode ID: 0x%02X",
890 cfg[2]);
871 iwe.u.data.length = strlen(buf); 891 iwe.u.data.length = strlen(buf);
872 current_ev = iwe_stream_add_point(info, current_ev, 892 current_ev = iwe_stream_add_point(info, current_ev,
873 end_buf, 893 end_buf,
874 &iwe, buf); 894 &iwe, buf);
875 sprintf(buf, "Path Selection Protocol ID: " 895 sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]);
876 "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
877 cfg[4]);
878 iwe.u.data.length = strlen(buf); 896 iwe.u.data.length = strlen(buf);
879 current_ev = iwe_stream_add_point(info, current_ev, 897 current_ev = iwe_stream_add_point(info, current_ev,
880 end_buf, 898 end_buf,
881 &iwe, buf); 899 &iwe, buf);
882 sprintf(buf, "Path Selection Metric ID: " 900 sprintf(buf, "Authentication ID: 0x%02X", cfg[4]);
883 "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
884 cfg[8]);
885 iwe.u.data.length = strlen(buf); 901 iwe.u.data.length = strlen(buf);
886 current_ev = iwe_stream_add_point(info, current_ev, 902 current_ev = iwe_stream_add_point(info, current_ev,
887 end_buf, 903 end_buf,
888 &iwe, buf); 904 &iwe, buf);
889 sprintf(buf, "Congestion Control Mode ID: " 905 sprintf(buf, "Formation Info: 0x%02X", cfg[5]);
890 "0x%02X%02X%02X%02X", cfg[9], cfg[10],
891 cfg[11], cfg[12]);
892 iwe.u.data.length = strlen(buf); 906 iwe.u.data.length = strlen(buf);
893 current_ev = iwe_stream_add_point(info, current_ev, 907 current_ev = iwe_stream_add_point(info, current_ev,
894 end_buf, 908 end_buf,
895 &iwe, buf); 909 &iwe, buf);
896 sprintf(buf, "Channel Precedence: " 910 sprintf(buf, "Capabilities: 0x%02X", cfg[6]);
897 "0x%02X%02X%02X%02X", cfg[13], cfg[14],
898 cfg[15], cfg[16]);
899 iwe.u.data.length = strlen(buf); 911 iwe.u.data.length = strlen(buf);
900 current_ev = iwe_stream_add_point(info, current_ev, 912 current_ev = iwe_stream_add_point(info, current_ev,
901 end_buf, 913 end_buf,
@@ -925,8 +937,8 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
925 ie += ie[1] + 2; 937 ie += ie[1] + 2;
926 } 938 }
927 939
928 if (bss->pub.capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) 940 if (bss->pub.capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) ||
929 || ismesh) { 941 ismesh) {
930 memset(&iwe, 0, sizeof(iwe)); 942 memset(&iwe, 0, sizeof(iwe));
931 iwe.cmd = SIOCGIWMODE; 943 iwe.cmd = SIOCGIWMODE;
932 if (ismesh) 944 if (ismesh)
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 9f0b2800a9d7..2333d78187e4 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -365,7 +365,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
365{ 365{
366 struct wireless_dev *wdev = dev->ieee80211_ptr; 366 struct wireless_dev *wdev = dev->ieee80211_ptr;
367 u8 *country_ie; 367 u8 *country_ie;
368#ifdef CONFIG_WIRELESS_EXT 368#ifdef CONFIG_CFG80211_WEXT
369 union iwreq_data wrqu; 369 union iwreq_data wrqu;
370#endif 370#endif
371 371
@@ -382,7 +382,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
382 resp_ie, resp_ie_len, 382 resp_ie, resp_ie_len,
383 status, GFP_KERNEL); 383 status, GFP_KERNEL);
384 384
385#ifdef CONFIG_WIRELESS_EXT 385#ifdef CONFIG_CFG80211_WEXT
386 if (wextev) { 386 if (wextev) {
387 if (req_ie && status == WLAN_STATUS_SUCCESS) { 387 if (req_ie && status == WLAN_STATUS_SUCCESS) {
388 memset(&wrqu, 0, sizeof(wrqu)); 388 memset(&wrqu, 0, sizeof(wrqu));
@@ -488,7 +488,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
488 spin_lock_irqsave(&wdev->event_lock, flags); 488 spin_lock_irqsave(&wdev->event_lock, flags);
489 list_add_tail(&ev->list, &wdev->event_list); 489 list_add_tail(&ev->list, &wdev->event_list);
490 spin_unlock_irqrestore(&wdev->event_lock, flags); 490 spin_unlock_irqrestore(&wdev->event_lock, flags);
491 schedule_work(&rdev->event_work); 491 queue_work(cfg80211_wq, &rdev->event_work);
492} 492}
493EXPORT_SYMBOL(cfg80211_connect_result); 493EXPORT_SYMBOL(cfg80211_connect_result);
494 494
@@ -497,7 +497,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
497 const u8 *resp_ie, size_t resp_ie_len) 497 const u8 *resp_ie, size_t resp_ie_len)
498{ 498{
499 struct cfg80211_bss *bss; 499 struct cfg80211_bss *bss;
500#ifdef CONFIG_WIRELESS_EXT 500#ifdef CONFIG_CFG80211_WEXT
501 union iwreq_data wrqu; 501 union iwreq_data wrqu;
502#endif 502#endif
503 503
@@ -532,7 +532,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
532 req_ie, req_ie_len, resp_ie, resp_ie_len, 532 req_ie, req_ie_len, resp_ie, resp_ie_len,
533 GFP_KERNEL); 533 GFP_KERNEL);
534 534
535#ifdef CONFIG_WIRELESS_EXT 535#ifdef CONFIG_CFG80211_WEXT
536 if (req_ie) { 536 if (req_ie) {
537 memset(&wrqu, 0, sizeof(wrqu)); 537 memset(&wrqu, 0, sizeof(wrqu));
538 wrqu.data.length = req_ie_len; 538 wrqu.data.length = req_ie_len;
@@ -583,7 +583,7 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
583 spin_lock_irqsave(&wdev->event_lock, flags); 583 spin_lock_irqsave(&wdev->event_lock, flags);
584 list_add_tail(&ev->list, &wdev->event_list); 584 list_add_tail(&ev->list, &wdev->event_list);
585 spin_unlock_irqrestore(&wdev->event_lock, flags); 585 spin_unlock_irqrestore(&wdev->event_lock, flags);
586 schedule_work(&rdev->event_work); 586 queue_work(cfg80211_wq, &rdev->event_work);
587} 587}
588EXPORT_SYMBOL(cfg80211_roamed); 588EXPORT_SYMBOL(cfg80211_roamed);
589 589
@@ -593,7 +593,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
593 struct wireless_dev *wdev = dev->ieee80211_ptr; 593 struct wireless_dev *wdev = dev->ieee80211_ptr;
594 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 594 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
595 int i; 595 int i;
596#ifdef CONFIG_WIRELESS_EXT 596#ifdef CONFIG_CFG80211_WEXT
597 union iwreq_data wrqu; 597 union iwreq_data wrqu;
598#endif 598#endif
599 599
@@ -651,7 +651,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
651 for (i = 0; i < 6; i++) 651 for (i = 0; i < 6; i++)
652 rdev->ops->del_key(wdev->wiphy, dev, i, NULL); 652 rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
653 653
654#ifdef CONFIG_WIRELESS_EXT 654#ifdef CONFIG_CFG80211_WEXT
655 memset(&wrqu, 0, sizeof(wrqu)); 655 memset(&wrqu, 0, sizeof(wrqu));
656 wrqu.ap_addr.sa_family = ARPHRD_ETHER; 656 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
657 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); 657 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
@@ -681,7 +681,7 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
681 spin_lock_irqsave(&wdev->event_lock, flags); 681 spin_lock_irqsave(&wdev->event_lock, flags);
682 list_add_tail(&ev->list, &wdev->event_list); 682 list_add_tail(&ev->list, &wdev->event_list);
683 spin_unlock_irqrestore(&wdev->event_lock, flags); 683 spin_unlock_irqrestore(&wdev->event_lock, flags);
684 schedule_work(&rdev->event_work); 684 queue_work(cfg80211_wq, &rdev->event_work);
685} 685}
686EXPORT_SYMBOL(cfg80211_disconnected); 686EXPORT_SYMBOL(cfg80211_disconnected);
687 687
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 3fc2df86278f..59361fdcb5d0 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -320,7 +320,9 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
320 break; 320 break;
321 case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): 321 case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
322 if (unlikely(iftype != NL80211_IFTYPE_WDS && 322 if (unlikely(iftype != NL80211_IFTYPE_WDS &&
323 iftype != NL80211_IFTYPE_MESH_POINT)) 323 iftype != NL80211_IFTYPE_MESH_POINT &&
324 iftype != NL80211_IFTYPE_AP_VLAN &&
325 iftype != NL80211_IFTYPE_STATION))
324 return -1; 326 return -1;
325 if (iftype == NL80211_IFTYPE_MESH_POINT) { 327 if (iftype == NL80211_IFTYPE_MESH_POINT) {
326 struct ieee80211s_hdr *meshdr = 328 struct ieee80211s_hdr *meshdr =
@@ -656,7 +658,14 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
656 !(rdev->wiphy.interface_modes & (1 << ntype))) 658 !(rdev->wiphy.interface_modes & (1 << ntype)))
657 return -EOPNOTSUPP; 659 return -EOPNOTSUPP;
658 660
661 /* if it's part of a bridge, reject changing type to station/ibss */
662 if (dev->br_port && (ntype == NL80211_IFTYPE_ADHOC ||
663 ntype == NL80211_IFTYPE_STATION))
664 return -EBUSY;
665
659 if (ntype != otype) { 666 if (ntype != otype) {
667 dev->ieee80211_ptr->use_4addr = false;
668
660 switch (otype) { 669 switch (otype) {
661 case NL80211_IFTYPE_ADHOC: 670 case NL80211_IFTYPE_ADHOC:
662 cfg80211_leave_ibss(rdev, dev, false); 671 cfg80211_leave_ibss(rdev, dev, false);
@@ -680,5 +689,34 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
680 689
681 WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); 690 WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
682 691
692 if (!err && params && params->use_4addr != -1)
693 dev->ieee80211_ptr->use_4addr = params->use_4addr;
694
695 if (!err) {
696 dev->priv_flags &= ~IFF_DONT_BRIDGE;
697 switch (ntype) {
698 case NL80211_IFTYPE_STATION:
699 if (dev->ieee80211_ptr->use_4addr)
700 break;
701 /* fall through */
702 case NL80211_IFTYPE_ADHOC:
703 dev->priv_flags |= IFF_DONT_BRIDGE;
704 break;
705 case NL80211_IFTYPE_AP:
706 case NL80211_IFTYPE_AP_VLAN:
707 case NL80211_IFTYPE_WDS:
708 case NL80211_IFTYPE_MESH_POINT:
709 /* bridging OK */
710 break;
711 case NL80211_IFTYPE_MONITOR:
712 /* monitor can't bridge anyway */
713 break;
714 case NL80211_IFTYPE_UNSPECIFIED:
715 case __NL80211_IFTYPE_AFTER_LAST:
716 /* not happening */
717 break;
718 }
719 }
720
683 return err; 721 return err;
684} 722}
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 561a45cf2a6a..584eb4826e02 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -437,6 +437,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
437{ 437{
438 struct wireless_dev *wdev = dev->ieee80211_ptr; 438 struct wireless_dev *wdev = dev->ieee80211_ptr;
439 int err, i; 439 int err, i;
440 bool rejoin = false;
440 441
441 if (!wdev->wext.keys) { 442 if (!wdev->wext.keys) {
442 wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), 443 wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
@@ -466,8 +467,24 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
466 467
467 if (remove) { 468 if (remove) {
468 err = 0; 469 err = 0;
469 if (wdev->current_bss) 470 if (wdev->current_bss) {
471 /*
472 * If removing the current TX key, we will need to
473 * join a new IBSS without the privacy bit clear.
474 */
475 if (idx == wdev->wext.default_key &&
476 wdev->iftype == NL80211_IFTYPE_ADHOC) {
477 __cfg80211_leave_ibss(rdev, wdev->netdev, true);
478 rejoin = true;
479 }
470 err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); 480 err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
481 }
482 /*
483 * Applications using wireless extensions expect to be
484 * able to delete keys that don't exist, so allow that.
485 */
486 if (err == -ENOENT)
487 err = 0;
471 if (!err) { 488 if (!err) {
472 if (!addr) { 489 if (!addr) {
473 wdev->wext.keys->params[idx].key_len = 0; 490 wdev->wext.keys->params[idx].key_len = 0;
@@ -478,12 +495,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
478 else if (idx == wdev->wext.default_mgmt_key) 495 else if (idx == wdev->wext.default_mgmt_key)
479 wdev->wext.default_mgmt_key = -1; 496 wdev->wext.default_mgmt_key = -1;
480 } 497 }
481 /* 498
482 * Applications using wireless extensions expect to be 499 if (!err && rejoin)
483 * able to delete keys that don't exist, so allow that. 500 err = cfg80211_ibss_wext_join(rdev, wdev);
484 */
485 if (err == -ENOENT)
486 return 0;
487 501
488 return err; 502 return err;
489 } 503 }
@@ -511,11 +525,25 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
511 if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 || 525 if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
512 params->cipher == WLAN_CIPHER_SUITE_WEP104) && 526 params->cipher == WLAN_CIPHER_SUITE_WEP104) &&
513 (tx_key || (!addr && wdev->wext.default_key == -1))) { 527 (tx_key || (!addr && wdev->wext.default_key == -1))) {
514 if (wdev->current_bss) 528 if (wdev->current_bss) {
529 /*
530 * If we are getting a new TX key from not having
531 * had one before we need to join a new IBSS with
532 * the privacy bit set.
533 */
534 if (wdev->iftype == NL80211_IFTYPE_ADHOC &&
535 wdev->wext.default_key == -1) {
536 __cfg80211_leave_ibss(rdev, wdev->netdev, true);
537 rejoin = true;
538 }
515 err = rdev->ops->set_default_key(&rdev->wiphy, 539 err = rdev->ops->set_default_key(&rdev->wiphy,
516 dev, idx); 540 dev, idx);
517 if (!err) 541 }
542 if (!err) {
518 wdev->wext.default_key = idx; 543 wdev->wext.default_key = idx;
544 if (rejoin)
545 err = cfg80211_ibss_wext_join(rdev, wdev);
546 }
519 return err; 547 return err;
520 } 548 }
521 549
@@ -539,10 +567,13 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
539{ 567{
540 int err; 568 int err;
541 569
570 /* devlist mutex needed for possible IBSS re-join */
571 mutex_lock(&rdev->devlist_mtx);
542 wdev_lock(dev->ieee80211_ptr); 572 wdev_lock(dev->ieee80211_ptr);
543 err = __cfg80211_set_encryption(rdev, dev, addr, remove, 573 err = __cfg80211_set_encryption(rdev, dev, addr, remove,
544 tx_key, idx, params); 574 tx_key, idx, params);
545 wdev_unlock(dev->ieee80211_ptr); 575 wdev_unlock(dev->ieee80211_ptr);
576 mutex_unlock(&rdev->devlist_mtx);
546 577
547 return err; 578 return err;
548} 579}
@@ -904,8 +935,6 @@ static int cfg80211_set_auth_alg(struct wireless_dev *wdev,
904 935
905static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions) 936static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions)
906{ 937{
907 wdev->wext.connect.crypto.wpa_versions = 0;
908
909 if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA | 938 if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA |
910 IW_AUTH_WPA_VERSION_WPA2| 939 IW_AUTH_WPA_VERSION_WPA2|
911 IW_AUTH_WPA_VERSION_DISABLED)) 940 IW_AUTH_WPA_VERSION_DISABLED))
@@ -933,8 +962,6 @@ static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions)
933 962
934static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher) 963static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher)
935{ 964{
936 wdev->wext.connect.crypto.cipher_group = 0;
937
938 if (cipher & IW_AUTH_CIPHER_WEP40) 965 if (cipher & IW_AUTH_CIPHER_WEP40)
939 wdev->wext.connect.crypto.cipher_group = 966 wdev->wext.connect.crypto.cipher_group =
940 WLAN_CIPHER_SUITE_WEP40; 967 WLAN_CIPHER_SUITE_WEP40;
@@ -950,6 +977,8 @@ static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher)
950 else if (cipher & IW_AUTH_CIPHER_AES_CMAC) 977 else if (cipher & IW_AUTH_CIPHER_AES_CMAC)
951 wdev->wext.connect.crypto.cipher_group = 978 wdev->wext.connect.crypto.cipher_group =
952 WLAN_CIPHER_SUITE_AES_CMAC; 979 WLAN_CIPHER_SUITE_AES_CMAC;
980 else if (cipher & IW_AUTH_CIPHER_NONE)
981 wdev->wext.connect.crypto.cipher_group = 0;
953 else 982 else
954 return -EINVAL; 983 return -EINVAL;
955 984
@@ -1372,6 +1401,47 @@ int cfg80211_wext_giwessid(struct net_device *dev,
1372} 1401}
1373EXPORT_SYMBOL_GPL(cfg80211_wext_giwessid); 1402EXPORT_SYMBOL_GPL(cfg80211_wext_giwessid);
1374 1403
1404int cfg80211_wext_siwpmksa(struct net_device *dev,
1405 struct iw_request_info *info,
1406 struct iw_point *data, char *extra)
1407{
1408 struct wireless_dev *wdev = dev->ieee80211_ptr;
1409 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
1410 struct cfg80211_pmksa cfg_pmksa;
1411 struct iw_pmksa *pmksa = (struct iw_pmksa *)extra;
1412
1413 memset(&cfg_pmksa, 0, sizeof(struct cfg80211_pmksa));
1414
1415 if (wdev->iftype != NL80211_IFTYPE_STATION)
1416 return -EINVAL;
1417
1418 cfg_pmksa.bssid = pmksa->bssid.sa_data;
1419 cfg_pmksa.pmkid = pmksa->pmkid;
1420
1421 switch (pmksa->cmd) {
1422 case IW_PMKSA_ADD:
1423 if (!rdev->ops->set_pmksa)
1424 return -EOPNOTSUPP;
1425
1426 return rdev->ops->set_pmksa(&rdev->wiphy, dev, &cfg_pmksa);
1427
1428 case IW_PMKSA_REMOVE:
1429 if (!rdev->ops->del_pmksa)
1430 return -EOPNOTSUPP;
1431
1432 return rdev->ops->del_pmksa(&rdev->wiphy, dev, &cfg_pmksa);
1433
1434 case IW_PMKSA_FLUSH:
1435 if (!rdev->ops->flush_pmksa)
1436 return -EOPNOTSUPP;
1437
1438 return rdev->ops->flush_pmksa(&rdev->wiphy, dev);
1439
1440 default:
1441 return -EOPNOTSUPP;
1442 }
1443}
1444
1375static const iw_handler cfg80211_handlers[] = { 1445static const iw_handler cfg80211_handlers[] = {
1376 [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname, 1446 [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname,
1377 [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq, 1447 [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq,
@@ -1404,6 +1474,7 @@ static const iw_handler cfg80211_handlers[] = {
1404 [IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth, 1474 [IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth,
1405 [IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth, 1475 [IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth,
1406 [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext, 1476 [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext,
1477 [IW_IOCTL_IDX(SIOCSIWPMKSA)] = (iw_handler) cfg80211_wext_siwpmksa,
1407}; 1478};
1408 1479
1409const struct iw_handler_def cfg80211_wext_handler = { 1480const struct iw_handler_def cfg80211_wext_handler = {
diff --git a/net/wireless/wext.c b/net/wireless/wext-core.c
index 60fe57761ca9..5e1656bdf23b 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext-core.c
@@ -1,112 +1,28 @@
1/* 1/*
2 * This file implement the Wireless Extensions APIs. 2 * This file implement the Wireless Extensions core API.
3 * 3 *
4 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> 4 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
5 * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. 5 * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
6 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
6 * 7 *
7 * (As all part of the Linux kernel, this file is GPL) 8 * (As all part of the Linux kernel, this file is GPL)
8 */ 9 */
9 10#include <linux/kernel.h>
10/************************** DOCUMENTATION **************************/ 11#include <linux/netdevice.h>
11/* 12#include <linux/rtnetlink.h>
12 * API definition : 13#include <linux/wireless.h>
13 * -------------- 14#include <linux/uaccess.h>
14 * See <linux/wireless.h> for details of the APIs and the rest. 15#include <net/cfg80211.h>
15 * 16#include <net/iw_handler.h>
16 * History :
17 * -------
18 *
19 * v1 - 5.12.01 - Jean II
20 * o Created this file.
21 *
22 * v2 - 13.12.01 - Jean II
23 * o Move /proc/net/wireless stuff from net/core/dev.c to here
24 * o Make Wireless Extension IOCTLs go through here
25 * o Added iw_handler handling ;-)
26 * o Added standard ioctl description
27 * o Initial dumb commit strategy based on orinoco.c
28 *
29 * v3 - 19.12.01 - Jean II
30 * o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call
31 * o Add event dispatcher function
32 * o Add event description
33 * o Propagate events as rtnetlink IFLA_WIRELESS option
34 * o Generate event on selected SET requests
35 *
36 * v4 - 18.04.02 - Jean II
37 * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
38 *
39 * v5 - 21.06.02 - Jean II
40 * o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
41 * o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
42 * o Add IWEVCUSTOM for driver specific event/scanning token
43 * o Turn on WE_STRICT_WRITE by default + kernel warning
44 * o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
45 * o Fix off-by-one in test (extra_size <= IFNAMSIZ)
46 *
47 * v6 - 9.01.03 - Jean II
48 * o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
49 * o Add enhanced spy support : iw_handler_set_thrspy() and event.
50 * o Add WIRELESS_EXT version display in /proc/net/wireless
51 *
52 * v6 - 18.06.04 - Jean II
53 * o Change get_spydata() method for added safety
54 * o Remove spy #ifdef, they are always on -> cleaner code
55 * o Allow any size GET request if user specifies length > max
56 * and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV
57 * o Start migrating get_wireless_stats to struct iw_handler_def
58 * o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus
59 * Based on patch from Pavel Roskin <proski@gnu.org> :
60 * o Fix kernel data leak to user space in private handler handling
61 *
62 * v7 - 18.3.05 - Jean II
63 * o Remove (struct iw_point *)->pointer from events and streams
64 * o Remove spy_offset from struct iw_handler_def
65 * o Start deprecating dev->get_wireless_stats, output a warning
66 * o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless
67 * o Don't lose INVALID/DBM flags when clearing UPDATED flags (iwstats)
68 *
69 * v8 - 17.02.06 - Jean II
70 * o RtNetlink requests support (SET/GET)
71 *
72 * v8b - 03.08.06 - Herbert Xu
73 * o Fix Wireless Event locking issues.
74 *
75 * v9 - 14.3.06 - Jean II
76 * o Change length in ESSID and NICK to strlen() instead of strlen()+1
77 * o Make standard_ioctl_num and standard_event_num unsigned
78 * o Remove (struct net_device *)->get_wireless_stats()
79 *
80 * v10 - 16.3.07 - Jean II
81 * o Prevent leaking of kernel space in stream on 64 bits.
82 */
83
84/***************************** INCLUDES *****************************/
85
86#include <linux/module.h>
87#include <linux/types.h> /* off_t */
88#include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */
89#include <linux/proc_fs.h>
90#include <linux/rtnetlink.h> /* rtnetlink stuff */
91#include <linux/seq_file.h>
92#include <linux/init.h> /* for __init */
93#include <linux/if_arp.h> /* ARPHRD_ETHER */
94#include <linux/etherdevice.h> /* compare_ether_addr */
95#include <linux/interrupt.h>
96#include <net/net_namespace.h>
97
98#include <linux/wireless.h> /* Pretty obvious */
99#include <net/iw_handler.h> /* New driver API */
100#include <net/netlink.h> 17#include <net/netlink.h>
101#include <net/wext.h> 18#include <net/wext.h>
19#include <net/net_namespace.h>
20
21typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
22 unsigned int, struct iw_request_info *,
23 iw_handler);
102 24
103#include <asm/uaccess.h> /* copy_to_user() */
104 25
105/************************* GLOBAL VARIABLES *************************/
106/*
107 * You should not use global variables, because of re-entrancy.
108 * On our case, it's only const, so it's OK...
109 */
110/* 26/*
111 * Meta-data about all the standard Wireless Extension request we 27 * Meta-data about all the standard Wireless Extension request we
112 * know about. 28 * know about.
@@ -390,18 +306,6 @@ static const struct iw_ioctl_description standard_event[] = {
390}; 306};
391static const unsigned standard_event_num = ARRAY_SIZE(standard_event); 307static const unsigned standard_event_num = ARRAY_SIZE(standard_event);
392 308
393/* Size (in bytes) of the various private data types */
394static const char iw_priv_type_size[] = {
395 0, /* IW_PRIV_TYPE_NONE */
396 1, /* IW_PRIV_TYPE_BYTE */
397 1, /* IW_PRIV_TYPE_CHAR */
398 0, /* Not defined */
399 sizeof(__u32), /* IW_PRIV_TYPE_INT */
400 sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
401 sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
402 0, /* Not defined */
403};
404
405/* Size (in bytes) of various events */ 309/* Size (in bytes) of various events */
406static const int event_type_size[] = { 310static const int event_type_size[] = {
407 IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ 311 IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */
@@ -433,323 +337,346 @@ static const int compat_event_type_size[] = {
433}; 337};
434#endif 338#endif
435 339
436/************************ COMMON SUBROUTINES ************************/
437/*
438 * Stuff that may be used in various place or doesn't fit in one
439 * of the section below.
440 */
441
442/* ---------------------------------------------------------------- */
443/*
444 * Return the driver handler associated with a specific Wireless Extension.
445 */
446static iw_handler get_handler(struct net_device *dev, unsigned int cmd)
447{
448 /* Don't "optimise" the following variable, it will crash */
449 unsigned int index; /* *MUST* be unsigned */
450 340
451 /* Check if we have some wireless handlers defined */ 341/* IW event code */
452 if (dev->wireless_handlers == NULL)
453 return NULL;
454
455 /* Try as a standard command */
456 index = cmd - SIOCIWFIRST;
457 if (index < dev->wireless_handlers->num_standard)
458 return dev->wireless_handlers->standard[index];
459
460 /* Try as a private command */
461 index = cmd - SIOCIWFIRSTPRIV;
462 if (index < dev->wireless_handlers->num_private)
463 return dev->wireless_handlers->private[index];
464 342
465 /* Not found */ 343static int __net_init wext_pernet_init(struct net *net)
466 return NULL;
467}
468
469/* ---------------------------------------------------------------- */
470/*
471 * Get statistics out of the driver
472 */
473struct iw_statistics *get_wireless_stats(struct net_device *dev)
474{ 344{
475 /* New location */ 345 skb_queue_head_init(&net->wext_nlevents);
476 if ((dev->wireless_handlers != NULL) && 346 return 0;
477 (dev->wireless_handlers->get_wireless_stats != NULL))
478 return dev->wireless_handlers->get_wireless_stats(dev);
479
480 /* Not found */
481 return NULL;
482} 347}
483 348
484/* ---------------------------------------------------------------- */ 349static void __net_exit wext_pernet_exit(struct net *net)
485/*
486 * Call the commit handler in the driver
487 * (if exist and if conditions are right)
488 *
489 * Note : our current commit strategy is currently pretty dumb,
490 * but we will be able to improve on that...
491 * The goal is to try to agreagate as many changes as possible
492 * before doing the commit. Drivers that will define a commit handler
493 * are usually those that need a reset after changing parameters, so
494 * we want to minimise the number of reset.
495 * A cool idea is to use a timer : at each "set" command, we re-set the
496 * timer, when the timer eventually fires, we call the driver.
497 * Hopefully, more on that later.
498 *
499 * Also, I'm waiting to see how many people will complain about the
500 * netif_running(dev) test. I'm open on that one...
501 * Hopefully, the driver will remember to do a commit in "open()" ;-)
502 */
503static int call_commit_handler(struct net_device *dev)
504{ 350{
505 if ((netif_running(dev)) && 351 skb_queue_purge(&net->wext_nlevents);
506 (dev->wireless_handlers->standard[0] != NULL))
507 /* Call the commit handler on the driver */
508 return dev->wireless_handlers->standard[0](dev, NULL,
509 NULL, NULL);
510 else
511 return 0; /* Command completed successfully */
512} 352}
513 353
514/* ---------------------------------------------------------------- */ 354static struct pernet_operations wext_pernet_ops = {
515/* 355 .init = wext_pernet_init,
516 * Calculate size of private arguments 356 .exit = wext_pernet_exit,
517 */ 357};
518static int get_priv_size(__u16 args)
519{
520 int num = args & IW_PRIV_SIZE_MASK;
521 int type = (args & IW_PRIV_TYPE_MASK) >> 12;
522 358
523 return num * iw_priv_type_size[type]; 359static int __init wireless_nlevent_init(void)
360{
361 return register_pernet_subsys(&wext_pernet_ops);
524} 362}
525 363
526/* ---------------------------------------------------------------- */ 364subsys_initcall(wireless_nlevent_init);
527/* 365
528 * Re-calculate the size of private arguments 366/* Process events generated by the wireless layer or the driver. */
529 */ 367static void wireless_nlevent_process(struct work_struct *work)
530static int adjust_priv_size(__u16 args, struct iw_point *iwp)
531{ 368{
532 int num = iwp->length; 369 struct sk_buff *skb;
533 int max = args & IW_PRIV_SIZE_MASK; 370 struct net *net;
534 int type = (args & IW_PRIV_TYPE_MASK) >> 12;
535 371
536 /* Make sure the driver doesn't goof up */ 372 rtnl_lock();
537 if (max < num) 373
538 num = max; 374 for_each_net(net) {
375 while ((skb = skb_dequeue(&net->wext_nlevents)))
376 rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
377 GFP_KERNEL);
378 }
539 379
540 return num * iw_priv_type_size[type]; 380 rtnl_unlock();
541} 381}
542 382
543/* ---------------------------------------------------------------- */ 383static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process);
544/* 384
545 * Standard Wireless Handler : get wireless stats 385static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev,
546 * Allow programatic access to /proc/net/wireless even if /proc 386 struct sk_buff *skb)
547 * doesn't exist... Also more efficient...
548 */
549static int iw_handler_get_iwstats(struct net_device * dev,
550 struct iw_request_info * info,
551 union iwreq_data * wrqu,
552 char * extra)
553{ 387{
554 /* Get stats from the driver */ 388 struct ifinfomsg *r;
555 struct iw_statistics *stats; 389 struct nlmsghdr *nlh;
556 390
557 stats = get_wireless_stats(dev); 391 nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0);
558 if (stats) { 392 if (!nlh)
559 /* Copy statistics to extra */ 393 return NULL;
560 memcpy(extra, stats, sizeof(struct iw_statistics));
561 wrqu->data.length = sizeof(struct iw_statistics);
562 394
563 /* Check if we need to clear the updated flag */ 395 r = nlmsg_data(nlh);
564 if (wrqu->data.flags != 0) 396 r->ifi_family = AF_UNSPEC;
565 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; 397 r->__ifi_pad = 0;
566 return 0; 398 r->ifi_type = dev->type;
567 } else 399 r->ifi_index = dev->ifindex;
568 return -EOPNOTSUPP; 400 r->ifi_flags = dev_get_flags(dev);
401 r->ifi_change = 0; /* Wireless changes don't affect those flags */
402
403 NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
404
405 return nlh;
406 nla_put_failure:
407 nlmsg_cancel(skb, nlh);
408 return NULL;
569} 409}
570 410
571/* ---------------------------------------------------------------- */ 411
572/* 412/*
573 * Standard Wireless Handler : get iwpriv definitions 413 * Main event dispatcher. Called from other parts and drivers.
574 * Export the driver private handler definition 414 * Send the event on the appropriate channels.
575 * They will be picked up by tools like iwpriv... 415 * May be called from interrupt context.
576 */ 416 */
577static int iw_handler_get_private(struct net_device * dev, 417void wireless_send_event(struct net_device * dev,
578 struct iw_request_info * info, 418 unsigned int cmd,
579 union iwreq_data * wrqu, 419 union iwreq_data * wrqu,
580 char * extra) 420 const char * extra)
581{ 421{
582 /* Check if the driver has something to export */ 422 const struct iw_ioctl_description * descr = NULL;
583 if ((dev->wireless_handlers->num_private_args == 0) || 423 int extra_len = 0;
584 (dev->wireless_handlers->private_args == NULL)) 424 struct iw_event *event; /* Mallocated whole event */
585 return -EOPNOTSUPP; 425 int event_len; /* Its size */
426 int hdr_len; /* Size of the event header */
427 int wrqu_off = 0; /* Offset in wrqu */
428 /* Don't "optimise" the following variable, it will crash */
429 unsigned cmd_index; /* *MUST* be unsigned */
430 struct sk_buff *skb;
431 struct nlmsghdr *nlh;
432 struct nlattr *nla;
433#ifdef CONFIG_COMPAT
434 struct __compat_iw_event *compat_event;
435 struct compat_iw_point compat_wrqu;
436 struct sk_buff *compskb;
437#endif
586 438
587 /* Check if there is enough buffer up there */ 439 /*
588 if (wrqu->data.length < dev->wireless_handlers->num_private_args) { 440 * Nothing in the kernel sends scan events with data, be safe.
589 /* User space can't know in advance how large the buffer 441 * This is necessary because we cannot fix up scan event data
590 * needs to be. Give it a hint, so that we can support 442 * for compat, due to being contained in 'extra', but normally
591 * any size buffer we want somewhat efficiently... */ 443 * applications are required to retrieve the scan data anyway
592 wrqu->data.length = dev->wireless_handlers->num_private_args; 444 * and no data is included in the event, this codifies that
593 return -E2BIG; 445 * practice.
446 */
447 if (WARN_ON(cmd == SIOCGIWSCAN && extra))
448 extra = NULL;
449
450 /* Get the description of the Event */
451 if (cmd <= SIOCIWLAST) {
452 cmd_index = cmd - SIOCIWFIRST;
453 if (cmd_index < standard_ioctl_num)
454 descr = &(standard_ioctl[cmd_index]);
455 } else {
456 cmd_index = cmd - IWEVFIRST;
457 if (cmd_index < standard_event_num)
458 descr = &(standard_event[cmd_index]);
459 }
460 /* Don't accept unknown events */
461 if (descr == NULL) {
462 /* Note : we don't return an error to the driver, because
463 * the driver would not know what to do about it. It can't
464 * return an error to the user, because the event is not
465 * initiated by a user request.
466 * The best the driver could do is to log an error message.
467 * We will do it ourselves instead...
468 */
469 printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
470 dev->name, cmd);
471 return;
594 } 472 }
595 473
596 /* Set the number of available ioctls. */ 474 /* Check extra parameters and set extra_len */
597 wrqu->data.length = dev->wireless_handlers->num_private_args; 475 if (descr->header_type == IW_HEADER_TYPE_POINT) {
476 /* Check if number of token fits within bounds */
477 if (wrqu->data.length > descr->max_tokens) {
478 printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
479 return;
480 }
481 if (wrqu->data.length < descr->min_tokens) {
482 printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
483 return;
484 }
485 /* Calculate extra_len - extra is NULL for restricted events */
486 if (extra != NULL)
487 extra_len = wrqu->data.length * descr->token_size;
488 /* Always at an offset in wrqu */
489 wrqu_off = IW_EV_POINT_OFF;
490 }
598 491
599 /* Copy structure to the user buffer. */ 492 /* Total length of the event */
600 memcpy(extra, dev->wireless_handlers->private_args, 493 hdr_len = event_type_size[descr->header_type];
601 sizeof(struct iw_priv_args) * wrqu->data.length); 494 event_len = hdr_len + extra_len;
602 495
603 return 0; 496 /*
604} 497 * The problem for 64/32 bit.
498 *
499 * On 64-bit, a regular event is laid out as follows:
500 * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
501 * | event.len | event.cmd | p a d d i n g |
502 * | wrqu data ... (with the correct size) |
503 *
504 * This padding exists because we manipulate event->u,
505 * and 'event' is not packed.
506 *
507 * An iw_point event is laid out like this instead:
508 * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
509 * | event.len | event.cmd | p a d d i n g |
510 * | iwpnt.len | iwpnt.flg | p a d d i n g |
511 * | extra data ...
512 *
513 * The second padding exists because struct iw_point is extended,
514 * but this depends on the platform...
515 *
516 * On 32-bit, all the padding shouldn't be there.
517 */
605 518
519 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
520 if (!skb)
521 return;
606 522
607/******************** /proc/net/wireless SUPPORT ********************/ 523 /* Send via the RtNetlink event channel */
608/* 524 nlh = rtnetlink_ifinfo_prep(dev, skb);
609 * The /proc/net/wireless file is a human readable user-space interface 525 if (WARN_ON(!nlh)) {
610 * exporting various wireless specific statistics from the wireless devices. 526 kfree_skb(skb);
611 * This is the most popular part of the Wireless Extensions ;-) 527 return;
612 * 528 }
613 * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
614 * The content of the file is basically the content of "struct iw_statistics".
615 */
616 529
617#ifdef CONFIG_PROC_FS 530 /* Add the wireless events in the netlink packet */
531 nla = nla_reserve(skb, IFLA_WIRELESS, event_len);
532 if (!nla) {
533 kfree_skb(skb);
534 return;
535 }
536 event = nla_data(nla);
618 537
619/* ---------------------------------------------------------------- */ 538 /* Fill event - first clear to avoid data leaking */
620/* 539 memset(event, 0, hdr_len);
621 * Print one entry (line) of /proc/net/wireless 540 event->len = event_len;
622 */ 541 event->cmd = cmd;
623static void wireless_seq_printf_stats(struct seq_file *seq, 542 memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
624 struct net_device *dev) 543 if (extra_len)
625{ 544 memcpy(((char *) event) + hdr_len, extra, extra_len);
626 /* Get stats from the driver */
627 struct iw_statistics *stats = get_wireless_stats(dev);
628 static struct iw_statistics nullstats = {};
629 545
630 /* show device if it's wireless regardless of current stats */ 546 nlmsg_end(skb, nlh);
631 if (!stats && dev->wireless_handlers) 547#ifdef CONFIG_COMPAT
632 stats = &nullstats; 548 hdr_len = compat_event_type_size[descr->header_type];
549 event_len = hdr_len + extra_len;
633 550
634 if (stats) { 551 compskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
635 seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " 552 if (!compskb) {
636 "%6d %6d %6d\n", 553 kfree_skb(skb);
637 dev->name, stats->status, stats->qual.qual, 554 return;
638 stats->qual.updated & IW_QUAL_QUAL_UPDATED
639 ? '.' : ' ',
640 ((__s32) stats->qual.level) -
641 ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
642 stats->qual.updated & IW_QUAL_LEVEL_UPDATED
643 ? '.' : ' ',
644 ((__s32) stats->qual.noise) -
645 ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
646 stats->qual.updated & IW_QUAL_NOISE_UPDATED
647 ? '.' : ' ',
648 stats->discard.nwid, stats->discard.code,
649 stats->discard.fragment, stats->discard.retries,
650 stats->discard.misc, stats->miss.beacon);
651
652 if (stats != &nullstats)
653 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
654 } 555 }
655}
656 556
657/* ---------------------------------------------------------------- */ 557 /* Send via the RtNetlink event channel */
658/* 558 nlh = rtnetlink_ifinfo_prep(dev, compskb);
659 * Print info for /proc/net/wireless (print all entries) 559 if (WARN_ON(!nlh)) {
660 */ 560 kfree_skb(skb);
661static int wireless_dev_seq_show(struct seq_file *seq, void *v) 561 kfree_skb(compskb);
662{ 562 return;
663 might_sleep(); 563 }
664 564
665 if (v == SEQ_START_TOKEN) 565 /* Add the wireless events in the netlink packet */
666 seq_printf(seq, "Inter-| sta-| Quality | Discarded " 566 nla = nla_reserve(compskb, IFLA_WIRELESS, event_len);
667 "packets | Missed | WE\n" 567 if (!nla) {
668 " face | tus | link level noise | nwid " 568 kfree_skb(skb);
669 "crypt frag retry misc | beacon | %d\n", 569 kfree_skb(compskb);
670 WIRELESS_EXT); 570 return;
671 else 571 }
672 wireless_seq_printf_stats(seq, v); 572 compat_event = nla_data(nla);
673 return 0; 573
574 compat_event->len = event_len;
575 compat_event->cmd = cmd;
576 if (descr->header_type == IW_HEADER_TYPE_POINT) {
577 compat_wrqu.length = wrqu->data.length;
578 compat_wrqu.flags = wrqu->data.flags;
579 memcpy(&compat_event->pointer,
580 ((char *) &compat_wrqu) + IW_EV_COMPAT_POINT_OFF,
581 hdr_len - IW_EV_COMPAT_LCP_LEN);
582 if (extra_len)
583 memcpy(((char *) compat_event) + hdr_len,
584 extra, extra_len);
585 } else {
586 /* extra_len must be zero, so no if (extra) needed */
587 memcpy(&compat_event->pointer, wrqu,
588 hdr_len - IW_EV_COMPAT_LCP_LEN);
589 }
590
591 nlmsg_end(compskb, nlh);
592
593 skb_shinfo(skb)->frag_list = compskb;
594#endif
595 skb_queue_tail(&dev_net(dev)->wext_nlevents, skb);
596 schedule_work(&wireless_nlevent_work);
674} 597}
598EXPORT_SYMBOL(wireless_send_event);
599
600
601
602/* IW handlers */
675 603
676static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos) 604struct iw_statistics *get_wireless_stats(struct net_device *dev)
677{ 605{
678 struct net *net = seq_file_net(seq); 606#ifdef CONFIG_WIRELESS_EXT
679 loff_t off; 607 if ((dev->wireless_handlers != NULL) &&
680 struct net_device *dev; 608 (dev->wireless_handlers->get_wireless_stats != NULL))
609 return dev->wireless_handlers->get_wireless_stats(dev);
610#endif
681 611
682 rtnl_lock(); 612#ifdef CONFIG_CFG80211_WEXT
683 if (!*pos) 613 if (dev->ieee80211_ptr && dev->ieee80211_ptr &&
684 return SEQ_START_TOKEN; 614 dev->ieee80211_ptr->wiphy &&
615 dev->ieee80211_ptr->wiphy->wext &&
616 dev->ieee80211_ptr->wiphy->wext->get_wireless_stats)
617 return dev->ieee80211_ptr->wiphy->wext->get_wireless_stats(dev);
618#endif
685 619
686 off = 1; 620 /* not found */
687 for_each_netdev(net, dev)
688 if (off++ == *pos)
689 return dev;
690 return NULL; 621 return NULL;
691} 622}
692 623
693static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) 624static int iw_handler_get_iwstats(struct net_device * dev,
625 struct iw_request_info * info,
626 union iwreq_data * wrqu,
627 char * extra)
694{ 628{
695 struct net *net = seq_file_net(seq); 629 /* Get stats from the driver */
630 struct iw_statistics *stats;
696 631
697 ++*pos; 632 stats = get_wireless_stats(dev);
633 if (stats) {
634 /* Copy statistics to extra */
635 memcpy(extra, stats, sizeof(struct iw_statistics));
636 wrqu->data.length = sizeof(struct iw_statistics);
698 637
699 return v == SEQ_START_TOKEN ? 638 /* Check if we need to clear the updated flag */
700 first_net_device(net) : next_net_device(v); 639 if (wrqu->data.flags != 0)
640 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
641 return 0;
642 } else
643 return -EOPNOTSUPP;
701} 644}
702 645
703static void wireless_dev_seq_stop(struct seq_file *seq, void *v) 646static iw_handler get_handler(struct net_device *dev, unsigned int cmd)
704{ 647{
705 rtnl_unlock(); 648 /* Don't "optimise" the following variable, it will crash */
706} 649 unsigned int index; /* *MUST* be unsigned */
707 650 const struct iw_handler_def *handlers = NULL;
708static const struct seq_operations wireless_seq_ops = {
709 .start = wireless_dev_seq_start,
710 .next = wireless_dev_seq_next,
711 .stop = wireless_dev_seq_stop,
712 .show = wireless_dev_seq_show,
713};
714 651
715static int seq_open_wireless(struct inode *inode, struct file *file) 652#ifdef CONFIG_CFG80211_WEXT
716{ 653 if (dev->ieee80211_ptr && dev->ieee80211_ptr->wiphy)
717 return seq_open_net(inode, file, &wireless_seq_ops, 654 handlers = dev->ieee80211_ptr->wiphy->wext;
718 sizeof(struct seq_net_private)); 655#endif
719} 656#ifdef CONFIG_WIRELESS_EXT
657 if (dev->wireless_handlers)
658 handlers = dev->wireless_handlers;
659#endif
720 660
721static const struct file_operations wireless_seq_fops = { 661 if (!handlers)
722 .owner = THIS_MODULE, 662 return NULL;
723 .open = seq_open_wireless,
724 .read = seq_read,
725 .llseek = seq_lseek,
726 .release = seq_release_net,
727};
728 663
729int wext_proc_init(struct net *net) 664 /* Try as a standard command */
730{ 665 index = cmd - SIOCIWFIRST;
731 /* Create /proc/net/wireless entry */ 666 if (index < handlers->num_standard)
732 if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops)) 667 return handlers->standard[index];
733 return -ENOMEM;
734 668
735 return 0; 669#ifdef CONFIG_WEXT_PRIV
736} 670 /* Try as a private command */
671 index = cmd - SIOCIWFIRSTPRIV;
672 if (index < handlers->num_private)
673 return handlers->private[index];
674#endif
737 675
738void wext_proc_exit(struct net *net) 676 /* Not found */
739{ 677 return NULL;
740 proc_net_remove(net, "wireless");
741} 678}
742#endif /* CONFIG_PROC_FS */
743 679
744/************************** IOCTL SUPPORT **************************/
745/*
746 * The original user space API to configure all those Wireless Extensions
747 * is through IOCTLs.
748 * In there, we check if we need to call the new driver API (iw_handler)
749 * or just call the driver ioctl handler.
750 */
751
752/* ---------------------------------------------------------------- */
753static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, 680static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd,
754 const struct iw_ioctl_description *descr, 681 const struct iw_ioctl_description *descr,
755 iw_handler handler, struct net_device *dev, 682 iw_handler handler, struct net_device *dev,
@@ -875,7 +802,8 @@ static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd,
875 } 802 }
876 803
877 /* Generate an event to notify listeners of the change */ 804 /* Generate an event to notify listeners of the change */
878 if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) { 805 if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
806 ((err == 0) || (err == -EIWCOMMIT))) {
879 union iwreq_data *data = (union iwreq_data *) iwp; 807 union iwreq_data *data = (union iwreq_data *) iwp;
880 808
881 if (descr->flags & IW_DESCR_FLAG_RESTRICT) 809 if (descr->flags & IW_DESCR_FLAG_RESTRICT)
@@ -893,188 +821,39 @@ out:
893} 821}
894 822
895/* 823/*
896 * Wrapper to call a standard Wireless Extension handler. 824 * Call the commit handler in the driver
897 * We do various checks and also take care of moving data between 825 * (if exist and if conditions are right)
898 * user space and kernel space. 826 *
899 */ 827 * Note : our current commit strategy is currently pretty dumb,
900static int ioctl_standard_call(struct net_device * dev, 828 * but we will be able to improve on that...
901 struct iwreq *iwr, 829 * The goal is to try to agreagate as many changes as possible
902 unsigned int cmd, 830 * before doing the commit. Drivers that will define a commit handler
903 struct iw_request_info *info, 831 * are usually those that need a reset after changing parameters, so
904 iw_handler handler) 832 * we want to minimise the number of reset.
905{ 833 * A cool idea is to use a timer : at each "set" command, we re-set the
906 const struct iw_ioctl_description * descr; 834 * timer, when the timer eventually fires, we call the driver.
907 int ret = -EINVAL; 835 * Hopefully, more on that later.
908
909 /* Get the description of the IOCTL */
910 if ((cmd - SIOCIWFIRST) >= standard_ioctl_num)
911 return -EOPNOTSUPP;
912 descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
913
914 /* Check if we have a pointer to user space data or not */
915 if (descr->header_type != IW_HEADER_TYPE_POINT) {
916
917 /* No extra arguments. Trivial to handle */
918 ret = handler(dev, info, &(iwr->u), NULL);
919
920 /* Generate an event to notify listeners of the change */
921 if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
922 ((ret == 0) || (ret == -EIWCOMMIT)))
923 wireless_send_event(dev, cmd, &(iwr->u), NULL);
924 } else {
925 ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr,
926 handler, dev, info);
927 }
928
929 /* Call commit handler if needed and defined */
930 if (ret == -EIWCOMMIT)
931 ret = call_commit_handler(dev);
932
933 /* Here, we will generate the appropriate event if needed */
934
935 return ret;
936}
937
938/* ---------------------------------------------------------------- */
939/*
940 * Wrapper to call a private Wireless Extension handler.
941 * We do various checks and also take care of moving data between
942 * user space and kernel space.
943 * It's not as nice and slimline as the standard wrapper. The cause
944 * is struct iw_priv_args, which was not really designed for the
945 * job we are going here.
946 * 836 *
947 * IMPORTANT : This function prevent to set and get data on the same 837 * Also, I'm waiting to see how many people will complain about the
948 * IOCTL and enforce the SET/GET convention. Not doing it would be 838 * netif_running(dev) test. I'm open on that one...
949 * far too hairy... 839 * Hopefully, the driver will remember to do a commit in "open()" ;-)
950 * If you need to set and get data at the same time, please don't use
951 * a iw_handler but process it in your ioctl handler (i.e. use the
952 * old driver API).
953 */ 840 */
954static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd, 841int call_commit_handler(struct net_device *dev)
955 const struct iw_priv_args **descrp)
956{
957 const struct iw_priv_args *descr;
958 int i, extra_size;
959
960 descr = NULL;
961 for (i = 0; i < dev->wireless_handlers->num_private_args; i++) {
962 if (cmd == dev->wireless_handlers->private_args[i].cmd) {
963 descr = &dev->wireless_handlers->private_args[i];
964 break;
965 }
966 }
967
968 extra_size = 0;
969 if (descr) {
970 if (IW_IS_SET(cmd)) {
971 int offset = 0; /* For sub-ioctls */
972 /* Check for sub-ioctl handler */
973 if (descr->name[0] == '\0')
974 /* Reserve one int for sub-ioctl index */
975 offset = sizeof(__u32);
976
977 /* Size of set arguments */
978 extra_size = get_priv_size(descr->set_args);
979
980 /* Does it fits in iwr ? */
981 if ((descr->set_args & IW_PRIV_SIZE_FIXED) &&
982 ((extra_size + offset) <= IFNAMSIZ))
983 extra_size = 0;
984 } else {
985 /* Size of get arguments */
986 extra_size = get_priv_size(descr->get_args);
987
988 /* Does it fits in iwr ? */
989 if ((descr->get_args & IW_PRIV_SIZE_FIXED) &&
990 (extra_size <= IFNAMSIZ))
991 extra_size = 0;
992 }
993 }
994 *descrp = descr;
995 return extra_size;
996}
997
998static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd,
999 const struct iw_priv_args *descr,
1000 iw_handler handler, struct net_device *dev,
1001 struct iw_request_info *info, int extra_size)
1002{
1003 char *extra;
1004 int err;
1005
1006 /* Check what user space is giving us */
1007 if (IW_IS_SET(cmd)) {
1008 if (!iwp->pointer && iwp->length != 0)
1009 return -EFAULT;
1010
1011 if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK))
1012 return -E2BIG;
1013 } else if (!iwp->pointer)
1014 return -EFAULT;
1015
1016 extra = kmalloc(extra_size, GFP_KERNEL);
1017 if (!extra)
1018 return -ENOMEM;
1019
1020 /* If it is a SET, get all the extra data in here */
1021 if (IW_IS_SET(cmd) && (iwp->length != 0)) {
1022 if (copy_from_user(extra, iwp->pointer, extra_size)) {
1023 err = -EFAULT;
1024 goto out;
1025 }
1026 }
1027
1028 /* Call the handler */
1029 err = handler(dev, info, (union iwreq_data *) iwp, extra);
1030
1031 /* If we have something to return to the user */
1032 if (!err && IW_IS_GET(cmd)) {
1033 /* Adjust for the actual length if it's variable,
1034 * avoid leaking kernel bits outside.
1035 */
1036 if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
1037 extra_size = adjust_priv_size(descr->get_args, iwp);
1038
1039 if (copy_to_user(iwp->pointer, extra, extra_size))
1040 err = -EFAULT;
1041 }
1042
1043out:
1044 kfree(extra);
1045 return err;
1046}
1047
1048static int ioctl_private_call(struct net_device *dev, struct iwreq *iwr,
1049 unsigned int cmd, struct iw_request_info *info,
1050 iw_handler handler)
1051{ 842{
1052 int extra_size = 0, ret = -EINVAL; 843#ifdef CONFIG_WIRELESS_EXT
1053 const struct iw_priv_args *descr; 844 if ((netif_running(dev)) &&
1054 845 (dev->wireless_handlers->standard[0] != NULL))
1055 extra_size = get_priv_descr_and_size(dev, cmd, &descr); 846 /* Call the commit handler on the driver */
1056 847 return dev->wireless_handlers->standard[0](dev, NULL,
1057 /* Check if we have a pointer to user space data or not. */ 848 NULL, NULL);
1058 if (extra_size == 0) { 849 else
1059 /* No extra arguments. Trivial to handle */ 850 return 0; /* Command completed successfully */
1060 ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); 851#else
1061 } else { 852 /* cfg80211 has no commit */
1062 ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr, 853 return 0;
1063 handler, dev, info, extra_size); 854#endif
1064 }
1065
1066 /* Call commit handler if needed and defined */
1067 if (ret == -EIWCOMMIT)
1068 ret = call_commit_handler(dev);
1069
1070 return ret;
1071} 855}
1072 856
1073/* ---------------------------------------------------------------- */
1074typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
1075 unsigned int, struct iw_request_info *,
1076 iw_handler);
1077
1078/* 857/*
1079 * Main IOCTl dispatcher. 858 * Main IOCTl dispatcher.
1080 * Check the type of IOCTL and call the appropriate wrapper... 859 * Check the type of IOCTL and call the appropriate wrapper...
@@ -1103,9 +882,11 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
1103 return standard(dev, iwr, cmd, info, 882 return standard(dev, iwr, cmd, info,
1104 &iw_handler_get_iwstats); 883 &iw_handler_get_iwstats);
1105 884
885#ifdef CONFIG_WEXT_PRIV
1106 if (cmd == SIOCGIWPRIV && dev->wireless_handlers) 886 if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
1107 return standard(dev, iwr, cmd, info, 887 return standard(dev, iwr, cmd, info,
1108 &iw_handler_get_private); 888 iw_handler_get_private);
889#endif
1109 890
1110 /* Basic check */ 891 /* Basic check */
1111 if (!netif_device_present(dev)) 892 if (!netif_device_present(dev))
@@ -1117,7 +898,7 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
1117 /* Standard and private are not the same */ 898 /* Standard and private are not the same */
1118 if (cmd < SIOCIWFIRSTPRIV) 899 if (cmd < SIOCIWFIRSTPRIV)
1119 return standard(dev, iwr, cmd, info, handler); 900 return standard(dev, iwr, cmd, info, handler);
1120 else 901 else if (private)
1121 return private(dev, iwr, cmd, info, handler); 902 return private(dev, iwr, cmd, info, handler);
1122 } 903 }
1123 /* Old driver API : call driver ioctl handler */ 904 /* Old driver API : call driver ioctl handler */
@@ -1131,8 +912,9 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
1131 */ 912 */
1132static int wext_permission_check(unsigned int cmd) 913static int wext_permission_check(unsigned int cmd)
1133{ 914{
1134 if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT) 915 if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE ||
1135 && !capable(CAP_NET_ADMIN)) 916 cmd == SIOCGIWENCODEEXT) &&
917 !capable(CAP_NET_ADMIN))
1136 return -EPERM; 918 return -EPERM;
1137 919
1138 return 0; 920 return 0;
@@ -1157,6 +939,50 @@ static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
1157 return ret; 939 return ret;
1158} 940}
1159 941
942/*
943 * Wrapper to call a standard Wireless Extension handler.
944 * We do various checks and also take care of moving data between
945 * user space and kernel space.
946 */
947static int ioctl_standard_call(struct net_device * dev,
948 struct iwreq *iwr,
949 unsigned int cmd,
950 struct iw_request_info *info,
951 iw_handler handler)
952{
953 const struct iw_ioctl_description * descr;
954 int ret = -EINVAL;
955
956 /* Get the description of the IOCTL */
957 if ((cmd - SIOCIWFIRST) >= standard_ioctl_num)
958 return -EOPNOTSUPP;
959 descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
960
961 /* Check if we have a pointer to user space data or not */
962 if (descr->header_type != IW_HEADER_TYPE_POINT) {
963
964 /* No extra arguments. Trivial to handle */
965 ret = handler(dev, info, &(iwr->u), NULL);
966
967 /* Generate an event to notify listeners of the change */
968 if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
969 ((ret == 0) || (ret == -EIWCOMMIT)))
970 wireless_send_event(dev, cmd, &(iwr->u), NULL);
971 } else {
972 ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr,
973 handler, dev, info);
974 }
975
976 /* Call commit handler if needed and defined */
977 if (ret == -EIWCOMMIT)
978 ret = call_commit_handler(dev);
979
980 /* Here, we will generate the appropriate event if needed */
981
982 return ret;
983}
984
985
1160int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, 986int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
1161 void __user *arg) 987 void __user *arg)
1162{ 988{
@@ -1205,43 +1031,6 @@ static int compat_standard_call(struct net_device *dev,
1205 return err; 1031 return err;
1206} 1032}
1207 1033
1208static int compat_private_call(struct net_device *dev, struct iwreq *iwr,
1209 unsigned int cmd, struct iw_request_info *info,
1210 iw_handler handler)
1211{
1212 const struct iw_priv_args *descr;
1213 int ret, extra_size;
1214
1215 extra_size = get_priv_descr_and_size(dev, cmd, &descr);
1216
1217 /* Check if we have a pointer to user space data or not. */
1218 if (extra_size == 0) {
1219 /* No extra arguments. Trivial to handle */
1220 ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
1221 } else {
1222 struct compat_iw_point *iwp_compat;
1223 struct iw_point iwp;
1224
1225 iwp_compat = (struct compat_iw_point *) &iwr->u.data;
1226 iwp.pointer = compat_ptr(iwp_compat->pointer);
1227 iwp.length = iwp_compat->length;
1228 iwp.flags = iwp_compat->flags;
1229
1230 ret = ioctl_private_iw_point(&iwp, cmd, descr,
1231 handler, dev, info, extra_size);
1232
1233 iwp_compat->pointer = ptr_to_compat(iwp.pointer);
1234 iwp_compat->length = iwp.length;
1235 iwp_compat->flags = iwp.flags;
1236 }
1237
1238 /* Call commit handler if needed and defined */
1239 if (ret == -EIWCOMMIT)
1240 ret = call_commit_handler(dev);
1241
1242 return ret;
1243}
1244
1245int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, 1034int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
1246 unsigned long arg) 1035 unsigned long arg)
1247{ 1036{
@@ -1274,502 +1063,3 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
1274 return ret; 1063 return ret;
1275} 1064}
1276#endif 1065#endif
1277
1278static int __net_init wext_pernet_init(struct net *net)
1279{
1280 skb_queue_head_init(&net->wext_nlevents);
1281 return 0;
1282}
1283
1284static void __net_exit wext_pernet_exit(struct net *net)
1285{
1286 skb_queue_purge(&net->wext_nlevents);
1287}
1288
1289static struct pernet_operations wext_pernet_ops = {
1290 .init = wext_pernet_init,
1291 .exit = wext_pernet_exit,
1292};
1293
1294static int __init wireless_nlevent_init(void)
1295{
1296 return register_pernet_subsys(&wext_pernet_ops);
1297}
1298
1299subsys_initcall(wireless_nlevent_init);
1300
1301/* Process events generated by the wireless layer or the driver. */
1302static void wireless_nlevent_process(struct work_struct *work)
1303{
1304 struct sk_buff *skb;
1305 struct net *net;
1306
1307 rtnl_lock();
1308
1309 for_each_net(net) {
1310 while ((skb = skb_dequeue(&net->wext_nlevents)))
1311 rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
1312 GFP_KERNEL);
1313 }
1314
1315 rtnl_unlock();
1316}
1317
1318static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process);
1319
1320static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev,
1321 struct sk_buff *skb)
1322{
1323 struct ifinfomsg *r;
1324 struct nlmsghdr *nlh;
1325
1326 nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0);
1327 if (!nlh)
1328 return NULL;
1329
1330 r = nlmsg_data(nlh);
1331 r->ifi_family = AF_UNSPEC;
1332 r->__ifi_pad = 0;
1333 r->ifi_type = dev->type;
1334 r->ifi_index = dev->ifindex;
1335 r->ifi_flags = dev_get_flags(dev);
1336 r->ifi_change = 0; /* Wireless changes don't affect those flags */
1337
1338 NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
1339
1340 return nlh;
1341 nla_put_failure:
1342 nlmsg_cancel(skb, nlh);
1343 return NULL;
1344}
1345
1346
1347/*
1348 * Main event dispatcher. Called from other parts and drivers.
1349 * Send the event on the appropriate channels.
1350 * May be called from interrupt context.
1351 */
1352void wireless_send_event(struct net_device * dev,
1353 unsigned int cmd,
1354 union iwreq_data * wrqu,
1355 const char * extra)
1356{
1357 const struct iw_ioctl_description * descr = NULL;
1358 int extra_len = 0;
1359 struct iw_event *event; /* Mallocated whole event */
1360 int event_len; /* Its size */
1361 int hdr_len; /* Size of the event header */
1362 int wrqu_off = 0; /* Offset in wrqu */
1363 /* Don't "optimise" the following variable, it will crash */
1364 unsigned cmd_index; /* *MUST* be unsigned */
1365 struct sk_buff *skb;
1366 struct nlmsghdr *nlh;
1367 struct nlattr *nla;
1368#ifdef CONFIG_COMPAT
1369 struct __compat_iw_event *compat_event;
1370 struct compat_iw_point compat_wrqu;
1371 struct sk_buff *compskb;
1372#endif
1373
1374 /*
1375 * Nothing in the kernel sends scan events with data, be safe.
1376 * This is necessary because we cannot fix up scan event data
1377 * for compat, due to being contained in 'extra', but normally
1378 * applications are required to retrieve the scan data anyway
1379 * and no data is included in the event, this codifies that
1380 * practice.
1381 */
1382 if (WARN_ON(cmd == SIOCGIWSCAN && extra))
1383 extra = NULL;
1384
1385 /* Get the description of the Event */
1386 if (cmd <= SIOCIWLAST) {
1387 cmd_index = cmd - SIOCIWFIRST;
1388 if (cmd_index < standard_ioctl_num)
1389 descr = &(standard_ioctl[cmd_index]);
1390 } else {
1391 cmd_index = cmd - IWEVFIRST;
1392 if (cmd_index < standard_event_num)
1393 descr = &(standard_event[cmd_index]);
1394 }
1395 /* Don't accept unknown events */
1396 if (descr == NULL) {
1397 /* Note : we don't return an error to the driver, because
1398 * the driver would not know what to do about it. It can't
1399 * return an error to the user, because the event is not
1400 * initiated by a user request.
1401 * The best the driver could do is to log an error message.
1402 * We will do it ourselves instead...
1403 */
1404 printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
1405 dev->name, cmd);
1406 return;
1407 }
1408
1409 /* Check extra parameters and set extra_len */
1410 if (descr->header_type == IW_HEADER_TYPE_POINT) {
1411 /* Check if number of token fits within bounds */
1412 if (wrqu->data.length > descr->max_tokens) {
1413 printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
1414 return;
1415 }
1416 if (wrqu->data.length < descr->min_tokens) {
1417 printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
1418 return;
1419 }
1420 /* Calculate extra_len - extra is NULL for restricted events */
1421 if (extra != NULL)
1422 extra_len = wrqu->data.length * descr->token_size;
1423 /* Always at an offset in wrqu */
1424 wrqu_off = IW_EV_POINT_OFF;
1425 }
1426
1427 /* Total length of the event */
1428 hdr_len = event_type_size[descr->header_type];
1429 event_len = hdr_len + extra_len;
1430
1431 /*
1432 * The problem for 64/32 bit.
1433 *
1434 * On 64-bit, a regular event is laid out as follows:
1435 * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
1436 * | event.len | event.cmd | p a d d i n g |
1437 * | wrqu data ... (with the correct size) |
1438 *
1439 * This padding exists because we manipulate event->u,
1440 * and 'event' is not packed.
1441 *
1442 * An iw_point event is laid out like this instead:
1443 * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
1444 * | event.len | event.cmd | p a d d i n g |
1445 * | iwpnt.len | iwpnt.flg | p a d d i n g |
1446 * | extra data ...
1447 *
1448 * The second padding exists because struct iw_point is extended,
1449 * but this depends on the platform...
1450 *
1451 * On 32-bit, all the padding shouldn't be there.
1452 */
1453
1454 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
1455 if (!skb)
1456 return;
1457
1458 /* Send via the RtNetlink event channel */
1459 nlh = rtnetlink_ifinfo_prep(dev, skb);
1460 if (WARN_ON(!nlh)) {
1461 kfree_skb(skb);
1462 return;
1463 }
1464
1465 /* Add the wireless events in the netlink packet */
1466 nla = nla_reserve(skb, IFLA_WIRELESS, event_len);
1467 if (!nla) {
1468 kfree_skb(skb);
1469 return;
1470 }
1471 event = nla_data(nla);
1472
1473 /* Fill event - first clear to avoid data leaking */
1474 memset(event, 0, hdr_len);
1475 event->len = event_len;
1476 event->cmd = cmd;
1477 memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
1478 if (extra_len)
1479 memcpy(((char *) event) + hdr_len, extra, extra_len);
1480
1481 nlmsg_end(skb, nlh);
1482#ifdef CONFIG_COMPAT
1483 hdr_len = compat_event_type_size[descr->header_type];
1484 event_len = hdr_len + extra_len;
1485
1486 compskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
1487 if (!compskb) {
1488 kfree_skb(skb);
1489 return;
1490 }
1491
1492 /* Send via the RtNetlink event channel */
1493 nlh = rtnetlink_ifinfo_prep(dev, compskb);
1494 if (WARN_ON(!nlh)) {
1495 kfree_skb(skb);
1496 kfree_skb(compskb);
1497 return;
1498 }
1499
1500 /* Add the wireless events in the netlink packet */
1501 nla = nla_reserve(compskb, IFLA_WIRELESS, event_len);
1502 if (!nla) {
1503 kfree_skb(skb);
1504 kfree_skb(compskb);
1505 return;
1506 }
1507 compat_event = nla_data(nla);
1508
1509 compat_event->len = event_len;
1510 compat_event->cmd = cmd;
1511 if (descr->header_type == IW_HEADER_TYPE_POINT) {
1512 compat_wrqu.length = wrqu->data.length;
1513 compat_wrqu.flags = wrqu->data.flags;
1514 memcpy(&compat_event->pointer,
1515 ((char *) &compat_wrqu) + IW_EV_COMPAT_POINT_OFF,
1516 hdr_len - IW_EV_COMPAT_LCP_LEN);
1517 if (extra_len)
1518 memcpy(((char *) compat_event) + hdr_len,
1519 extra, extra_len);
1520 } else {
1521 /* extra_len must be zero, so no if (extra) needed */
1522 memcpy(&compat_event->pointer, wrqu,
1523 hdr_len - IW_EV_COMPAT_LCP_LEN);
1524 }
1525
1526 nlmsg_end(compskb, nlh);
1527
1528 skb_shinfo(skb)->frag_list = compskb;
1529#endif
1530 skb_queue_tail(&dev_net(dev)->wext_nlevents, skb);
1531 schedule_work(&wireless_nlevent_work);
1532}
1533EXPORT_SYMBOL(wireless_send_event);
1534
1535/********************** ENHANCED IWSPY SUPPORT **********************/
1536/*
1537 * In the old days, the driver was handling spy support all by itself.
1538 * Now, the driver can delegate this task to Wireless Extensions.
1539 * It needs to use those standard spy iw_handler in struct iw_handler_def,
1540 * push data to us via wireless_spy_update() and include struct iw_spy_data
1541 * in its private part (and export it in net_device->wireless_data->spy_data).
1542 * One of the main advantage of centralising spy support here is that
1543 * it becomes much easier to improve and extend it without having to touch
1544 * the drivers. One example is the addition of the Spy-Threshold events.
1545 */
1546
1547/* ---------------------------------------------------------------- */
1548/*
1549 * Return the pointer to the spy data in the driver.
1550 * Because this is called on the Rx path via wireless_spy_update(),
1551 * we want it to be efficient...
1552 */
1553static inline struct iw_spy_data *get_spydata(struct net_device *dev)
1554{
1555 /* This is the new way */
1556 if (dev->wireless_data)
1557 return dev->wireless_data->spy_data;
1558 return NULL;
1559}
1560
1561/*------------------------------------------------------------------*/
1562/*
1563 * Standard Wireless Handler : set Spy List
1564 */
1565int iw_handler_set_spy(struct net_device * dev,
1566 struct iw_request_info * info,
1567 union iwreq_data * wrqu,
1568 char * extra)
1569{
1570 struct iw_spy_data * spydata = get_spydata(dev);
1571 struct sockaddr * address = (struct sockaddr *) extra;
1572
1573 /* Make sure driver is not buggy or using the old API */
1574 if (!spydata)
1575 return -EOPNOTSUPP;
1576
1577 /* Disable spy collection while we copy the addresses.
1578 * While we copy addresses, any call to wireless_spy_update()
1579 * will NOP. This is OK, as anyway the addresses are changing. */
1580 spydata->spy_number = 0;
1581
1582 /* We want to operate without locking, because wireless_spy_update()
1583 * most likely will happen in the interrupt handler, and therefore
1584 * have its own locking constraints and needs performance.
1585 * The rtnl_lock() make sure we don't race with the other iw_handlers.
1586 * This make sure wireless_spy_update() "see" that the spy list
1587 * is temporarily disabled. */
1588 smp_wmb();
1589
1590 /* Are there are addresses to copy? */
1591 if (wrqu->data.length > 0) {
1592 int i;
1593
1594 /* Copy addresses */
1595 for (i = 0; i < wrqu->data.length; i++)
1596 memcpy(spydata->spy_address[i], address[i].sa_data,
1597 ETH_ALEN);
1598 /* Reset stats */
1599 memset(spydata->spy_stat, 0,
1600 sizeof(struct iw_quality) * IW_MAX_SPY);
1601 }
1602
1603 /* Make sure above is updated before re-enabling */
1604 smp_wmb();
1605
1606 /* Enable addresses */
1607 spydata->spy_number = wrqu->data.length;
1608
1609 return 0;
1610}
1611EXPORT_SYMBOL(iw_handler_set_spy);
1612
1613/*------------------------------------------------------------------*/
1614/*
1615 * Standard Wireless Handler : get Spy List
1616 */
1617int iw_handler_get_spy(struct net_device * dev,
1618 struct iw_request_info * info,
1619 union iwreq_data * wrqu,
1620 char * extra)
1621{
1622 struct iw_spy_data * spydata = get_spydata(dev);
1623 struct sockaddr * address = (struct sockaddr *) extra;
1624 int i;
1625
1626 /* Make sure driver is not buggy or using the old API */
1627 if (!spydata)
1628 return -EOPNOTSUPP;
1629
1630 wrqu->data.length = spydata->spy_number;
1631
1632 /* Copy addresses. */
1633 for (i = 0; i < spydata->spy_number; i++) {
1634 memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
1635 address[i].sa_family = AF_UNIX;
1636 }
1637 /* Copy stats to the user buffer (just after). */
1638 if (spydata->spy_number > 0)
1639 memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number),
1640 spydata->spy_stat,
1641 sizeof(struct iw_quality) * spydata->spy_number);
1642 /* Reset updated flags. */
1643 for (i = 0; i < spydata->spy_number; i++)
1644 spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
1645 return 0;
1646}
1647EXPORT_SYMBOL(iw_handler_get_spy);
1648
1649/*------------------------------------------------------------------*/
1650/*
1651 * Standard Wireless Handler : set spy threshold
1652 */
1653int iw_handler_set_thrspy(struct net_device * dev,
1654 struct iw_request_info *info,
1655 union iwreq_data * wrqu,
1656 char * extra)
1657{
1658 struct iw_spy_data * spydata = get_spydata(dev);
1659 struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
1660
1661 /* Make sure driver is not buggy or using the old API */
1662 if (!spydata)
1663 return -EOPNOTSUPP;
1664
1665 /* Just do it */
1666 memcpy(&(spydata->spy_thr_low), &(threshold->low),
1667 2 * sizeof(struct iw_quality));
1668
1669 /* Clear flag */
1670 memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
1671
1672 return 0;
1673}
1674EXPORT_SYMBOL(iw_handler_set_thrspy);
1675
1676/*------------------------------------------------------------------*/
1677/*
1678 * Standard Wireless Handler : get spy threshold
1679 */
1680int iw_handler_get_thrspy(struct net_device * dev,
1681 struct iw_request_info *info,
1682 union iwreq_data * wrqu,
1683 char * extra)
1684{
1685 struct iw_spy_data * spydata = get_spydata(dev);
1686 struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
1687
1688 /* Make sure driver is not buggy or using the old API */
1689 if (!spydata)
1690 return -EOPNOTSUPP;
1691
1692 /* Just do it */
1693 memcpy(&(threshold->low), &(spydata->spy_thr_low),
1694 2 * sizeof(struct iw_quality));
1695
1696 return 0;
1697}
1698EXPORT_SYMBOL(iw_handler_get_thrspy);
1699
1700/*------------------------------------------------------------------*/
1701/*
1702 * Prepare and send a Spy Threshold event
1703 */
1704static void iw_send_thrspy_event(struct net_device * dev,
1705 struct iw_spy_data * spydata,
1706 unsigned char * address,
1707 struct iw_quality * wstats)
1708{
1709 union iwreq_data wrqu;
1710 struct iw_thrspy threshold;
1711
1712 /* Init */
1713 wrqu.data.length = 1;
1714 wrqu.data.flags = 0;
1715 /* Copy address */
1716 memcpy(threshold.addr.sa_data, address, ETH_ALEN);
1717 threshold.addr.sa_family = ARPHRD_ETHER;
1718 /* Copy stats */
1719 memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
1720 /* Copy also thresholds */
1721 memcpy(&(threshold.low), &(spydata->spy_thr_low),
1722 2 * sizeof(struct iw_quality));
1723
1724 /* Send event to user space */
1725 wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
1726}
1727
1728/* ---------------------------------------------------------------- */
1729/*
1730 * Call for the driver to update the spy data.
1731 * For now, the spy data is a simple array. As the size of the array is
1732 * small, this is good enough. If we wanted to support larger number of
1733 * spy addresses, we should use something more efficient...
1734 */
1735void wireless_spy_update(struct net_device * dev,
1736 unsigned char * address,
1737 struct iw_quality * wstats)
1738{
1739 struct iw_spy_data * spydata = get_spydata(dev);
1740 int i;
1741 int match = -1;
1742
1743 /* Make sure driver is not buggy or using the old API */
1744 if (!spydata)
1745 return;
1746
1747 /* Update all records that match */
1748 for (i = 0; i < spydata->spy_number; i++)
1749 if (!compare_ether_addr(address, spydata->spy_address[i])) {
1750 memcpy(&(spydata->spy_stat[i]), wstats,
1751 sizeof(struct iw_quality));
1752 match = i;
1753 }
1754
1755 /* Generate an event if we cross the spy threshold.
1756 * To avoid event storms, we have a simple hysteresis : we generate
1757 * event only when we go under the low threshold or above the
1758 * high threshold. */
1759 if (match >= 0) {
1760 if (spydata->spy_thr_under[match]) {
1761 if (wstats->level > spydata->spy_thr_high.level) {
1762 spydata->spy_thr_under[match] = 0;
1763 iw_send_thrspy_event(dev, spydata,
1764 address, wstats);
1765 }
1766 } else {
1767 if (wstats->level < spydata->spy_thr_low.level) {
1768 spydata->spy_thr_under[match] = 1;
1769 iw_send_thrspy_event(dev, spydata,
1770 address, wstats);
1771 }
1772 }
1773 }
1774}
1775EXPORT_SYMBOL(wireless_spy_update);
diff --git a/net/wireless/wext-priv.c b/net/wireless/wext-priv.c
new file mode 100644
index 000000000000..a3c2277de9e5
--- /dev/null
+++ b/net/wireless/wext-priv.c
@@ -0,0 +1,248 @@
1/*
2 * This file implement the Wireless Extensions priv API.
3 *
4 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
5 * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
6 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
7 *
8 * (As all part of the Linux kernel, this file is GPL)
9 */
10#include <linux/wireless.h>
11#include <linux/netdevice.h>
12#include <net/iw_handler.h>
13#include <net/wext.h>
14
15int iw_handler_get_private(struct net_device * dev,
16 struct iw_request_info * info,
17 union iwreq_data * wrqu,
18 char * extra)
19{
20 /* Check if the driver has something to export */
21 if ((dev->wireless_handlers->num_private_args == 0) ||
22 (dev->wireless_handlers->private_args == NULL))
23 return -EOPNOTSUPP;
24
25 /* Check if there is enough buffer up there */
26 if (wrqu->data.length < dev->wireless_handlers->num_private_args) {
27 /* User space can't know in advance how large the buffer
28 * needs to be. Give it a hint, so that we can support
29 * any size buffer we want somewhat efficiently... */
30 wrqu->data.length = dev->wireless_handlers->num_private_args;
31 return -E2BIG;
32 }
33
34 /* Set the number of available ioctls. */
35 wrqu->data.length = dev->wireless_handlers->num_private_args;
36
37 /* Copy structure to the user buffer. */
38 memcpy(extra, dev->wireless_handlers->private_args,
39 sizeof(struct iw_priv_args) * wrqu->data.length);
40
41 return 0;
42}
43
44/* Size (in bytes) of the various private data types */
45static const char iw_priv_type_size[] = {
46 0, /* IW_PRIV_TYPE_NONE */
47 1, /* IW_PRIV_TYPE_BYTE */
48 1, /* IW_PRIV_TYPE_CHAR */
49 0, /* Not defined */
50 sizeof(__u32), /* IW_PRIV_TYPE_INT */
51 sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
52 sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
53 0, /* Not defined */
54};
55
56static int get_priv_size(__u16 args)
57{
58 int num = args & IW_PRIV_SIZE_MASK;
59 int type = (args & IW_PRIV_TYPE_MASK) >> 12;
60
61 return num * iw_priv_type_size[type];
62}
63
64static int adjust_priv_size(__u16 args, struct iw_point *iwp)
65{
66 int num = iwp->length;
67 int max = args & IW_PRIV_SIZE_MASK;
68 int type = (args & IW_PRIV_TYPE_MASK) >> 12;
69
70 /* Make sure the driver doesn't goof up */
71 if (max < num)
72 num = max;
73
74 return num * iw_priv_type_size[type];
75}
76
77/*
78 * Wrapper to call a private Wireless Extension handler.
79 * We do various checks and also take care of moving data between
80 * user space and kernel space.
81 * It's not as nice and slimline as the standard wrapper. The cause
82 * is struct iw_priv_args, which was not really designed for the
83 * job we are going here.
84 *
85 * IMPORTANT : This function prevent to set and get data on the same
86 * IOCTL and enforce the SET/GET convention. Not doing it would be
87 * far too hairy...
88 * If you need to set and get data at the same time, please don't use
89 * a iw_handler but process it in your ioctl handler (i.e. use the
90 * old driver API).
91 */
92static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd,
93 const struct iw_priv_args **descrp)
94{
95 const struct iw_priv_args *descr;
96 int i, extra_size;
97
98 descr = NULL;
99 for (i = 0; i < dev->wireless_handlers->num_private_args; i++) {
100 if (cmd == dev->wireless_handlers->private_args[i].cmd) {
101 descr = &dev->wireless_handlers->private_args[i];
102 break;
103 }
104 }
105
106 extra_size = 0;
107 if (descr) {
108 if (IW_IS_SET(cmd)) {
109 int offset = 0; /* For sub-ioctls */
110 /* Check for sub-ioctl handler */
111 if (descr->name[0] == '\0')
112 /* Reserve one int for sub-ioctl index */
113 offset = sizeof(__u32);
114
115 /* Size of set arguments */
116 extra_size = get_priv_size(descr->set_args);
117
118 /* Does it fits in iwr ? */
119 if ((descr->set_args & IW_PRIV_SIZE_FIXED) &&
120 ((extra_size + offset) <= IFNAMSIZ))
121 extra_size = 0;
122 } else {
123 /* Size of get arguments */
124 extra_size = get_priv_size(descr->get_args);
125
126 /* Does it fits in iwr ? */
127 if ((descr->get_args & IW_PRIV_SIZE_FIXED) &&
128 (extra_size <= IFNAMSIZ))
129 extra_size = 0;
130 }
131 }
132 *descrp = descr;
133 return extra_size;
134}
135
136static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd,
137 const struct iw_priv_args *descr,
138 iw_handler handler, struct net_device *dev,
139 struct iw_request_info *info, int extra_size)
140{
141 char *extra;
142 int err;
143
144 /* Check what user space is giving us */
145 if (IW_IS_SET(cmd)) {
146 if (!iwp->pointer && iwp->length != 0)
147 return -EFAULT;
148
149 if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK))
150 return -E2BIG;
151 } else if (!iwp->pointer)
152 return -EFAULT;
153
154 extra = kmalloc(extra_size, GFP_KERNEL);
155 if (!extra)
156 return -ENOMEM;
157
158 /* If it is a SET, get all the extra data in here */
159 if (IW_IS_SET(cmd) && (iwp->length != 0)) {
160 if (copy_from_user(extra, iwp->pointer, extra_size)) {
161 err = -EFAULT;
162 goto out;
163 }
164 }
165
166 /* Call the handler */
167 err = handler(dev, info, (union iwreq_data *) iwp, extra);
168
169 /* If we have something to return to the user */
170 if (!err && IW_IS_GET(cmd)) {
171 /* Adjust for the actual length if it's variable,
172 * avoid leaking kernel bits outside.
173 */
174 if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
175 extra_size = adjust_priv_size(descr->get_args, iwp);
176
177 if (copy_to_user(iwp->pointer, extra, extra_size))
178 err = -EFAULT;
179 }
180
181out:
182 kfree(extra);
183 return err;
184}
185
186int ioctl_private_call(struct net_device *dev, struct iwreq *iwr,
187 unsigned int cmd, struct iw_request_info *info,
188 iw_handler handler)
189{
190 int extra_size = 0, ret = -EINVAL;
191 const struct iw_priv_args *descr;
192
193 extra_size = get_priv_descr_and_size(dev, cmd, &descr);
194
195 /* Check if we have a pointer to user space data or not. */
196 if (extra_size == 0) {
197 /* No extra arguments. Trivial to handle */
198 ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
199 } else {
200 ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr,
201 handler, dev, info, extra_size);
202 }
203
204 /* Call commit handler if needed and defined */
205 if (ret == -EIWCOMMIT)
206 ret = call_commit_handler(dev);
207
208 return ret;
209}
210
211#ifdef CONFIG_COMPAT
212int compat_private_call(struct net_device *dev, struct iwreq *iwr,
213 unsigned int cmd, struct iw_request_info *info,
214 iw_handler handler)
215{
216 const struct iw_priv_args *descr;
217 int ret, extra_size;
218
219 extra_size = get_priv_descr_and_size(dev, cmd, &descr);
220
221 /* Check if we have a pointer to user space data or not. */
222 if (extra_size == 0) {
223 /* No extra arguments. Trivial to handle */
224 ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
225 } else {
226 struct compat_iw_point *iwp_compat;
227 struct iw_point iwp;
228
229 iwp_compat = (struct compat_iw_point *) &iwr->u.data;
230 iwp.pointer = compat_ptr(iwp_compat->pointer);
231 iwp.length = iwp_compat->length;
232 iwp.flags = iwp_compat->flags;
233
234 ret = ioctl_private_iw_point(&iwp, cmd, descr,
235 handler, dev, info, extra_size);
236
237 iwp_compat->pointer = ptr_to_compat(iwp.pointer);
238 iwp_compat->length = iwp.length;
239 iwp_compat->flags = iwp.flags;
240 }
241
242 /* Call commit handler if needed and defined */
243 if (ret == -EIWCOMMIT)
244 ret = call_commit_handler(dev);
245
246 return ret;
247}
248#endif
diff --git a/net/wireless/wext-proc.c b/net/wireless/wext-proc.c
new file mode 100644
index 000000000000..273a7f77c834
--- /dev/null
+++ b/net/wireless/wext-proc.c
@@ -0,0 +1,155 @@
1/*
2 * This file implement the Wireless Extensions proc API.
3 *
4 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
5 * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
6 *
7 * (As all part of the Linux kernel, this file is GPL)
8 */
9
10/*
11 * The /proc/net/wireless file is a human readable user-space interface
12 * exporting various wireless specific statistics from the wireless devices.
13 * This is the most popular part of the Wireless Extensions ;-)
14 *
15 * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
16 * The content of the file is basically the content of "struct iw_statistics".
17 */
18
19#include <linux/module.h>
20#include <linux/proc_fs.h>
21#include <linux/seq_file.h>
22#include <linux/wireless.h>
23#include <linux/netdevice.h>
24#include <linux/rtnetlink.h>
25#include <net/iw_handler.h>
26#include <net/wext.h>
27
28
29static void wireless_seq_printf_stats(struct seq_file *seq,
30 struct net_device *dev)
31{
32 /* Get stats from the driver */
33 struct iw_statistics *stats = get_wireless_stats(dev);
34 static struct iw_statistics nullstats = {};
35
36 /* show device if it's wireless regardless of current stats */
37 if (!stats) {
38#ifdef CONFIG_WIRELESS_EXT
39 if (dev->wireless_handlers)
40 stats = &nullstats;
41#endif
42#ifdef CONFIG_CFG80211
43 if (dev->ieee80211_ptr)
44 stats = &nullstats;
45#endif
46 }
47
48 if (stats) {
49 seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d "
50 "%6d %6d %6d\n",
51 dev->name, stats->status, stats->qual.qual,
52 stats->qual.updated & IW_QUAL_QUAL_UPDATED
53 ? '.' : ' ',
54 ((__s32) stats->qual.level) -
55 ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
56 stats->qual.updated & IW_QUAL_LEVEL_UPDATED
57 ? '.' : ' ',
58 ((__s32) stats->qual.noise) -
59 ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
60 stats->qual.updated & IW_QUAL_NOISE_UPDATED
61 ? '.' : ' ',
62 stats->discard.nwid, stats->discard.code,
63 stats->discard.fragment, stats->discard.retries,
64 stats->discard.misc, stats->miss.beacon);
65
66 if (stats != &nullstats)
67 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
68 }
69}
70
71/* ---------------------------------------------------------------- */
72/*
73 * Print info for /proc/net/wireless (print all entries)
74 */
75static int wireless_dev_seq_show(struct seq_file *seq, void *v)
76{
77 might_sleep();
78
79 if (v == SEQ_START_TOKEN)
80 seq_printf(seq, "Inter-| sta-| Quality | Discarded "
81 "packets | Missed | WE\n"
82 " face | tus | link level noise | nwid "
83 "crypt frag retry misc | beacon | %d\n",
84 WIRELESS_EXT);
85 else
86 wireless_seq_printf_stats(seq, v);
87 return 0;
88}
89
90static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos)
91{
92 struct net *net = seq_file_net(seq);
93 loff_t off;
94 struct net_device *dev;
95
96 rtnl_lock();
97 if (!*pos)
98 return SEQ_START_TOKEN;
99
100 off = 1;
101 for_each_netdev(net, dev)
102 if (off++ == *pos)
103 return dev;
104 return NULL;
105}
106
107static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
108{
109 struct net *net = seq_file_net(seq);
110
111 ++*pos;
112
113 return v == SEQ_START_TOKEN ?
114 first_net_device(net) : next_net_device(v);
115}
116
117static void wireless_dev_seq_stop(struct seq_file *seq, void *v)
118{
119 rtnl_unlock();
120}
121
122static const struct seq_operations wireless_seq_ops = {
123 .start = wireless_dev_seq_start,
124 .next = wireless_dev_seq_next,
125 .stop = wireless_dev_seq_stop,
126 .show = wireless_dev_seq_show,
127};
128
129static int seq_open_wireless(struct inode *inode, struct file *file)
130{
131 return seq_open_net(inode, file, &wireless_seq_ops,
132 sizeof(struct seq_net_private));
133}
134
135static const struct file_operations wireless_seq_fops = {
136 .owner = THIS_MODULE,
137 .open = seq_open_wireless,
138 .read = seq_read,
139 .llseek = seq_lseek,
140 .release = seq_release_net,
141};
142
143int wext_proc_init(struct net *net)
144{
145 /* Create /proc/net/wireless entry */
146 if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops))
147 return -ENOMEM;
148
149 return 0;
150}
151
152void wext_proc_exit(struct net *net)
153{
154 proc_net_remove(net, "wireless");
155}
diff --git a/net/wireless/wext-spy.c b/net/wireless/wext-spy.c
new file mode 100644
index 000000000000..6dcfe65a2d1a
--- /dev/null
+++ b/net/wireless/wext-spy.c
@@ -0,0 +1,231 @@
1/*
2 * This file implement the Wireless Extensions spy API.
3 *
4 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
5 * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
6 *
7 * (As all part of the Linux kernel, this file is GPL)
8 */
9
10#include <linux/wireless.h>
11#include <linux/netdevice.h>
12#include <linux/etherdevice.h>
13#include <net/iw_handler.h>
14#include <net/arp.h>
15#include <net/wext.h>
16
17static inline struct iw_spy_data *get_spydata(struct net_device *dev)
18{
19 /* This is the new way */
20 if (dev->wireless_data)
21 return dev->wireless_data->spy_data;
22 return NULL;
23}
24
25int iw_handler_set_spy(struct net_device * dev,
26 struct iw_request_info * info,
27 union iwreq_data * wrqu,
28 char * extra)
29{
30 struct iw_spy_data * spydata = get_spydata(dev);
31 struct sockaddr * address = (struct sockaddr *) extra;
32
33 /* Make sure driver is not buggy or using the old API */
34 if (!spydata)
35 return -EOPNOTSUPP;
36
37 /* Disable spy collection while we copy the addresses.
38 * While we copy addresses, any call to wireless_spy_update()
39 * will NOP. This is OK, as anyway the addresses are changing. */
40 spydata->spy_number = 0;
41
42 /* We want to operate without locking, because wireless_spy_update()
43 * most likely will happen in the interrupt handler, and therefore
44 * have its own locking constraints and needs performance.
45 * The rtnl_lock() make sure we don't race with the other iw_handlers.
46 * This make sure wireless_spy_update() "see" that the spy list
47 * is temporarily disabled. */
48 smp_wmb();
49
50 /* Are there are addresses to copy? */
51 if (wrqu->data.length > 0) {
52 int i;
53
54 /* Copy addresses */
55 for (i = 0; i < wrqu->data.length; i++)
56 memcpy(spydata->spy_address[i], address[i].sa_data,
57 ETH_ALEN);
58 /* Reset stats */
59 memset(spydata->spy_stat, 0,
60 sizeof(struct iw_quality) * IW_MAX_SPY);
61 }
62
63 /* Make sure above is updated before re-enabling */
64 smp_wmb();
65
66 /* Enable addresses */
67 spydata->spy_number = wrqu->data.length;
68
69 return 0;
70}
71EXPORT_SYMBOL(iw_handler_set_spy);
72
73int iw_handler_get_spy(struct net_device * dev,
74 struct iw_request_info * info,
75 union iwreq_data * wrqu,
76 char * extra)
77{
78 struct iw_spy_data * spydata = get_spydata(dev);
79 struct sockaddr * address = (struct sockaddr *) extra;
80 int i;
81
82 /* Make sure driver is not buggy or using the old API */
83 if (!spydata)
84 return -EOPNOTSUPP;
85
86 wrqu->data.length = spydata->spy_number;
87
88 /* Copy addresses. */
89 for (i = 0; i < spydata->spy_number; i++) {
90 memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
91 address[i].sa_family = AF_UNIX;
92 }
93 /* Copy stats to the user buffer (just after). */
94 if (spydata->spy_number > 0)
95 memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number),
96 spydata->spy_stat,
97 sizeof(struct iw_quality) * spydata->spy_number);
98 /* Reset updated flags. */
99 for (i = 0; i < spydata->spy_number; i++)
100 spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
101 return 0;
102}
103EXPORT_SYMBOL(iw_handler_get_spy);
104
105/*------------------------------------------------------------------*/
106/*
107 * Standard Wireless Handler : set spy threshold
108 */
109int iw_handler_set_thrspy(struct net_device * dev,
110 struct iw_request_info *info,
111 union iwreq_data * wrqu,
112 char * extra)
113{
114 struct iw_spy_data * spydata = get_spydata(dev);
115 struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
116
117 /* Make sure driver is not buggy or using the old API */
118 if (!spydata)
119 return -EOPNOTSUPP;
120
121 /* Just do it */
122 memcpy(&(spydata->spy_thr_low), &(threshold->low),
123 2 * sizeof(struct iw_quality));
124
125 /* Clear flag */
126 memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
127
128 return 0;
129}
130EXPORT_SYMBOL(iw_handler_set_thrspy);
131
132/*------------------------------------------------------------------*/
133/*
134 * Standard Wireless Handler : get spy threshold
135 */
136int iw_handler_get_thrspy(struct net_device * dev,
137 struct iw_request_info *info,
138 union iwreq_data * wrqu,
139 char * extra)
140{
141 struct iw_spy_data * spydata = get_spydata(dev);
142 struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
143
144 /* Make sure driver is not buggy or using the old API */
145 if (!spydata)
146 return -EOPNOTSUPP;
147
148 /* Just do it */
149 memcpy(&(threshold->low), &(spydata->spy_thr_low),
150 2 * sizeof(struct iw_quality));
151
152 return 0;
153}
154EXPORT_SYMBOL(iw_handler_get_thrspy);
155
156/*------------------------------------------------------------------*/
157/*
158 * Prepare and send a Spy Threshold event
159 */
160static void iw_send_thrspy_event(struct net_device * dev,
161 struct iw_spy_data * spydata,
162 unsigned char * address,
163 struct iw_quality * wstats)
164{
165 union iwreq_data wrqu;
166 struct iw_thrspy threshold;
167
168 /* Init */
169 wrqu.data.length = 1;
170 wrqu.data.flags = 0;
171 /* Copy address */
172 memcpy(threshold.addr.sa_data, address, ETH_ALEN);
173 threshold.addr.sa_family = ARPHRD_ETHER;
174 /* Copy stats */
175 memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
176 /* Copy also thresholds */
177 memcpy(&(threshold.low), &(spydata->spy_thr_low),
178 2 * sizeof(struct iw_quality));
179
180 /* Send event to user space */
181 wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
182}
183
184/* ---------------------------------------------------------------- */
185/*
186 * Call for the driver to update the spy data.
187 * For now, the spy data is a simple array. As the size of the array is
188 * small, this is good enough. If we wanted to support larger number of
189 * spy addresses, we should use something more efficient...
190 */
191void wireless_spy_update(struct net_device * dev,
192 unsigned char * address,
193 struct iw_quality * wstats)
194{
195 struct iw_spy_data * spydata = get_spydata(dev);
196 int i;
197 int match = -1;
198
199 /* Make sure driver is not buggy or using the old API */
200 if (!spydata)
201 return;
202
203 /* Update all records that match */
204 for (i = 0; i < spydata->spy_number; i++)
205 if (!compare_ether_addr(address, spydata->spy_address[i])) {
206 memcpy(&(spydata->spy_stat[i]), wstats,
207 sizeof(struct iw_quality));
208 match = i;
209 }
210
211 /* Generate an event if we cross the spy threshold.
212 * To avoid event storms, we have a simple hysteresis : we generate
213 * event only when we go under the low threshold or above the
214 * high threshold. */
215 if (match >= 0) {
216 if (spydata->spy_thr_under[match]) {
217 if (wstats->level > spydata->spy_thr_high.level) {
218 spydata->spy_thr_under[match] = 0;
219 iw_send_thrspy_event(dev, spydata,
220 address, wstats);
221 }
222 } else {
223 if (wstats->level < spydata->spy_thr_low.level) {
224 spydata->spy_thr_under[match] = 1;
225 iw_send_thrspy_event(dev, spydata,
226 address, wstats);
227 }
228 }
229 }
230}
231EXPORT_SYMBOL(wireless_spy_update);