aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-04-23 15:20:05 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-26 01:29:41 -0400
commit704232c2718c9d4b3375ec15a14fc0397970c449 (patch)
tree6ffaa759ebaee36c4242bff6b7630f148efcaea3 /net/wireless
parent2a5e1c0eb9efe26eed1dd072fe08de5797a7efd5 (diff)
[WIRELESS] cfg80211: New wireless config infrastructure.
This patch creates the core cfg80211 code along with some sysfs bits. This is a stripped down version to allow mac80211 to function, but doesn't include any configuration yet except for creating and removing virtual interfaces. This patch includes the nl80211 header file but it only contains the interface types which the cfg80211 interface for creating virtual interfaces relies on. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/Kconfig3
-rw-r--r--net/wireless/Makefile4
-rw-r--r--net/wireless/core.c209
-rw-r--r--net/wireless/core.h49
-rw-r--r--net/wireless/sysfs.c80
-rw-r--r--net/wireless/sysfs.h9
6 files changed, 353 insertions, 1 deletions
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index ca2f05c29760..1863c0b07d45 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -1,3 +1,6 @@
1config CFG80211
2 tristate "Improved wireless configuration API"
3
1config WIRELESS_EXT 4config WIRELESS_EXT
2 bool "Wireless extensions" 5 bool "Wireless extensions"
3 default n 6 default n
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index cf4e3d9726b8..3f082ffae387 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -1 +1,3 @@
1# dummy file for now 1obj-$(CONFIG_CFG80211) += cfg80211.o
2
3cfg80211-y += core.o sysfs.o
diff --git a/net/wireless/core.c b/net/wireless/core.c
new file mode 100644
index 000000000000..532e1e09e028
--- /dev/null
+++ b/net/wireless/core.c
@@ -0,0 +1,209 @@
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 if (unlikely(wiphy_counter<0)) {
57 /* ugh, wrapped! */
58 kfree(drv);
59 return NULL;
60 }
61 drv->idx = wiphy_counter;
62
63 /* give it a proper name */
64 snprintf(drv->wiphy.dev.bus_id, BUS_ID_SIZE,
65 PHY_NAME "%d", drv->idx);
66
67 /* now increase counter for the next time */
68 wiphy_counter++;
69 mutex_unlock(&cfg80211_drv_mutex);
70
71 mutex_init(&drv->mtx);
72 mutex_init(&drv->devlist_mtx);
73 INIT_LIST_HEAD(&drv->netdev_list);
74
75 device_initialize(&drv->wiphy.dev);
76 drv->wiphy.dev.class = &ieee80211_class;
77 drv->wiphy.dev.platform_data = drv;
78
79 return &drv->wiphy;
80}
81EXPORT_SYMBOL(wiphy_new);
82
83int wiphy_register(struct wiphy *wiphy)
84{
85 struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
86 int res;
87
88 mutex_lock(&cfg80211_drv_mutex);
89
90
91 res = device_add(&drv->wiphy.dev);
92 if (res)
93 goto out_unlock;
94
95 list_add(&drv->list, &cfg80211_drv_list);
96
97 /* add to debugfs */
98 drv->wiphy.debugfsdir =
99 debugfs_create_dir(wiphy_name(&drv->wiphy),
100 ieee80211_debugfs_dir);
101
102 res = 0;
103out_unlock:
104 mutex_unlock(&cfg80211_drv_mutex);
105 return res;
106}
107EXPORT_SYMBOL(wiphy_register);
108
109void wiphy_unregister(struct wiphy *wiphy)
110{
111 struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
112
113 mutex_lock(&cfg80211_drv_mutex);
114
115 /* hold registered driver mutex during list removal as well
116 * to make sure no commands are in progress at the moment */
117 mutex_lock(&drv->mtx);
118 list_del(&drv->list);
119 mutex_unlock(&drv->mtx);
120
121 device_del(&drv->wiphy.dev);
122 debugfs_remove(drv->wiphy.debugfsdir);
123
124 mutex_unlock(&cfg80211_drv_mutex);
125}
126EXPORT_SYMBOL(wiphy_unregister);
127
128void cfg80211_dev_free(struct cfg80211_registered_device *drv)
129{
130 mutex_destroy(&drv->mtx);
131 mutex_destroy(&drv->devlist_mtx);
132 kfree(drv);
133}
134
135void wiphy_free(struct wiphy *wiphy)
136{
137 put_device(&wiphy->dev);
138}
139EXPORT_SYMBOL(wiphy_free);
140
141static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
142 unsigned long state,
143 void *ndev)
144{
145 struct net_device *dev = ndev;
146 struct cfg80211_registered_device *rdev;
147
148 if (!dev->ieee80211_ptr)
149 return 0;
150
151 rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
152
153 switch (state) {
154 case NETDEV_REGISTER:
155 mutex_lock(&rdev->devlist_mtx);
156 list_add(&dev->ieee80211_ptr->list, &rdev->netdev_list);
157 if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj,
158 "phy80211")) {
159 printk(KERN_ERR "wireless: failed to add phy80211 "
160 "symlink to netdev!\n");
161 }
162 dev->ieee80211_ptr->netdev = dev;
163 mutex_unlock(&rdev->devlist_mtx);
164 break;
165 case NETDEV_UNREGISTER:
166 mutex_lock(&rdev->devlist_mtx);
167 if (!list_empty(&dev->ieee80211_ptr->list)) {
168 sysfs_remove_link(&dev->dev.kobj, "phy80211");
169 list_del_init(&dev->ieee80211_ptr->list);
170 }
171 mutex_unlock(&rdev->devlist_mtx);
172 break;
173 }
174
175 return 0;
176}
177
178static struct notifier_block cfg80211_netdev_notifier = {
179 .notifier_call = cfg80211_netdev_notifier_call,
180};
181
182static int cfg80211_init(void)
183{
184 int err = wiphy_sysfs_init();
185 if (err)
186 goto out_fail_sysfs;
187
188 err = register_netdevice_notifier(&cfg80211_netdev_notifier);
189 if (err)
190 goto out_fail_notifier;
191
192 ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL);
193
194 return 0;
195
196out_fail_notifier:
197 wiphy_sysfs_exit();
198out_fail_sysfs:
199 return err;
200}
201module_init(cfg80211_init);
202
203static void cfg80211_exit(void)
204{
205 debugfs_remove(ieee80211_debugfs_dir);
206 unregister_netdevice_notifier(&cfg80211_netdev_notifier);
207 wiphy_sysfs_exit();
208}
209module_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 */