aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-09-20 13:09:35 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:52:14 -0400
commit556829657397b9b05baec6691ead4e22ee8d1567 (patch)
tree44242431553e5e22c0bceaab7a06d9d7bf0dd2f6 /net
parent0800f170263d19b882e519441156c5f6ed190fc1 (diff)
[NL80211]: add netlink interface to cfg80211
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')
-rw-r--r--net/mac80211/ieee80211_cfg.c2
-rw-r--r--net/wireless/Kconfig17
-rw-r--r--net/wireless/Makefile1
-rw-r--r--net/wireless/core.c148
-rw-r--r--net/wireless/core.h32
-rw-r--r--net/wireless/nl80211.c431
-rw-r--r--net/wireless/nl80211.h24
7 files changed, 653 insertions, 2 deletions
diff --git a/net/mac80211/ieee80211_cfg.c b/net/mac80211/ieee80211_cfg.c
index b1c13bc9c3ca..d6fc55cc8ad4 100644
--- a/net/mac80211/ieee80211_cfg.c
+++ b/net/mac80211/ieee80211_cfg.c
@@ -14,7 +14,7 @@
14#include "ieee80211_cfg.h" 14#include "ieee80211_cfg.h"
15 15
16static int ieee80211_add_iface(struct wiphy *wiphy, char *name, 16static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
17 unsigned int type) 17 enum nl80211_iftype type)
18{ 18{
19 struct ieee80211_local *local = wiphy_priv(wiphy); 19 struct ieee80211_local *local = wiphy_priv(wiphy);
20 int itype; 20 int itype;
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index a228d56a91b8..6291f13bba09 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -1,6 +1,19 @@
1config CFG80211 1config CFG80211
2 tristate "Improved wireless configuration API" 2 tristate "Improved wireless configuration API"
3 3
4config NL80211
5 bool "nl80211 new netlink interface support"
6 depends CFG80211
7 default y
8 ---help---
9 This option turns on the new netlink interface
10 (nl80211) support in cfg80211.
11
12 If =n, drivers using mac80211 will be configured via
13 wireless extension support provided by that subsystem.
14
15 If unsure, say Y.
16
4config WIRELESS_EXT 17config WIRELESS_EXT
5 bool "Wireless extensions" 18 bool "Wireless extensions"
6 default n 19 default n
@@ -10,7 +23,9 @@ config WIRELESS_EXT
10 23
11 Wireless extensions will be replaced by cfg80211 and 24 Wireless extensions will be replaced by cfg80211 and
12 will be required only by legacy drivers that implement 25 will be required only by legacy drivers that implement
13 wireless extension handlers. 26 wireless extension handlers. This option does not
27 affect the wireless-extension backward compatibility
28 code in cfg80211.
14 29
15 Say N (if you can) unless you know you need wireless 30 Say N (if you can) unless you know you need wireless
16 extensions for external modules. 31 extensions for external modules.
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 092116e390b6..65710a42e5a7 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_WIRELESS_EXT) += wext.o
2obj-$(CONFIG_CFG80211) += cfg80211.o 2obj-$(CONFIG_CFG80211) += cfg80211.o
3 3
4cfg80211-y += core.o sysfs.o radiotap.o 4cfg80211-y += core.o sysfs.o radiotap.o
5cfg80211-$(CONFIG_NL80211) += nl80211.o
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 9771451eae21..febc33bc9c09 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -16,6 +16,7 @@
16#include <net/genetlink.h> 16#include <net/genetlink.h>
17#include <net/cfg80211.h> 17#include <net/cfg80211.h>
18#include <net/wireless.h> 18#include <net/wireless.h>
19#include "nl80211.h"
19#include "core.h" 20#include "core.h"
20#include "sysfs.h" 21#include "sysfs.h"
21 22
@@ -36,6 +37,146 @@ static int wiphy_counter;
36/* for debugfs */ 37/* for debugfs */
37static struct dentry *ieee80211_debugfs_dir; 38static struct dentry *ieee80211_debugfs_dir;
38 39
40/* requires cfg80211_drv_mutex to be held! */
41static struct cfg80211_registered_device *cfg80211_drv_by_wiphy(int wiphy)
42{
43 struct cfg80211_registered_device *result = NULL, *drv;
44
45 list_for_each_entry(drv, &cfg80211_drv_list, list) {
46 if (drv->idx == wiphy) {
47 result = drv;
48 break;
49 }
50 }
51
52 return result;
53}
54
55/* requires cfg80211_drv_mutex to be held! */
56static struct cfg80211_registered_device *
57__cfg80211_drv_from_info(struct genl_info *info)
58{
59 int ifindex;
60 struct cfg80211_registered_device *bywiphy = NULL, *byifidx = NULL;
61 struct net_device *dev;
62 int err = -EINVAL;
63
64 if (info->attrs[NL80211_ATTR_WIPHY]) {
65 bywiphy = cfg80211_drv_by_wiphy(
66 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY]));
67 err = -ENODEV;
68 }
69
70 if (info->attrs[NL80211_ATTR_IFINDEX]) {
71 ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
72 dev = dev_get_by_index(&init_net, ifindex);
73 if (dev) {
74 if (dev->ieee80211_ptr)
75 byifidx =
76 wiphy_to_dev(dev->ieee80211_ptr->wiphy);
77 dev_put(dev);
78 }
79 err = -ENODEV;
80 }
81
82 if (bywiphy && byifidx) {
83 if (bywiphy != byifidx)
84 return ERR_PTR(-EINVAL);
85 else
86 return bywiphy; /* == byifidx */
87 }
88 if (bywiphy)
89 return bywiphy;
90
91 if (byifidx)
92 return byifidx;
93
94 return ERR_PTR(err);
95}
96
97struct cfg80211_registered_device *
98cfg80211_get_dev_from_info(struct genl_info *info)
99{
100 struct cfg80211_registered_device *drv;
101
102 mutex_lock(&cfg80211_drv_mutex);
103 drv = __cfg80211_drv_from_info(info);
104
105 /* if it is not an error we grab the lock on
106 * it to assure it won't be going away while
107 * we operate on it */
108 if (!IS_ERR(drv))
109 mutex_lock(&drv->mtx);
110
111 mutex_unlock(&cfg80211_drv_mutex);
112
113 return drv;
114}
115
116struct cfg80211_registered_device *
117cfg80211_get_dev_from_ifindex(int ifindex)
118{
119 struct cfg80211_registered_device *drv = ERR_PTR(-ENODEV);
120 struct net_device *dev;
121
122 mutex_lock(&cfg80211_drv_mutex);
123 dev = dev_get_by_index(&init_net, ifindex);
124 if (!dev)
125 goto out;
126 if (dev->ieee80211_ptr) {
127 drv = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
128 mutex_lock(&drv->mtx);
129 } else
130 drv = ERR_PTR(-ENODEV);
131 dev_put(dev);
132 out:
133 mutex_unlock(&cfg80211_drv_mutex);
134 return drv;
135}
136
137void cfg80211_put_dev(struct cfg80211_registered_device *drv)
138{
139 BUG_ON(IS_ERR(drv));
140 mutex_unlock(&drv->mtx);
141}
142
143int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
144 char *newname)
145{
146 int idx, taken = -1, result, digits;
147
148 /* prohibit calling the thing phy%d when %d is not its number */
149 sscanf(newname, PHY_NAME "%d%n", &idx, &taken);
150 if (taken == strlen(newname) && idx != rdev->idx) {
151 /* count number of places needed to print idx */
152 digits = 1;
153 while (idx /= 10)
154 digits++;
155 /*
156 * deny the name if it is phy<idx> where <idx> is printed
157 * without leading zeroes. taken == strlen(newname) here
158 */
159 if (taken == strlen(PHY_NAME) + digits)
160 return -EINVAL;
161 }
162
163 /* this will check for collisions */
164 result = device_rename(&rdev->wiphy.dev, newname);
165 if (result)
166 return result;
167
168 if (!debugfs_rename(rdev->wiphy.debugfsdir->d_parent,
169 rdev->wiphy.debugfsdir,
170 rdev->wiphy.debugfsdir->d_parent,
171 newname))
172 printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n",
173 newname);
174
175 nl80211_notify_dev_rename(rdev);
176
177 return 0;
178}
179
39/* exported functions */ 180/* exported functions */
40 181
41struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv) 182struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
@@ -204,10 +345,16 @@ static int cfg80211_init(void)
204 if (err) 345 if (err)
205 goto out_fail_notifier; 346 goto out_fail_notifier;
206 347
348 err = nl80211_init();
349 if (err)
350 goto out_fail_nl80211;
351
207 ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL); 352 ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL);
208 353
209 return 0; 354 return 0;
210 355
356out_fail_nl80211:
357 unregister_netdevice_notifier(&cfg80211_netdev_notifier);
211out_fail_notifier: 358out_fail_notifier:
212 wiphy_sysfs_exit(); 359 wiphy_sysfs_exit();
213out_fail_sysfs: 360out_fail_sysfs:
@@ -218,6 +365,7 @@ subsys_initcall(cfg80211_init);
218static void cfg80211_exit(void) 365static void cfg80211_exit(void)
219{ 366{
220 debugfs_remove(ieee80211_debugfs_dir); 367 debugfs_remove(ieee80211_debugfs_dir);
368 nl80211_exit();
221 unregister_netdevice_notifier(&cfg80211_netdev_notifier); 369 unregister_netdevice_notifier(&cfg80211_netdev_notifier);
222 wiphy_sysfs_exit(); 370 wiphy_sysfs_exit();
223} 371}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 158db1edb92a..eb0f846b40df 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -43,7 +43,39 @@ struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy)
43extern struct mutex cfg80211_drv_mutex; 43extern struct mutex cfg80211_drv_mutex;
44extern struct list_head cfg80211_drv_list; 44extern struct list_head cfg80211_drv_list;
45 45
46/*
47 * This function returns a pointer to the driver
48 * that the genl_info item that is passed refers to.
49 * If successful, it returns non-NULL and also locks
50 * the driver's mutex!
51 *
52 * This means that you need to call cfg80211_put_dev()
53 * before being allowed to acquire &cfg80211_drv_mutex!
54 *
55 * This is necessary because we need to lock the global
56 * mutex to get an item off the list safely, and then
57 * we lock the drv mutex so it doesn't go away under us.
58 *
59 * We don't want to keep cfg80211_drv_mutex locked
60 * for all the time in order to allow requests on
61 * other interfaces to go through at the same time.
62 *
63 * The result of this can be a PTR_ERR and hence must
64 * be checked with IS_ERR() for errors.
65 */
66extern struct cfg80211_registered_device *
67cfg80211_get_dev_from_info(struct genl_info *info);
68
69/* identical to cfg80211_get_dev_from_info but only operate on ifindex */
70extern struct cfg80211_registered_device *
71cfg80211_get_dev_from_ifindex(int ifindex);
72
73extern void cfg80211_put_dev(struct cfg80211_registered_device *drv);
74
46/* free object */ 75/* free object */
47extern void cfg80211_dev_free(struct cfg80211_registered_device *drv); 76extern void cfg80211_dev_free(struct cfg80211_registered_device *drv);
48 77
78extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv,
79 char *newname);
80
49#endif /* __NET_WIRELESS_CORE_H */ 81#endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
new file mode 100644
index 000000000000..48b0d453e4e1
--- /dev/null
+++ b/net/wireless/nl80211.c
@@ -0,0 +1,431 @@
1/*
2 * This is the new netlink-based 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/if_ether.h>
13#include <linux/ieee80211.h>
14#include <linux/nl80211.h>
15#include <linux/rtnetlink.h>
16#include <linux/netlink.h>
17#include <net/genetlink.h>
18#include <net/cfg80211.h>
19#include "core.h"
20#include "nl80211.h"
21
22/* the netlink family */
23static struct genl_family nl80211_fam = {
24 .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */
25 .name = "nl80211", /* have users key off the name instead */
26 .hdrsize = 0, /* no private header */
27 .version = 1, /* no particular meaning now */
28 .maxattr = NL80211_ATTR_MAX,
29};
30
31/* internal helper: get drv and dev */
32static int get_drv_dev_by_info_ifindex(struct genl_info *info,
33 struct cfg80211_registered_device **drv,
34 struct net_device **dev)
35{
36 int ifindex;
37
38 if (!info->attrs[NL80211_ATTR_IFINDEX])
39 return -EINVAL;
40
41 ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
42 *dev = dev_get_by_index(&init_net, ifindex);
43 if (!*dev)
44 return -ENODEV;
45
46 *drv = cfg80211_get_dev_from_ifindex(ifindex);
47 if (IS_ERR(*drv)) {
48 dev_put(*dev);
49 return PTR_ERR(*drv);
50 }
51
52 return 0;
53}
54
55/* policy for the attributes */
56static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
57 [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
58 [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
59 .len = BUS_ID_SIZE-1 },
60
61 [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
62 [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
63 [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
64};
65
66/* message building helper */
67static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq,
68 int flags, u8 cmd)
69{
70 /* since there is no private header just add the generic one */
71 return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd);
72}
73
74/* netlink command implementations */
75
76static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
77 struct cfg80211_registered_device *dev)
78{
79 void *hdr;
80
81 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
82 if (!hdr)
83 return -1;
84
85 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
86 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
87 return genlmsg_end(msg, hdr);
88
89 nla_put_failure:
90 return genlmsg_cancel(msg, hdr);
91}
92
93static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
94{
95 int idx = 0;
96 int start = cb->args[0];
97 struct cfg80211_registered_device *dev;
98
99 mutex_lock(&cfg80211_drv_mutex);
100 list_for_each_entry(dev, &cfg80211_drv_list, list) {
101 if (++idx < start)
102 continue;
103 if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid,
104 cb->nlh->nlmsg_seq, NLM_F_MULTI,
105 dev) < 0)
106 break;
107 }
108 mutex_unlock(&cfg80211_drv_mutex);
109
110 cb->args[0] = idx;
111
112 return skb->len;
113}
114
115static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
116{
117 struct sk_buff *msg;
118 struct cfg80211_registered_device *dev;
119
120 dev = cfg80211_get_dev_from_info(info);
121 if (IS_ERR(dev))
122 return PTR_ERR(dev);
123
124 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
125 if (!msg)
126 goto out_err;
127
128 if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0)
129 goto out_free;
130
131 cfg80211_put_dev(dev);
132
133 return genlmsg_unicast(msg, info->snd_pid);
134
135 out_free:
136 nlmsg_free(msg);
137 out_err:
138 cfg80211_put_dev(dev);
139 return -ENOBUFS;
140}
141
142static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
143{
144 struct cfg80211_registered_device *rdev;
145 int result;
146
147 if (!info->attrs[NL80211_ATTR_WIPHY_NAME])
148 return -EINVAL;
149
150 rdev = cfg80211_get_dev_from_info(info);
151 if (IS_ERR(rdev))
152 return PTR_ERR(rdev);
153
154 result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
155
156 cfg80211_put_dev(rdev);
157 return result;
158}
159
160
161static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
162 struct net_device *dev)
163{
164 void *hdr;
165
166 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE);
167 if (!hdr)
168 return -1;
169
170 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
171 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name);
172 /* TODO: interface type */
173 return genlmsg_end(msg, hdr);
174
175 nla_put_failure:
176 return genlmsg_cancel(msg, hdr);
177}
178
179static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
180{
181 int wp_idx = 0;
182 int if_idx = 0;
183 int wp_start = cb->args[0];
184 int if_start = cb->args[1];
185 struct cfg80211_registered_device *dev;
186 struct wireless_dev *wdev;
187
188 mutex_lock(&cfg80211_drv_mutex);
189 list_for_each_entry(dev, &cfg80211_drv_list, list) {
190 if (++wp_idx < wp_start)
191 continue;
192 if_idx = 0;
193
194 mutex_lock(&dev->devlist_mtx);
195 list_for_each_entry(wdev, &dev->netdev_list, list) {
196 if (++if_idx < if_start)
197 continue;
198 if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid,
199 cb->nlh->nlmsg_seq, NLM_F_MULTI,
200 wdev->netdev) < 0)
201 break;
202 }
203 mutex_unlock(&dev->devlist_mtx);
204 }
205 mutex_unlock(&cfg80211_drv_mutex);
206
207 cb->args[0] = wp_idx;
208 cb->args[1] = if_idx;
209
210 return skb->len;
211}
212
213static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
214{
215 struct sk_buff *msg;
216 struct cfg80211_registered_device *dev;
217 struct net_device *netdev;
218 int err;
219
220 err = get_drv_dev_by_info_ifindex(info, &dev, &netdev);
221 if (err)
222 return err;
223
224 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
225 if (!msg)
226 goto out_err;
227
228 if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0)
229 goto out_free;
230
231 dev_put(netdev);
232 cfg80211_put_dev(dev);
233
234 return genlmsg_unicast(msg, info->snd_pid);
235
236 out_free:
237 nlmsg_free(msg);
238 out_err:
239 dev_put(netdev);
240 cfg80211_put_dev(dev);
241 return -ENOBUFS;
242}
243
244static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
245{
246 struct cfg80211_registered_device *drv;
247 int err, ifindex;
248 enum nl80211_iftype type;
249 struct net_device *dev;
250
251 if (info->attrs[NL80211_ATTR_IFTYPE]) {
252 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
253 if (type > NL80211_IFTYPE_MAX)
254 return -EINVAL;
255 } else
256 return -EINVAL;
257
258 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
259 if (err)
260 return err;
261 ifindex = dev->ifindex;
262 dev_put(dev);
263
264 if (!drv->ops->change_virtual_intf) {
265 err = -EOPNOTSUPP;
266 goto unlock;
267 }
268
269 rtnl_lock();
270 err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type);
271 rtnl_unlock();
272
273 unlock:
274 cfg80211_put_dev(drv);
275 return err;
276}
277
278static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
279{
280 struct cfg80211_registered_device *drv;
281 int err;
282 enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
283
284 if (!info->attrs[NL80211_ATTR_IFNAME])
285 return -EINVAL;
286
287 if (info->attrs[NL80211_ATTR_IFTYPE]) {
288 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
289 if (type > NL80211_IFTYPE_MAX)
290 return -EINVAL;
291 }
292
293 drv = cfg80211_get_dev_from_info(info);
294 if (IS_ERR(drv))
295 return PTR_ERR(drv);
296
297 if (!drv->ops->add_virtual_intf) {
298 err = -EOPNOTSUPP;
299 goto unlock;
300 }
301
302 rtnl_lock();
303 err = drv->ops->add_virtual_intf(&drv->wiphy,
304 nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
305 rtnl_unlock();
306
307 unlock:
308 cfg80211_put_dev(drv);
309 return err;
310}
311
312static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
313{
314 struct cfg80211_registered_device *drv;
315 int ifindex, err;
316 struct net_device *dev;
317
318 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
319 if (err)
320 return err;
321 ifindex = dev->ifindex;
322 dev_put(dev);
323
324 if (!drv->ops->del_virtual_intf) {
325 err = -EOPNOTSUPP;
326 goto out;
327 }
328
329 rtnl_lock();
330 err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex);
331 rtnl_unlock();
332
333 out:
334 cfg80211_put_dev(drv);
335 return err;
336}
337
338static struct genl_ops nl80211_ops[] = {
339 {
340 .cmd = NL80211_CMD_GET_WIPHY,
341 .doit = nl80211_get_wiphy,
342 .dumpit = nl80211_dump_wiphy,
343 .policy = nl80211_policy,
344 /* can be retrieved by unprivileged users */
345 },
346 {
347 .cmd = NL80211_CMD_SET_WIPHY,
348 .doit = nl80211_set_wiphy,
349 .policy = nl80211_policy,
350 .flags = GENL_ADMIN_PERM,
351 },
352 {
353 .cmd = NL80211_CMD_GET_INTERFACE,
354 .doit = nl80211_get_interface,
355 .dumpit = nl80211_dump_interface,
356 .policy = nl80211_policy,
357 /* can be retrieved by unprivileged users */
358 },
359 {
360 .cmd = NL80211_CMD_SET_INTERFACE,
361 .doit = nl80211_set_interface,
362 .policy = nl80211_policy,
363 .flags = GENL_ADMIN_PERM,
364 },
365 {
366 .cmd = NL80211_CMD_NEW_INTERFACE,
367 .doit = nl80211_new_interface,
368 .policy = nl80211_policy,
369 .flags = GENL_ADMIN_PERM,
370 },
371 {
372 .cmd = NL80211_CMD_DEL_INTERFACE,
373 .doit = nl80211_del_interface,
374 .policy = nl80211_policy,
375 .flags = GENL_ADMIN_PERM,
376 },
377};
378
379/* multicast groups */
380static struct genl_multicast_group nl80211_config_mcgrp = {
381 .name = "config",
382};
383
384/* notification functions */
385
386void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
387{
388 struct sk_buff *msg;
389
390 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
391 if (!msg)
392 return;
393
394 if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) {
395 nlmsg_free(msg);
396 return;
397 }
398
399 genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
400}
401
402/* initialisation/exit functions */
403
404int nl80211_init(void)
405{
406 int err, i;
407
408 err = genl_register_family(&nl80211_fam);
409 if (err)
410 return err;
411
412 for (i = 0; i < ARRAY_SIZE(nl80211_ops); i++) {
413 err = genl_register_ops(&nl80211_fam, &nl80211_ops[i]);
414 if (err)
415 goto err_out;
416 }
417
418 err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp);
419 if (err)
420 goto err_out;
421
422 return 0;
423 err_out:
424 genl_unregister_family(&nl80211_fam);
425 return err;
426}
427
428void nl80211_exit(void)
429{
430 genl_unregister_family(&nl80211_fam);
431}
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
new file mode 100644
index 000000000000..f3ea5c029aee
--- /dev/null
+++ b/net/wireless/nl80211.h
@@ -0,0 +1,24 @@
1#ifndef __NET_WIRELESS_NL80211_H
2#define __NET_WIRELESS_NL80211_H
3
4#include "core.h"
5
6#ifdef CONFIG_NL80211
7extern int nl80211_init(void);
8extern void nl80211_exit(void);
9extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev);
10#else
11static inline int nl80211_init(void)
12{
13 return 0;
14}
15static inline void nl80211_exit(void)
16{
17}
18static inline void nl80211_notify_dev_rename(
19 struct cfg80211_registered_device *rdev)
20{
21}
22#endif /* CONFIG_NL80211 */
23
24#endif /* __NET_WIRELESS_NL80211_H */