Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6] / net / wireless / nl80211.c
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 */
23 static 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 */
32 static 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 */
56 static 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 */
67 static 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
76 static 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
93 static 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
115 static 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
142 static 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
161 static 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
179 static 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
213 static 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
244 static 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
278 static 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
312 static 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
338 static 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 */
380 static struct genl_multicast_group nl80211_config_mcgrp = {
381         .name = "config",
382 };
383
384 /* notification functions */
385
386 void 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
404 int 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
428 void nl80211_exit(void)
429 {
430         genl_unregister_family(&nl80211_fam);
431 }