aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/Kconfig16
-rw-r--r--net/wireless/Makefile4
-rw-r--r--net/wireless/core.c224
-rw-r--r--net/wireless/core.h49
-rw-r--r--net/wireless/sysfs.c80
-rw-r--r--net/wireless/sysfs.h9
-rw-r--r--net/wireless/wext.c1509
7 files changed, 1891 insertions, 0 deletions
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
new file mode 100644
index 000000000000..a228d56a91b8
--- /dev/null
+++ b/net/wireless/Kconfig
@@ -0,0 +1,16 @@
1config CFG80211
2 tristate "Improved wireless configuration API"
3
4config WIRELESS_EXT
5 bool "Wireless extensions"
6 default n
7 ---help---
8 This option enables the legacy wireless extensions
9 (wireless network interface configuration via ioctls.)
10
11 Wireless extensions will be replaced by cfg80211 and
12 will be required only by legacy drivers that implement
13 wireless extension handlers.
14
15 Say N (if you can) unless you know you need wireless
16 extensions for external modules.
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
new file mode 100644
index 000000000000..3a96ae60271c
--- /dev/null
+++ b/net/wireless/Makefile
@@ -0,0 +1,4 @@
1obj-$(CONFIG_WIRELESS_EXT) += wext.o
2obj-$(CONFIG_CFG80211) += cfg80211.o
3
4cfg80211-y += core.o sysfs.o
diff --git a/net/wireless/core.c b/net/wireless/core.c
new file mode 100644
index 000000000000..7eabd55417a5
--- /dev/null
+++ b/net/wireless/core.c
@@ -0,0 +1,224 @@
1/*
2 * This is the linux wireless configuration interface.
3 *
4 * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
5 */
6
7#include <linux/if.h>
8#include <linux/module.h>
9#include <linux/err.h>
10#include <linux/mutex.h>
11#include <linux/list.h>
12#include <linux/nl80211.h>
13#include <linux/debugfs.h>
14#include <linux/notifier.h>
15#include <linux/device.h>
16#include <net/genetlink.h>
17#include <net/cfg80211.h>
18#include <net/wireless.h>
19#include "core.h"
20#include "sysfs.h"
21
22/* name for sysfs, %d is appended */
23#define PHY_NAME "phy"
24
25MODULE_AUTHOR("Johannes Berg");
26MODULE_LICENSE("GPL");
27MODULE_DESCRIPTION("wireless configuration support");
28
29/* RCU might be appropriate here since we usually
30 * only read the list, and that can happen quite
31 * often because we need to do it for each command */
32LIST_HEAD(cfg80211_drv_list);
33DEFINE_MUTEX(cfg80211_drv_mutex);
34static int wiphy_counter;
35
36/* for debugfs */
37static struct dentry *ieee80211_debugfs_dir;
38
39/* exported functions */
40
41struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
42{
43 struct cfg80211_registered_device *drv;
44 int alloc_size;
45
46 alloc_size = sizeof(*drv) + sizeof_priv;
47
48 drv = kzalloc(alloc_size, GFP_KERNEL);
49 if (!drv)
50 return NULL;
51
52 drv->ops = ops;
53
54 mutex_lock(&cfg80211_drv_mutex);
55
56 drv->idx = wiphy_counter;
57
58 /* now increase counter for the next device unless
59 * it has wrapped previously */
60 if (wiphy_counter >= 0)
61 wiphy_counter++;
62
63 mutex_unlock(&cfg80211_drv_mutex);
64
65 if (unlikely(drv->idx < 0)) {
66 /* ugh, wrapped! */
67 kfree(drv);
68 return NULL;
69 }
70
71 /* give it a proper name */
72 snprintf(drv->wiphy.dev.bus_id, BUS_ID_SIZE,
73 PHY_NAME "%d", drv->idx);
74
75 mutex_init(&drv->mtx);
76 mutex_init(&drv->devlist_mtx);
77 INIT_LIST_HEAD(&drv->netdev_list);
78
79 device_initialize(&drv->wiphy.dev);
80 drv->wiphy.dev.class = &ieee80211_class;
81 drv->wiphy.dev.platform_data = drv;
82
83 return &drv->wiphy;
84}
85EXPORT_SYMBOL(wiphy_new);
86
87int wiphy_register(struct wiphy *wiphy)
88{
89 struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
90 int res;
91
92 mutex_lock(&cfg80211_drv_mutex);
93
94 res = device_add(&drv->wiphy.dev);
95 if (res)
96 goto out_unlock;
97
98 list_add(&drv->list, &cfg80211_drv_list);
99
100 /* add to debugfs */
101 drv->wiphy.debugfsdir =
102 debugfs_create_dir(wiphy_name(&drv->wiphy),
103 ieee80211_debugfs_dir);
104
105 res = 0;
106out_unlock:
107 mutex_unlock(&cfg80211_drv_mutex);
108 return res;
109}
110EXPORT_SYMBOL(wiphy_register);
111
112void wiphy_unregister(struct wiphy *wiphy)
113{
114 struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
115
116 /* protect the device list */
117 mutex_lock(&cfg80211_drv_mutex);
118
119 BUG_ON(!list_empty(&drv->netdev_list));
120
121 /*
122 * Try to grab drv->mtx. If a command is still in progress,
123 * hopefully the driver will refuse it since it's tearing
124 * down the device already. We wait for this command to complete
125 * before unlinking the item from the list.
126 * Note: as codified by the BUG_ON above we cannot get here if
127 * a virtual interface is still associated. Hence, we can only
128 * get to lock contention here if userspace issues a command
129 * that identified the hardware by wiphy index.
130 */
131 mutex_lock(&drv->mtx);
132 /* unlock again before freeing */
133 mutex_unlock(&drv->mtx);
134
135 list_del(&drv->list);
136 device_del(&drv->wiphy.dev);
137 debugfs_remove(drv->wiphy.debugfsdir);
138
139 mutex_unlock(&cfg80211_drv_mutex);
140}
141EXPORT_SYMBOL(wiphy_unregister);
142
143void cfg80211_dev_free(struct cfg80211_registered_device *drv)
144{
145 mutex_destroy(&drv->mtx);
146 mutex_destroy(&drv->devlist_mtx);
147 kfree(drv);
148}
149
150void wiphy_free(struct wiphy *wiphy)
151{
152 put_device(&wiphy->dev);
153}
154EXPORT_SYMBOL(wiphy_free);
155
156static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
157 unsigned long state,
158 void *ndev)
159{
160 struct net_device *dev = ndev;
161 struct cfg80211_registered_device *rdev;
162
163 if (!dev->ieee80211_ptr)
164 return 0;
165
166 rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
167
168 switch (state) {
169 case NETDEV_REGISTER:
170 mutex_lock(&rdev->devlist_mtx);
171 list_add(&dev->ieee80211_ptr->list, &rdev->netdev_list);
172 if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj,
173 "phy80211")) {
174 printk(KERN_ERR "wireless: failed to add phy80211 "
175 "symlink to netdev!\n");
176 }
177 dev->ieee80211_ptr->netdev = dev;
178 mutex_unlock(&rdev->devlist_mtx);
179 break;
180 case NETDEV_UNREGISTER:
181 mutex_lock(&rdev->devlist_mtx);
182 if (!list_empty(&dev->ieee80211_ptr->list)) {
183 sysfs_remove_link(&dev->dev.kobj, "phy80211");
184 list_del_init(&dev->ieee80211_ptr->list);
185 }
186 mutex_unlock(&rdev->devlist_mtx);
187 break;
188 }
189
190 return 0;
191}
192
193static struct notifier_block cfg80211_netdev_notifier = {
194 .notifier_call = cfg80211_netdev_notifier_call,
195};
196
197static int cfg80211_init(void)
198{
199 int err = wiphy_sysfs_init();
200 if (err)
201 goto out_fail_sysfs;
202
203 err = register_netdevice_notifier(&cfg80211_netdev_notifier);
204 if (err)
205 goto out_fail_notifier;
206
207 ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL);
208
209 return 0;
210
211out_fail_notifier:
212 wiphy_sysfs_exit();
213out_fail_sysfs:
214 return err;
215}
216module_init(cfg80211_init);
217
218static void cfg80211_exit(void)
219{
220 debugfs_remove(ieee80211_debugfs_dir);
221 unregister_netdevice_notifier(&cfg80211_netdev_notifier);
222 wiphy_sysfs_exit();
223}
224module_exit(cfg80211_exit);
diff --git a/net/wireless/core.h b/net/wireless/core.h
new file mode 100644
index 000000000000..158db1edb92a
--- /dev/null
+++ b/net/wireless/core.h
@@ -0,0 +1,49 @@
1/*
2 * Wireless configuration interface internals.
3 *
4 * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
5 */
6#ifndef __NET_WIRELESS_CORE_H
7#define __NET_WIRELESS_CORE_H
8#include <linux/mutex.h>
9#include <linux/list.h>
10#include <linux/netdevice.h>
11#include <net/genetlink.h>
12#include <net/wireless.h>
13#include <net/cfg80211.h>
14
15struct cfg80211_registered_device {
16 struct cfg80211_ops *ops;
17 struct list_head list;
18 /* we hold this mutex during any call so that
19 * we cannot do multiple calls at once, and also
20 * to avoid the deregister call to proceed while
21 * any call is in progress */
22 struct mutex mtx;
23
24 /* wiphy index, internal only */
25 int idx;
26
27 /* associate netdev list */
28 struct mutex devlist_mtx;
29 struct list_head netdev_list;
30
31 /* must be last because of the way we do wiphy_priv(),
32 * and it should at least be aligned to NETDEV_ALIGN */
33 struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
34};
35
36static inline
37struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy)
38{
39 BUG_ON(!wiphy);
40 return container_of(wiphy, struct cfg80211_registered_device, wiphy);
41}
42
43extern struct mutex cfg80211_drv_mutex;
44extern struct list_head cfg80211_drv_list;
45
46/* free object */
47extern void cfg80211_dev_free(struct cfg80211_registered_device *drv);
48
49#endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
new file mode 100644
index 000000000000..3ebae1442963
--- /dev/null
+++ b/net/wireless/sysfs.c
@@ -0,0 +1,80 @@
1/*
2 * This file provides /sys/class/ieee80211/<wiphy name>/
3 * and some default attributes.
4 *
5 * Copyright 2005-2006 Jiri Benc <jbenc@suse.cz>
6 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
7 *
8 * This file is GPLv2 as found in COPYING.
9 */
10
11#include <linux/device.h>
12#include <linux/module.h>
13#include <linux/netdevice.h>
14#include <linux/nl80211.h>
15#include <linux/rtnetlink.h>
16#include <net/cfg80211.h>
17#include "sysfs.h"
18#include "core.h"
19
20static inline struct cfg80211_registered_device *dev_to_rdev(
21 struct device *dev)
22{
23 return container_of(dev, struct cfg80211_registered_device, wiphy.dev);
24}
25
26static ssize_t _show_index(struct device *dev, struct device_attribute *attr,
27 char *buf)
28{
29 return sprintf(buf, "%d\n", dev_to_rdev(dev)->idx);
30}
31
32static ssize_t _show_permaddr(struct device *dev,
33 struct device_attribute *attr,
34 char *buf)
35{
36 char *addr = dev_to_rdev(dev)->wiphy.perm_addr;
37
38 return sprintf(buf, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
39 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
40}
41
42static struct device_attribute ieee80211_dev_attrs[] = {
43 __ATTR(index, S_IRUGO, _show_index, NULL),
44 __ATTR(macaddress, S_IRUGO, _show_permaddr, NULL),
45 {}
46};
47
48static void wiphy_dev_release(struct device *dev)
49{
50 struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
51
52 cfg80211_dev_free(rdev);
53}
54
55static int wiphy_uevent(struct device *dev, char **envp,
56 int num_envp, char *buf, int size)
57{
58 /* TODO, we probably need stuff here */
59 return 0;
60}
61
62struct class ieee80211_class = {
63 .name = "ieee80211",
64 .owner = THIS_MODULE,
65 .dev_release = wiphy_dev_release,
66 .dev_attrs = ieee80211_dev_attrs,
67#ifdef CONFIG_HOTPLUG
68 .dev_uevent = wiphy_uevent,
69#endif
70};
71
72int wiphy_sysfs_init(void)
73{
74 return class_register(&ieee80211_class);
75}
76
77void wiphy_sysfs_exit(void)
78{
79 class_unregister(&ieee80211_class);
80}
diff --git a/net/wireless/sysfs.h b/net/wireless/sysfs.h
new file mode 100644
index 000000000000..65acbebd3711
--- /dev/null
+++ b/net/wireless/sysfs.h
@@ -0,0 +1,9 @@
1#ifndef __WIRELESS_SYSFS_H
2#define __WIRELESS_SYSFS_H
3
4extern int wiphy_sysfs_init(void);
5extern void wiphy_sysfs_exit(void);
6
7extern struct class ieee80211_class;
8
9#endif /* __WIRELESS_SYSFS_H */
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
new file mode 100644
index 000000000000..d6aaf65192e9
--- /dev/null
+++ b/net/wireless/wext.c
@@ -0,0 +1,1509 @@
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 loose 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
97#include <linux/wireless.h> /* Pretty obvious */
98#include <net/iw_handler.h> /* New driver API */
99#include <net/netlink.h>
100#include <net/wext.h>
101
102#include <asm/uaccess.h> /* copy_to_user() */
103
104/************************* GLOBAL VARIABLES *************************/
105/*
106 * You should not use global variables, because of re-entrancy.
107 * On our case, it's only const, so it's OK...
108 */
109/*
110 * Meta-data about all the standard Wireless Extension request we
111 * know about.
112 */
113static const struct iw_ioctl_description standard_ioctl[] = {
114 [SIOCSIWCOMMIT - SIOCIWFIRST] = {
115 .header_type = IW_HEADER_TYPE_NULL,
116 },
117 [SIOCGIWNAME - SIOCIWFIRST] = {
118 .header_type = IW_HEADER_TYPE_CHAR,
119 .flags = IW_DESCR_FLAG_DUMP,
120 },
121 [SIOCSIWNWID - SIOCIWFIRST] = {
122 .header_type = IW_HEADER_TYPE_PARAM,
123 .flags = IW_DESCR_FLAG_EVENT,
124 },
125 [SIOCGIWNWID - SIOCIWFIRST] = {
126 .header_type = IW_HEADER_TYPE_PARAM,
127 .flags = IW_DESCR_FLAG_DUMP,
128 },
129 [SIOCSIWFREQ - SIOCIWFIRST] = {
130 .header_type = IW_HEADER_TYPE_FREQ,
131 .flags = IW_DESCR_FLAG_EVENT,
132 },
133 [SIOCGIWFREQ - SIOCIWFIRST] = {
134 .header_type = IW_HEADER_TYPE_FREQ,
135 .flags = IW_DESCR_FLAG_DUMP,
136 },
137 [SIOCSIWMODE - SIOCIWFIRST] = {
138 .header_type = IW_HEADER_TYPE_UINT,
139 .flags = IW_DESCR_FLAG_EVENT,
140 },
141 [SIOCGIWMODE - SIOCIWFIRST] = {
142 .header_type = IW_HEADER_TYPE_UINT,
143 .flags = IW_DESCR_FLAG_DUMP,
144 },
145 [SIOCSIWSENS - SIOCIWFIRST] = {
146 .header_type = IW_HEADER_TYPE_PARAM,
147 },
148 [SIOCGIWSENS - SIOCIWFIRST] = {
149 .header_type = IW_HEADER_TYPE_PARAM,
150 },
151 [SIOCSIWRANGE - SIOCIWFIRST] = {
152 .header_type = IW_HEADER_TYPE_NULL,
153 },
154 [SIOCGIWRANGE - SIOCIWFIRST] = {
155 .header_type = IW_HEADER_TYPE_POINT,
156 .token_size = 1,
157 .max_tokens = sizeof(struct iw_range),
158 .flags = IW_DESCR_FLAG_DUMP,
159 },
160 [SIOCSIWPRIV - SIOCIWFIRST] = {
161 .header_type = IW_HEADER_TYPE_NULL,
162 },
163 [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */
164 .header_type = IW_HEADER_TYPE_POINT,
165 .token_size = sizeof(struct iw_priv_args),
166 .max_tokens = 16,
167 .flags = IW_DESCR_FLAG_NOMAX,
168 },
169 [SIOCSIWSTATS - SIOCIWFIRST] = {
170 .header_type = IW_HEADER_TYPE_NULL,
171 },
172 [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */
173 .header_type = IW_HEADER_TYPE_POINT,
174 .token_size = 1,
175 .max_tokens = sizeof(struct iw_statistics),
176 .flags = IW_DESCR_FLAG_DUMP,
177 },
178 [SIOCSIWSPY - SIOCIWFIRST] = {
179 .header_type = IW_HEADER_TYPE_POINT,
180 .token_size = sizeof(struct sockaddr),
181 .max_tokens = IW_MAX_SPY,
182 },
183 [SIOCGIWSPY - SIOCIWFIRST] = {
184 .header_type = IW_HEADER_TYPE_POINT,
185 .token_size = sizeof(struct sockaddr) +
186 sizeof(struct iw_quality),
187 .max_tokens = IW_MAX_SPY,
188 },
189 [SIOCSIWTHRSPY - SIOCIWFIRST] = {
190 .header_type = IW_HEADER_TYPE_POINT,
191 .token_size = sizeof(struct iw_thrspy),
192 .min_tokens = 1,
193 .max_tokens = 1,
194 },
195 [SIOCGIWTHRSPY - SIOCIWFIRST] = {
196 .header_type = IW_HEADER_TYPE_POINT,
197 .token_size = sizeof(struct iw_thrspy),
198 .min_tokens = 1,
199 .max_tokens = 1,
200 },
201 [SIOCSIWAP - SIOCIWFIRST] = {
202 .header_type = IW_HEADER_TYPE_ADDR,
203 },
204 [SIOCGIWAP - SIOCIWFIRST] = {
205 .header_type = IW_HEADER_TYPE_ADDR,
206 .flags = IW_DESCR_FLAG_DUMP,
207 },
208 [SIOCSIWMLME - SIOCIWFIRST] = {
209 .header_type = IW_HEADER_TYPE_POINT,
210 .token_size = 1,
211 .min_tokens = sizeof(struct iw_mlme),
212 .max_tokens = sizeof(struct iw_mlme),
213 },
214 [SIOCGIWAPLIST - SIOCIWFIRST] = {
215 .header_type = IW_HEADER_TYPE_POINT,
216 .token_size = sizeof(struct sockaddr) +
217 sizeof(struct iw_quality),
218 .max_tokens = IW_MAX_AP,
219 .flags = IW_DESCR_FLAG_NOMAX,
220 },
221 [SIOCSIWSCAN - SIOCIWFIRST] = {
222 .header_type = IW_HEADER_TYPE_POINT,
223 .token_size = 1,
224 .min_tokens = 0,
225 .max_tokens = sizeof(struct iw_scan_req),
226 },
227 [SIOCGIWSCAN - SIOCIWFIRST] = {
228 .header_type = IW_HEADER_TYPE_POINT,
229 .token_size = 1,
230 .max_tokens = IW_SCAN_MAX_DATA,
231 .flags = IW_DESCR_FLAG_NOMAX,
232 },
233 [SIOCSIWESSID - SIOCIWFIRST] = {
234 .header_type = IW_HEADER_TYPE_POINT,
235 .token_size = 1,
236 .max_tokens = IW_ESSID_MAX_SIZE,
237 .flags = IW_DESCR_FLAG_EVENT,
238 },
239 [SIOCGIWESSID - SIOCIWFIRST] = {
240 .header_type = IW_HEADER_TYPE_POINT,
241 .token_size = 1,
242 .max_tokens = IW_ESSID_MAX_SIZE,
243 .flags = IW_DESCR_FLAG_DUMP,
244 },
245 [SIOCSIWNICKN - SIOCIWFIRST] = {
246 .header_type = IW_HEADER_TYPE_POINT,
247 .token_size = 1,
248 .max_tokens = IW_ESSID_MAX_SIZE,
249 },
250 [SIOCGIWNICKN - SIOCIWFIRST] = {
251 .header_type = IW_HEADER_TYPE_POINT,
252 .token_size = 1,
253 .max_tokens = IW_ESSID_MAX_SIZE,
254 },
255 [SIOCSIWRATE - SIOCIWFIRST] = {
256 .header_type = IW_HEADER_TYPE_PARAM,
257 },
258 [SIOCGIWRATE - SIOCIWFIRST] = {
259 .header_type = IW_HEADER_TYPE_PARAM,
260 },
261 [SIOCSIWRTS - SIOCIWFIRST] = {
262 .header_type = IW_HEADER_TYPE_PARAM,
263 },
264 [SIOCGIWRTS - SIOCIWFIRST] = {
265 .header_type = IW_HEADER_TYPE_PARAM,
266 },
267 [SIOCSIWFRAG - SIOCIWFIRST] = {
268 .header_type = IW_HEADER_TYPE_PARAM,
269 },
270 [SIOCGIWFRAG - SIOCIWFIRST] = {
271 .header_type = IW_HEADER_TYPE_PARAM,
272 },
273 [SIOCSIWTXPOW - SIOCIWFIRST] = {
274 .header_type = IW_HEADER_TYPE_PARAM,
275 },
276 [SIOCGIWTXPOW - SIOCIWFIRST] = {
277 .header_type = IW_HEADER_TYPE_PARAM,
278 },
279 [SIOCSIWRETRY - SIOCIWFIRST] = {
280 .header_type = IW_HEADER_TYPE_PARAM,
281 },
282 [SIOCGIWRETRY - SIOCIWFIRST] = {
283 .header_type = IW_HEADER_TYPE_PARAM,
284 },
285 [SIOCSIWENCODE - SIOCIWFIRST] = {
286 .header_type = IW_HEADER_TYPE_POINT,
287 .token_size = 1,
288 .max_tokens = IW_ENCODING_TOKEN_MAX,
289 .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
290 },
291 [SIOCGIWENCODE - SIOCIWFIRST] = {
292 .header_type = IW_HEADER_TYPE_POINT,
293 .token_size = 1,
294 .max_tokens = IW_ENCODING_TOKEN_MAX,
295 .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
296 },
297 [SIOCSIWPOWER - SIOCIWFIRST] = {
298 .header_type = IW_HEADER_TYPE_PARAM,
299 },
300 [SIOCGIWPOWER - SIOCIWFIRST] = {
301 .header_type = IW_HEADER_TYPE_PARAM,
302 },
303 [SIOCSIWGENIE - SIOCIWFIRST] = {
304 .header_type = IW_HEADER_TYPE_POINT,
305 .token_size = 1,
306 .max_tokens = IW_GENERIC_IE_MAX,
307 },
308 [SIOCGIWGENIE - SIOCIWFIRST] = {
309 .header_type = IW_HEADER_TYPE_POINT,
310 .token_size = 1,
311 .max_tokens = IW_GENERIC_IE_MAX,
312 },
313 [SIOCSIWAUTH - SIOCIWFIRST] = {
314 .header_type = IW_HEADER_TYPE_PARAM,
315 },
316 [SIOCGIWAUTH - SIOCIWFIRST] = {
317 .header_type = IW_HEADER_TYPE_PARAM,
318 },
319 [SIOCSIWENCODEEXT - SIOCIWFIRST] = {
320 .header_type = IW_HEADER_TYPE_POINT,
321 .token_size = 1,
322 .min_tokens = sizeof(struct iw_encode_ext),
323 .max_tokens = sizeof(struct iw_encode_ext) +
324 IW_ENCODING_TOKEN_MAX,
325 },
326 [SIOCGIWENCODEEXT - SIOCIWFIRST] = {
327 .header_type = IW_HEADER_TYPE_POINT,
328 .token_size = 1,
329 .min_tokens = sizeof(struct iw_encode_ext),
330 .max_tokens = sizeof(struct iw_encode_ext) +
331 IW_ENCODING_TOKEN_MAX,
332 },
333 [SIOCSIWPMKSA - SIOCIWFIRST] = {
334 .header_type = IW_HEADER_TYPE_POINT,
335 .token_size = 1,
336 .min_tokens = sizeof(struct iw_pmksa),
337 .max_tokens = sizeof(struct iw_pmksa),
338 },
339};
340static const unsigned standard_ioctl_num = ARRAY_SIZE(standard_ioctl);
341
342/*
343 * Meta-data about all the additional standard Wireless Extension events
344 * we know about.
345 */
346static const struct iw_ioctl_description standard_event[] = {
347 [IWEVTXDROP - IWEVFIRST] = {
348 .header_type = IW_HEADER_TYPE_ADDR,
349 },
350 [IWEVQUAL - IWEVFIRST] = {
351 .header_type = IW_HEADER_TYPE_QUAL,
352 },
353 [IWEVCUSTOM - IWEVFIRST] = {
354 .header_type = IW_HEADER_TYPE_POINT,
355 .token_size = 1,
356 .max_tokens = IW_CUSTOM_MAX,
357 },
358 [IWEVREGISTERED - IWEVFIRST] = {
359 .header_type = IW_HEADER_TYPE_ADDR,
360 },
361 [IWEVEXPIRED - IWEVFIRST] = {
362 .header_type = IW_HEADER_TYPE_ADDR,
363 },
364 [IWEVGENIE - IWEVFIRST] = {
365 .header_type = IW_HEADER_TYPE_POINT,
366 .token_size = 1,
367 .max_tokens = IW_GENERIC_IE_MAX,
368 },
369 [IWEVMICHAELMICFAILURE - IWEVFIRST] = {
370 .header_type = IW_HEADER_TYPE_POINT,
371 .token_size = 1,
372 .max_tokens = sizeof(struct iw_michaelmicfailure),
373 },
374 [IWEVASSOCREQIE - IWEVFIRST] = {
375 .header_type = IW_HEADER_TYPE_POINT,
376 .token_size = 1,
377 .max_tokens = IW_GENERIC_IE_MAX,
378 },
379 [IWEVASSOCRESPIE - IWEVFIRST] = {
380 .header_type = IW_HEADER_TYPE_POINT,
381 .token_size = 1,
382 .max_tokens = IW_GENERIC_IE_MAX,
383 },
384 [IWEVPMKIDCAND - IWEVFIRST] = {
385 .header_type = IW_HEADER_TYPE_POINT,
386 .token_size = 1,
387 .max_tokens = sizeof(struct iw_pmkid_cand),
388 },
389};
390static const unsigned standard_event_num = ARRAY_SIZE(standard_event);
391
392/* Size (in bytes) of the various private data types */
393static const char iw_priv_type_size[] = {
394 0, /* IW_PRIV_TYPE_NONE */
395 1, /* IW_PRIV_TYPE_BYTE */
396 1, /* IW_PRIV_TYPE_CHAR */
397 0, /* Not defined */
398 sizeof(__u32), /* IW_PRIV_TYPE_INT */
399 sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
400 sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
401 0, /* Not defined */
402};
403
404/* Size (in bytes) of various events */
405static const int event_type_size[] = {
406 IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */
407 0,
408 IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */
409 0,
410 IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */
411 IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */
412 IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */
413 0,
414 IW_EV_POINT_LEN, /* Without variable payload */
415 IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */
416 IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */
417};
418
419/* Size (in bytes) of various events, as packed */
420static const int event_type_pk_size[] = {
421 IW_EV_LCP_PK_LEN, /* IW_HEADER_TYPE_NULL */
422 0,
423 IW_EV_CHAR_PK_LEN, /* IW_HEADER_TYPE_CHAR */
424 0,
425 IW_EV_UINT_PK_LEN, /* IW_HEADER_TYPE_UINT */
426 IW_EV_FREQ_PK_LEN, /* IW_HEADER_TYPE_FREQ */
427 IW_EV_ADDR_PK_LEN, /* IW_HEADER_TYPE_ADDR */
428 0,
429 IW_EV_POINT_PK_LEN, /* Without variable payload */
430 IW_EV_PARAM_PK_LEN, /* IW_HEADER_TYPE_PARAM */
431 IW_EV_QUAL_PK_LEN, /* IW_HEADER_TYPE_QUAL */
432};
433
434/************************ COMMON SUBROUTINES ************************/
435/*
436 * Stuff that may be used in various place or doesn't fit in one
437 * of the section below.
438 */
439
440/* ---------------------------------------------------------------- */
441/*
442 * Return the driver handler associated with a specific Wireless Extension.
443 */
444static iw_handler get_handler(struct net_device *dev, unsigned int cmd)
445{
446 /* Don't "optimise" the following variable, it will crash */
447 unsigned int index; /* *MUST* be unsigned */
448
449 /* Check if we have some wireless handlers defined */
450 if (dev->wireless_handlers == NULL)
451 return NULL;
452
453 /* Try as a standard command */
454 index = cmd - SIOCIWFIRST;
455 if (index < dev->wireless_handlers->num_standard)
456 return dev->wireless_handlers->standard[index];
457
458 /* Try as a private command */
459 index = cmd - SIOCIWFIRSTPRIV;
460 if (index < dev->wireless_handlers->num_private)
461 return dev->wireless_handlers->private[index];
462
463 /* Not found */
464 return NULL;
465}
466
467/* ---------------------------------------------------------------- */
468/*
469 * Get statistics out of the driver
470 */
471static struct iw_statistics *get_wireless_stats(struct net_device *dev)
472{
473 /* New location */
474 if ((dev->wireless_handlers != NULL) &&
475 (dev->wireless_handlers->get_wireless_stats != NULL))
476 return dev->wireless_handlers->get_wireless_stats(dev);
477
478 /* Not found */
479 return NULL;
480}
481
482/* ---------------------------------------------------------------- */
483/*
484 * Call the commit handler in the driver
485 * (if exist and if conditions are right)
486 *
487 * Note : our current commit strategy is currently pretty dumb,
488 * but we will be able to improve on that...
489 * The goal is to try to agreagate as many changes as possible
490 * before doing the commit. Drivers that will define a commit handler
491 * are usually those that need a reset after changing parameters, so
492 * we want to minimise the number of reset.
493 * A cool idea is to use a timer : at each "set" command, we re-set the
494 * timer, when the timer eventually fires, we call the driver.
495 * Hopefully, more on that later.
496 *
497 * Also, I'm waiting to see how many people will complain about the
498 * netif_running(dev) test. I'm open on that one...
499 * Hopefully, the driver will remember to do a commit in "open()" ;-)
500 */
501static int call_commit_handler(struct net_device *dev)
502{
503 if ((netif_running(dev)) &&
504 (dev->wireless_handlers->standard[0] != NULL))
505 /* Call the commit handler on the driver */
506 return dev->wireless_handlers->standard[0](dev, NULL,
507 NULL, NULL);
508 else
509 return 0; /* Command completed successfully */
510}
511
512/* ---------------------------------------------------------------- */
513/*
514 * Calculate size of private arguments
515 */
516static inline int get_priv_size(__u16 args)
517{
518 int num = args & IW_PRIV_SIZE_MASK;
519 int type = (args & IW_PRIV_TYPE_MASK) >> 12;
520
521 return num * iw_priv_type_size[type];
522}
523
524/* ---------------------------------------------------------------- */
525/*
526 * Re-calculate the size of private arguments
527 */
528static inline int adjust_priv_size(__u16 args,
529 union iwreq_data * wrqu)
530{
531 int num = wrqu->data.length;
532 int max = args & IW_PRIV_SIZE_MASK;
533 int type = (args & IW_PRIV_TYPE_MASK) >> 12;
534
535 /* Make sure the driver doesn't goof up */
536 if (max < num)
537 num = max;
538
539 return num * iw_priv_type_size[type];
540}
541
542/* ---------------------------------------------------------------- */
543/*
544 * Standard Wireless Handler : get wireless stats
545 * Allow programatic access to /proc/net/wireless even if /proc
546 * doesn't exist... Also more efficient...
547 */
548static int iw_handler_get_iwstats(struct net_device * dev,
549 struct iw_request_info * info,
550 union iwreq_data * wrqu,
551 char * extra)
552{
553 /* Get stats from the driver */
554 struct iw_statistics *stats;
555
556 stats = get_wireless_stats(dev);
557 if (stats) {
558 /* Copy statistics to extra */
559 memcpy(extra, stats, sizeof(struct iw_statistics));
560 wrqu->data.length = sizeof(struct iw_statistics);
561
562 /* Check if we need to clear the updated flag */
563 if (wrqu->data.flags != 0)
564 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
565 return 0;
566 } else
567 return -EOPNOTSUPP;
568}
569
570/* ---------------------------------------------------------------- */
571/*
572 * Standard Wireless Handler : get iwpriv definitions
573 * Export the driver private handler definition
574 * They will be picked up by tools like iwpriv...
575 */
576static int iw_handler_get_private(struct net_device * dev,
577 struct iw_request_info * info,
578 union iwreq_data * wrqu,
579 char * extra)
580{
581 /* Check if the driver has something to export */
582 if ((dev->wireless_handlers->num_private_args == 0) ||
583 (dev->wireless_handlers->private_args == NULL))
584 return -EOPNOTSUPP;
585
586 /* Check if there is enough buffer up there */
587 if (wrqu->data.length < dev->wireless_handlers->num_private_args) {
588 /* User space can't know in advance how large the buffer
589 * needs to be. Give it a hint, so that we can support
590 * any size buffer we want somewhat efficiently... */
591 wrqu->data.length = dev->wireless_handlers->num_private_args;
592 return -E2BIG;
593 }
594
595 /* Set the number of available ioctls. */
596 wrqu->data.length = dev->wireless_handlers->num_private_args;
597
598 /* Copy structure to the user buffer. */
599 memcpy(extra, dev->wireless_handlers->private_args,
600 sizeof(struct iw_priv_args) * wrqu->data.length);
601
602 return 0;
603}
604
605
606/******************** /proc/net/wireless SUPPORT ********************/
607/*
608 * The /proc/net/wireless file is a human readable user-space interface
609 * exporting various wireless specific statistics from the wireless devices.
610 * This is the most popular part of the Wireless Extensions ;-)
611 *
612 * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
613 * The content of the file is basically the content of "struct iw_statistics".
614 */
615
616#ifdef CONFIG_PROC_FS
617
618/* ---------------------------------------------------------------- */
619/*
620 * Print one entry (line) of /proc/net/wireless
621 */
622static void wireless_seq_printf_stats(struct seq_file *seq,
623 struct net_device *dev)
624{
625 /* Get stats from the driver */
626 struct iw_statistics *stats = get_wireless_stats(dev);
627
628 if (stats) {
629 seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d "
630 "%6d %6d %6d\n",
631 dev->name, stats->status, stats->qual.qual,
632 stats->qual.updated & IW_QUAL_QUAL_UPDATED
633 ? '.' : ' ',
634 ((__s32) stats->qual.level) -
635 ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
636 stats->qual.updated & IW_QUAL_LEVEL_UPDATED
637 ? '.' : ' ',
638 ((__s32) stats->qual.noise) -
639 ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
640 stats->qual.updated & IW_QUAL_NOISE_UPDATED
641 ? '.' : ' ',
642 stats->discard.nwid, stats->discard.code,
643 stats->discard.fragment, stats->discard.retries,
644 stats->discard.misc, stats->miss.beacon);
645 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
646 }
647}
648
649/* ---------------------------------------------------------------- */
650/*
651 * Print info for /proc/net/wireless (print all entries)
652 */
653static int wireless_seq_show(struct seq_file *seq, void *v)
654{
655 if (v == SEQ_START_TOKEN)
656 seq_printf(seq, "Inter-| sta-| Quality | Discarded "
657 "packets | Missed | WE\n"
658 " face | tus | link level noise | nwid "
659 "crypt frag retry misc | beacon | %d\n",
660 WIRELESS_EXT);
661 else
662 wireless_seq_printf_stats(seq, v);
663 return 0;
664}
665
666static const struct seq_operations wireless_seq_ops = {
667 .start = dev_seq_start,
668 .next = dev_seq_next,
669 .stop = dev_seq_stop,
670 .show = wireless_seq_show,
671};
672
673static int wireless_seq_open(struct inode *inode, struct file *file)
674{
675 return seq_open(file, &wireless_seq_ops);
676}
677
678static const struct file_operations wireless_seq_fops = {
679 .owner = THIS_MODULE,
680 .open = wireless_seq_open,
681 .read = seq_read,
682 .llseek = seq_lseek,
683 .release = seq_release,
684};
685
686int __init wext_proc_init(void)
687{
688 /* Create /proc/net/wireless entry */
689 if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops))
690 return -ENOMEM;
691
692 return 0;
693}
694#endif /* CONFIG_PROC_FS */
695
696/************************** IOCTL SUPPORT **************************/
697/*
698 * The original user space API to configure all those Wireless Extensions
699 * is through IOCTLs.
700 * In there, we check if we need to call the new driver API (iw_handler)
701 * or just call the driver ioctl handler.
702 */
703
704/* ---------------------------------------------------------------- */
705/*
706 * Wrapper to call a standard Wireless Extension handler.
707 * We do various checks and also take care of moving data between
708 * user space and kernel space.
709 */
710static int ioctl_standard_call(struct net_device * dev,
711 struct ifreq * ifr,
712 unsigned int cmd,
713 iw_handler handler)
714{
715 struct iwreq * iwr = (struct iwreq *) ifr;
716 const struct iw_ioctl_description * descr;
717 struct iw_request_info info;
718 int ret = -EINVAL;
719
720 /* Get the description of the IOCTL */
721 if ((cmd - SIOCIWFIRST) >= standard_ioctl_num)
722 return -EOPNOTSUPP;
723 descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
724
725 /* Prepare the call */
726 info.cmd = cmd;
727 info.flags = 0;
728
729 /* Check if we have a pointer to user space data or not */
730 if (descr->header_type != IW_HEADER_TYPE_POINT) {
731
732 /* No extra arguments. Trivial to handle */
733 ret = handler(dev, &info, &(iwr->u), NULL);
734
735 /* Generate an event to notify listeners of the change */
736 if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
737 ((ret == 0) || (ret == -EIWCOMMIT)))
738 wireless_send_event(dev, cmd, &(iwr->u), NULL);
739 } else {
740 char * extra;
741 int extra_size;
742 int user_length = 0;
743 int err;
744 int essid_compat = 0;
745
746 /* Calculate space needed by arguments. Always allocate
747 * for max space. Easier, and won't last long... */
748 extra_size = descr->max_tokens * descr->token_size;
749
750 /* Check need for ESSID compatibility for WE < 21 */
751 switch (cmd) {
752 case SIOCSIWESSID:
753 case SIOCGIWESSID:
754 case SIOCSIWNICKN:
755 case SIOCGIWNICKN:
756 if (iwr->u.data.length == descr->max_tokens + 1)
757 essid_compat = 1;
758 else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
759 char essid[IW_ESSID_MAX_SIZE + 1];
760
761 err = copy_from_user(essid, iwr->u.data.pointer,
762 iwr->u.data.length *
763 descr->token_size);
764 if (err)
765 return -EFAULT;
766
767 if (essid[iwr->u.data.length - 1] == '\0')
768 essid_compat = 1;
769 }
770 break;
771 default:
772 break;
773 }
774
775 iwr->u.data.length -= essid_compat;
776
777 /* Check what user space is giving us */
778 if (IW_IS_SET(cmd)) {
779 /* Check NULL pointer */
780 if ((iwr->u.data.pointer == NULL) &&
781 (iwr->u.data.length != 0))
782 return -EFAULT;
783 /* Check if number of token fits within bounds */
784 if (iwr->u.data.length > descr->max_tokens)
785 return -E2BIG;
786 if (iwr->u.data.length < descr->min_tokens)
787 return -EINVAL;
788 } else {
789 /* Check NULL pointer */
790 if (iwr->u.data.pointer == NULL)
791 return -EFAULT;
792 /* Save user space buffer size for checking */
793 user_length = iwr->u.data.length;
794
795 /* Don't check if user_length > max to allow forward
796 * compatibility. The test user_length < min is
797 * implied by the test at the end. */
798
799 /* Support for very large requests */
800 if ((descr->flags & IW_DESCR_FLAG_NOMAX) &&
801 (user_length > descr->max_tokens)) {
802 /* Allow userspace to GET more than max so
803 * we can support any size GET requests.
804 * There is still a limit : -ENOMEM. */
805 extra_size = user_length * descr->token_size;
806 /* Note : user_length is originally a __u16,
807 * and token_size is controlled by us,
808 * so extra_size won't get negative and
809 * won't overflow... */
810 }
811 }
812
813 /* Create the kernel buffer */
814 /* kzalloc ensures NULL-termination for essid_compat */
815 extra = kzalloc(extra_size, GFP_KERNEL);
816 if (extra == NULL)
817 return -ENOMEM;
818
819 /* If it is a SET, get all the extra data in here */
820 if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
821 err = copy_from_user(extra, iwr->u.data.pointer,
822 iwr->u.data.length *
823 descr->token_size);
824 if (err) {
825 kfree(extra);
826 return -EFAULT;
827 }
828 }
829
830 /* Call the handler */
831 ret = handler(dev, &info, &(iwr->u), extra);
832
833 iwr->u.data.length += essid_compat;
834
835 /* If we have something to return to the user */
836 if (!ret && IW_IS_GET(cmd)) {
837 /* Check if there is enough buffer up there */
838 if (user_length < iwr->u.data.length) {
839 kfree(extra);
840 return -E2BIG;
841 }
842
843 err = copy_to_user(iwr->u.data.pointer, extra,
844 iwr->u.data.length *
845 descr->token_size);
846 if (err)
847 ret = -EFAULT;
848 }
849
850 /* Generate an event to notify listeners of the change */
851 if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
852 ((ret == 0) || (ret == -EIWCOMMIT))) {
853 if (descr->flags & IW_DESCR_FLAG_RESTRICT)
854 /* If the event is restricted, don't
855 * export the payload */
856 wireless_send_event(dev, cmd, &(iwr->u), NULL);
857 else
858 wireless_send_event(dev, cmd, &(iwr->u),
859 extra);
860 }
861
862 /* Cleanup - I told you it wasn't that long ;-) */
863 kfree(extra);
864 }
865
866 /* Call commit handler if needed and defined */
867 if (ret == -EIWCOMMIT)
868 ret = call_commit_handler(dev);
869
870 /* Here, we will generate the appropriate event if needed */
871
872 return ret;
873}
874
875/* ---------------------------------------------------------------- */
876/*
877 * Wrapper to call a private Wireless Extension handler.
878 * We do various checks and also take care of moving data between
879 * user space and kernel space.
880 * It's not as nice and slimline as the standard wrapper. The cause
881 * is struct iw_priv_args, which was not really designed for the
882 * job we are going here.
883 *
884 * IMPORTANT : This function prevent to set and get data on the same
885 * IOCTL and enforce the SET/GET convention. Not doing it would be
886 * far too hairy...
887 * If you need to set and get data at the same time, please don't use
888 * a iw_handler but process it in your ioctl handler (i.e. use the
889 * old driver API).
890 */
891static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
892 unsigned int cmd, iw_handler handler)
893{
894 struct iwreq * iwr = (struct iwreq *) ifr;
895 const struct iw_priv_args * descr = NULL;
896 struct iw_request_info info;
897 int extra_size = 0;
898 int i;
899 int ret = -EINVAL;
900
901 /* Get the description of the IOCTL */
902 for (i = 0; i < dev->wireless_handlers->num_private_args; i++)
903 if (cmd == dev->wireless_handlers->private_args[i].cmd) {
904 descr = &(dev->wireless_handlers->private_args[i]);
905 break;
906 }
907
908 /* Compute the size of the set/get arguments */
909 if (descr != NULL) {
910 if (IW_IS_SET(cmd)) {
911 int offset = 0; /* For sub-ioctls */
912 /* Check for sub-ioctl handler */
913 if (descr->name[0] == '\0')
914 /* Reserve one int for sub-ioctl index */
915 offset = sizeof(__u32);
916
917 /* Size of set arguments */
918 extra_size = get_priv_size(descr->set_args);
919
920 /* Does it fits in iwr ? */
921 if ((descr->set_args & IW_PRIV_SIZE_FIXED) &&
922 ((extra_size + offset) <= IFNAMSIZ))
923 extra_size = 0;
924 } else {
925 /* Size of get arguments */
926 extra_size = get_priv_size(descr->get_args);
927
928 /* Does it fits in iwr ? */
929 if ((descr->get_args & IW_PRIV_SIZE_FIXED) &&
930 (extra_size <= IFNAMSIZ))
931 extra_size = 0;
932 }
933 }
934
935 /* Prepare the call */
936 info.cmd = cmd;
937 info.flags = 0;
938
939 /* Check if we have a pointer to user space data or not. */
940 if (extra_size == 0) {
941 /* No extra arguments. Trivial to handle */
942 ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
943 } else {
944 char * extra;
945 int err;
946
947 /* Check what user space is giving us */
948 if (IW_IS_SET(cmd)) {
949 /* Check NULL pointer */
950 if ((iwr->u.data.pointer == NULL) &&
951 (iwr->u.data.length != 0))
952 return -EFAULT;
953
954 /* Does it fits within bounds ? */
955 if (iwr->u.data.length > (descr->set_args &
956 IW_PRIV_SIZE_MASK))
957 return -E2BIG;
958 } else if (iwr->u.data.pointer == NULL)
959 return -EFAULT;
960
961 /* Always allocate for max space. Easier, and won't last
962 * long... */
963 extra = kmalloc(extra_size, GFP_KERNEL);
964 if (extra == NULL)
965 return -ENOMEM;
966
967 /* If it is a SET, get all the extra data in here */
968 if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
969 err = copy_from_user(extra, iwr->u.data.pointer,
970 extra_size);
971 if (err) {
972 kfree(extra);
973 return -EFAULT;
974 }
975 }
976
977 /* Call the handler */
978 ret = handler(dev, &info, &(iwr->u), extra);
979
980 /* If we have something to return to the user */
981 if (!ret && IW_IS_GET(cmd)) {
982
983 /* Adjust for the actual length if it's variable,
984 * avoid leaking kernel bits outside. */
985 if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) {
986 extra_size = adjust_priv_size(descr->get_args,
987 &(iwr->u));
988 }
989
990 err = copy_to_user(iwr->u.data.pointer, extra,
991 extra_size);
992 if (err)
993 ret = -EFAULT;
994 }
995
996 /* Cleanup - I told you it wasn't that long ;-) */
997 kfree(extra);
998 }
999
1000
1001 /* Call commit handler if needed and defined */
1002 if (ret == -EIWCOMMIT)
1003 ret = call_commit_handler(dev);
1004
1005 return ret;
1006}
1007
1008/* ---------------------------------------------------------------- */
1009/*
1010 * Main IOCTl dispatcher.
1011 * Check the type of IOCTL and call the appropriate wrapper...
1012 */
1013static int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
1014{
1015 struct net_device *dev;
1016 iw_handler handler;
1017
1018 /* Permissions are already checked in dev_ioctl() before calling us.
1019 * The copy_to/from_user() of ifr is also dealt with in there */
1020
1021 /* Make sure the device exist */
1022 if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
1023 return -ENODEV;
1024
1025 /* A bunch of special cases, then the generic case...
1026 * Note that 'cmd' is already filtered in dev_ioctl() with
1027 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
1028 if (cmd == SIOCGIWSTATS)
1029 return ioctl_standard_call(dev, ifr, cmd,
1030 &iw_handler_get_iwstats);
1031
1032 if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
1033 return ioctl_standard_call(dev, ifr, cmd,
1034 &iw_handler_get_private);
1035
1036 /* Basic check */
1037 if (!netif_device_present(dev))
1038 return -ENODEV;
1039
1040 /* New driver API : try to find the handler */
1041 handler = get_handler(dev, cmd);
1042 if (handler) {
1043 /* Standard and private are not the same */
1044 if (cmd < SIOCIWFIRSTPRIV)
1045 return ioctl_standard_call(dev, ifr, cmd, handler);
1046 else
1047 return ioctl_private_call(dev, ifr, cmd, handler);
1048 }
1049 /* Old driver API : call driver ioctl handler */
1050 if (dev->do_ioctl)
1051 return dev->do_ioctl(dev, ifr, cmd);
1052 return -EOPNOTSUPP;
1053}
1054
1055/* entry point from dev ioctl */
1056int wext_handle_ioctl(struct ifreq *ifr, unsigned int cmd,
1057 void __user *arg)
1058{
1059 int ret;
1060
1061 /* If command is `set a parameter', or
1062 * `get the encoding parameters', check if
1063 * the user has the right to do it */
1064 if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT)
1065 && !capable(CAP_NET_ADMIN))
1066 return -EPERM;
1067
1068 dev_load(ifr->ifr_name);
1069 rtnl_lock();
1070 ret = wireless_process_ioctl(ifr, cmd);
1071 rtnl_unlock();
1072 if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct ifreq)))
1073 return -EFAULT;
1074 return ret;
1075}
1076
1077/************************* EVENT PROCESSING *************************/
1078/*
1079 * Process events generated by the wireless layer or the driver.
1080 * Most often, the event will be propagated through rtnetlink
1081 */
1082
1083/* ---------------------------------------------------------------- */
1084/*
1085 * Locking...
1086 * ----------
1087 *
1088 * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing
1089 * the locking issue in here and implementing this code !
1090 *
1091 * The issue : wireless_send_event() is often called in interrupt context,
1092 * while the Netlink layer can never be called in interrupt context.
1093 * The fully formed RtNetlink events are queued, and then a tasklet is run
1094 * to feed those to Netlink.
1095 * The skb_queue is interrupt safe, and its lock is not held while calling
1096 * Netlink, so there is no possibility of dealock.
1097 * Jean II
1098 */
1099
1100static struct sk_buff_head wireless_nlevent_queue;
1101
1102static int __init wireless_nlevent_init(void)
1103{
1104 skb_queue_head_init(&wireless_nlevent_queue);
1105 return 0;
1106}
1107
1108subsys_initcall(wireless_nlevent_init);
1109
1110static void wireless_nlevent_process(unsigned long data)
1111{
1112 struct sk_buff *skb;
1113
1114 while ((skb = skb_dequeue(&wireless_nlevent_queue)))
1115 rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
1116}
1117
1118static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0);
1119
1120/* ---------------------------------------------------------------- */
1121/*
1122 * Fill a rtnetlink message with our event data.
1123 * Note that we propage only the specified event and don't dump the
1124 * current wireless config. Dumping the wireless config is far too
1125 * expensive (for each parameter, the driver need to query the hardware).
1126 */
1127static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev,
1128 int type, char *event, int event_len)
1129{
1130 struct ifinfomsg *r;
1131 struct nlmsghdr *nlh;
1132 unsigned char *b = skb_tail_pointer(skb);
1133
1134 nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
1135 r = NLMSG_DATA(nlh);
1136 r->ifi_family = AF_UNSPEC;
1137 r->__ifi_pad = 0;
1138 r->ifi_type = dev->type;
1139 r->ifi_index = dev->ifindex;
1140 r->ifi_flags = dev_get_flags(dev);
1141 r->ifi_change = 0; /* Wireless changes don't affect those flags */
1142
1143 /* Add the wireless events in the netlink packet */
1144 RTA_PUT(skb, IFLA_WIRELESS, event_len, event);
1145
1146 nlh->nlmsg_len = skb_tail_pointer(skb) - b;
1147 return skb->len;
1148
1149nlmsg_failure:
1150rtattr_failure:
1151 nlmsg_trim(skb, b);
1152 return -1;
1153}
1154
1155/* ---------------------------------------------------------------- */
1156/*
1157 * Create and broadcast and send it on the standard rtnetlink socket
1158 * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
1159 * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
1160 * within a RTM_NEWLINK event.
1161 */
1162static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
1163{
1164 struct sk_buff *skb;
1165 int size = NLMSG_GOODSIZE;
1166
1167 skb = alloc_skb(size, GFP_ATOMIC);
1168 if (!skb)
1169 return;
1170
1171 if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
1172 event, event_len) < 0) {
1173 kfree_skb(skb);
1174 return;
1175 }
1176 NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
1177 skb_queue_tail(&wireless_nlevent_queue, skb);
1178 tasklet_schedule(&wireless_nlevent_tasklet);
1179}
1180
1181/* ---------------------------------------------------------------- */
1182/*
1183 * Main event dispatcher. Called from other parts and drivers.
1184 * Send the event on the appropriate channels.
1185 * May be called from interrupt context.
1186 */
1187void wireless_send_event(struct net_device * dev,
1188 unsigned int cmd,
1189 union iwreq_data * wrqu,
1190 char * extra)
1191{
1192 const struct iw_ioctl_description * descr = NULL;
1193 int extra_len = 0;
1194 struct iw_event *event; /* Mallocated whole event */
1195 int event_len; /* Its size */
1196 int hdr_len; /* Size of the event header */
1197 int wrqu_off = 0; /* Offset in wrqu */
1198 /* Don't "optimise" the following variable, it will crash */
1199 unsigned cmd_index; /* *MUST* be unsigned */
1200
1201 /* Get the description of the Event */
1202 if (cmd <= SIOCIWLAST) {
1203 cmd_index = cmd - SIOCIWFIRST;
1204 if (cmd_index < standard_ioctl_num)
1205 descr = &(standard_ioctl[cmd_index]);
1206 } else {
1207 cmd_index = cmd - IWEVFIRST;
1208 if (cmd_index < standard_event_num)
1209 descr = &(standard_event[cmd_index]);
1210 }
1211 /* Don't accept unknown events */
1212 if (descr == NULL) {
1213 /* Note : we don't return an error to the driver, because
1214 * the driver would not know what to do about it. It can't
1215 * return an error to the user, because the event is not
1216 * initiated by a user request.
1217 * The best the driver could do is to log an error message.
1218 * We will do it ourselves instead...
1219 */
1220 printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
1221 dev->name, cmd);
1222 return;
1223 }
1224
1225 /* Check extra parameters and set extra_len */
1226 if (descr->header_type == IW_HEADER_TYPE_POINT) {
1227 /* Check if number of token fits within bounds */
1228 if (wrqu->data.length > descr->max_tokens) {
1229 printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
1230 return;
1231 }
1232 if (wrqu->data.length < descr->min_tokens) {
1233 printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
1234 return;
1235 }
1236 /* Calculate extra_len - extra is NULL for restricted events */
1237 if (extra != NULL)
1238 extra_len = wrqu->data.length * descr->token_size;
1239 /* Always at an offset in wrqu */
1240 wrqu_off = IW_EV_POINT_OFF;
1241 }
1242
1243 /* Total length of the event */
1244 hdr_len = event_type_size[descr->header_type];
1245 event_len = hdr_len + extra_len;
1246
1247 /* Create temporary buffer to hold the event */
1248 event = kmalloc(event_len, GFP_ATOMIC);
1249 if (event == NULL)
1250 return;
1251
1252 /* Fill event */
1253 event->len = event_len;
1254 event->cmd = cmd;
1255 memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
1256 if (extra)
1257 memcpy(((char *) event) + hdr_len, extra, extra_len);
1258
1259 /* Send via the RtNetlink event channel */
1260 rtmsg_iwinfo(dev, (char *) event, event_len);
1261
1262 /* Cleanup */
1263 kfree(event);
1264
1265 return; /* Always success, I guess ;-) */
1266}
1267EXPORT_SYMBOL(wireless_send_event);
1268
1269/********************** ENHANCED IWSPY SUPPORT **********************/
1270/*
1271 * In the old days, the driver was handling spy support all by itself.
1272 * Now, the driver can delegate this task to Wireless Extensions.
1273 * It needs to use those standard spy iw_handler in struct iw_handler_def,
1274 * push data to us via wireless_spy_update() and include struct iw_spy_data
1275 * in its private part (and export it in net_device->wireless_data->spy_data).
1276 * One of the main advantage of centralising spy support here is that
1277 * it becomes much easier to improve and extend it without having to touch
1278 * the drivers. One example is the addition of the Spy-Threshold events.
1279 */
1280
1281/* ---------------------------------------------------------------- */
1282/*
1283 * Return the pointer to the spy data in the driver.
1284 * Because this is called on the Rx path via wireless_spy_update(),
1285 * we want it to be efficient...
1286 */
1287static inline struct iw_spy_data *get_spydata(struct net_device *dev)
1288{
1289 /* This is the new way */
1290 if (dev->wireless_data)
1291 return dev->wireless_data->spy_data;
1292 return NULL;
1293}
1294
1295/*------------------------------------------------------------------*/
1296/*
1297 * Standard Wireless Handler : set Spy List
1298 */
1299int iw_handler_set_spy(struct net_device * dev,
1300 struct iw_request_info * info,
1301 union iwreq_data * wrqu,
1302 char * extra)
1303{
1304 struct iw_spy_data * spydata = get_spydata(dev);
1305 struct sockaddr * address = (struct sockaddr *) extra;
1306
1307 /* Make sure driver is not buggy or using the old API */
1308 if (!spydata)
1309 return -EOPNOTSUPP;
1310
1311 /* Disable spy collection while we copy the addresses.
1312 * While we copy addresses, any call to wireless_spy_update()
1313 * will NOP. This is OK, as anyway the addresses are changing. */
1314 spydata->spy_number = 0;
1315
1316 /* We want to operate without locking, because wireless_spy_update()
1317 * most likely will happen in the interrupt handler, and therefore
1318 * have its own locking constraints and needs performance.
1319 * The rtnl_lock() make sure we don't race with the other iw_handlers.
1320 * This make sure wireless_spy_update() "see" that the spy list
1321 * is temporarily disabled. */
1322 smp_wmb();
1323
1324 /* Are there are addresses to copy? */
1325 if (wrqu->data.length > 0) {
1326 int i;
1327
1328 /* Copy addresses */
1329 for (i = 0; i < wrqu->data.length; i++)
1330 memcpy(spydata->spy_address[i], address[i].sa_data,
1331 ETH_ALEN);
1332 /* Reset stats */
1333 memset(spydata->spy_stat, 0,
1334 sizeof(struct iw_quality) * IW_MAX_SPY);
1335 }
1336
1337 /* Make sure above is updated before re-enabling */
1338 smp_wmb();
1339
1340 /* Enable addresses */
1341 spydata->spy_number = wrqu->data.length;
1342
1343 return 0;
1344}
1345EXPORT_SYMBOL(iw_handler_set_spy);
1346
1347/*------------------------------------------------------------------*/
1348/*
1349 * Standard Wireless Handler : get Spy List
1350 */
1351int iw_handler_get_spy(struct net_device * dev,
1352 struct iw_request_info * info,
1353 union iwreq_data * wrqu,
1354 char * extra)
1355{
1356 struct iw_spy_data * spydata = get_spydata(dev);
1357 struct sockaddr * address = (struct sockaddr *) extra;
1358 int i;
1359
1360 /* Make sure driver is not buggy or using the old API */
1361 if (!spydata)
1362 return -EOPNOTSUPP;
1363
1364 wrqu->data.length = spydata->spy_number;
1365
1366 /* Copy addresses. */
1367 for (i = 0; i < spydata->spy_number; i++) {
1368 memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
1369 address[i].sa_family = AF_UNIX;
1370 }
1371 /* Copy stats to the user buffer (just after). */
1372 if (spydata->spy_number > 0)
1373 memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number),
1374 spydata->spy_stat,
1375 sizeof(struct iw_quality) * spydata->spy_number);
1376 /* Reset updated flags. */
1377 for (i = 0; i < spydata->spy_number; i++)
1378 spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
1379 return 0;
1380}
1381EXPORT_SYMBOL(iw_handler_get_spy);
1382
1383/*------------------------------------------------------------------*/
1384/*
1385 * Standard Wireless Handler : set spy threshold
1386 */
1387int iw_handler_set_thrspy(struct net_device * dev,
1388 struct iw_request_info *info,
1389 union iwreq_data * wrqu,
1390 char * extra)
1391{
1392 struct iw_spy_data * spydata = get_spydata(dev);
1393 struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
1394
1395 /* Make sure driver is not buggy or using the old API */
1396 if (!spydata)
1397 return -EOPNOTSUPP;
1398
1399 /* Just do it */
1400 memcpy(&(spydata->spy_thr_low), &(threshold->low),
1401 2 * sizeof(struct iw_quality));
1402
1403 /* Clear flag */
1404 memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
1405
1406 return 0;
1407}
1408EXPORT_SYMBOL(iw_handler_set_thrspy);
1409
1410/*------------------------------------------------------------------*/
1411/*
1412 * Standard Wireless Handler : get spy threshold
1413 */
1414int iw_handler_get_thrspy(struct net_device * dev,
1415 struct iw_request_info *info,
1416 union iwreq_data * wrqu,
1417 char * extra)
1418{
1419 struct iw_spy_data * spydata = get_spydata(dev);
1420 struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
1421
1422 /* Make sure driver is not buggy or using the old API */
1423 if (!spydata)
1424 return -EOPNOTSUPP;
1425
1426 /* Just do it */
1427 memcpy(&(threshold->low), &(spydata->spy_thr_low),
1428 2 * sizeof(struct iw_quality));
1429
1430 return 0;
1431}
1432EXPORT_SYMBOL(iw_handler_get_thrspy);
1433
1434/*------------------------------------------------------------------*/
1435/*
1436 * Prepare and send a Spy Threshold event
1437 */
1438static void iw_send_thrspy_event(struct net_device * dev,
1439 struct iw_spy_data * spydata,
1440 unsigned char * address,
1441 struct iw_quality * wstats)
1442{
1443 union iwreq_data wrqu;
1444 struct iw_thrspy threshold;
1445
1446 /* Init */
1447 wrqu.data.length = 1;
1448 wrqu.data.flags = 0;
1449 /* Copy address */
1450 memcpy(threshold.addr.sa_data, address, ETH_ALEN);
1451 threshold.addr.sa_family = ARPHRD_ETHER;
1452 /* Copy stats */
1453 memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
1454 /* Copy also thresholds */
1455 memcpy(&(threshold.low), &(spydata->spy_thr_low),
1456 2 * sizeof(struct iw_quality));
1457
1458 /* Send event to user space */
1459 wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
1460}
1461
1462/* ---------------------------------------------------------------- */
1463/*
1464 * Call for the driver to update the spy data.
1465 * For now, the spy data is a simple array. As the size of the array is
1466 * small, this is good enough. If we wanted to support larger number of
1467 * spy addresses, we should use something more efficient...
1468 */
1469void wireless_spy_update(struct net_device * dev,
1470 unsigned char * address,
1471 struct iw_quality * wstats)
1472{
1473 struct iw_spy_data * spydata = get_spydata(dev);
1474 int i;
1475 int match = -1;
1476
1477 /* Make sure driver is not buggy or using the old API */
1478 if (!spydata)
1479 return;
1480
1481 /* Update all records that match */
1482 for (i = 0; i < spydata->spy_number; i++)
1483 if (!compare_ether_addr(address, spydata->spy_address[i])) {
1484 memcpy(&(spydata->spy_stat[i]), wstats,
1485 sizeof(struct iw_quality));
1486 match = i;
1487 }
1488
1489 /* Generate an event if we cross the spy threshold.
1490 * To avoid event storms, we have a simple hysteresis : we generate
1491 * event only when we go under the low threshold or above the
1492 * high threshold. */
1493 if (match >= 0) {
1494 if (spydata->spy_thr_under[match]) {
1495 if (wstats->level > spydata->spy_thr_high.level) {
1496 spydata->spy_thr_under[match] = 0;
1497 iw_send_thrspy_event(dev, spydata,
1498 address, wstats);
1499 }
1500 } else {
1501 if (wstats->level < spydata->spy_thr_low.level) {
1502 spydata->spy_thr_under[match] = 1;
1503 iw_send_thrspy_event(dev, spydata,
1504 address, wstats);
1505 }
1506 }
1507 }
1508}
1509EXPORT_SYMBOL(wireless_spy_update);