Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

wext: refactor

Refactor wext to
* split out iwpriv handling
* split out iwspy handling
* split out procfs support
* allow cfg80211 to have wireless extensions compat code
w/o CONFIG_WIRELESS_EXT

After this, drivers need to
- select WIRELESS_EXT - for wext support
- select WEXT_PRIV - for iwpriv support
- select WEXT_SPY - for iwspy support

except cfg80211 -- which gets new hooks in wext-core.c
and can then get wext handlers without CONFIG_WIRELESS_EXT.

Wireless extensions procfs support is auto-selected
based on PROC_FS and anything that requires the wext core
(i.e. WIRELESS_EXT or CFG80211_WEXT).

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Johannes Berg and committed by
John W. Linville
3d23e349 bc974f4a

+1850 -1847
+22 -7
drivers/net/wireless/Kconfig
··· 67 67 tristate "AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support" 68 68 depends on ISA && WLAN_PRE80211 69 69 select WIRELESS_EXT 70 + select WEXT_SPY 71 + select WEXT_PRIV 70 72 ---help--- 71 73 The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is 72 74 a Radio LAN (wireless Ethernet-like Local Area Network) using the ··· 92 90 tristate "AT&T/Lucent old WaveLAN Pcmcia wireless support" 93 91 depends on PCMCIA && WLAN_PRE80211 94 92 select WIRELESS_EXT 93 + select WEXT_SPY 94 + select WEXT_PRIV 95 95 help 96 96 Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA 97 97 (PC-card) wireless Ethernet networking card to your computer. This ··· 106 102 tristate "Xircom Netwave AirSurfer Pcmcia wireless support" 107 103 depends on PCMCIA && WLAN_PRE80211 108 104 select WIRELESS_EXT 105 + select WEXT_PRIV 109 106 help 110 107 Say Y here if you intend to attach this type of PCMCIA (PC-card) 111 108 wireless Ethernet networking card to your computer. ··· 128 123 tristate "Aviator/Raytheon 2.4GHz wireless support" 129 124 depends on PCMCIA && WLAN_80211 130 125 select WIRELESS_EXT 126 + select WEXT_SPY 127 + select WEXT_PRIV 131 128 ---help--- 132 129 Say Y here if you intend to attach an Aviator/Raytheon PCMCIA 133 130 (PC-card) wireless Ethernet networking card to your computer. ··· 143 136 tristate "Marvell 8xxx Libertas WLAN driver support" 144 137 depends on WLAN_80211 145 138 select WIRELESS_EXT 139 + select WEXT_SPY 146 140 select LIB80211 147 141 select FW_LOADER 148 142 ---help--- ··· 198 190 depends on ISA_DMA_API && WLAN_80211 && (PCI || BROKEN) 199 191 select WIRELESS_EXT 200 192 select CRYPTO 193 + select WEXT_SPY 194 + select WEXT_PRIV 201 195 ---help--- 202 196 This is the standard Linux driver to support Cisco/Aironet ISA and 203 197 PCI 802.11 wireless cards. ··· 217 207 tristate "Atmel at76c50x chipset 802.11b support" 218 208 depends on (PCI || PCMCIA) && WLAN_80211 219 209 select WIRELESS_EXT 210 + select WEXT_PRIV 220 211 select FW_LOADER 221 212 select CRC32 222 213 ---help--- ··· 277 266 Cisco Linux utilities can be used to configure the card. 278 267 279 268 config PCMCIA_WL3501 280 - tristate "Planet WL3501 PCMCIA cards" 281 - depends on EXPERIMENTAL && PCMCIA && WLAN_80211 282 - select WIRELESS_EXT 283 - ---help--- 284 - A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet. 285 - It has basic support for Linux wireless extensions and initial 286 - micro support for ethtool. 269 + tristate "Planet WL3501 PCMCIA cards" 270 + depends on EXPERIMENTAL && PCMCIA && WLAN_80211 271 + select WIRELESS_EXT 272 + select WEXT_SPY 273 + help 274 + A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet. 275 + It has basic support for Linux wireless extensions and initial 276 + micro support for ethtool. 287 277 288 278 config PRISM54 289 279 tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)' 290 280 depends on PCI && EXPERIMENTAL && WLAN_80211 291 281 select WIRELESS_EXT 282 + select WEXT_SPY 283 + select WEXT_PRIV 292 284 select FW_LOADER 293 285 ---help--- 294 286 This enables support for FullMAC PCI/Cardbus prism54 devices. This ··· 314 300 tristate "USB ZD1201 based Wireless device support" 315 301 depends on USB && WLAN_80211 316 302 select WIRELESS_EXT 303 + select WEXT_PRIV 317 304 select FW_LOADER 318 305 ---help--- 319 306 Say Y if you want to use wireless LAN adapters based on the ZyDAS
+2
drivers/net/wireless/hostap/Kconfig
··· 2 2 tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" 3 3 depends on WLAN_80211 4 4 select WIRELESS_EXT 5 + select WEXT_SPY 6 + select WEXT_PRIV 5 7 select CRYPTO 6 8 select CRYPTO_ARC4 7 9 select CRYPTO_ECB
+5
drivers/net/wireless/ipw2x00/Kconfig
··· 6 6 tristate "Intel PRO/Wireless 2100 Network Connection" 7 7 depends on PCI && WLAN_80211 && CFG80211 8 8 select WIRELESS_EXT 9 + select WEXT_SPY 10 + select WEXT_PRIV 9 11 select FW_LOADER 10 12 select LIB80211 11 13 select LIBIPW ··· 67 65 tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" 68 66 depends on PCI && WLAN_80211 && CFG80211 69 67 select WIRELESS_EXT 68 + select WEXT_SPY 69 + select WEXT_PRIV 70 70 select FW_LOADER 71 71 select LIB80211 72 72 select LIBIPW ··· 156 152 tristate 157 153 depends on PCI && WLAN_80211 && CFG80211 158 154 select WIRELESS_EXT 155 + select WEXT_SPY 159 156 select CRYPTO 160 157 select CRYPTO_ARC4 161 158 select CRYPTO_ECB
+2
drivers/net/wireless/orinoco/Kconfig
··· 3 3 depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211 4 4 depends on CFG80211 5 5 select WIRELESS_EXT 6 + select WEXT_SPY 7 + select WEXT_PRIV 6 8 select FW_LOADER 7 9 select CRYPTO 8 10 select CRYPTO_MICHAEL_MIC
+5 -1
include/net/cfg80211.h
··· 1171 1171 struct net *_net; 1172 1172 #endif 1173 1173 1174 + #ifdef CONFIG_CFG80211_WEXT 1175 + const struct iw_handler_def *wext; 1176 + #endif 1177 + 1174 1178 char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); 1175 1179 }; 1176 1180 ··· 1349 1345 struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES]; 1350 1346 struct cfg80211_internal_bss *current_bss; /* associated / joined */ 1351 1347 1352 - #ifdef CONFIG_WIRELESS_EXT 1348 + #ifdef CONFIG_CFG80211_WEXT 1353 1349 /* wext data */ 1354 1350 struct { 1355 1351 struct cfg80211_ibss_params ibss;
+8 -6
include/net/iw_handler.h
··· 323 323 */ 324 324 struct iw_handler_def 325 325 { 326 - /* Number of handlers defined (more precisely, index of the 327 - * last defined handler + 1) */ 328 - __u16 num_standard; 329 - __u16 num_private; 330 - /* Number of private arg description */ 331 - __u16 num_private_args; 332 326 333 327 /* Array of handlers for standard ioctls 334 328 * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWCOMMIT] 335 329 */ 336 330 const iw_handler * standard; 331 + /* Number of handlers defined (more precisely, index of the 332 + * last defined handler + 1) */ 333 + __u16 num_standard; 337 334 335 + #ifdef CONFIG_WEXT_PRIV 336 + __u16 num_private; 337 + /* Number of private arg description */ 338 + __u16 num_private_args; 338 339 /* Array of handlers for private ioctls 339 340 * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV] 340 341 */ ··· 345 344 * can put it in any order you want and should not leave holes... 346 345 * We will automatically export that to user space... */ 347 346 const struct iw_priv_args * private_args; 347 + #endif 348 348 349 349 /* New location of get_wireless_stats, to de-bloat struct net_device. 350 350 * The old pointer in struct net_device will be gradually phased
+1 -1
include/net/net_namespace.h
··· 80 80 #ifdef CONFIG_XFRM 81 81 struct netns_xfrm xfrm; 82 82 #endif 83 - #ifdef CONFIG_WIRELESS_EXT 83 + #ifdef CONFIG_WEXT_CORE 84 84 struct sk_buff_head wext_nlevents; 85 85 #endif 86 86 struct net_generic *gen;
+35 -14
include/net/wext.h
··· 1 1 #ifndef __NET_WEXT_H 2 2 #define __NET_WEXT_H 3 3 4 - /* 5 - * wireless extensions interface to the core code 6 - */ 4 + #include <net/iw_handler.h> 7 5 8 6 struct net; 9 7 10 - #ifdef CONFIG_WIRELESS_EXT 11 - extern int wext_proc_init(struct net *net); 12 - extern void wext_proc_exit(struct net *net); 8 + #ifdef CONFIG_WEXT_CORE 13 9 extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, 14 10 void __user *arg); 15 11 extern int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, 16 12 unsigned long arg); 13 + 17 14 extern struct iw_statistics *get_wireless_stats(struct net_device *dev); 15 + extern int call_commit_handler(struct net_device *dev); 18 16 #else 19 - static inline int wext_proc_init(struct net *net) 20 - { 21 - return 0; 22 - } 23 - static inline void wext_proc_exit(struct net *net) 24 - { 25 - return; 26 - } 27 17 static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, 28 18 void __user *arg) 29 19 { ··· 25 35 return -EINVAL; 26 36 } 27 37 #endif 38 + 39 + #ifdef CONFIG_WEXT_PROC 40 + extern int wext_proc_init(struct net *net); 41 + extern void wext_proc_exit(struct net *net); 42 + #else 43 + static inline int wext_proc_init(struct net *net) 44 + { 45 + return 0; 46 + } 47 + static inline void wext_proc_exit(struct net *net) 48 + { 49 + return; 50 + } 51 + #endif 52 + 53 + #ifdef CONFIG_WEXT_PRIV 54 + int ioctl_private_call(struct net_device *dev, struct iwreq *iwr, 55 + unsigned int cmd, struct iw_request_info *info, 56 + iw_handler handler); 57 + int compat_private_call(struct net_device *dev, struct iwreq *iwr, 58 + unsigned int cmd, struct iw_request_info *info, 59 + iw_handler handler); 60 + int iw_handler_get_private(struct net_device * dev, 61 + struct iw_request_info * info, 62 + union iwreq_data * wrqu, 63 + char * extra); 64 + #else 65 + #define ioctl_private_call NULL 66 + #define compat_private_call NULL 67 + #endif 68 + 28 69 29 70 #endif /* __NET_WEXT_H */
+5 -1
net/core/net-sysfs.c
··· 543 543 *groups++ = &netstat_group; 544 544 545 545 #ifdef CONFIG_WIRELESS_EXT_SYSFS 546 - if (net->wireless_handlers || net->ieee80211_ptr) 546 + if (net->ieee80211_ptr) 547 547 *groups++ = &wireless_group; 548 + #ifdef CONFIG_WIRELESS_EXT 549 + else if (net->wireless_handlers) 550 + *groups++ = &wireless_group; 551 + #endif 548 552 #endif 549 553 #endif /* CONFIG_SYSFS */ 550 554
+2 -2
net/socket.c
··· 905 905 if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { 906 906 err = dev_ioctl(net, cmd, argp); 907 907 } else 908 - #ifdef CONFIG_WIRELESS_EXT 908 + #ifdef CONFIG_WEXT_CORE 909 909 if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { 910 910 err = dev_ioctl(net, cmd, argp); 911 911 } else 912 - #endif /* CONFIG_WIRELESS_EXT */ 912 + #endif 913 913 switch (cmd) { 914 914 case FIOSETOWN: 915 915 case SIOCSPGRP:
+35 -15
net/wireless/Kconfig
··· 1 + config WIRELESS_EXT 2 + bool 3 + 4 + config WEXT_CORE 5 + def_bool y 6 + depends on CFG80211_WEXT || WIRELESS_EXT 7 + 8 + config WEXT_PROC 9 + def_bool y 10 + depends on PROC_FS 11 + depends on WEXT_CORE 12 + 13 + config WEXT_SPY 14 + bool 15 + 16 + config WEXT_PRIV 17 + bool 18 + 1 19 config CFG80211 2 20 tristate "cfg80211 - wireless configuration API" 3 21 depends on RFKILL || !RFKILL ··· 74 56 75 57 If unsure, say N. 76 58 59 + config CFG80211_DEFAULT_PS_VALUE 60 + int 61 + default 1 if CFG80211_DEFAULT_PS 62 + default 0 63 + depends on CFG80211 64 + 77 65 config CFG80211_DEFAULT_PS 78 66 bool "enable powersave by default" 79 67 depends on CFG80211 ··· 91 67 applications instead -- they need to register their network 92 68 latency requirement, see Documentation/power/pm_qos_interface.txt. 93 69 94 - config CFG80211_DEFAULT_PS_VALUE 95 - int 96 - default 1 if CFG80211_DEFAULT_PS 97 - default 0 98 - 99 70 config CFG80211_DEBUGFS 100 71 bool "cfg80211 DebugFS entries" 101 - depends on CFG80211 && DEBUG_FS 72 + depends on CFG80211 73 + depends on DEBUG_FS 102 74 ---help--- 103 75 You can enable this if you want to debugfs entries for cfg80211. 104 76 ··· 103 83 config WIRELESS_OLD_REGULATORY 104 84 bool "Old wireless static regulatory definitions" 105 85 default n 86 + depends on CFG80211 106 87 ---help--- 107 88 This option enables the old static regulatory information 108 89 and uses it within the new framework. This option is available ··· 115 94 116 95 Say N and if you say Y, please tell us why. The default is N. 117 96 118 - config WIRELESS_EXT 119 - bool "Wireless extensions" 97 + config CFG80211_WEXT 98 + bool "cfg80211 wireless extensions compatibility" 99 + depends on CFG80211 100 + select WEXT_CORE 120 101 default y 121 - ---help--- 122 - This option enables the legacy wireless extensions 123 - (wireless network interface configuration via ioctls.) 124 - 125 - Say Y unless you've upgraded all your userspace to use 126 - nl80211 instead of wireless extensions. 102 + help 103 + Enable this option if you need old userspace for wireless 104 + extensions with cfg80211-based drivers. 127 105 128 106 config WIRELESS_EXT_SYSFS 129 107 bool "Wireless extensions sysfs files" 130 108 default y 131 - depends on WIRELESS_EXT && SYSFS 109 + depends on WEXT_CORE && SYSFS 132 110 help 133 111 This option enables the deprecated wireless statistics 134 112 files in /sys/class/net/*/wireless/. The same information
+6 -2
net/wireless/Makefile
··· 1 - obj-$(CONFIG_WIRELESS_EXT) += wext.o 2 1 obj-$(CONFIG_CFG80211) += cfg80211.o 3 2 obj-$(CONFIG_LIB80211) += lib80211.o 4 3 obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o 5 4 obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o 6 5 obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o 7 6 7 + obj-$(CONFIG_WEXT_CORE) += wext-core.o 8 + obj-$(CONFIG_WEXT_PROC) += wext-proc.o 9 + obj-$(CONFIG_WEXT_SPY) += wext-spy.o 10 + obj-$(CONFIG_WEXT_PRIV) += wext-priv.o 11 + 8 12 cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o 9 13 cfg80211-y += mlme.o ibss.o sme.o chan.o 10 14 cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o 11 - cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o 15 + cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o 12 16 13 17 ccflags-y += -D__CHECK_ENDIAN__
+8 -6
net/wireless/core.c
··· 358 358 INIT_LIST_HEAD(&rdev->bss_list); 359 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 365 device_initialize(&rdev->wiphy.dev); 362 366 rdev->wiphy.dev.class = &ieee80211_class; 363 367 rdev->wiphy.dev.platform_data = rdev; ··· 676 672 wdev->netdev = dev; 677 673 wdev->sme_state = CFG80211_SME_IDLE; 678 674 mutex_unlock(&rdev->devlist_mtx); 679 - #ifdef CONFIG_WIRELESS_EXT 680 - if (!dev->wireless_handlers) 681 - dev->wireless_handlers = &cfg80211_wext_handler; 675 + #ifdef CONFIG_CFG80211_WEXT 682 676 wdev->wext.default_key = -1; 683 677 wdev->wext.default_mgmt_key = -1; 684 678 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; ··· 698 696 break; 699 697 case NL80211_IFTYPE_STATION: 700 698 wdev_lock(wdev); 701 - #ifdef CONFIG_WIRELESS_EXT 699 + #ifdef CONFIG_CFG80211_WEXT 702 700 kfree(wdev->wext.ie); 703 701 wdev->wext.ie = NULL; 704 702 wdev->wext.ie_len = 0; ··· 730 728 mutex_unlock(&rdev->devlist_mtx); 731 729 dev_put(dev); 732 730 } 733 - #ifdef CONFIG_WIRELESS_EXT 731 + #ifdef CONFIG_CFG80211_WEXT 734 732 cfg80211_lock_rdev(rdev); 735 733 mutex_lock(&rdev->devlist_mtx); 736 734 wdev_lock(wdev); ··· 768 766 sysfs_remove_link(&dev->dev.kobj, "phy80211"); 769 767 list_del_init(&wdev->list); 770 768 rdev->devlist_generation++; 771 - #ifdef CONFIG_WIRELESS_EXT 769 + #ifdef CONFIG_CFG80211_WEXT 772 770 kfree(wdev->wext.keys); 773 771 #endif 774 772 }
+5 -5
net/wireless/ibss.c
··· 15 15 { 16 16 struct wireless_dev *wdev = dev->ieee80211_ptr; 17 17 struct cfg80211_bss *bss; 18 - #ifdef CONFIG_WIRELESS_EXT 18 + #ifdef CONFIG_CFG80211_WEXT 19 19 union iwreq_data wrqu; 20 20 #endif 21 21 ··· 44 44 45 45 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, 46 46 GFP_KERNEL); 47 - #ifdef CONFIG_WIRELESS_EXT 47 + #ifdef CONFIG_CFG80211_WEXT 48 48 memset(&wrqu, 0, sizeof(wrqu)); 49 49 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); 50 50 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); ··· 96 96 kfree(wdev->connect_keys); 97 97 wdev->connect_keys = connkeys; 98 98 99 - #ifdef CONFIG_WIRELESS_EXT 99 + #ifdef CONFIG_CFG80211_WEXT 100 100 wdev->wext.ibss.channel = params->channel; 101 101 #endif 102 102 err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); ··· 154 154 155 155 wdev->current_bss = NULL; 156 156 wdev->ssid_len = 0; 157 - #ifdef CONFIG_WIRELESS_EXT 157 + #ifdef CONFIG_CFG80211_WEXT 158 158 if (!nowext) 159 159 wdev->wext.ibss.ssid_len = 0; 160 160 #endif ··· 203 203 return err; 204 204 } 205 205 206 - #ifdef CONFIG_WIRELESS_EXT 206 + #ifdef CONFIG_CFG80211_WEXT 207 207 int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, 208 208 struct wireless_dev *wdev) 209 209 {
+1 -1
net/wireless/mlme.c
··· 331 331 { 332 332 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; 333 333 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 334 - #ifdef CONFIG_WIRELESS_EXT 334 + #ifdef CONFIG_CFG80211_WEXT 335 335 union iwreq_data wrqu; 336 336 char *buf = kmalloc(128, gfp); 337 337
+2 -2
net/wireless/nl80211.c
··· 1264 1264 if (!err) 1265 1265 err = func(&rdev->wiphy, dev, key.idx); 1266 1266 1267 - #ifdef CONFIG_WIRELESS_EXT 1267 + #ifdef CONFIG_CFG80211_WEXT 1268 1268 if (!err) { 1269 1269 if (func == rdev->ops->set_default_key) 1270 1270 dev->ieee80211_ptr->wext.default_key = key.idx; ··· 1365 1365 if (!err) 1366 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 1369 if (!err) { 1370 1370 if (key.idx == dev->ieee80211_ptr->wext.default_key) 1371 1371 dev->ieee80211_ptr->wext.default_key = -1;
+3 -3
net/wireless/scan.c
··· 22 22 { 23 23 struct cfg80211_scan_request *request; 24 24 struct net_device *dev; 25 - #ifdef CONFIG_WIRELESS_EXT 25 + #ifdef CONFIG_CFG80211_WEXT 26 26 union iwreq_data wrqu; 27 27 #endif 28 28 ··· 47 47 else 48 48 nl80211_send_scan_done(rdev, dev); 49 49 50 - #ifdef CONFIG_WIRELESS_EXT 50 + #ifdef CONFIG_CFG80211_WEXT 51 51 if (!request->aborted) { 52 52 memset(&wrqu, 0, sizeof(wrqu)); 53 53 ··· 592 592 } 593 593 EXPORT_SYMBOL(cfg80211_unlink_bss); 594 594 595 - #ifdef CONFIG_WIRELESS_EXT 595 + #ifdef CONFIG_CFG80211_WEXT 596 596 int cfg80211_wext_siwscan(struct net_device *dev, 597 597 struct iw_request_info *info, 598 598 union iwreq_data *wrqu, char *extra)
+6 -6
net/wireless/sme.c
··· 345 345 { 346 346 struct wireless_dev *wdev = dev->ieee80211_ptr; 347 347 u8 *country_ie; 348 - #ifdef CONFIG_WIRELESS_EXT 348 + #ifdef CONFIG_CFG80211_WEXT 349 349 union iwreq_data wrqu; 350 350 #endif 351 351 ··· 362 362 resp_ie, resp_ie_len, 363 363 status, GFP_KERNEL); 364 364 365 - #ifdef CONFIG_WIRELESS_EXT 365 + #ifdef CONFIG_CFG80211_WEXT 366 366 if (wextev) { 367 367 if (req_ie && status == WLAN_STATUS_SUCCESS) { 368 368 memset(&wrqu, 0, sizeof(wrqu)); ··· 477 477 const u8 *resp_ie, size_t resp_ie_len) 478 478 { 479 479 struct cfg80211_bss *bss; 480 - #ifdef CONFIG_WIRELESS_EXT 480 + #ifdef CONFIG_CFG80211_WEXT 481 481 union iwreq_data wrqu; 482 482 #endif 483 483 ··· 512 512 req_ie, req_ie_len, resp_ie, resp_ie_len, 513 513 GFP_KERNEL); 514 514 515 - #ifdef CONFIG_WIRELESS_EXT 515 + #ifdef CONFIG_CFG80211_WEXT 516 516 if (req_ie) { 517 517 memset(&wrqu, 0, sizeof(wrqu)); 518 518 wrqu.data.length = req_ie_len; ··· 573 573 struct wireless_dev *wdev = dev->ieee80211_ptr; 574 574 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 575 575 int i; 576 - #ifdef CONFIG_WIRELESS_EXT 576 + #ifdef CONFIG_CFG80211_WEXT 577 577 union iwreq_data wrqu; 578 578 #endif 579 579 ··· 631 631 for (i = 0; i < 6; i++) 632 632 rdev->ops->del_key(wdev->wiphy, dev, i, NULL); 633 633 634 - #ifdef CONFIG_WIRELESS_EXT 634 + #ifdef CONFIG_CFG80211_WEXT 635 635 memset(&wrqu, 0, sizeof(wrqu)); 636 636 wrqu.ap_addr.sa_family = ARPHRD_ETHER; 637 637 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+1063
net/wireless/wext-core.c
··· 1 + /* 2 + * This file implement the Wireless Extensions core 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/kernel.h> 11 + #include <linux/netdevice.h> 12 + #include <linux/rtnetlink.h> 13 + #include <linux/wireless.h> 14 + #include <linux/uaccess.h> 15 + #include <net/cfg80211.h> 16 + #include <net/iw_handler.h> 17 + #include <net/netlink.h> 18 + #include <net/wext.h> 19 + #include <net/net_namespace.h> 20 + 21 + typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *, 22 + unsigned int, struct iw_request_info *, 23 + iw_handler); 24 + 25 + 26 + /* 27 + * Meta-data about all the standard Wireless Extension request we 28 + * know about. 29 + */ 30 + static const struct iw_ioctl_description standard_ioctl[] = { 31 + [SIOCSIWCOMMIT - SIOCIWFIRST] = { 32 + .header_type = IW_HEADER_TYPE_NULL, 33 + }, 34 + [SIOCGIWNAME - SIOCIWFIRST] = { 35 + .header_type = IW_HEADER_TYPE_CHAR, 36 + .flags = IW_DESCR_FLAG_DUMP, 37 + }, 38 + [SIOCSIWNWID - SIOCIWFIRST] = { 39 + .header_type = IW_HEADER_TYPE_PARAM, 40 + .flags = IW_DESCR_FLAG_EVENT, 41 + }, 42 + [SIOCGIWNWID - SIOCIWFIRST] = { 43 + .header_type = IW_HEADER_TYPE_PARAM, 44 + .flags = IW_DESCR_FLAG_DUMP, 45 + }, 46 + [SIOCSIWFREQ - SIOCIWFIRST] = { 47 + .header_type = IW_HEADER_TYPE_FREQ, 48 + .flags = IW_DESCR_FLAG_EVENT, 49 + }, 50 + [SIOCGIWFREQ - SIOCIWFIRST] = { 51 + .header_type = IW_HEADER_TYPE_FREQ, 52 + .flags = IW_DESCR_FLAG_DUMP, 53 + }, 54 + [SIOCSIWMODE - SIOCIWFIRST] = { 55 + .header_type = IW_HEADER_TYPE_UINT, 56 + .flags = IW_DESCR_FLAG_EVENT, 57 + }, 58 + [SIOCGIWMODE - SIOCIWFIRST] = { 59 + .header_type = IW_HEADER_TYPE_UINT, 60 + .flags = IW_DESCR_FLAG_DUMP, 61 + }, 62 + [SIOCSIWSENS - SIOCIWFIRST] = { 63 + .header_type = IW_HEADER_TYPE_PARAM, 64 + }, 65 + [SIOCGIWSENS - SIOCIWFIRST] = { 66 + .header_type = IW_HEADER_TYPE_PARAM, 67 + }, 68 + [SIOCSIWRANGE - SIOCIWFIRST] = { 69 + .header_type = IW_HEADER_TYPE_NULL, 70 + }, 71 + [SIOCGIWRANGE - SIOCIWFIRST] = { 72 + .header_type = IW_HEADER_TYPE_POINT, 73 + .token_size = 1, 74 + .max_tokens = sizeof(struct iw_range), 75 + .flags = IW_DESCR_FLAG_DUMP, 76 + }, 77 + [SIOCSIWPRIV - SIOCIWFIRST] = { 78 + .header_type = IW_HEADER_TYPE_NULL, 79 + }, 80 + [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */ 81 + .header_type = IW_HEADER_TYPE_POINT, 82 + .token_size = sizeof(struct iw_priv_args), 83 + .max_tokens = 16, 84 + .flags = IW_DESCR_FLAG_NOMAX, 85 + }, 86 + [SIOCSIWSTATS - SIOCIWFIRST] = { 87 + .header_type = IW_HEADER_TYPE_NULL, 88 + }, 89 + [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */ 90 + .header_type = IW_HEADER_TYPE_POINT, 91 + .token_size = 1, 92 + .max_tokens = sizeof(struct iw_statistics), 93 + .flags = IW_DESCR_FLAG_DUMP, 94 + }, 95 + [SIOCSIWSPY - SIOCIWFIRST] = { 96 + .header_type = IW_HEADER_TYPE_POINT, 97 + .token_size = sizeof(struct sockaddr), 98 + .max_tokens = IW_MAX_SPY, 99 + }, 100 + [SIOCGIWSPY - SIOCIWFIRST] = { 101 + .header_type = IW_HEADER_TYPE_POINT, 102 + .token_size = sizeof(struct sockaddr) + 103 + sizeof(struct iw_quality), 104 + .max_tokens = IW_MAX_SPY, 105 + }, 106 + [SIOCSIWTHRSPY - SIOCIWFIRST] = { 107 + .header_type = IW_HEADER_TYPE_POINT, 108 + .token_size = sizeof(struct iw_thrspy), 109 + .min_tokens = 1, 110 + .max_tokens = 1, 111 + }, 112 + [SIOCGIWTHRSPY - SIOCIWFIRST] = { 113 + .header_type = IW_HEADER_TYPE_POINT, 114 + .token_size = sizeof(struct iw_thrspy), 115 + .min_tokens = 1, 116 + .max_tokens = 1, 117 + }, 118 + [SIOCSIWAP - SIOCIWFIRST] = { 119 + .header_type = IW_HEADER_TYPE_ADDR, 120 + }, 121 + [SIOCGIWAP - SIOCIWFIRST] = { 122 + .header_type = IW_HEADER_TYPE_ADDR, 123 + .flags = IW_DESCR_FLAG_DUMP, 124 + }, 125 + [SIOCSIWMLME - SIOCIWFIRST] = { 126 + .header_type = IW_HEADER_TYPE_POINT, 127 + .token_size = 1, 128 + .min_tokens = sizeof(struct iw_mlme), 129 + .max_tokens = sizeof(struct iw_mlme), 130 + }, 131 + [SIOCGIWAPLIST - SIOCIWFIRST] = { 132 + .header_type = IW_HEADER_TYPE_POINT, 133 + .token_size = sizeof(struct sockaddr) + 134 + sizeof(struct iw_quality), 135 + .max_tokens = IW_MAX_AP, 136 + .flags = IW_DESCR_FLAG_NOMAX, 137 + }, 138 + [SIOCSIWSCAN - SIOCIWFIRST] = { 139 + .header_type = IW_HEADER_TYPE_POINT, 140 + .token_size = 1, 141 + .min_tokens = 0, 142 + .max_tokens = sizeof(struct iw_scan_req), 143 + }, 144 + [SIOCGIWSCAN - SIOCIWFIRST] = { 145 + .header_type = IW_HEADER_TYPE_POINT, 146 + .token_size = 1, 147 + .max_tokens = IW_SCAN_MAX_DATA, 148 + .flags = IW_DESCR_FLAG_NOMAX, 149 + }, 150 + [SIOCSIWESSID - SIOCIWFIRST] = { 151 + .header_type = IW_HEADER_TYPE_POINT, 152 + .token_size = 1, 153 + .max_tokens = IW_ESSID_MAX_SIZE, 154 + .flags = IW_DESCR_FLAG_EVENT, 155 + }, 156 + [SIOCGIWESSID - SIOCIWFIRST] = { 157 + .header_type = IW_HEADER_TYPE_POINT, 158 + .token_size = 1, 159 + .max_tokens = IW_ESSID_MAX_SIZE, 160 + .flags = IW_DESCR_FLAG_DUMP, 161 + }, 162 + [SIOCSIWNICKN - SIOCIWFIRST] = { 163 + .header_type = IW_HEADER_TYPE_POINT, 164 + .token_size = 1, 165 + .max_tokens = IW_ESSID_MAX_SIZE, 166 + }, 167 + [SIOCGIWNICKN - SIOCIWFIRST] = { 168 + .header_type = IW_HEADER_TYPE_POINT, 169 + .token_size = 1, 170 + .max_tokens = IW_ESSID_MAX_SIZE, 171 + }, 172 + [SIOCSIWRATE - SIOCIWFIRST] = { 173 + .header_type = IW_HEADER_TYPE_PARAM, 174 + }, 175 + [SIOCGIWRATE - SIOCIWFIRST] = { 176 + .header_type = IW_HEADER_TYPE_PARAM, 177 + }, 178 + [SIOCSIWRTS - SIOCIWFIRST] = { 179 + .header_type = IW_HEADER_TYPE_PARAM, 180 + }, 181 + [SIOCGIWRTS - SIOCIWFIRST] = { 182 + .header_type = IW_HEADER_TYPE_PARAM, 183 + }, 184 + [SIOCSIWFRAG - SIOCIWFIRST] = { 185 + .header_type = IW_HEADER_TYPE_PARAM, 186 + }, 187 + [SIOCGIWFRAG - SIOCIWFIRST] = { 188 + .header_type = IW_HEADER_TYPE_PARAM, 189 + }, 190 + [SIOCSIWTXPOW - SIOCIWFIRST] = { 191 + .header_type = IW_HEADER_TYPE_PARAM, 192 + }, 193 + [SIOCGIWTXPOW - SIOCIWFIRST] = { 194 + .header_type = IW_HEADER_TYPE_PARAM, 195 + }, 196 + [SIOCSIWRETRY - SIOCIWFIRST] = { 197 + .header_type = IW_HEADER_TYPE_PARAM, 198 + }, 199 + [SIOCGIWRETRY - SIOCIWFIRST] = { 200 + .header_type = IW_HEADER_TYPE_PARAM, 201 + }, 202 + [SIOCSIWENCODE - SIOCIWFIRST] = { 203 + .header_type = IW_HEADER_TYPE_POINT, 204 + .token_size = 1, 205 + .max_tokens = IW_ENCODING_TOKEN_MAX, 206 + .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT, 207 + }, 208 + [SIOCGIWENCODE - SIOCIWFIRST] = { 209 + .header_type = IW_HEADER_TYPE_POINT, 210 + .token_size = 1, 211 + .max_tokens = IW_ENCODING_TOKEN_MAX, 212 + .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT, 213 + }, 214 + [SIOCSIWPOWER - SIOCIWFIRST] = { 215 + .header_type = IW_HEADER_TYPE_PARAM, 216 + }, 217 + [SIOCGIWPOWER - SIOCIWFIRST] = { 218 + .header_type = IW_HEADER_TYPE_PARAM, 219 + }, 220 + [SIOCSIWGENIE - SIOCIWFIRST] = { 221 + .header_type = IW_HEADER_TYPE_POINT, 222 + .token_size = 1, 223 + .max_tokens = IW_GENERIC_IE_MAX, 224 + }, 225 + [SIOCGIWGENIE - SIOCIWFIRST] = { 226 + .header_type = IW_HEADER_TYPE_POINT, 227 + .token_size = 1, 228 + .max_tokens = IW_GENERIC_IE_MAX, 229 + }, 230 + [SIOCSIWAUTH - SIOCIWFIRST] = { 231 + .header_type = IW_HEADER_TYPE_PARAM, 232 + }, 233 + [SIOCGIWAUTH - SIOCIWFIRST] = { 234 + .header_type = IW_HEADER_TYPE_PARAM, 235 + }, 236 + [SIOCSIWENCODEEXT - SIOCIWFIRST] = { 237 + .header_type = IW_HEADER_TYPE_POINT, 238 + .token_size = 1, 239 + .min_tokens = sizeof(struct iw_encode_ext), 240 + .max_tokens = sizeof(struct iw_encode_ext) + 241 + IW_ENCODING_TOKEN_MAX, 242 + }, 243 + [SIOCGIWENCODEEXT - SIOCIWFIRST] = { 244 + .header_type = IW_HEADER_TYPE_POINT, 245 + .token_size = 1, 246 + .min_tokens = sizeof(struct iw_encode_ext), 247 + .max_tokens = sizeof(struct iw_encode_ext) + 248 + IW_ENCODING_TOKEN_MAX, 249 + }, 250 + [SIOCSIWPMKSA - SIOCIWFIRST] = { 251 + .header_type = IW_HEADER_TYPE_POINT, 252 + .token_size = 1, 253 + .min_tokens = sizeof(struct iw_pmksa), 254 + .max_tokens = sizeof(struct iw_pmksa), 255 + }, 256 + }; 257 + static const unsigned standard_ioctl_num = ARRAY_SIZE(standard_ioctl); 258 + 259 + /* 260 + * Meta-data about all the additional standard Wireless Extension events 261 + * we know about. 262 + */ 263 + static const struct iw_ioctl_description standard_event[] = { 264 + [IWEVTXDROP - IWEVFIRST] = { 265 + .header_type = IW_HEADER_TYPE_ADDR, 266 + }, 267 + [IWEVQUAL - IWEVFIRST] = { 268 + .header_type = IW_HEADER_TYPE_QUAL, 269 + }, 270 + [IWEVCUSTOM - IWEVFIRST] = { 271 + .header_type = IW_HEADER_TYPE_POINT, 272 + .token_size = 1, 273 + .max_tokens = IW_CUSTOM_MAX, 274 + }, 275 + [IWEVREGISTERED - IWEVFIRST] = { 276 + .header_type = IW_HEADER_TYPE_ADDR, 277 + }, 278 + [IWEVEXPIRED - IWEVFIRST] = { 279 + .header_type = IW_HEADER_TYPE_ADDR, 280 + }, 281 + [IWEVGENIE - IWEVFIRST] = { 282 + .header_type = IW_HEADER_TYPE_POINT, 283 + .token_size = 1, 284 + .max_tokens = IW_GENERIC_IE_MAX, 285 + }, 286 + [IWEVMICHAELMICFAILURE - IWEVFIRST] = { 287 + .header_type = IW_HEADER_TYPE_POINT, 288 + .token_size = 1, 289 + .max_tokens = sizeof(struct iw_michaelmicfailure), 290 + }, 291 + [IWEVASSOCREQIE - IWEVFIRST] = { 292 + .header_type = IW_HEADER_TYPE_POINT, 293 + .token_size = 1, 294 + .max_tokens = IW_GENERIC_IE_MAX, 295 + }, 296 + [IWEVASSOCRESPIE - IWEVFIRST] = { 297 + .header_type = IW_HEADER_TYPE_POINT, 298 + .token_size = 1, 299 + .max_tokens = IW_GENERIC_IE_MAX, 300 + }, 301 + [IWEVPMKIDCAND - IWEVFIRST] = { 302 + .header_type = IW_HEADER_TYPE_POINT, 303 + .token_size = 1, 304 + .max_tokens = sizeof(struct iw_pmkid_cand), 305 + }, 306 + }; 307 + static const unsigned standard_event_num = ARRAY_SIZE(standard_event); 308 + 309 + /* Size (in bytes) of various events */ 310 + static const int event_type_size[] = { 311 + IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ 312 + 0, 313 + IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ 314 + 0, 315 + IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ 316 + IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ 317 + IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ 318 + 0, 319 + IW_EV_POINT_LEN, /* Without variable payload */ 320 + IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ 321 + IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ 322 + }; 323 + 324 + #ifdef CONFIG_COMPAT 325 + static const int compat_event_type_size[] = { 326 + IW_EV_COMPAT_LCP_LEN, /* IW_HEADER_TYPE_NULL */ 327 + 0, 328 + IW_EV_COMPAT_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ 329 + 0, 330 + IW_EV_COMPAT_UINT_LEN, /* IW_HEADER_TYPE_UINT */ 331 + IW_EV_COMPAT_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ 332 + IW_EV_COMPAT_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ 333 + 0, 334 + IW_EV_COMPAT_POINT_LEN, /* Without variable payload */ 335 + IW_EV_COMPAT_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ 336 + IW_EV_COMPAT_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ 337 + }; 338 + #endif 339 + 340 + 341 + /* IW event code */ 342 + 343 + static int __net_init wext_pernet_init(struct net *net) 344 + { 345 + skb_queue_head_init(&net->wext_nlevents); 346 + return 0; 347 + } 348 + 349 + static void __net_exit wext_pernet_exit(struct net *net) 350 + { 351 + skb_queue_purge(&net->wext_nlevents); 352 + } 353 + 354 + static struct pernet_operations wext_pernet_ops = { 355 + .init = wext_pernet_init, 356 + .exit = wext_pernet_exit, 357 + }; 358 + 359 + static int __init wireless_nlevent_init(void) 360 + { 361 + return register_pernet_subsys(&wext_pernet_ops); 362 + } 363 + 364 + subsys_initcall(wireless_nlevent_init); 365 + 366 + /* Process events generated by the wireless layer or the driver. */ 367 + static void wireless_nlevent_process(struct work_struct *work) 368 + { 369 + struct sk_buff *skb; 370 + struct net *net; 371 + 372 + rtnl_lock(); 373 + 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 + } 379 + 380 + rtnl_unlock(); 381 + } 382 + 383 + static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process); 384 + 385 + static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev, 386 + struct sk_buff *skb) 387 + { 388 + struct ifinfomsg *r; 389 + struct nlmsghdr *nlh; 390 + 391 + nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0); 392 + if (!nlh) 393 + return NULL; 394 + 395 + r = nlmsg_data(nlh); 396 + r->ifi_family = AF_UNSPEC; 397 + r->__ifi_pad = 0; 398 + r->ifi_type = dev->type; 399 + r->ifi_index = dev->ifindex; 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; 409 + } 410 + 411 + 412 + /* 413 + * Main event dispatcher. Called from other parts and drivers. 414 + * Send the event on the appropriate channels. 415 + * May be called from interrupt context. 416 + */ 417 + void wireless_send_event(struct net_device * dev, 418 + unsigned int cmd, 419 + union iwreq_data * wrqu, 420 + const char * extra) 421 + { 422 + const struct iw_ioctl_description * descr = NULL; 423 + int extra_len = 0; 424 + struct iw_event *event; /* Mallocated whole event */ 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 438 + 439 + /* 440 + * Nothing in the kernel sends scan events with data, be safe. 441 + * This is necessary because we cannot fix up scan event data 442 + * for compat, due to being contained in 'extra', but normally 443 + * applications are required to retrieve the scan data anyway 444 + * and no data is included in the event, this codifies that 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; 472 + } 473 + 474 + /* Check extra parameters and set extra_len */ 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 + } 491 + 492 + /* Total length of the event */ 493 + hdr_len = event_type_size[descr->header_type]; 494 + event_len = hdr_len + extra_len; 495 + 496 + /* 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 + */ 518 + 519 + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 520 + if (!skb) 521 + return; 522 + 523 + /* Send via the RtNetlink event channel */ 524 + nlh = rtnetlink_ifinfo_prep(dev, skb); 525 + if (WARN_ON(!nlh)) { 526 + kfree_skb(skb); 527 + return; 528 + } 529 + 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); 537 + 538 + /* Fill event - first clear to avoid data leaking */ 539 + memset(event, 0, hdr_len); 540 + event->len = event_len; 541 + event->cmd = cmd; 542 + memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN); 543 + if (extra_len) 544 + memcpy(((char *) event) + hdr_len, extra, extra_len); 545 + 546 + nlmsg_end(skb, nlh); 547 + #ifdef CONFIG_COMPAT 548 + hdr_len = compat_event_type_size[descr->header_type]; 549 + event_len = hdr_len + extra_len; 550 + 551 + compskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 552 + if (!compskb) { 553 + kfree_skb(skb); 554 + return; 555 + } 556 + 557 + /* Send via the RtNetlink event channel */ 558 + nlh = rtnetlink_ifinfo_prep(dev, compskb); 559 + if (WARN_ON(!nlh)) { 560 + kfree_skb(skb); 561 + kfree_skb(compskb); 562 + return; 563 + } 564 + 565 + /* Add the wireless events in the netlink packet */ 566 + nla = nla_reserve(compskb, IFLA_WIRELESS, event_len); 567 + if (!nla) { 568 + kfree_skb(skb); 569 + kfree_skb(compskb); 570 + return; 571 + } 572 + compat_event = nla_data(nla); 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); 597 + } 598 + EXPORT_SYMBOL(wireless_send_event); 599 + 600 + 601 + 602 + /* IW handlers */ 603 + 604 + struct iw_statistics *get_wireless_stats(struct net_device *dev) 605 + { 606 + #ifdef CONFIG_WIRELESS_EXT 607 + if ((dev->wireless_handlers != NULL) && 608 + (dev->wireless_handlers->get_wireless_stats != NULL)) 609 + return dev->wireless_handlers->get_wireless_stats(dev); 610 + #endif 611 + 612 + #ifdef CONFIG_CFG80211_WEXT 613 + if (dev->ieee80211_ptr && dev->ieee80211_ptr && 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 619 + 620 + /* not found */ 621 + return NULL; 622 + } 623 + 624 + static int iw_handler_get_iwstats(struct net_device * dev, 625 + struct iw_request_info * info, 626 + union iwreq_data * wrqu, 627 + char * extra) 628 + { 629 + /* Get stats from the driver */ 630 + struct iw_statistics *stats; 631 + 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); 637 + 638 + /* Check if we need to clear the updated flag */ 639 + if (wrqu->data.flags != 0) 640 + stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; 641 + return 0; 642 + } else 643 + return -EOPNOTSUPP; 644 + } 645 + 646 + static iw_handler get_handler(struct net_device *dev, unsigned int cmd) 647 + { 648 + /* Don't "optimise" the following variable, it will crash */ 649 + unsigned int index; /* *MUST* be unsigned */ 650 + const struct iw_handler_def *handlers = NULL; 651 + 652 + #ifdef CONFIG_CFG80211_WEXT 653 + if (dev->ieee80211_ptr && dev->ieee80211_ptr->wiphy) 654 + handlers = dev->ieee80211_ptr->wiphy->wext; 655 + #endif 656 + #ifdef CONFIG_WIRELESS_EXT 657 + if (dev->wireless_handlers) 658 + handlers = dev->wireless_handlers; 659 + #endif 660 + 661 + if (!handlers) 662 + return NULL; 663 + 664 + /* Try as a standard command */ 665 + index = cmd - SIOCIWFIRST; 666 + if (index < handlers->num_standard) 667 + return handlers->standard[index]; 668 + 669 + #ifdef CONFIG_WEXT_PRIV 670 + /* Try as a private command */ 671 + index = cmd - SIOCIWFIRSTPRIV; 672 + if (index < handlers->num_private) 673 + return handlers->private[index]; 674 + #endif 675 + 676 + /* Not found */ 677 + return NULL; 678 + } 679 + 680 + static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, 681 + const struct iw_ioctl_description *descr, 682 + iw_handler handler, struct net_device *dev, 683 + struct iw_request_info *info) 684 + { 685 + int err, extra_size, user_length = 0, essid_compat = 0; 686 + char *extra; 687 + 688 + /* Calculate space needed by arguments. Always allocate 689 + * for max space. 690 + */ 691 + extra_size = descr->max_tokens * descr->token_size; 692 + 693 + /* Check need for ESSID compatibility for WE < 21 */ 694 + switch (cmd) { 695 + case SIOCSIWESSID: 696 + case SIOCGIWESSID: 697 + case SIOCSIWNICKN: 698 + case SIOCGIWNICKN: 699 + if (iwp->length == descr->max_tokens + 1) 700 + essid_compat = 1; 701 + else if (IW_IS_SET(cmd) && (iwp->length != 0)) { 702 + char essid[IW_ESSID_MAX_SIZE + 1]; 703 + unsigned int len; 704 + len = iwp->length * descr->token_size; 705 + 706 + if (len > IW_ESSID_MAX_SIZE) 707 + return -EFAULT; 708 + 709 + err = copy_from_user(essid, iwp->pointer, len); 710 + if (err) 711 + return -EFAULT; 712 + 713 + if (essid[iwp->length - 1] == '\0') 714 + essid_compat = 1; 715 + } 716 + break; 717 + default: 718 + break; 719 + } 720 + 721 + iwp->length -= essid_compat; 722 + 723 + /* Check what user space is giving us */ 724 + if (IW_IS_SET(cmd)) { 725 + /* Check NULL pointer */ 726 + if (!iwp->pointer && iwp->length != 0) 727 + return -EFAULT; 728 + /* Check if number of token fits within bounds */ 729 + if (iwp->length > descr->max_tokens) 730 + return -E2BIG; 731 + if (iwp->length < descr->min_tokens) 732 + return -EINVAL; 733 + } else { 734 + /* Check NULL pointer */ 735 + if (!iwp->pointer) 736 + return -EFAULT; 737 + /* Save user space buffer size for checking */ 738 + user_length = iwp->length; 739 + 740 + /* Don't check if user_length > max to allow forward 741 + * compatibility. The test user_length < min is 742 + * implied by the test at the end. 743 + */ 744 + 745 + /* Support for very large requests */ 746 + if ((descr->flags & IW_DESCR_FLAG_NOMAX) && 747 + (user_length > descr->max_tokens)) { 748 + /* Allow userspace to GET more than max so 749 + * we can support any size GET requests. 750 + * There is still a limit : -ENOMEM. 751 + */ 752 + extra_size = user_length * descr->token_size; 753 + 754 + /* Note : user_length is originally a __u16, 755 + * and token_size is controlled by us, 756 + * so extra_size won't get negative and 757 + * won't overflow... 758 + */ 759 + } 760 + } 761 + 762 + /* kzalloc() ensures NULL-termination for essid_compat. */ 763 + extra = kzalloc(extra_size, GFP_KERNEL); 764 + if (!extra) 765 + return -ENOMEM; 766 + 767 + /* If it is a SET, get all the extra data in here */ 768 + if (IW_IS_SET(cmd) && (iwp->length != 0)) { 769 + if (copy_from_user(extra, iwp->pointer, 770 + iwp->length * 771 + descr->token_size)) { 772 + err = -EFAULT; 773 + goto out; 774 + } 775 + 776 + if (cmd == SIOCSIWENCODEEXT) { 777 + struct iw_encode_ext *ee = (void *) extra; 778 + 779 + if (iwp->length < sizeof(*ee) + ee->key_len) 780 + return -EFAULT; 781 + } 782 + } 783 + 784 + err = handler(dev, info, (union iwreq_data *) iwp, extra); 785 + 786 + iwp->length += essid_compat; 787 + 788 + /* If we have something to return to the user */ 789 + if (!err && IW_IS_GET(cmd)) { 790 + /* Check if there is enough buffer up there */ 791 + if (user_length < iwp->length) { 792 + err = -E2BIG; 793 + goto out; 794 + } 795 + 796 + if (copy_to_user(iwp->pointer, extra, 797 + iwp->length * 798 + descr->token_size)) { 799 + err = -EFAULT; 800 + goto out; 801 + } 802 + } 803 + 804 + /* Generate an event to notify listeners of the change */ 805 + if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) { 806 + union iwreq_data *data = (union iwreq_data *) iwp; 807 + 808 + if (descr->flags & IW_DESCR_FLAG_RESTRICT) 809 + /* If the event is restricted, don't 810 + * export the payload. 811 + */ 812 + wireless_send_event(dev, cmd, data, NULL); 813 + else 814 + wireless_send_event(dev, cmd, data, extra); 815 + } 816 + 817 + out: 818 + kfree(extra); 819 + return err; 820 + } 821 + 822 + /* 823 + * Call the commit handler in the driver 824 + * (if exist and if conditions are right) 825 + * 826 + * Note : our current commit strategy is currently pretty dumb, 827 + * but we will be able to improve on that... 828 + * The goal is to try to agreagate as many changes as possible 829 + * before doing the commit. Drivers that will define a commit handler 830 + * are usually those that need a reset after changing parameters, so 831 + * we want to minimise the number of reset. 832 + * A cool idea is to use a timer : at each "set" command, we re-set the 833 + * timer, when the timer eventually fires, we call the driver. 834 + * Hopefully, more on that later. 835 + * 836 + * Also, I'm waiting to see how many people will complain about the 837 + * netif_running(dev) test. I'm open on that one... 838 + * Hopefully, the driver will remember to do a commit in "open()" ;-) 839 + */ 840 + int call_commit_handler(struct net_device *dev) 841 + { 842 + #ifdef CONFIG_WIRELESS_EXT 843 + if ((netif_running(dev)) && 844 + (dev->wireless_handlers->standard[0] != NULL)) 845 + /* Call the commit handler on the driver */ 846 + return dev->wireless_handlers->standard[0](dev, NULL, 847 + NULL, NULL); 848 + else 849 + return 0; /* Command completed successfully */ 850 + #else 851 + /* cfg80211 has no commit */ 852 + return 0; 853 + #endif 854 + } 855 + 856 + /* 857 + * Main IOCTl dispatcher. 858 + * Check the type of IOCTL and call the appropriate wrapper... 859 + */ 860 + static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, 861 + unsigned int cmd, 862 + struct iw_request_info *info, 863 + wext_ioctl_func standard, 864 + wext_ioctl_func private) 865 + { 866 + struct iwreq *iwr = (struct iwreq *) ifr; 867 + struct net_device *dev; 868 + iw_handler handler; 869 + 870 + /* Permissions are already checked in dev_ioctl() before calling us. 871 + * The copy_to/from_user() of ifr is also dealt with in there */ 872 + 873 + /* Make sure the device exist */ 874 + if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) 875 + return -ENODEV; 876 + 877 + /* A bunch of special cases, then the generic case... 878 + * Note that 'cmd' is already filtered in dev_ioctl() with 879 + * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ 880 + if (cmd == SIOCGIWSTATS) 881 + return standard(dev, iwr, cmd, info, 882 + &iw_handler_get_iwstats); 883 + 884 + #ifdef CONFIG_WEXT_PRIV 885 + if (cmd == SIOCGIWPRIV && dev->wireless_handlers) 886 + return standard(dev, iwr, cmd, info, 887 + iw_handler_get_private); 888 + #endif 889 + 890 + /* Basic check */ 891 + if (!netif_device_present(dev)) 892 + return -ENODEV; 893 + 894 + /* New driver API : try to find the handler */ 895 + handler = get_handler(dev, cmd); 896 + if (handler) { 897 + /* Standard and private are not the same */ 898 + if (cmd < SIOCIWFIRSTPRIV) 899 + return standard(dev, iwr, cmd, info, handler); 900 + else if (private) 901 + return private(dev, iwr, cmd, info, handler); 902 + } 903 + /* Old driver API : call driver ioctl handler */ 904 + if (dev->netdev_ops->ndo_do_ioctl) 905 + return dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd); 906 + return -EOPNOTSUPP; 907 + } 908 + 909 + /* If command is `set a parameter', or `get the encoding parameters', 910 + * check if the user has the right to do it. 911 + */ 912 + static int wext_permission_check(unsigned int cmd) 913 + { 914 + if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT) 915 + && !capable(CAP_NET_ADMIN)) 916 + return -EPERM; 917 + 918 + return 0; 919 + } 920 + 921 + /* entry point from dev ioctl */ 922 + static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr, 923 + unsigned int cmd, struct iw_request_info *info, 924 + wext_ioctl_func standard, 925 + wext_ioctl_func private) 926 + { 927 + int ret = wext_permission_check(cmd); 928 + 929 + if (ret) 930 + return ret; 931 + 932 + dev_load(net, ifr->ifr_name); 933 + rtnl_lock(); 934 + ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private); 935 + rtnl_unlock(); 936 + 937 + return ret; 938 + } 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 + */ 945 + static 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 + 984 + int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, 985 + void __user *arg) 986 + { 987 + struct iw_request_info info = { .cmd = cmd, .flags = 0 }; 988 + int ret; 989 + 990 + ret = wext_ioctl_dispatch(net, ifr, cmd, &info, 991 + ioctl_standard_call, 992 + ioctl_private_call); 993 + if (ret >= 0 && 994 + IW_IS_GET(cmd) && 995 + copy_to_user(arg, ifr, sizeof(struct iwreq))) 996 + return -EFAULT; 997 + 998 + return ret; 999 + } 1000 + 1001 + #ifdef CONFIG_COMPAT 1002 + static int compat_standard_call(struct net_device *dev, 1003 + struct iwreq *iwr, 1004 + unsigned int cmd, 1005 + struct iw_request_info *info, 1006 + iw_handler handler) 1007 + { 1008 + const struct iw_ioctl_description *descr; 1009 + struct compat_iw_point *iwp_compat; 1010 + struct iw_point iwp; 1011 + int err; 1012 + 1013 + descr = standard_ioctl + (cmd - SIOCIWFIRST); 1014 + 1015 + if (descr->header_type != IW_HEADER_TYPE_POINT) 1016 + return ioctl_standard_call(dev, iwr, cmd, info, handler); 1017 + 1018 + iwp_compat = (struct compat_iw_point *) &iwr->u.data; 1019 + iwp.pointer = compat_ptr(iwp_compat->pointer); 1020 + iwp.length = iwp_compat->length; 1021 + iwp.flags = iwp_compat->flags; 1022 + 1023 + err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info); 1024 + 1025 + iwp_compat->pointer = ptr_to_compat(iwp.pointer); 1026 + iwp_compat->length = iwp.length; 1027 + iwp_compat->flags = iwp.flags; 1028 + 1029 + return err; 1030 + } 1031 + 1032 + int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, 1033 + unsigned long arg) 1034 + { 1035 + void __user *argp = (void __user *)arg; 1036 + struct iw_request_info info; 1037 + struct iwreq iwr; 1038 + char *colon; 1039 + int ret; 1040 + 1041 + if (copy_from_user(&iwr, argp, sizeof(struct iwreq))) 1042 + return -EFAULT; 1043 + 1044 + iwr.ifr_name[IFNAMSIZ-1] = 0; 1045 + colon = strchr(iwr.ifr_name, ':'); 1046 + if (colon) 1047 + *colon = 0; 1048 + 1049 + info.cmd = cmd; 1050 + info.flags = IW_REQUEST_FLAG_COMPAT; 1051 + 1052 + ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info, 1053 + compat_standard_call, 1054 + compat_private_call); 1055 + 1056 + if (ret >= 0 && 1057 + IW_IS_GET(cmd) && 1058 + copy_to_user(argp, &iwr, sizeof(struct iwreq))) 1059 + return -EFAULT; 1060 + 1061 + return ret; 1062 + } 1063 + #endif
+248
net/wireless/wext-priv.c
··· 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 + 15 + int 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 */ 45 + static 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 + 56 + static 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 + 64 + static 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 + */ 92 + static 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 + 136 + static 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 + 181 + out: 182 + kfree(extra); 183 + return err; 184 + } 185 + 186 + int 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 212 + int 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
+155
net/wireless/wext-proc.c
··· 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 + 29 + static 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 + */ 75 + static 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 + 90 + static 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 + 107 + static 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 + 117 + static void wireless_dev_seq_stop(struct seq_file *seq, void *v) 118 + { 119 + rtnl_unlock(); 120 + } 121 + 122 + static 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 + 129 + static 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 + 135 + static 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 + 143 + int 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 + 152 + void wext_proc_exit(struct net *net) 153 + { 154 + proc_net_remove(net, "wireless"); 155 + }
+231
net/wireless/wext-spy.c
··· 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 + 17 + static 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 + 25 + int 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 + } 71 + EXPORT_SYMBOL(iw_handler_set_spy); 72 + 73 + int 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 + } 103 + EXPORT_SYMBOL(iw_handler_get_spy); 104 + 105 + /*------------------------------------------------------------------*/ 106 + /* 107 + * Standard Wireless Handler : set spy threshold 108 + */ 109 + int 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 + } 130 + EXPORT_SYMBOL(iw_handler_set_thrspy); 131 + 132 + /*------------------------------------------------------------------*/ 133 + /* 134 + * Standard Wireless Handler : get spy threshold 135 + */ 136 + int 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 + } 154 + EXPORT_SYMBOL(iw_handler_get_thrspy); 155 + 156 + /*------------------------------------------------------------------*/ 157 + /* 158 + * Prepare and send a Spy Threshold event 159 + */ 160 + static 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 + */ 191 + void 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 + } 231 + EXPORT_SYMBOL(wireless_spy_update);
-1775
net/wireless/wext.c
··· 1 - /* 2 - * This file implement the Wireless Extensions APIs. 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 - /************************** DOCUMENTATION **************************/ 11 - /* 12 - * API definition : 13 - * -------------- 14 - * See <linux/wireless.h> for details of the APIs and the rest. 15 - * 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> 101 - #include <net/wext.h> 102 - 103 - #include <asm/uaccess.h> /* copy_to_user() */ 104 - 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 - /* 111 - * Meta-data about all the standard Wireless Extension request we 112 - * know about. 113 - */ 114 - static const struct iw_ioctl_description standard_ioctl[] = { 115 - [SIOCSIWCOMMIT - SIOCIWFIRST] = { 116 - .header_type = IW_HEADER_TYPE_NULL, 117 - }, 118 - [SIOCGIWNAME - SIOCIWFIRST] = { 119 - .header_type = IW_HEADER_TYPE_CHAR, 120 - .flags = IW_DESCR_FLAG_DUMP, 121 - }, 122 - [SIOCSIWNWID - SIOCIWFIRST] = { 123 - .header_type = IW_HEADER_TYPE_PARAM, 124 - .flags = IW_DESCR_FLAG_EVENT, 125 - }, 126 - [SIOCGIWNWID - SIOCIWFIRST] = { 127 - .header_type = IW_HEADER_TYPE_PARAM, 128 - .flags = IW_DESCR_FLAG_DUMP, 129 - }, 130 - [SIOCSIWFREQ - SIOCIWFIRST] = { 131 - .header_type = IW_HEADER_TYPE_FREQ, 132 - .flags = IW_DESCR_FLAG_EVENT, 133 - }, 134 - [SIOCGIWFREQ - SIOCIWFIRST] = { 135 - .header_type = IW_HEADER_TYPE_FREQ, 136 - .flags = IW_DESCR_FLAG_DUMP, 137 - }, 138 - [SIOCSIWMODE - SIOCIWFIRST] = { 139 - .header_type = IW_HEADER_TYPE_UINT, 140 - .flags = IW_DESCR_FLAG_EVENT, 141 - }, 142 - [SIOCGIWMODE - SIOCIWFIRST] = { 143 - .header_type = IW_HEADER_TYPE_UINT, 144 - .flags = IW_DESCR_FLAG_DUMP, 145 - }, 146 - [SIOCSIWSENS - SIOCIWFIRST] = { 147 - .header_type = IW_HEADER_TYPE_PARAM, 148 - }, 149 - [SIOCGIWSENS - SIOCIWFIRST] = { 150 - .header_type = IW_HEADER_TYPE_PARAM, 151 - }, 152 - [SIOCSIWRANGE - SIOCIWFIRST] = { 153 - .header_type = IW_HEADER_TYPE_NULL, 154 - }, 155 - [SIOCGIWRANGE - SIOCIWFIRST] = { 156 - .header_type = IW_HEADER_TYPE_POINT, 157 - .token_size = 1, 158 - .max_tokens = sizeof(struct iw_range), 159 - .flags = IW_DESCR_FLAG_DUMP, 160 - }, 161 - [SIOCSIWPRIV - SIOCIWFIRST] = { 162 - .header_type = IW_HEADER_TYPE_NULL, 163 - }, 164 - [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */ 165 - .header_type = IW_HEADER_TYPE_POINT, 166 - .token_size = sizeof(struct iw_priv_args), 167 - .max_tokens = 16, 168 - .flags = IW_DESCR_FLAG_NOMAX, 169 - }, 170 - [SIOCSIWSTATS - SIOCIWFIRST] = { 171 - .header_type = IW_HEADER_TYPE_NULL, 172 - }, 173 - [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */ 174 - .header_type = IW_HEADER_TYPE_POINT, 175 - .token_size = 1, 176 - .max_tokens = sizeof(struct iw_statistics), 177 - .flags = IW_DESCR_FLAG_DUMP, 178 - }, 179 - [SIOCSIWSPY - SIOCIWFIRST] = { 180 - .header_type = IW_HEADER_TYPE_POINT, 181 - .token_size = sizeof(struct sockaddr), 182 - .max_tokens = IW_MAX_SPY, 183 - }, 184 - [SIOCGIWSPY - SIOCIWFIRST] = { 185 - .header_type = IW_HEADER_TYPE_POINT, 186 - .token_size = sizeof(struct sockaddr) + 187 - sizeof(struct iw_quality), 188 - .max_tokens = IW_MAX_SPY, 189 - }, 190 - [SIOCSIWTHRSPY - SIOCIWFIRST] = { 191 - .header_type = IW_HEADER_TYPE_POINT, 192 - .token_size = sizeof(struct iw_thrspy), 193 - .min_tokens = 1, 194 - .max_tokens = 1, 195 - }, 196 - [SIOCGIWTHRSPY - SIOCIWFIRST] = { 197 - .header_type = IW_HEADER_TYPE_POINT, 198 - .token_size = sizeof(struct iw_thrspy), 199 - .min_tokens = 1, 200 - .max_tokens = 1, 201 - }, 202 - [SIOCSIWAP - SIOCIWFIRST] = { 203 - .header_type = IW_HEADER_TYPE_ADDR, 204 - }, 205 - [SIOCGIWAP - SIOCIWFIRST] = { 206 - .header_type = IW_HEADER_TYPE_ADDR, 207 - .flags = IW_DESCR_FLAG_DUMP, 208 - }, 209 - [SIOCSIWMLME - SIOCIWFIRST] = { 210 - .header_type = IW_HEADER_TYPE_POINT, 211 - .token_size = 1, 212 - .min_tokens = sizeof(struct iw_mlme), 213 - .max_tokens = sizeof(struct iw_mlme), 214 - }, 215 - [SIOCGIWAPLIST - SIOCIWFIRST] = { 216 - .header_type = IW_HEADER_TYPE_POINT, 217 - .token_size = sizeof(struct sockaddr) + 218 - sizeof(struct iw_quality), 219 - .max_tokens = IW_MAX_AP, 220 - .flags = IW_DESCR_FLAG_NOMAX, 221 - }, 222 - [SIOCSIWSCAN - SIOCIWFIRST] = { 223 - .header_type = IW_HEADER_TYPE_POINT, 224 - .token_size = 1, 225 - .min_tokens = 0, 226 - .max_tokens = sizeof(struct iw_scan_req), 227 - }, 228 - [SIOCGIWSCAN - SIOCIWFIRST] = { 229 - .header_type = IW_HEADER_TYPE_POINT, 230 - .token_size = 1, 231 - .max_tokens = IW_SCAN_MAX_DATA, 232 - .flags = IW_DESCR_FLAG_NOMAX, 233 - }, 234 - [SIOCSIWESSID - SIOCIWFIRST] = { 235 - .header_type = IW_HEADER_TYPE_POINT, 236 - .token_size = 1, 237 - .max_tokens = IW_ESSID_MAX_SIZE, 238 - .flags = IW_DESCR_FLAG_EVENT, 239 - }, 240 - [SIOCGIWESSID - SIOCIWFIRST] = { 241 - .header_type = IW_HEADER_TYPE_POINT, 242 - .token_size = 1, 243 - .max_tokens = IW_ESSID_MAX_SIZE, 244 - .flags = IW_DESCR_FLAG_DUMP, 245 - }, 246 - [SIOCSIWNICKN - SIOCIWFIRST] = { 247 - .header_type = IW_HEADER_TYPE_POINT, 248 - .token_size = 1, 249 - .max_tokens = IW_ESSID_MAX_SIZE, 250 - }, 251 - [SIOCGIWNICKN - SIOCIWFIRST] = { 252 - .header_type = IW_HEADER_TYPE_POINT, 253 - .token_size = 1, 254 - .max_tokens = IW_ESSID_MAX_SIZE, 255 - }, 256 - [SIOCSIWRATE - SIOCIWFIRST] = { 257 - .header_type = IW_HEADER_TYPE_PARAM, 258 - }, 259 - [SIOCGIWRATE - SIOCIWFIRST] = { 260 - .header_type = IW_HEADER_TYPE_PARAM, 261 - }, 262 - [SIOCSIWRTS - SIOCIWFIRST] = { 263 - .header_type = IW_HEADER_TYPE_PARAM, 264 - }, 265 - [SIOCGIWRTS - SIOCIWFIRST] = { 266 - .header_type = IW_HEADER_TYPE_PARAM, 267 - }, 268 - [SIOCSIWFRAG - SIOCIWFIRST] = { 269 - .header_type = IW_HEADER_TYPE_PARAM, 270 - }, 271 - [SIOCGIWFRAG - SIOCIWFIRST] = { 272 - .header_type = IW_HEADER_TYPE_PARAM, 273 - }, 274 - [SIOCSIWTXPOW - SIOCIWFIRST] = { 275 - .header_type = IW_HEADER_TYPE_PARAM, 276 - }, 277 - [SIOCGIWTXPOW - SIOCIWFIRST] = { 278 - .header_type = IW_HEADER_TYPE_PARAM, 279 - }, 280 - [SIOCSIWRETRY - SIOCIWFIRST] = { 281 - .header_type = IW_HEADER_TYPE_PARAM, 282 - }, 283 - [SIOCGIWRETRY - SIOCIWFIRST] = { 284 - .header_type = IW_HEADER_TYPE_PARAM, 285 - }, 286 - [SIOCSIWENCODE - SIOCIWFIRST] = { 287 - .header_type = IW_HEADER_TYPE_POINT, 288 - .token_size = 1, 289 - .max_tokens = IW_ENCODING_TOKEN_MAX, 290 - .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT, 291 - }, 292 - [SIOCGIWENCODE - SIOCIWFIRST] = { 293 - .header_type = IW_HEADER_TYPE_POINT, 294 - .token_size = 1, 295 - .max_tokens = IW_ENCODING_TOKEN_MAX, 296 - .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT, 297 - }, 298 - [SIOCSIWPOWER - SIOCIWFIRST] = { 299 - .header_type = IW_HEADER_TYPE_PARAM, 300 - }, 301 - [SIOCGIWPOWER - SIOCIWFIRST] = { 302 - .header_type = IW_HEADER_TYPE_PARAM, 303 - }, 304 - [SIOCSIWGENIE - SIOCIWFIRST] = { 305 - .header_type = IW_HEADER_TYPE_POINT, 306 - .token_size = 1, 307 - .max_tokens = IW_GENERIC_IE_MAX, 308 - }, 309 - [SIOCGIWGENIE - SIOCIWFIRST] = { 310 - .header_type = IW_HEADER_TYPE_POINT, 311 - .token_size = 1, 312 - .max_tokens = IW_GENERIC_IE_MAX, 313 - }, 314 - [SIOCSIWAUTH - SIOCIWFIRST] = { 315 - .header_type = IW_HEADER_TYPE_PARAM, 316 - }, 317 - [SIOCGIWAUTH - SIOCIWFIRST] = { 318 - .header_type = IW_HEADER_TYPE_PARAM, 319 - }, 320 - [SIOCSIWENCODEEXT - SIOCIWFIRST] = { 321 - .header_type = IW_HEADER_TYPE_POINT, 322 - .token_size = 1, 323 - .min_tokens = sizeof(struct iw_encode_ext), 324 - .max_tokens = sizeof(struct iw_encode_ext) + 325 - IW_ENCODING_TOKEN_MAX, 326 - }, 327 - [SIOCGIWENCODEEXT - SIOCIWFIRST] = { 328 - .header_type = IW_HEADER_TYPE_POINT, 329 - .token_size = 1, 330 - .min_tokens = sizeof(struct iw_encode_ext), 331 - .max_tokens = sizeof(struct iw_encode_ext) + 332 - IW_ENCODING_TOKEN_MAX, 333 - }, 334 - [SIOCSIWPMKSA - SIOCIWFIRST] = { 335 - .header_type = IW_HEADER_TYPE_POINT, 336 - .token_size = 1, 337 - .min_tokens = sizeof(struct iw_pmksa), 338 - .max_tokens = sizeof(struct iw_pmksa), 339 - }, 340 - }; 341 - static const unsigned standard_ioctl_num = ARRAY_SIZE(standard_ioctl); 342 - 343 - /* 344 - * Meta-data about all the additional standard Wireless Extension events 345 - * we know about. 346 - */ 347 - static const struct iw_ioctl_description standard_event[] = { 348 - [IWEVTXDROP - IWEVFIRST] = { 349 - .header_type = IW_HEADER_TYPE_ADDR, 350 - }, 351 - [IWEVQUAL - IWEVFIRST] = { 352 - .header_type = IW_HEADER_TYPE_QUAL, 353 - }, 354 - [IWEVCUSTOM - IWEVFIRST] = { 355 - .header_type = IW_HEADER_TYPE_POINT, 356 - .token_size = 1, 357 - .max_tokens = IW_CUSTOM_MAX, 358 - }, 359 - [IWEVREGISTERED - IWEVFIRST] = { 360 - .header_type = IW_HEADER_TYPE_ADDR, 361 - }, 362 - [IWEVEXPIRED - IWEVFIRST] = { 363 - .header_type = IW_HEADER_TYPE_ADDR, 364 - }, 365 - [IWEVGENIE - IWEVFIRST] = { 366 - .header_type = IW_HEADER_TYPE_POINT, 367 - .token_size = 1, 368 - .max_tokens = IW_GENERIC_IE_MAX, 369 - }, 370 - [IWEVMICHAELMICFAILURE - IWEVFIRST] = { 371 - .header_type = IW_HEADER_TYPE_POINT, 372 - .token_size = 1, 373 - .max_tokens = sizeof(struct iw_michaelmicfailure), 374 - }, 375 - [IWEVASSOCREQIE - IWEVFIRST] = { 376 - .header_type = IW_HEADER_TYPE_POINT, 377 - .token_size = 1, 378 - .max_tokens = IW_GENERIC_IE_MAX, 379 - }, 380 - [IWEVASSOCRESPIE - IWEVFIRST] = { 381 - .header_type = IW_HEADER_TYPE_POINT, 382 - .token_size = 1, 383 - .max_tokens = IW_GENERIC_IE_MAX, 384 - }, 385 - [IWEVPMKIDCAND - IWEVFIRST] = { 386 - .header_type = IW_HEADER_TYPE_POINT, 387 - .token_size = 1, 388 - .max_tokens = sizeof(struct iw_pmkid_cand), 389 - }, 390 - }; 391 - static const unsigned standard_event_num = ARRAY_SIZE(standard_event); 392 - 393 - /* Size (in bytes) of the various private data types */ 394 - static 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 */ 406 - static const int event_type_size[] = { 407 - IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ 408 - 0, 409 - IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ 410 - 0, 411 - IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ 412 - IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ 413 - IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ 414 - 0, 415 - IW_EV_POINT_LEN, /* Without variable payload */ 416 - IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ 417 - IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ 418 - }; 419 - 420 - #ifdef CONFIG_COMPAT 421 - static const int compat_event_type_size[] = { 422 - IW_EV_COMPAT_LCP_LEN, /* IW_HEADER_TYPE_NULL */ 423 - 0, 424 - IW_EV_COMPAT_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ 425 - 0, 426 - IW_EV_COMPAT_UINT_LEN, /* IW_HEADER_TYPE_UINT */ 427 - IW_EV_COMPAT_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ 428 - IW_EV_COMPAT_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ 429 - 0, 430 - IW_EV_COMPAT_POINT_LEN, /* Without variable payload */ 431 - IW_EV_COMPAT_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ 432 - IW_EV_COMPAT_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ 433 - }; 434 - #endif 435 - 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 - */ 446 - static 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 - 451 - /* Check if we have some wireless handlers defined */ 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 - 465 - /* Not found */ 466 - return NULL; 467 - } 468 - 469 - /* ---------------------------------------------------------------- */ 470 - /* 471 - * Get statistics out of the driver 472 - */ 473 - struct iw_statistics *get_wireless_stats(struct net_device *dev) 474 - { 475 - /* New location */ 476 - if ((dev->wireless_handlers != NULL) && 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 - } 483 - 484 - /* ---------------------------------------------------------------- */ 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 - */ 503 - static int call_commit_handler(struct net_device *dev) 504 - { 505 - if ((netif_running(dev)) && 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 - } 513 - 514 - /* ---------------------------------------------------------------- */ 515 - /* 516 - * Calculate size of private arguments 517 - */ 518 - static 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 - 523 - return num * iw_priv_type_size[type]; 524 - } 525 - 526 - /* ---------------------------------------------------------------- */ 527 - /* 528 - * Re-calculate the size of private arguments 529 - */ 530 - static int adjust_priv_size(__u16 args, struct iw_point *iwp) 531 - { 532 - int num = iwp->length; 533 - int max = args & IW_PRIV_SIZE_MASK; 534 - int type = (args & IW_PRIV_TYPE_MASK) >> 12; 535 - 536 - /* Make sure the driver doesn't goof up */ 537 - if (max < num) 538 - num = max; 539 - 540 - return num * iw_priv_type_size[type]; 541 - } 542 - 543 - /* ---------------------------------------------------------------- */ 544 - /* 545 - * Standard Wireless Handler : get wireless stats 546 - * Allow programatic access to /proc/net/wireless even if /proc 547 - * doesn't exist... Also more efficient... 548 - */ 549 - static int iw_handler_get_iwstats(struct net_device * dev, 550 - struct iw_request_info * info, 551 - union iwreq_data * wrqu, 552 - char * extra) 553 - { 554 - /* Get stats from the driver */ 555 - struct iw_statistics *stats; 556 - 557 - stats = get_wireless_stats(dev); 558 - if (stats) { 559 - /* Copy statistics to extra */ 560 - memcpy(extra, stats, sizeof(struct iw_statistics)); 561 - wrqu->data.length = sizeof(struct iw_statistics); 562 - 563 - /* Check if we need to clear the updated flag */ 564 - if (wrqu->data.flags != 0) 565 - stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; 566 - return 0; 567 - } else 568 - return -EOPNOTSUPP; 569 - } 570 - 571 - /* ---------------------------------------------------------------- */ 572 - /* 573 - * Standard Wireless Handler : get iwpriv definitions 574 - * Export the driver private handler definition 575 - * They will be picked up by tools like iwpriv... 576 - */ 577 - static int iw_handler_get_private(struct net_device * dev, 578 - struct iw_request_info * info, 579 - union iwreq_data * wrqu, 580 - char * extra) 581 - { 582 - /* Check if the driver has something to export */ 583 - if ((dev->wireless_handlers->num_private_args == 0) || 584 - (dev->wireless_handlers->private_args == NULL)) 585 - return -EOPNOTSUPP; 586 - 587 - /* Check if there is enough buffer up there */ 588 - if (wrqu->data.length < dev->wireless_handlers->num_private_args) { 589 - /* User space can't know in advance how large the buffer 590 - * needs to be. Give it a hint, so that we can support 591 - * any size buffer we want somewhat efficiently... */ 592 - wrqu->data.length = dev->wireless_handlers->num_private_args; 593 - return -E2BIG; 594 - } 595 - 596 - /* Set the number of available ioctls. */ 597 - wrqu->data.length = dev->wireless_handlers->num_private_args; 598 - 599 - /* Copy structure to the user buffer. */ 600 - memcpy(extra, dev->wireless_handlers->private_args, 601 - sizeof(struct iw_priv_args) * wrqu->data.length); 602 - 603 - return 0; 604 - } 605 - 606 - 607 - /******************** /proc/net/wireless SUPPORT ********************/ 608 - /* 609 - * The /proc/net/wireless file is a human readable user-space interface 610 - * exporting various wireless specific statistics from the wireless devices. 611 - * This is the most popular part of the Wireless Extensions ;-) 612 - * 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 - 617 - #ifdef CONFIG_PROC_FS 618 - 619 - /* ---------------------------------------------------------------- */ 620 - /* 621 - * Print one entry (line) of /proc/net/wireless 622 - */ 623 - static void wireless_seq_printf_stats(struct seq_file *seq, 624 - struct net_device *dev) 625 - { 626 - /* Get stats from the driver */ 627 - struct iw_statistics *stats = get_wireless_stats(dev); 628 - static struct iw_statistics nullstats = {}; 629 - 630 - /* show device if it's wireless regardless of current stats */ 631 - if (!stats && dev->wireless_handlers) 632 - stats = &nullstats; 633 - 634 - if (stats) { 635 - seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " 636 - "%6d %6d %6d\n", 637 - dev->name, stats->status, stats->qual.qual, 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 - } 655 - } 656 - 657 - /* ---------------------------------------------------------------- */ 658 - /* 659 - * Print info for /proc/net/wireless (print all entries) 660 - */ 661 - static int wireless_dev_seq_show(struct seq_file *seq, void *v) 662 - { 663 - might_sleep(); 664 - 665 - if (v == SEQ_START_TOKEN) 666 - seq_printf(seq, "Inter-| sta-| Quality | Discarded " 667 - "packets | Missed | WE\n" 668 - " face | tus | link level noise | nwid " 669 - "crypt frag retry misc | beacon | %d\n", 670 - WIRELESS_EXT); 671 - else 672 - wireless_seq_printf_stats(seq, v); 673 - return 0; 674 - } 675 - 676 - static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos) 677 - { 678 - struct net *net = seq_file_net(seq); 679 - loff_t off; 680 - struct net_device *dev; 681 - 682 - rtnl_lock(); 683 - if (!*pos) 684 - return SEQ_START_TOKEN; 685 - 686 - off = 1; 687 - for_each_netdev(net, dev) 688 - if (off++ == *pos) 689 - return dev; 690 - return NULL; 691 - } 692 - 693 - static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) 694 - { 695 - struct net *net = seq_file_net(seq); 696 - 697 - ++*pos; 698 - 699 - return v == SEQ_START_TOKEN ? 700 - first_net_device(net) : next_net_device(v); 701 - } 702 - 703 - static void wireless_dev_seq_stop(struct seq_file *seq, void *v) 704 - { 705 - rtnl_unlock(); 706 - } 707 - 708 - static 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 - 715 - static int seq_open_wireless(struct inode *inode, struct file *file) 716 - { 717 - return seq_open_net(inode, file, &wireless_seq_ops, 718 - sizeof(struct seq_net_private)); 719 - } 720 - 721 - static const struct file_operations wireless_seq_fops = { 722 - .owner = THIS_MODULE, 723 - .open = seq_open_wireless, 724 - .read = seq_read, 725 - .llseek = seq_lseek, 726 - .release = seq_release_net, 727 - }; 728 - 729 - int wext_proc_init(struct net *net) 730 - { 731 - /* Create /proc/net/wireless entry */ 732 - if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops)) 733 - return -ENOMEM; 734 - 735 - return 0; 736 - } 737 - 738 - void wext_proc_exit(struct net *net) 739 - { 740 - proc_net_remove(net, "wireless"); 741 - } 742 - #endif /* CONFIG_PROC_FS */ 743 - 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 - /* ---------------------------------------------------------------- */ 753 - static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, 754 - const struct iw_ioctl_description *descr, 755 - iw_handler handler, struct net_device *dev, 756 - struct iw_request_info *info) 757 - { 758 - int err, extra_size, user_length = 0, essid_compat = 0; 759 - char *extra; 760 - 761 - /* Calculate space needed by arguments. Always allocate 762 - * for max space. 763 - */ 764 - extra_size = descr->max_tokens * descr->token_size; 765 - 766 - /* Check need for ESSID compatibility for WE < 21 */ 767 - switch (cmd) { 768 - case SIOCSIWESSID: 769 - case SIOCGIWESSID: 770 - case SIOCSIWNICKN: 771 - case SIOCGIWNICKN: 772 - if (iwp->length == descr->max_tokens + 1) 773 - essid_compat = 1; 774 - else if (IW_IS_SET(cmd) && (iwp->length != 0)) { 775 - char essid[IW_ESSID_MAX_SIZE + 1]; 776 - unsigned int len; 777 - len = iwp->length * descr->token_size; 778 - 779 - if (len > IW_ESSID_MAX_SIZE) 780 - return -EFAULT; 781 - 782 - err = copy_from_user(essid, iwp->pointer, len); 783 - if (err) 784 - return -EFAULT; 785 - 786 - if (essid[iwp->length - 1] == '\0') 787 - essid_compat = 1; 788 - } 789 - break; 790 - default: 791 - break; 792 - } 793 - 794 - iwp->length -= essid_compat; 795 - 796 - /* Check what user space is giving us */ 797 - if (IW_IS_SET(cmd)) { 798 - /* Check NULL pointer */ 799 - if (!iwp->pointer && iwp->length != 0) 800 - return -EFAULT; 801 - /* Check if number of token fits within bounds */ 802 - if (iwp->length > descr->max_tokens) 803 - return -E2BIG; 804 - if (iwp->length < descr->min_tokens) 805 - return -EINVAL; 806 - } else { 807 - /* Check NULL pointer */ 808 - if (!iwp->pointer) 809 - return -EFAULT; 810 - /* Save user space buffer size for checking */ 811 - user_length = iwp->length; 812 - 813 - /* Don't check if user_length > max to allow forward 814 - * compatibility. The test user_length < min is 815 - * implied by the test at the end. 816 - */ 817 - 818 - /* Support for very large requests */ 819 - if ((descr->flags & IW_DESCR_FLAG_NOMAX) && 820 - (user_length > descr->max_tokens)) { 821 - /* Allow userspace to GET more than max so 822 - * we can support any size GET requests. 823 - * There is still a limit : -ENOMEM. 824 - */ 825 - extra_size = user_length * descr->token_size; 826 - 827 - /* Note : user_length is originally a __u16, 828 - * and token_size is controlled by us, 829 - * so extra_size won't get negative and 830 - * won't overflow... 831 - */ 832 - } 833 - } 834 - 835 - /* kzalloc() ensures NULL-termination for essid_compat. */ 836 - extra = kzalloc(extra_size, GFP_KERNEL); 837 - if (!extra) 838 - return -ENOMEM; 839 - 840 - /* If it is a SET, get all the extra data in here */ 841 - if (IW_IS_SET(cmd) && (iwp->length != 0)) { 842 - if (copy_from_user(extra, iwp->pointer, 843 - iwp->length * 844 - descr->token_size)) { 845 - err = -EFAULT; 846 - goto out; 847 - } 848 - 849 - if (cmd == SIOCSIWENCODEEXT) { 850 - struct iw_encode_ext *ee = (void *) extra; 851 - 852 - if (iwp->length < sizeof(*ee) + ee->key_len) 853 - return -EFAULT; 854 - } 855 - } 856 - 857 - err = handler(dev, info, (union iwreq_data *) iwp, extra); 858 - 859 - iwp->length += essid_compat; 860 - 861 - /* If we have something to return to the user */ 862 - if (!err && IW_IS_GET(cmd)) { 863 - /* Check if there is enough buffer up there */ 864 - if (user_length < iwp->length) { 865 - err = -E2BIG; 866 - goto out; 867 - } 868 - 869 - if (copy_to_user(iwp->pointer, extra, 870 - iwp->length * 871 - descr->token_size)) { 872 - err = -EFAULT; 873 - goto out; 874 - } 875 - } 876 - 877 - /* Generate an event to notify listeners of the change */ 878 - if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) { 879 - union iwreq_data *data = (union iwreq_data *) iwp; 880 - 881 - if (descr->flags & IW_DESCR_FLAG_RESTRICT) 882 - /* If the event is restricted, don't 883 - * export the payload. 884 - */ 885 - wireless_send_event(dev, cmd, data, NULL); 886 - else 887 - wireless_send_event(dev, cmd, data, extra); 888 - } 889 - 890 - out: 891 - kfree(extra); 892 - return err; 893 - } 894 - 895 - /* 896 - * Wrapper to call a standard Wireless Extension handler. 897 - * We do various checks and also take care of moving data between 898 - * user space and kernel space. 899 - */ 900 - static int ioctl_standard_call(struct net_device * dev, 901 - struct iwreq *iwr, 902 - unsigned int cmd, 903 - struct iw_request_info *info, 904 - iw_handler handler) 905 - { 906 - const struct iw_ioctl_description * descr; 907 - int ret = -EINVAL; 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 - * 947 - * IMPORTANT : This function prevent to set and get data on the same 948 - * IOCTL and enforce the SET/GET convention. Not doing it would be 949 - * far too hairy... 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 - */ 954 - static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd, 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 - 998 - static 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 - 1043 - out: 1044 - kfree(extra); 1045 - return err; 1046 - } 1047 - 1048 - static 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 - { 1052 - int extra_size = 0, ret = -EINVAL; 1053 - const struct iw_priv_args *descr; 1054 - 1055 - extra_size = get_priv_descr_and_size(dev, cmd, &descr); 1056 - 1057 - /* Check if we have a pointer to user space data or not. */ 1058 - if (extra_size == 0) { 1059 - /* No extra arguments. Trivial to handle */ 1060 - ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); 1061 - } else { 1062 - ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr, 1063 - handler, dev, info, extra_size); 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 - } 1072 - 1073 - /* ---------------------------------------------------------------- */ 1074 - typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *, 1075 - unsigned int, struct iw_request_info *, 1076 - iw_handler); 1077 - 1078 - /* 1079 - * Main IOCTl dispatcher. 1080 - * Check the type of IOCTL and call the appropriate wrapper... 1081 - */ 1082 - static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, 1083 - unsigned int cmd, 1084 - struct iw_request_info *info, 1085 - wext_ioctl_func standard, 1086 - wext_ioctl_func private) 1087 - { 1088 - struct iwreq *iwr = (struct iwreq *) ifr; 1089 - struct net_device *dev; 1090 - iw_handler handler; 1091 - 1092 - /* Permissions are already checked in dev_ioctl() before calling us. 1093 - * The copy_to/from_user() of ifr is also dealt with in there */ 1094 - 1095 - /* Make sure the device exist */ 1096 - if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) 1097 - return -ENODEV; 1098 - 1099 - /* A bunch of special cases, then the generic case... 1100 - * Note that 'cmd' is already filtered in dev_ioctl() with 1101 - * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ 1102 - if (cmd == SIOCGIWSTATS) 1103 - return standard(dev, iwr, cmd, info, 1104 - &iw_handler_get_iwstats); 1105 - 1106 - if (cmd == SIOCGIWPRIV && dev->wireless_handlers) 1107 - return standard(dev, iwr, cmd, info, 1108 - &iw_handler_get_private); 1109 - 1110 - /* Basic check */ 1111 - if (!netif_device_present(dev)) 1112 - return -ENODEV; 1113 - 1114 - /* New driver API : try to find the handler */ 1115 - handler = get_handler(dev, cmd); 1116 - if (handler) { 1117 - /* Standard and private are not the same */ 1118 - if (cmd < SIOCIWFIRSTPRIV) 1119 - return standard(dev, iwr, cmd, info, handler); 1120 - else 1121 - return private(dev, iwr, cmd, info, handler); 1122 - } 1123 - /* Old driver API : call driver ioctl handler */ 1124 - if (dev->netdev_ops->ndo_do_ioctl) 1125 - return dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd); 1126 - return -EOPNOTSUPP; 1127 - } 1128 - 1129 - /* If command is `set a parameter', or `get the encoding parameters', 1130 - * check if the user has the right to do it. 1131 - */ 1132 - static int wext_permission_check(unsigned int cmd) 1133 - { 1134 - if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT) 1135 - && !capable(CAP_NET_ADMIN)) 1136 - return -EPERM; 1137 - 1138 - return 0; 1139 - } 1140 - 1141 - /* entry point from dev ioctl */ 1142 - static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr, 1143 - unsigned int cmd, struct iw_request_info *info, 1144 - wext_ioctl_func standard, 1145 - wext_ioctl_func private) 1146 - { 1147 - int ret = wext_permission_check(cmd); 1148 - 1149 - if (ret) 1150 - return ret; 1151 - 1152 - dev_load(net, ifr->ifr_name); 1153 - rtnl_lock(); 1154 - ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private); 1155 - rtnl_unlock(); 1156 - 1157 - return ret; 1158 - } 1159 - 1160 - int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, 1161 - void __user *arg) 1162 - { 1163 - struct iw_request_info info = { .cmd = cmd, .flags = 0 }; 1164 - int ret; 1165 - 1166 - ret = wext_ioctl_dispatch(net, ifr, cmd, &info, 1167 - ioctl_standard_call, 1168 - ioctl_private_call); 1169 - if (ret >= 0 && 1170 - IW_IS_GET(cmd) && 1171 - copy_to_user(arg, ifr, sizeof(struct iwreq))) 1172 - return -EFAULT; 1173 - 1174 - return ret; 1175 - } 1176 - 1177 - #ifdef CONFIG_COMPAT 1178 - static int compat_standard_call(struct net_device *dev, 1179 - struct iwreq *iwr, 1180 - unsigned int cmd, 1181 - struct iw_request_info *info, 1182 - iw_handler handler) 1183 - { 1184 - const struct iw_ioctl_description *descr; 1185 - struct compat_iw_point *iwp_compat; 1186 - struct iw_point iwp; 1187 - int err; 1188 - 1189 - descr = standard_ioctl + (cmd - SIOCIWFIRST); 1190 - 1191 - if (descr->header_type != IW_HEADER_TYPE_POINT) 1192 - return ioctl_standard_call(dev, iwr, cmd, info, handler); 1193 - 1194 - iwp_compat = (struct compat_iw_point *) &iwr->u.data; 1195 - iwp.pointer = compat_ptr(iwp_compat->pointer); 1196 - iwp.length = iwp_compat->length; 1197 - iwp.flags = iwp_compat->flags; 1198 - 1199 - err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info); 1200 - 1201 - iwp_compat->pointer = ptr_to_compat(iwp.pointer); 1202 - iwp_compat->length = iwp.length; 1203 - iwp_compat->flags = iwp.flags; 1204 - 1205 - return err; 1206 - } 1207 - 1208 - static 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 - 1245 - int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, 1246 - unsigned long arg) 1247 - { 1248 - void __user *argp = (void __user *)arg; 1249 - struct iw_request_info info; 1250 - struct iwreq iwr; 1251 - char *colon; 1252 - int ret; 1253 - 1254 - if (copy_from_user(&iwr, argp, sizeof(struct iwreq))) 1255 - return -EFAULT; 1256 - 1257 - iwr.ifr_name[IFNAMSIZ-1] = 0; 1258 - colon = strchr(iwr.ifr_name, ':'); 1259 - if (colon) 1260 - *colon = 0; 1261 - 1262 - info.cmd = cmd; 1263 - info.flags = IW_REQUEST_FLAG_COMPAT; 1264 - 1265 - ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info, 1266 - compat_standard_call, 1267 - compat_private_call); 1268 - 1269 - if (ret >= 0 && 1270 - IW_IS_GET(cmd) && 1271 - copy_to_user(argp, &iwr, sizeof(struct iwreq))) 1272 - return -EFAULT; 1273 - 1274 - return ret; 1275 - } 1276 - #endif 1277 - 1278 - static int __net_init wext_pernet_init(struct net *net) 1279 - { 1280 - skb_queue_head_init(&net->wext_nlevents); 1281 - return 0; 1282 - } 1283 - 1284 - static void __net_exit wext_pernet_exit(struct net *net) 1285 - { 1286 - skb_queue_purge(&net->wext_nlevents); 1287 - } 1288 - 1289 - static struct pernet_operations wext_pernet_ops = { 1290 - .init = wext_pernet_init, 1291 - .exit = wext_pernet_exit, 1292 - }; 1293 - 1294 - static int __init wireless_nlevent_init(void) 1295 - { 1296 - return register_pernet_subsys(&wext_pernet_ops); 1297 - } 1298 - 1299 - subsys_initcall(wireless_nlevent_init); 1300 - 1301 - /* Process events generated by the wireless layer or the driver. */ 1302 - static 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 - 1318 - static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process); 1319 - 1320 - static 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 - */ 1352 - void 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 - } 1533 - EXPORT_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 - */ 1553 - static 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 - */ 1565 - int 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 - } 1611 - EXPORT_SYMBOL(iw_handler_set_spy); 1612 - 1613 - /*------------------------------------------------------------------*/ 1614 - /* 1615 - * Standard Wireless Handler : get Spy List 1616 - */ 1617 - int 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 - } 1647 - EXPORT_SYMBOL(iw_handler_get_spy); 1648 - 1649 - /*------------------------------------------------------------------*/ 1650 - /* 1651 - * Standard Wireless Handler : set spy threshold 1652 - */ 1653 - int 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 - } 1674 - EXPORT_SYMBOL(iw_handler_set_thrspy); 1675 - 1676 - /*------------------------------------------------------------------*/ 1677 - /* 1678 - * Standard Wireless Handler : get spy threshold 1679 - */ 1680 - int 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 - } 1698 - EXPORT_SYMBOL(iw_handler_get_thrspy); 1699 - 1700 - /*------------------------------------------------------------------*/ 1701 - /* 1702 - * Prepare and send a Spy Threshold event 1703 - */ 1704 - static 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 - */ 1735 - void 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 - } 1775 - EXPORT_SYMBOL(wireless_spy_update);