aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/core/net-sysfs.c6
-rw-r--r--net/socket.c4
-rw-r--r--net/wireless/Kconfig50
-rw-r--r--net/wireless/Makefile8
-rw-r--r--net/wireless/core.c14
-rw-r--r--net/wireless/ibss.c10
-rw-r--r--net/wireless/mlme.c2
-rw-r--r--net/wireless/nl80211.c4
-rw-r--r--net/wireless/scan.c6
-rw-r--r--net/wireless/sme.c12
-rw-r--r--net/wireless/wext-core.c (renamed from net/wireless/wext.c)1456
-rw-r--r--net/wireless/wext-priv.c248
-rw-r--r--net/wireless/wext-proc.c155
-rw-r--r--net/wireless/wext-spy.c231
14 files changed, 1079 insertions, 1127 deletions
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index effb78410eb..9b07535c288 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -543,8 +543,12 @@ int netdev_register_kobject(struct net_device *net)
543 *groups++ = &netstat_group; 543 *groups++ = &netstat_group;
544 544
545#ifdef CONFIG_WIRELESS_EXT_SYSFS 545#ifdef CONFIG_WIRELESS_EXT_SYSFS
546 if (net->wireless_handlers || net->ieee80211_ptr) 546 if (net->ieee80211_ptr)
547 *groups++ = &wireless_group; 547 *groups++ = &wireless_group;
548#ifdef CONFIG_WIRELESS_EXT
549 else if (net->wireless_handlers)
550 *groups++ = &wireless_group;
551#endif
548#endif 552#endif
549#endif /* CONFIG_SYSFS */ 553#endif /* CONFIG_SYSFS */
550 554
diff --git a/net/socket.c b/net/socket.c
index 75655365b5f..92a56709fd7 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -905,11 +905,11 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
905 if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { 905 if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
906 err = dev_ioctl(net, cmd, argp); 906 err = dev_ioctl(net, cmd, argp);
907 } else 907 } else
908#ifdef CONFIG_WIRELESS_EXT 908#ifdef CONFIG_WEXT_CORE
909 if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { 909 if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
910 err = dev_ioctl(net, cmd, argp); 910 err = dev_ioctl(net, cmd, argp);
911 } else 911 } else
912#endif /* CONFIG_WIRELESS_EXT */ 912#endif
913 switch (cmd) { 913 switch (cmd) {
914 case FIOSETOWN: 914 case FIOSETOWN:
915 case SIOCSPGRP: 915 case SIOCSPGRP:
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index abf7ca3f9ff..614bdcec1c8 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
@@ -56,6 +74,12 @@ config CFG80211_REG_DEBUG
56 74
57 If unsure, say N. 75 If unsure, say N.
58 76
77config CFG80211_DEFAULT_PS_VALUE
78 int
79 default 1 if CFG80211_DEFAULT_PS
80 default 0
81 depends on CFG80211
82
59config CFG80211_DEFAULT_PS 83config CFG80211_DEFAULT_PS
60 bool "enable powersave by default" 84 bool "enable powersave by default"
61 depends on CFG80211 85 depends on CFG80211
@@ -67,14 +91,10 @@ config CFG80211_DEFAULT_PS
67 applications instead -- they need to register their network 91 applications instead -- they need to register their network
68 latency requirement, see Documentation/power/pm_qos_interface.txt. 92 latency requirement, see Documentation/power/pm_qos_interface.txt.
69 93
70config CFG80211_DEFAULT_PS_VALUE
71 int
72 default 1 if CFG80211_DEFAULT_PS
73 default 0
74
75config CFG80211_DEBUGFS 94config CFG80211_DEBUGFS
76 bool "cfg80211 DebugFS entries" 95 bool "cfg80211 DebugFS entries"
77 depends on CFG80211 && DEBUG_FS 96 depends on CFG80211
97 depends on DEBUG_FS
78 ---help--- 98 ---help---
79 You can enable this if you want to debugfs entries for cfg80211. 99 You can enable this if you want to debugfs entries for cfg80211.
80 100
@@ -83,6 +103,7 @@ config CFG80211_DEBUGFS
83config WIRELESS_OLD_REGULATORY 103config WIRELESS_OLD_REGULATORY
84 bool "Old wireless static regulatory definitions" 104 bool "Old wireless static regulatory definitions"
85 default n 105 default n
106 depends on CFG80211
86 ---help--- 107 ---help---
87 This option enables the old static regulatory information 108 This option enables the old static regulatory information
88 and uses it within the new framework. This option is available 109 and uses it within the new framework. This option is available
@@ -94,20 +115,19 @@ config WIRELESS_OLD_REGULATORY
94 115
95 Say N and if you say Y, please tell us why. The default is N. 116 Say N and if you say Y, please tell us why. The default is N.
96 117
97config WIRELESS_EXT 118config CFG80211_WEXT
98 bool "Wireless extensions" 119 bool "cfg80211 wireless extensions compatibility"
120 depends on CFG80211
121 select WEXT_CORE
99 default y 122 default y
100 ---help--- 123 help
101 This option enables the legacy wireless extensions 124 Enable this option if you need old userspace for wireless
102 (wireless network interface configuration via ioctls.) 125 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 126
107config WIRELESS_EXT_SYSFS 127config WIRELESS_EXT_SYSFS
108 bool "Wireless extensions sysfs files" 128 bool "Wireless extensions sysfs files"
109 default y 129 default y
110 depends on WIRELESS_EXT && SYSFS 130 depends on WEXT_CORE && SYSFS
111 help 131 help
112 This option enables the deprecated wireless statistics 132 This option enables the deprecated wireless statistics
113 files in /sys/class/net/*/wireless/. The same information 133 files in /sys/class/net/*/wireless/. The same information
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 3ecaa917997..c8141505a83 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
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 e6f02e98e5f..eb0bb24b99c 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -358,6 +358,10 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
358 INIT_LIST_HEAD(&rdev->bss_list); 358 INIT_LIST_HEAD(&rdev->bss_list);
359 INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); 359 INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
360 360
361#ifdef CONFIG_CFG80211_WEXT
362 rdev->wiphy.wext = &cfg80211_wext_handler;
363#endif
364
361 device_initialize(&rdev->wiphy.dev); 365 device_initialize(&rdev->wiphy.dev);
362 rdev->wiphy.dev.class = &ieee80211_class; 366 rdev->wiphy.dev.class = &ieee80211_class;
363 rdev->wiphy.dev.platform_data = rdev; 367 rdev->wiphy.dev.platform_data = rdev;
@@ -672,9 +676,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
672 wdev->netdev = dev; 676 wdev->netdev = dev;
673 wdev->sme_state = CFG80211_SME_IDLE; 677 wdev->sme_state = CFG80211_SME_IDLE;
674 mutex_unlock(&rdev->devlist_mtx); 678 mutex_unlock(&rdev->devlist_mtx);
675#ifdef CONFIG_WIRELESS_EXT 679#ifdef CONFIG_CFG80211_WEXT
676 if (!dev->wireless_handlers)
677 dev->wireless_handlers = &cfg80211_wext_handler;
678 wdev->wext.default_key = -1; 680 wdev->wext.default_key = -1;
679 wdev->wext.default_mgmt_key = -1; 681 wdev->wext.default_mgmt_key = -1;
680 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; 682 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
@@ -696,7 +698,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
696 break; 698 break;
697 case NL80211_IFTYPE_STATION: 699 case NL80211_IFTYPE_STATION:
698 wdev_lock(wdev); 700 wdev_lock(wdev);
699#ifdef CONFIG_WIRELESS_EXT 701#ifdef CONFIG_CFG80211_WEXT
700 kfree(wdev->wext.ie); 702 kfree(wdev->wext.ie);
701 wdev->wext.ie = NULL; 703 wdev->wext.ie = NULL;
702 wdev->wext.ie_len = 0; 704 wdev->wext.ie_len = 0;
@@ -728,7 +730,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
728 mutex_unlock(&rdev->devlist_mtx); 730 mutex_unlock(&rdev->devlist_mtx);
729 dev_put(dev); 731 dev_put(dev);
730 } 732 }
731#ifdef CONFIG_WIRELESS_EXT 733#ifdef CONFIG_CFG80211_WEXT
732 cfg80211_lock_rdev(rdev); 734 cfg80211_lock_rdev(rdev);
733 mutex_lock(&rdev->devlist_mtx); 735 mutex_lock(&rdev->devlist_mtx);
734 wdev_lock(wdev); 736 wdev_lock(wdev);
@@ -766,7 +768,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
766 sysfs_remove_link(&dev->dev.kobj, "phy80211"); 768 sysfs_remove_link(&dev->dev.kobj, "phy80211");
767 list_del_init(&wdev->list); 769 list_del_init(&wdev->list);
768 rdev->devlist_generation++; 770 rdev->devlist_generation++;
769#ifdef CONFIG_WIRELESS_EXT 771#ifdef CONFIG_CFG80211_WEXT
770 kfree(wdev->wext.keys); 772 kfree(wdev->wext.keys);
771#endif 773#endif
772 } 774 }
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index c8833891197..39b6d92e282 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);
@@ -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
@@ -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 79d2eec54ce..ceb2c14c8f4 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -331,7 +331,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
331{ 331{
332 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; 332 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
333 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 333 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
334#ifdef CONFIG_WIRELESS_EXT 334#ifdef CONFIG_CFG80211_WEXT
335 union iwreq_data wrqu; 335 union iwreq_data wrqu;
336 char *buf = kmalloc(128, gfp); 336 char *buf = kmalloc(128, gfp);
337 337
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e0ecc9f153d..14004e2ebd6 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1264,7 +1264,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
1264 if (!err) 1264 if (!err)
1265 err = func(&rdev->wiphy, dev, key.idx); 1265 err = func(&rdev->wiphy, dev, key.idx);
1266 1266
1267#ifdef CONFIG_WIRELESS_EXT 1267#ifdef CONFIG_CFG80211_WEXT
1268 if (!err) { 1268 if (!err) {
1269 if (func == rdev->ops->set_default_key) 1269 if (func == rdev->ops->set_default_key)
1270 dev->ieee80211_ptr->wext.default_key = key.idx; 1270 dev->ieee80211_ptr->wext.default_key = key.idx;
@@ -1365,7 +1365,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
1365 if (!err) 1365 if (!err)
1366 err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); 1366 err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
1367 1367
1368#ifdef CONFIG_WIRELESS_EXT 1368#ifdef CONFIG_CFG80211_WEXT
1369 if (!err) { 1369 if (!err) {
1370 if (key.idx == dev->ieee80211_ptr->wext.default_key) 1370 if (key.idx == dev->ieee80211_ptr->wext.default_key)
1371 dev->ieee80211_ptr->wext.default_key = -1; 1371 dev->ieee80211_ptr->wext.default_key = -1;
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index e5f92ee758f..2e8c515f3c5 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
@@ -592,7 +592,7 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
592} 592}
593EXPORT_SYMBOL(cfg80211_unlink_bss); 593EXPORT_SYMBOL(cfg80211_unlink_bss);
594 594
595#ifdef CONFIG_WIRELESS_EXT 595#ifdef CONFIG_CFG80211_WEXT
596int cfg80211_wext_siwscan(struct net_device *dev, 596int cfg80211_wext_siwscan(struct net_device *dev,
597 struct iw_request_info *info, 597 struct iw_request_info *info,
598 union iwreq_data *wrqu, char *extra) 598 union iwreq_data *wrqu, char *extra)
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 93c3ed32920..d3624152f7f 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -345,7 +345,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
345{ 345{
346 struct wireless_dev *wdev = dev->ieee80211_ptr; 346 struct wireless_dev *wdev = dev->ieee80211_ptr;
347 u8 *country_ie; 347 u8 *country_ie;
348#ifdef CONFIG_WIRELESS_EXT 348#ifdef CONFIG_CFG80211_WEXT
349 union iwreq_data wrqu; 349 union iwreq_data wrqu;
350#endif 350#endif
351 351
@@ -362,7 +362,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
362 resp_ie, resp_ie_len, 362 resp_ie, resp_ie_len,
363 status, GFP_KERNEL); 363 status, GFP_KERNEL);
364 364
365#ifdef CONFIG_WIRELESS_EXT 365#ifdef CONFIG_CFG80211_WEXT
366 if (wextev) { 366 if (wextev) {
367 if (req_ie && status == WLAN_STATUS_SUCCESS) { 367 if (req_ie && status == WLAN_STATUS_SUCCESS) {
368 memset(&wrqu, 0, sizeof(wrqu)); 368 memset(&wrqu, 0, sizeof(wrqu));
@@ -477,7 +477,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
477 const u8 *resp_ie, size_t resp_ie_len) 477 const u8 *resp_ie, size_t resp_ie_len)
478{ 478{
479 struct cfg80211_bss *bss; 479 struct cfg80211_bss *bss;
480#ifdef CONFIG_WIRELESS_EXT 480#ifdef CONFIG_CFG80211_WEXT
481 union iwreq_data wrqu; 481 union iwreq_data wrqu;
482#endif 482#endif
483 483
@@ -512,7 +512,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
512 req_ie, req_ie_len, resp_ie, resp_ie_len, 512 req_ie, req_ie_len, resp_ie, resp_ie_len,
513 GFP_KERNEL); 513 GFP_KERNEL);
514 514
515#ifdef CONFIG_WIRELESS_EXT 515#ifdef CONFIG_CFG80211_WEXT
516 if (req_ie) { 516 if (req_ie) {
517 memset(&wrqu, 0, sizeof(wrqu)); 517 memset(&wrqu, 0, sizeof(wrqu));
518 wrqu.data.length = req_ie_len; 518 wrqu.data.length = req_ie_len;
@@ -573,7 +573,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
573 struct wireless_dev *wdev = dev->ieee80211_ptr; 573 struct wireless_dev *wdev = dev->ieee80211_ptr;
574 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 574 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
575 int i; 575 int i;
576#ifdef CONFIG_WIRELESS_EXT 576#ifdef CONFIG_CFG80211_WEXT
577 union iwreq_data wrqu; 577 union iwreq_data wrqu;
578#endif 578#endif
579 579
@@ -631,7 +631,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
631 for (i = 0; i < 6; i++) 631 for (i = 0; i < 6; i++)
632 rdev->ops->del_key(wdev->wiphy, dev, i, NULL); 632 rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
633 633
634#ifdef CONFIG_WIRELESS_EXT 634#ifdef CONFIG_CFG80211_WEXT
635 memset(&wrqu, 0, sizeof(wrqu)); 635 memset(&wrqu, 0, sizeof(wrqu));
636 wrqu.ap_addr.sa_family = ARPHRD_ETHER; 636 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
637 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); 637 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
diff --git a/net/wireless/wext.c b/net/wireless/wext-core.c
index 60fe57761ca..a4e5ddc8d4f 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,
@@ -893,188 +820,39 @@ out:
893} 820}
894 821
895/* 822/*
896 * Wrapper to call a standard Wireless Extension handler. 823 * Call the commit handler in the driver
897 * We do various checks and also take care of moving data between 824 * (if exist and if conditions are right)
898 * user space and kernel space. 825 *
899 */ 826 * Note : our current commit strategy is currently pretty dumb,
900static int ioctl_standard_call(struct net_device * dev, 827 * but we will be able to improve on that...
901 struct iwreq *iwr, 828 * The goal is to try to agreagate as many changes as possible
902 unsigned int cmd, 829 * before doing the commit. Drivers that will define a commit handler
903 struct iw_request_info *info, 830 * are usually those that need a reset after changing parameters, so
904 iw_handler handler) 831 * we want to minimise the number of reset.
905{ 832 * A cool idea is to use a timer : at each "set" command, we re-set the
906 const struct iw_ioctl_description * descr; 833 * timer, when the timer eventually fires, we call the driver.
907 int ret = -EINVAL; 834 * 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 * 835 *
947 * IMPORTANT : This function prevent to set and get data on the same 836 * 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 837 * netif_running(dev) test. I'm open on that one...
949 * far too hairy... 838 * 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 */ 839 */
954static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd, 840int 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{ 841{
1052 int extra_size = 0, ret = -EINVAL; 842#ifdef CONFIG_WIRELESS_EXT
1053 const struct iw_priv_args *descr; 843 if ((netif_running(dev)) &&
1054 844 (dev->wireless_handlers->standard[0] != NULL))
1055 extra_size = get_priv_descr_and_size(dev, cmd, &descr); 845 /* Call the commit handler on the driver */
1056 846 return dev->wireless_handlers->standard[0](dev, NULL,
1057 /* Check if we have a pointer to user space data or not. */ 847 NULL, NULL);
1058 if (extra_size == 0) { 848 else
1059 /* No extra arguments. Trivial to handle */ 849 return 0; /* Command completed successfully */
1060 ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); 850#else
1061 } else { 851 /* cfg80211 has no commit */
1062 ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr, 852 return 0;
1063 handler, dev, info, extra_size); 853#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} 854}
1072 855
1073/* ---------------------------------------------------------------- */
1074typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
1075 unsigned int, struct iw_request_info *,
1076 iw_handler);
1077
1078/* 856/*
1079 * Main IOCTl dispatcher. 857 * Main IOCTl dispatcher.
1080 * Check the type of IOCTL and call the appropriate wrapper... 858 * Check the type of IOCTL and call the appropriate wrapper...
@@ -1103,9 +881,11 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
1103 return standard(dev, iwr, cmd, info, 881 return standard(dev, iwr, cmd, info,
1104 &iw_handler_get_iwstats); 882 &iw_handler_get_iwstats);
1105 883
884#ifdef CONFIG_WEXT_PRIV
1106 if (cmd == SIOCGIWPRIV && dev->wireless_handlers) 885 if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
1107 return standard(dev, iwr, cmd, info, 886 return standard(dev, iwr, cmd, info,
1108 &iw_handler_get_private); 887 iw_handler_get_private);
888#endif
1109 889
1110 /* Basic check */ 890 /* Basic check */
1111 if (!netif_device_present(dev)) 891 if (!netif_device_present(dev))
@@ -1117,7 +897,7 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
1117 /* Standard and private are not the same */ 897 /* Standard and private are not the same */
1118 if (cmd < SIOCIWFIRSTPRIV) 898 if (cmd < SIOCIWFIRSTPRIV)
1119 return standard(dev, iwr, cmd, info, handler); 899 return standard(dev, iwr, cmd, info, handler);
1120 else 900 else if (private)
1121 return private(dev, iwr, cmd, info, handler); 901 return private(dev, iwr, cmd, info, handler);
1122 } 902 }
1123 /* Old driver API : call driver ioctl handler */ 903 /* Old driver API : call driver ioctl handler */
@@ -1157,6 +937,50 @@ static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
1157 return ret; 937 return ret;
1158} 938}
1159 939
940/*
941 * Wrapper to call a standard Wireless Extension handler.
942 * We do various checks and also take care of moving data between
943 * user space and kernel space.
944 */
945static int ioctl_standard_call(struct net_device * dev,
946 struct iwreq *iwr,
947 unsigned int cmd,
948 struct iw_request_info *info,
949 iw_handler handler)
950{
951 const struct iw_ioctl_description * descr;
952 int ret = -EINVAL;
953
954 /* Get the description of the IOCTL */
955 if ((cmd - SIOCIWFIRST) >= standard_ioctl_num)
956 return -EOPNOTSUPP;
957 descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
958
959 /* Check if we have a pointer to user space data or not */
960 if (descr->header_type != IW_HEADER_TYPE_POINT) {
961
962 /* No extra arguments. Trivial to handle */
963 ret = handler(dev, info, &(iwr->u), NULL);
964
965 /* Generate an event to notify listeners of the change */
966 if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
967 ((ret == 0) || (ret == -EIWCOMMIT)))
968 wireless_send_event(dev, cmd, &(iwr->u), NULL);
969 } else {
970 ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr,
971 handler, dev, info);
972 }
973
974 /* Call commit handler if needed and defined */
975 if (ret == -EIWCOMMIT)
976 ret = call_commit_handler(dev);
977
978 /* Here, we will generate the appropriate event if needed */
979
980 return ret;
981}
982
983
1160int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, 984int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
1161 void __user *arg) 985 void __user *arg)
1162{ 986{
@@ -1205,43 +1029,6 @@ static int compat_standard_call(struct net_device *dev,
1205 return err; 1029 return err;
1206} 1030}
1207 1031
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, 1032int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
1246 unsigned long arg) 1033 unsigned long arg)
1247{ 1034{
@@ -1274,502 +1061,3 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
1274 return ret; 1061 return ret;
1275} 1062}
1276#endif 1063#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 00000000000..a3c2277de9e
--- /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 00000000000..273a7f77c83
--- /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 00000000000..6dcfe65a2d1
--- /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);