blob: 090936388528945762e5a621eb30de58a8ccb94d [file] [log] [blame]
Johannes Berg55682962007-09-20 13:09:35 -04001/*
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 },
Johannes Berg41ade002007-12-19 02:03:29 +010064
65 [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
66
67 [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
68 .len = WLAN_MAX_KEY_LEN },
69 [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
70 [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
71 [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
Johannes Berg55682962007-09-20 13:09:35 -040072};
73
74/* message building helper */
75static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq,
76 int flags, u8 cmd)
77{
78 /* since there is no private header just add the generic one */
79 return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd);
80}
81
82/* netlink command implementations */
83
84static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
85 struct cfg80211_registered_device *dev)
86{
87 void *hdr;
88
89 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
90 if (!hdr)
91 return -1;
92
93 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
94 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
95 return genlmsg_end(msg, hdr);
96
97 nla_put_failure:
98 return genlmsg_cancel(msg, hdr);
99}
100
101static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
102{
103 int idx = 0;
104 int start = cb->args[0];
105 struct cfg80211_registered_device *dev;
106
107 mutex_lock(&cfg80211_drv_mutex);
108 list_for_each_entry(dev, &cfg80211_drv_list, list) {
109 if (++idx < start)
110 continue;
111 if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid,
112 cb->nlh->nlmsg_seq, NLM_F_MULTI,
113 dev) < 0)
114 break;
115 }
116 mutex_unlock(&cfg80211_drv_mutex);
117
118 cb->args[0] = idx;
119
120 return skb->len;
121}
122
123static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
124{
125 struct sk_buff *msg;
126 struct cfg80211_registered_device *dev;
127
128 dev = cfg80211_get_dev_from_info(info);
129 if (IS_ERR(dev))
130 return PTR_ERR(dev);
131
132 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
133 if (!msg)
134 goto out_err;
135
136 if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0)
137 goto out_free;
138
139 cfg80211_put_dev(dev);
140
141 return genlmsg_unicast(msg, info->snd_pid);
142
143 out_free:
144 nlmsg_free(msg);
145 out_err:
146 cfg80211_put_dev(dev);
147 return -ENOBUFS;
148}
149
150static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
151{
152 struct cfg80211_registered_device *rdev;
153 int result;
154
155 if (!info->attrs[NL80211_ATTR_WIPHY_NAME])
156 return -EINVAL;
157
158 rdev = cfg80211_get_dev_from_info(info);
159 if (IS_ERR(rdev))
160 return PTR_ERR(rdev);
161
162 result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
163
164 cfg80211_put_dev(rdev);
165 return result;
166}
167
168
169static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
170 struct net_device *dev)
171{
172 void *hdr;
173
174 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE);
175 if (!hdr)
176 return -1;
177
178 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
179 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name);
180 /* TODO: interface type */
181 return genlmsg_end(msg, hdr);
182
183 nla_put_failure:
184 return genlmsg_cancel(msg, hdr);
185}
186
187static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
188{
189 int wp_idx = 0;
190 int if_idx = 0;
191 int wp_start = cb->args[0];
192 int if_start = cb->args[1];
193 struct cfg80211_registered_device *dev;
194 struct wireless_dev *wdev;
195
196 mutex_lock(&cfg80211_drv_mutex);
197 list_for_each_entry(dev, &cfg80211_drv_list, list) {
198 if (++wp_idx < wp_start)
199 continue;
200 if_idx = 0;
201
202 mutex_lock(&dev->devlist_mtx);
203 list_for_each_entry(wdev, &dev->netdev_list, list) {
204 if (++if_idx < if_start)
205 continue;
206 if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid,
207 cb->nlh->nlmsg_seq, NLM_F_MULTI,
208 wdev->netdev) < 0)
209 break;
210 }
211 mutex_unlock(&dev->devlist_mtx);
212 }
213 mutex_unlock(&cfg80211_drv_mutex);
214
215 cb->args[0] = wp_idx;
216 cb->args[1] = if_idx;
217
218 return skb->len;
219}
220
221static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
222{
223 struct sk_buff *msg;
224 struct cfg80211_registered_device *dev;
225 struct net_device *netdev;
226 int err;
227
228 err = get_drv_dev_by_info_ifindex(info, &dev, &netdev);
229 if (err)
230 return err;
231
232 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
233 if (!msg)
234 goto out_err;
235
236 if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0)
237 goto out_free;
238
239 dev_put(netdev);
240 cfg80211_put_dev(dev);
241
242 return genlmsg_unicast(msg, info->snd_pid);
243
244 out_free:
245 nlmsg_free(msg);
246 out_err:
247 dev_put(netdev);
248 cfg80211_put_dev(dev);
249 return -ENOBUFS;
250}
251
252static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
253{
254 struct cfg80211_registered_device *drv;
255 int err, ifindex;
256 enum nl80211_iftype type;
257 struct net_device *dev;
258
259 if (info->attrs[NL80211_ATTR_IFTYPE]) {
260 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
261 if (type > NL80211_IFTYPE_MAX)
262 return -EINVAL;
263 } else
264 return -EINVAL;
265
266 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
267 if (err)
268 return err;
269 ifindex = dev->ifindex;
270 dev_put(dev);
271
272 if (!drv->ops->change_virtual_intf) {
273 err = -EOPNOTSUPP;
274 goto unlock;
275 }
276
277 rtnl_lock();
278 err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type);
279 rtnl_unlock();
280
281 unlock:
282 cfg80211_put_dev(drv);
283 return err;
284}
285
286static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
287{
288 struct cfg80211_registered_device *drv;
289 int err;
290 enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
291
292 if (!info->attrs[NL80211_ATTR_IFNAME])
293 return -EINVAL;
294
295 if (info->attrs[NL80211_ATTR_IFTYPE]) {
296 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
297 if (type > NL80211_IFTYPE_MAX)
298 return -EINVAL;
299 }
300
301 drv = cfg80211_get_dev_from_info(info);
302 if (IS_ERR(drv))
303 return PTR_ERR(drv);
304
305 if (!drv->ops->add_virtual_intf) {
306 err = -EOPNOTSUPP;
307 goto unlock;
308 }
309
310 rtnl_lock();
311 err = drv->ops->add_virtual_intf(&drv->wiphy,
312 nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
313 rtnl_unlock();
314
315 unlock:
316 cfg80211_put_dev(drv);
317 return err;
318}
319
320static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
321{
322 struct cfg80211_registered_device *drv;
323 int ifindex, err;
324 struct net_device *dev;
325
326 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
327 if (err)
328 return err;
329 ifindex = dev->ifindex;
330 dev_put(dev);
331
332 if (!drv->ops->del_virtual_intf) {
333 err = -EOPNOTSUPP;
334 goto out;
335 }
336
337 rtnl_lock();
338 err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex);
339 rtnl_unlock();
340
341 out:
342 cfg80211_put_dev(drv);
343 return err;
344}
345
Johannes Berg41ade002007-12-19 02:03:29 +0100346struct get_key_cookie {
347 struct sk_buff *msg;
348 int error;
349};
350
351static void get_key_callback(void *c, struct key_params *params)
352{
353 struct get_key_cookie *cookie = c;
354
355 if (params->key)
356 NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA,
357 params->key_len, params->key);
358
359 if (params->seq)
360 NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ,
361 params->seq_len, params->seq);
362
363 if (params->cipher)
364 NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
365 params->cipher);
366
367 return;
368 nla_put_failure:
369 cookie->error = 1;
370}
371
372static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
373{
374 struct cfg80211_registered_device *drv;
375 int err;
376 struct net_device *dev;
377 u8 key_idx = 0;
378 u8 *mac_addr = NULL;
379 struct get_key_cookie cookie = {
380 .error = 0,
381 };
382 void *hdr;
383 struct sk_buff *msg;
384
385 if (info->attrs[NL80211_ATTR_KEY_IDX])
386 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
387
388 if (key_idx > 3)
389 return -EINVAL;
390
391 if (info->attrs[NL80211_ATTR_MAC])
392 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
393
394 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
395 if (err)
396 return err;
397
398 if (!drv->ops->get_key) {
399 err = -EOPNOTSUPP;
400 goto out;
401 }
402
403 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
404 if (!msg) {
405 err = -ENOMEM;
406 goto out;
407 }
408
409 hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
410 NL80211_CMD_NEW_KEY);
411
412 if (IS_ERR(hdr)) {
413 err = PTR_ERR(hdr);
414 goto out;
415 }
416
417 cookie.msg = msg;
418
419 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
420 NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
421 if (mac_addr)
422 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
423
424 rtnl_lock();
425 err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
426 &cookie, get_key_callback);
427 rtnl_unlock();
428
429 if (err)
430 goto out;
431
432 if (cookie.error)
433 goto nla_put_failure;
434
435 genlmsg_end(msg, hdr);
436 err = genlmsg_unicast(msg, info->snd_pid);
437 goto out;
438
439 nla_put_failure:
440 err = -ENOBUFS;
441 nlmsg_free(msg);
442 out:
443 cfg80211_put_dev(drv);
444 dev_put(dev);
445 return err;
446}
447
448static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
449{
450 struct cfg80211_registered_device *drv;
451 int err;
452 struct net_device *dev;
453 u8 key_idx;
454
455 if (!info->attrs[NL80211_ATTR_KEY_IDX])
456 return -EINVAL;
457
458 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
459
460 if (key_idx > 3)
461 return -EINVAL;
462
463 /* currently only support setting default key */
464 if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
465 return -EINVAL;
466
467 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
468 if (err)
469 return err;
470
471 if (!drv->ops->set_default_key) {
472 err = -EOPNOTSUPP;
473 goto out;
474 }
475
476 rtnl_lock();
477 err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
478 rtnl_unlock();
479
480 out:
481 cfg80211_put_dev(drv);
482 dev_put(dev);
483 return err;
484}
485
486static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
487{
488 struct cfg80211_registered_device *drv;
489 int err;
490 struct net_device *dev;
491 struct key_params params;
492 u8 key_idx = 0;
493 u8 *mac_addr = NULL;
494
495 memset(&params, 0, sizeof(params));
496
497 if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
498 return -EINVAL;
499
500 if (info->attrs[NL80211_ATTR_KEY_DATA]) {
501 params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
502 params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
503 }
504
505 if (info->attrs[NL80211_ATTR_KEY_IDX])
506 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
507
508 params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
509
510 if (info->attrs[NL80211_ATTR_MAC])
511 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
512
513 if (key_idx > 3)
514 return -EINVAL;
515
516 /*
517 * Disallow pairwise keys with non-zero index unless it's WEP
518 * (because current deployments use pairwise WEP keys with
519 * non-zero indizes but 802.11i clearly specifies to use zero)
520 */
521 if (mac_addr && key_idx &&
522 params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
523 params.cipher != WLAN_CIPHER_SUITE_WEP104)
524 return -EINVAL;
525
526 /* TODO: add definitions for the lengths to linux/ieee80211.h */
527 switch (params.cipher) {
528 case WLAN_CIPHER_SUITE_WEP40:
529 if (params.key_len != 5)
530 return -EINVAL;
531 break;
532 case WLAN_CIPHER_SUITE_TKIP:
533 if (params.key_len != 32)
534 return -EINVAL;
535 break;
536 case WLAN_CIPHER_SUITE_CCMP:
537 if (params.key_len != 16)
538 return -EINVAL;
539 break;
540 case WLAN_CIPHER_SUITE_WEP104:
541 if (params.key_len != 13)
542 return -EINVAL;
543 break;
544 default:
545 return -EINVAL;
546 }
547
548 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
549 if (err)
550 return err;
551
552 if (!drv->ops->add_key) {
553 err = -EOPNOTSUPP;
554 goto out;
555 }
556
557 rtnl_lock();
558 err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params);
559 rtnl_unlock();
560
561 out:
562 cfg80211_put_dev(drv);
563 dev_put(dev);
564 return err;
565}
566
567static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
568{
569 struct cfg80211_registered_device *drv;
570 int err;
571 struct net_device *dev;
572 u8 key_idx = 0;
573 u8 *mac_addr = NULL;
574
575 if (info->attrs[NL80211_ATTR_KEY_IDX])
576 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
577
578 if (key_idx > 3)
579 return -EINVAL;
580
581 if (info->attrs[NL80211_ATTR_MAC])
582 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
583
584 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
585 if (err)
586 return err;
587
588 if (!drv->ops->del_key) {
589 err = -EOPNOTSUPP;
590 goto out;
591 }
592
593 rtnl_lock();
594 err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
595 rtnl_unlock();
596
597 out:
598 cfg80211_put_dev(drv);
599 dev_put(dev);
600 return err;
601}
602
Johannes Berg55682962007-09-20 13:09:35 -0400603static struct genl_ops nl80211_ops[] = {
604 {
605 .cmd = NL80211_CMD_GET_WIPHY,
606 .doit = nl80211_get_wiphy,
607 .dumpit = nl80211_dump_wiphy,
608 .policy = nl80211_policy,
609 /* can be retrieved by unprivileged users */
610 },
611 {
612 .cmd = NL80211_CMD_SET_WIPHY,
613 .doit = nl80211_set_wiphy,
614 .policy = nl80211_policy,
615 .flags = GENL_ADMIN_PERM,
616 },
617 {
618 .cmd = NL80211_CMD_GET_INTERFACE,
619 .doit = nl80211_get_interface,
620 .dumpit = nl80211_dump_interface,
621 .policy = nl80211_policy,
622 /* can be retrieved by unprivileged users */
623 },
624 {
625 .cmd = NL80211_CMD_SET_INTERFACE,
626 .doit = nl80211_set_interface,
627 .policy = nl80211_policy,
628 .flags = GENL_ADMIN_PERM,
629 },
630 {
631 .cmd = NL80211_CMD_NEW_INTERFACE,
632 .doit = nl80211_new_interface,
633 .policy = nl80211_policy,
634 .flags = GENL_ADMIN_PERM,
635 },
636 {
637 .cmd = NL80211_CMD_DEL_INTERFACE,
638 .doit = nl80211_del_interface,
639 .policy = nl80211_policy,
640 .flags = GENL_ADMIN_PERM,
641 },
Johannes Berg41ade002007-12-19 02:03:29 +0100642 {
643 .cmd = NL80211_CMD_GET_KEY,
644 .doit = nl80211_get_key,
645 .policy = nl80211_policy,
646 .flags = GENL_ADMIN_PERM,
647 },
648 {
649 .cmd = NL80211_CMD_SET_KEY,
650 .doit = nl80211_set_key,
651 .policy = nl80211_policy,
652 .flags = GENL_ADMIN_PERM,
653 },
654 {
655 .cmd = NL80211_CMD_NEW_KEY,
656 .doit = nl80211_new_key,
657 .policy = nl80211_policy,
658 .flags = GENL_ADMIN_PERM,
659 },
660 {
661 .cmd = NL80211_CMD_DEL_KEY,
662 .doit = nl80211_del_key,
663 .policy = nl80211_policy,
664 .flags = GENL_ADMIN_PERM,
665 },
Johannes Berg55682962007-09-20 13:09:35 -0400666};
667
668/* multicast groups */
669static struct genl_multicast_group nl80211_config_mcgrp = {
670 .name = "config",
671};
672
673/* notification functions */
674
675void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
676{
677 struct sk_buff *msg;
678
679 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
680 if (!msg)
681 return;
682
683 if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) {
684 nlmsg_free(msg);
685 return;
686 }
687
688 genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
689}
690
691/* initialisation/exit functions */
692
693int nl80211_init(void)
694{
695 int err, i;
696
697 err = genl_register_family(&nl80211_fam);
698 if (err)
699 return err;
700
701 for (i = 0; i < ARRAY_SIZE(nl80211_ops); i++) {
702 err = genl_register_ops(&nl80211_fam, &nl80211_ops[i]);
703 if (err)
704 goto err_out;
705 }
706
707 err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp);
708 if (err)
709 goto err_out;
710
711 return 0;
712 err_out:
713 genl_unregister_family(&nl80211_fam);
714 return err;
715}
716
717void nl80211_exit(void)
718{
719 genl_unregister_family(&nl80211_fam);
720}