diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-29 06:54:01 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-29 06:54:01 -0500 |
commit | 0ba6c33bcddc64a54b5f1c25a696c4767dc76292 (patch) | |
tree | 62e616f97a4762d8e75bf732e4827af2d15d52c5 /net/wireless | |
parent | 21af0297c7e56024a5ccc4d8ad2a590f9ec371ba (diff) | |
parent | 85040bcb4643cba578839e953f25e2d1965d83d0 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.25
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.25: (1470 commits)
[IPV6] ADDRLABEL: Fix double free on label deletion.
[PPP]: Sparse warning fixes.
[IPV4] fib_trie: remove unneeded NULL check
[IPV4] fib_trie: More whitespace cleanup.
[NET_SCHED]: Use nla_policy for attribute validation in ematches
[NET_SCHED]: Use nla_policy for attribute validation in actions
[NET_SCHED]: Use nla_policy for attribute validation in classifiers
[NET_SCHED]: Use nla_policy for attribute validation in packet schedulers
[NET_SCHED]: sch_api: introduce constant for rate table size
[NET_SCHED]: Use typeful attribute parsing helpers
[NET_SCHED]: Use typeful attribute construction helpers
[NET_SCHED]: Use NLA_PUT_STRING for string dumping
[NET_SCHED]: Use nla_nest_start/nla_nest_end
[NET_SCHED]: Propagate nla_parse return value
[NET_SCHED]: act_api: use PTR_ERR in tcf_action_init/tcf_action_get
[NET_SCHED]: act_api: use nlmsg_parse
[NET_SCHED]: act_api: fix netlink API conversion bug
[NET_SCHED]: sch_netem: use nla_parse_nested_compat
[NET_SCHED]: sch_atm: fix format string warning
[NETNS]: Add namespace for ICMP replying code.
...
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/Kconfig | 10 | ||||
-rw-r--r-- | net/wireless/core.c | 3 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 737 | ||||
-rw-r--r-- | net/wireless/wext.c | 43 |
4 files changed, 752 insertions, 41 deletions
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 6426055a8be0..79270903bda6 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig | |||
@@ -6,13 +6,13 @@ config NL80211 | |||
6 | depends on CFG80211 | 6 | depends on CFG80211 |
7 | default y | 7 | default y |
8 | ---help--- | 8 | ---help--- |
9 | This option turns on the new netlink interface | 9 | This option turns on the new netlink interface |
10 | (nl80211) support in cfg80211. | 10 | (nl80211) support in cfg80211. |
11 | 11 | ||
12 | If =n, drivers using mac80211 will be configured via | 12 | If =n, drivers using mac80211 will be configured via |
13 | wireless extension support provided by that subsystem. | 13 | wireless extension support provided by that subsystem. |
14 | 14 | ||
15 | If unsure, say Y. | 15 | If unsure, say Y. |
16 | 16 | ||
17 | config WIRELESS_EXT | 17 | config WIRELESS_EXT |
18 | bool "Wireless extensions" | 18 | bool "Wireless extensions" |
diff --git a/net/wireless/core.c b/net/wireless/core.c index febc33bc9c09..cfc5fc5f9e75 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -184,6 +184,9 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv) | |||
184 | struct cfg80211_registered_device *drv; | 184 | struct cfg80211_registered_device *drv; |
185 | int alloc_size; | 185 | int alloc_size; |
186 | 186 | ||
187 | WARN_ON(!ops->add_key && ops->del_key); | ||
188 | WARN_ON(ops->add_key && !ops->del_key); | ||
189 | |||
187 | alloc_size = sizeof(*drv) + sizeof_priv; | 190 | alloc_size = sizeof(*drv) + sizeof_priv; |
188 | 191 | ||
189 | drv = kzalloc(alloc_size, GFP_KERNEL); | 192 | drv = kzalloc(alloc_size, GFP_KERNEL); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 48b0d453e4e1..e3a214f63f91 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -61,6 +61,27 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
61 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, | 61 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, |
62 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, | 62 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, |
63 | [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, | 63 | [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, |
64 | |||
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 }, | ||
72 | |||
73 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, | ||
74 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, | ||
75 | [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY, | ||
76 | .len = IEEE80211_MAX_DATA_LEN }, | ||
77 | [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY, | ||
78 | .len = IEEE80211_MAX_DATA_LEN }, | ||
79 | [NL80211_ATTR_STA_AID] = { .type = NLA_U16 }, | ||
80 | [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED }, | ||
81 | [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, | ||
82 | [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, | ||
83 | .len = NL80211_MAX_SUPP_RATES }, | ||
84 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, | ||
64 | }; | 85 | }; |
65 | 86 | ||
66 | /* message building helper */ | 87 | /* message building helper */ |
@@ -335,6 +356,655 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | |||
335 | return err; | 356 | return err; |
336 | } | 357 | } |
337 | 358 | ||
359 | struct get_key_cookie { | ||
360 | struct sk_buff *msg; | ||
361 | int error; | ||
362 | }; | ||
363 | |||
364 | static void get_key_callback(void *c, struct key_params *params) | ||
365 | { | ||
366 | struct get_key_cookie *cookie = c; | ||
367 | |||
368 | if (params->key) | ||
369 | NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA, | ||
370 | params->key_len, params->key); | ||
371 | |||
372 | if (params->seq) | ||
373 | NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ, | ||
374 | params->seq_len, params->seq); | ||
375 | |||
376 | if (params->cipher) | ||
377 | NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER, | ||
378 | params->cipher); | ||
379 | |||
380 | return; | ||
381 | nla_put_failure: | ||
382 | cookie->error = 1; | ||
383 | } | ||
384 | |||
385 | static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | ||
386 | { | ||
387 | struct cfg80211_registered_device *drv; | ||
388 | int err; | ||
389 | struct net_device *dev; | ||
390 | u8 key_idx = 0; | ||
391 | u8 *mac_addr = NULL; | ||
392 | struct get_key_cookie cookie = { | ||
393 | .error = 0, | ||
394 | }; | ||
395 | void *hdr; | ||
396 | struct sk_buff *msg; | ||
397 | |||
398 | if (info->attrs[NL80211_ATTR_KEY_IDX]) | ||
399 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | ||
400 | |||
401 | if (key_idx > 3) | ||
402 | return -EINVAL; | ||
403 | |||
404 | if (info->attrs[NL80211_ATTR_MAC]) | ||
405 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
406 | |||
407 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
408 | if (err) | ||
409 | return err; | ||
410 | |||
411 | if (!drv->ops->get_key) { | ||
412 | err = -EOPNOTSUPP; | ||
413 | goto out; | ||
414 | } | ||
415 | |||
416 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
417 | if (!msg) { | ||
418 | err = -ENOMEM; | ||
419 | goto out; | ||
420 | } | ||
421 | |||
422 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | ||
423 | NL80211_CMD_NEW_KEY); | ||
424 | |||
425 | if (IS_ERR(hdr)) { | ||
426 | err = PTR_ERR(hdr); | ||
427 | goto out; | ||
428 | } | ||
429 | |||
430 | cookie.msg = msg; | ||
431 | |||
432 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | ||
433 | NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); | ||
434 | if (mac_addr) | ||
435 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | ||
436 | |||
437 | rtnl_lock(); | ||
438 | err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr, | ||
439 | &cookie, get_key_callback); | ||
440 | rtnl_unlock(); | ||
441 | |||
442 | if (err) | ||
443 | goto out; | ||
444 | |||
445 | if (cookie.error) | ||
446 | goto nla_put_failure; | ||
447 | |||
448 | genlmsg_end(msg, hdr); | ||
449 | err = genlmsg_unicast(msg, info->snd_pid); | ||
450 | goto out; | ||
451 | |||
452 | nla_put_failure: | ||
453 | err = -ENOBUFS; | ||
454 | nlmsg_free(msg); | ||
455 | out: | ||
456 | cfg80211_put_dev(drv); | ||
457 | dev_put(dev); | ||
458 | return err; | ||
459 | } | ||
460 | |||
461 | static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | ||
462 | { | ||
463 | struct cfg80211_registered_device *drv; | ||
464 | int err; | ||
465 | struct net_device *dev; | ||
466 | u8 key_idx; | ||
467 | |||
468 | if (!info->attrs[NL80211_ATTR_KEY_IDX]) | ||
469 | return -EINVAL; | ||
470 | |||
471 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | ||
472 | |||
473 | if (key_idx > 3) | ||
474 | return -EINVAL; | ||
475 | |||
476 | /* currently only support setting default key */ | ||
477 | if (!info->attrs[NL80211_ATTR_KEY_DEFAULT]) | ||
478 | return -EINVAL; | ||
479 | |||
480 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
481 | if (err) | ||
482 | return err; | ||
483 | |||
484 | if (!drv->ops->set_default_key) { | ||
485 | err = -EOPNOTSUPP; | ||
486 | goto out; | ||
487 | } | ||
488 | |||
489 | rtnl_lock(); | ||
490 | err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx); | ||
491 | rtnl_unlock(); | ||
492 | |||
493 | out: | ||
494 | cfg80211_put_dev(drv); | ||
495 | dev_put(dev); | ||
496 | return err; | ||
497 | } | ||
498 | |||
499 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | ||
500 | { | ||
501 | struct cfg80211_registered_device *drv; | ||
502 | int err; | ||
503 | struct net_device *dev; | ||
504 | struct key_params params; | ||
505 | u8 key_idx = 0; | ||
506 | u8 *mac_addr = NULL; | ||
507 | |||
508 | memset(¶ms, 0, sizeof(params)); | ||
509 | |||
510 | if (!info->attrs[NL80211_ATTR_KEY_CIPHER]) | ||
511 | return -EINVAL; | ||
512 | |||
513 | if (info->attrs[NL80211_ATTR_KEY_DATA]) { | ||
514 | params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]); | ||
515 | params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]); | ||
516 | } | ||
517 | |||
518 | if (info->attrs[NL80211_ATTR_KEY_IDX]) | ||
519 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | ||
520 | |||
521 | params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]); | ||
522 | |||
523 | if (info->attrs[NL80211_ATTR_MAC]) | ||
524 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
525 | |||
526 | if (key_idx > 3) | ||
527 | return -EINVAL; | ||
528 | |||
529 | /* | ||
530 | * Disallow pairwise keys with non-zero index unless it's WEP | ||
531 | * (because current deployments use pairwise WEP keys with | ||
532 | * non-zero indizes but 802.11i clearly specifies to use zero) | ||
533 | */ | ||
534 | if (mac_addr && key_idx && | ||
535 | params.cipher != WLAN_CIPHER_SUITE_WEP40 && | ||
536 | params.cipher != WLAN_CIPHER_SUITE_WEP104) | ||
537 | return -EINVAL; | ||
538 | |||
539 | /* TODO: add definitions for the lengths to linux/ieee80211.h */ | ||
540 | switch (params.cipher) { | ||
541 | case WLAN_CIPHER_SUITE_WEP40: | ||
542 | if (params.key_len != 5) | ||
543 | return -EINVAL; | ||
544 | break; | ||
545 | case WLAN_CIPHER_SUITE_TKIP: | ||
546 | if (params.key_len != 32) | ||
547 | return -EINVAL; | ||
548 | break; | ||
549 | case WLAN_CIPHER_SUITE_CCMP: | ||
550 | if (params.key_len != 16) | ||
551 | return -EINVAL; | ||
552 | break; | ||
553 | case WLAN_CIPHER_SUITE_WEP104: | ||
554 | if (params.key_len != 13) | ||
555 | return -EINVAL; | ||
556 | break; | ||
557 | default: | ||
558 | return -EINVAL; | ||
559 | } | ||
560 | |||
561 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
562 | if (err) | ||
563 | return err; | ||
564 | |||
565 | if (!drv->ops->add_key) { | ||
566 | err = -EOPNOTSUPP; | ||
567 | goto out; | ||
568 | } | ||
569 | |||
570 | rtnl_lock(); | ||
571 | err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, ¶ms); | ||
572 | rtnl_unlock(); | ||
573 | |||
574 | out: | ||
575 | cfg80211_put_dev(drv); | ||
576 | dev_put(dev); | ||
577 | return err; | ||
578 | } | ||
579 | |||
580 | static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | ||
581 | { | ||
582 | struct cfg80211_registered_device *drv; | ||
583 | int err; | ||
584 | struct net_device *dev; | ||
585 | u8 key_idx = 0; | ||
586 | u8 *mac_addr = NULL; | ||
587 | |||
588 | if (info->attrs[NL80211_ATTR_KEY_IDX]) | ||
589 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | ||
590 | |||
591 | if (key_idx > 3) | ||
592 | return -EINVAL; | ||
593 | |||
594 | if (info->attrs[NL80211_ATTR_MAC]) | ||
595 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
596 | |||
597 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
598 | if (err) | ||
599 | return err; | ||
600 | |||
601 | if (!drv->ops->del_key) { | ||
602 | err = -EOPNOTSUPP; | ||
603 | goto out; | ||
604 | } | ||
605 | |||
606 | rtnl_lock(); | ||
607 | err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); | ||
608 | rtnl_unlock(); | ||
609 | |||
610 | out: | ||
611 | cfg80211_put_dev(drv); | ||
612 | dev_put(dev); | ||
613 | return err; | ||
614 | } | ||
615 | |||
616 | static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | ||
617 | { | ||
618 | int (*call)(struct wiphy *wiphy, struct net_device *dev, | ||
619 | struct beacon_parameters *info); | ||
620 | struct cfg80211_registered_device *drv; | ||
621 | int err; | ||
622 | struct net_device *dev; | ||
623 | struct beacon_parameters params; | ||
624 | int haveinfo = 0; | ||
625 | |||
626 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
627 | if (err) | ||
628 | return err; | ||
629 | |||
630 | switch (info->genlhdr->cmd) { | ||
631 | case NL80211_CMD_NEW_BEACON: | ||
632 | /* these are required for NEW_BEACON */ | ||
633 | if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || | ||
634 | !info->attrs[NL80211_ATTR_DTIM_PERIOD] || | ||
635 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) { | ||
636 | err = -EINVAL; | ||
637 | goto out; | ||
638 | } | ||
639 | |||
640 | call = drv->ops->add_beacon; | ||
641 | break; | ||
642 | case NL80211_CMD_SET_BEACON: | ||
643 | call = drv->ops->set_beacon; | ||
644 | break; | ||
645 | default: | ||
646 | WARN_ON(1); | ||
647 | err = -EOPNOTSUPP; | ||
648 | goto out; | ||
649 | } | ||
650 | |||
651 | if (!call) { | ||
652 | err = -EOPNOTSUPP; | ||
653 | goto out; | ||
654 | } | ||
655 | |||
656 | memset(¶ms, 0, sizeof(params)); | ||
657 | |||
658 | if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { | ||
659 | params.interval = | ||
660 | nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); | ||
661 | haveinfo = 1; | ||
662 | } | ||
663 | |||
664 | if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) { | ||
665 | params.dtim_period = | ||
666 | nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); | ||
667 | haveinfo = 1; | ||
668 | } | ||
669 | |||
670 | if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { | ||
671 | params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); | ||
672 | params.head_len = | ||
673 | nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]); | ||
674 | haveinfo = 1; | ||
675 | } | ||
676 | |||
677 | if (info->attrs[NL80211_ATTR_BEACON_TAIL]) { | ||
678 | params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]); | ||
679 | params.tail_len = | ||
680 | nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]); | ||
681 | haveinfo = 1; | ||
682 | } | ||
683 | |||
684 | if (!haveinfo) { | ||
685 | err = -EINVAL; | ||
686 | goto out; | ||
687 | } | ||
688 | |||
689 | rtnl_lock(); | ||
690 | err = call(&drv->wiphy, dev, ¶ms); | ||
691 | rtnl_unlock(); | ||
692 | |||
693 | out: | ||
694 | cfg80211_put_dev(drv); | ||
695 | dev_put(dev); | ||
696 | return err; | ||
697 | } | ||
698 | |||
699 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | ||
700 | { | ||
701 | struct cfg80211_registered_device *drv; | ||
702 | int err; | ||
703 | struct net_device *dev; | ||
704 | |||
705 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
706 | if (err) | ||
707 | return err; | ||
708 | |||
709 | if (!drv->ops->del_beacon) { | ||
710 | err = -EOPNOTSUPP; | ||
711 | goto out; | ||
712 | } | ||
713 | |||
714 | rtnl_lock(); | ||
715 | err = drv->ops->del_beacon(&drv->wiphy, dev); | ||
716 | rtnl_unlock(); | ||
717 | |||
718 | out: | ||
719 | cfg80211_put_dev(drv); | ||
720 | dev_put(dev); | ||
721 | return err; | ||
722 | } | ||
723 | |||
724 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | ||
725 | [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG }, | ||
726 | [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG }, | ||
727 | [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG }, | ||
728 | }; | ||
729 | |||
730 | static int parse_station_flags(struct nlattr *nla, u32 *staflags) | ||
731 | { | ||
732 | struct nlattr *flags[NL80211_STA_FLAG_MAX + 1]; | ||
733 | int flag; | ||
734 | |||
735 | *staflags = 0; | ||
736 | |||
737 | if (!nla) | ||
738 | return 0; | ||
739 | |||
740 | if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX, | ||
741 | nla, sta_flags_policy)) | ||
742 | return -EINVAL; | ||
743 | |||
744 | *staflags = STATION_FLAG_CHANGED; | ||
745 | |||
746 | for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) | ||
747 | if (flags[flag]) | ||
748 | *staflags |= (1<<flag); | ||
749 | |||
750 | return 0; | ||
751 | } | ||
752 | |||
753 | static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | ||
754 | int flags, struct net_device *dev, | ||
755 | u8 *mac_addr, struct station_stats *stats) | ||
756 | { | ||
757 | void *hdr; | ||
758 | struct nlattr *statsattr; | ||
759 | |||
760 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); | ||
761 | if (!hdr) | ||
762 | return -1; | ||
763 | |||
764 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | ||
765 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | ||
766 | |||
767 | statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS); | ||
768 | if (!statsattr) | ||
769 | goto nla_put_failure; | ||
770 | if (stats->filled & STATION_STAT_INACTIVE_TIME) | ||
771 | NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME, | ||
772 | stats->inactive_time); | ||
773 | if (stats->filled & STATION_STAT_RX_BYTES) | ||
774 | NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES, | ||
775 | stats->rx_bytes); | ||
776 | if (stats->filled & STATION_STAT_TX_BYTES) | ||
777 | NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES, | ||
778 | stats->tx_bytes); | ||
779 | |||
780 | nla_nest_end(msg, statsattr); | ||
781 | |||
782 | return genlmsg_end(msg, hdr); | ||
783 | |||
784 | nla_put_failure: | ||
785 | return genlmsg_cancel(msg, hdr); | ||
786 | } | ||
787 | |||
788 | |||
789 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | ||
790 | { | ||
791 | struct cfg80211_registered_device *drv; | ||
792 | int err; | ||
793 | struct net_device *dev; | ||
794 | struct station_stats stats; | ||
795 | struct sk_buff *msg; | ||
796 | u8 *mac_addr = NULL; | ||
797 | |||
798 | memset(&stats, 0, sizeof(stats)); | ||
799 | |||
800 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
801 | return -EINVAL; | ||
802 | |||
803 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
804 | |||
805 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
806 | if (err) | ||
807 | return err; | ||
808 | |||
809 | if (!drv->ops->get_station) { | ||
810 | err = -EOPNOTSUPP; | ||
811 | goto out; | ||
812 | } | ||
813 | |||
814 | rtnl_lock(); | ||
815 | err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats); | ||
816 | rtnl_unlock(); | ||
817 | |||
818 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
819 | if (!msg) | ||
820 | goto out; | ||
821 | |||
822 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, | ||
823 | dev, mac_addr, &stats) < 0) | ||
824 | goto out_free; | ||
825 | |||
826 | err = genlmsg_unicast(msg, info->snd_pid); | ||
827 | goto out; | ||
828 | |||
829 | out_free: | ||
830 | nlmsg_free(msg); | ||
831 | |||
832 | out: | ||
833 | cfg80211_put_dev(drv); | ||
834 | dev_put(dev); | ||
835 | return err; | ||
836 | } | ||
837 | |||
838 | /* | ||
839 | * Get vlan interface making sure it is on the right wiphy. | ||
840 | */ | ||
841 | static int get_vlan(struct nlattr *vlanattr, | ||
842 | struct cfg80211_registered_device *rdev, | ||
843 | struct net_device **vlan) | ||
844 | { | ||
845 | *vlan = NULL; | ||
846 | |||
847 | if (vlanattr) { | ||
848 | *vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr)); | ||
849 | if (!*vlan) | ||
850 | return -ENODEV; | ||
851 | if (!(*vlan)->ieee80211_ptr) | ||
852 | return -EINVAL; | ||
853 | if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) | ||
854 | return -EINVAL; | ||
855 | } | ||
856 | return 0; | ||
857 | } | ||
858 | |||
859 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | ||
860 | { | ||
861 | struct cfg80211_registered_device *drv; | ||
862 | int err; | ||
863 | struct net_device *dev; | ||
864 | struct station_parameters params; | ||
865 | u8 *mac_addr = NULL; | ||
866 | |||
867 | memset(¶ms, 0, sizeof(params)); | ||
868 | |||
869 | params.listen_interval = -1; | ||
870 | |||
871 | if (info->attrs[NL80211_ATTR_STA_AID]) | ||
872 | return -EINVAL; | ||
873 | |||
874 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
875 | return -EINVAL; | ||
876 | |||
877 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
878 | |||
879 | if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) { | ||
880 | params.supported_rates = | ||
881 | nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | ||
882 | params.supported_rates_len = | ||
883 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | ||
884 | } | ||
885 | |||
886 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | ||
887 | params.listen_interval = | ||
888 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); | ||
889 | |||
890 | if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], | ||
891 | ¶ms.station_flags)) | ||
892 | return -EINVAL; | ||
893 | |||
894 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
895 | if (err) | ||
896 | return err; | ||
897 | |||
898 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); | ||
899 | if (err) | ||
900 | goto out; | ||
901 | |||
902 | if (!drv->ops->change_station) { | ||
903 | err = -EOPNOTSUPP; | ||
904 | goto out; | ||
905 | } | ||
906 | |||
907 | rtnl_lock(); | ||
908 | err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, ¶ms); | ||
909 | rtnl_unlock(); | ||
910 | |||
911 | out: | ||
912 | if (params.vlan) | ||
913 | dev_put(params.vlan); | ||
914 | cfg80211_put_dev(drv); | ||
915 | dev_put(dev); | ||
916 | return err; | ||
917 | } | ||
918 | |||
919 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | ||
920 | { | ||
921 | struct cfg80211_registered_device *drv; | ||
922 | int err; | ||
923 | struct net_device *dev; | ||
924 | struct station_parameters params; | ||
925 | u8 *mac_addr = NULL; | ||
926 | |||
927 | memset(¶ms, 0, sizeof(params)); | ||
928 | |||
929 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
930 | return -EINVAL; | ||
931 | |||
932 | if (!info->attrs[NL80211_ATTR_STA_AID]) | ||
933 | return -EINVAL; | ||
934 | |||
935 | if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | ||
936 | return -EINVAL; | ||
937 | |||
938 | if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) | ||
939 | return -EINVAL; | ||
940 | |||
941 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
942 | params.supported_rates = | ||
943 | nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | ||
944 | params.supported_rates_len = | ||
945 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | ||
946 | params.listen_interval = | ||
947 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); | ||
948 | params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); | ||
949 | |||
950 | if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], | ||
951 | ¶ms.station_flags)) | ||
952 | return -EINVAL; | ||
953 | |||
954 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
955 | if (err) | ||
956 | return err; | ||
957 | |||
958 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); | ||
959 | if (err) | ||
960 | goto out; | ||
961 | |||
962 | if (!drv->ops->add_station) { | ||
963 | err = -EOPNOTSUPP; | ||
964 | goto out; | ||
965 | } | ||
966 | |||
967 | rtnl_lock(); | ||
968 | err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, ¶ms); | ||
969 | rtnl_unlock(); | ||
970 | |||
971 | out: | ||
972 | if (params.vlan) | ||
973 | dev_put(params.vlan); | ||
974 | cfg80211_put_dev(drv); | ||
975 | dev_put(dev); | ||
976 | return err; | ||
977 | } | ||
978 | |||
979 | static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | ||
980 | { | ||
981 | struct cfg80211_registered_device *drv; | ||
982 | int err; | ||
983 | struct net_device *dev; | ||
984 | u8 *mac_addr = NULL; | ||
985 | |||
986 | if (info->attrs[NL80211_ATTR_MAC]) | ||
987 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
988 | |||
989 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
990 | if (err) | ||
991 | return err; | ||
992 | |||
993 | if (!drv->ops->del_station) { | ||
994 | err = -EOPNOTSUPP; | ||
995 | goto out; | ||
996 | } | ||
997 | |||
998 | rtnl_lock(); | ||
999 | err = drv->ops->del_station(&drv->wiphy, dev, mac_addr); | ||
1000 | rtnl_unlock(); | ||
1001 | |||
1002 | out: | ||
1003 | cfg80211_put_dev(drv); | ||
1004 | dev_put(dev); | ||
1005 | return err; | ||
1006 | } | ||
1007 | |||
338 | static struct genl_ops nl80211_ops[] = { | 1008 | static struct genl_ops nl80211_ops[] = { |
339 | { | 1009 | { |
340 | .cmd = NL80211_CMD_GET_WIPHY, | 1010 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -374,6 +1044,73 @@ static struct genl_ops nl80211_ops[] = { | |||
374 | .policy = nl80211_policy, | 1044 | .policy = nl80211_policy, |
375 | .flags = GENL_ADMIN_PERM, | 1045 | .flags = GENL_ADMIN_PERM, |
376 | }, | 1046 | }, |
1047 | { | ||
1048 | .cmd = NL80211_CMD_GET_KEY, | ||
1049 | .doit = nl80211_get_key, | ||
1050 | .policy = nl80211_policy, | ||
1051 | .flags = GENL_ADMIN_PERM, | ||
1052 | }, | ||
1053 | { | ||
1054 | .cmd = NL80211_CMD_SET_KEY, | ||
1055 | .doit = nl80211_set_key, | ||
1056 | .policy = nl80211_policy, | ||
1057 | .flags = GENL_ADMIN_PERM, | ||
1058 | }, | ||
1059 | { | ||
1060 | .cmd = NL80211_CMD_NEW_KEY, | ||
1061 | .doit = nl80211_new_key, | ||
1062 | .policy = nl80211_policy, | ||
1063 | .flags = GENL_ADMIN_PERM, | ||
1064 | }, | ||
1065 | { | ||
1066 | .cmd = NL80211_CMD_DEL_KEY, | ||
1067 | .doit = nl80211_del_key, | ||
1068 | .policy = nl80211_policy, | ||
1069 | .flags = GENL_ADMIN_PERM, | ||
1070 | }, | ||
1071 | { | ||
1072 | .cmd = NL80211_CMD_SET_BEACON, | ||
1073 | .policy = nl80211_policy, | ||
1074 | .flags = GENL_ADMIN_PERM, | ||
1075 | .doit = nl80211_addset_beacon, | ||
1076 | }, | ||
1077 | { | ||
1078 | .cmd = NL80211_CMD_NEW_BEACON, | ||
1079 | .policy = nl80211_policy, | ||
1080 | .flags = GENL_ADMIN_PERM, | ||
1081 | .doit = nl80211_addset_beacon, | ||
1082 | }, | ||
1083 | { | ||
1084 | .cmd = NL80211_CMD_DEL_BEACON, | ||
1085 | .policy = nl80211_policy, | ||
1086 | .flags = GENL_ADMIN_PERM, | ||
1087 | .doit = nl80211_del_beacon, | ||
1088 | }, | ||
1089 | { | ||
1090 | .cmd = NL80211_CMD_GET_STATION, | ||
1091 | .doit = nl80211_get_station, | ||
1092 | /* TODO: implement dumpit */ | ||
1093 | .policy = nl80211_policy, | ||
1094 | .flags = GENL_ADMIN_PERM, | ||
1095 | }, | ||
1096 | { | ||
1097 | .cmd = NL80211_CMD_SET_STATION, | ||
1098 | .doit = nl80211_set_station, | ||
1099 | .policy = nl80211_policy, | ||
1100 | .flags = GENL_ADMIN_PERM, | ||
1101 | }, | ||
1102 | { | ||
1103 | .cmd = NL80211_CMD_NEW_STATION, | ||
1104 | .doit = nl80211_new_station, | ||
1105 | .policy = nl80211_policy, | ||
1106 | .flags = GENL_ADMIN_PERM, | ||
1107 | }, | ||
1108 | { | ||
1109 | .cmd = NL80211_CMD_DEL_STATION, | ||
1110 | .doit = nl80211_del_station, | ||
1111 | .policy = nl80211_policy, | ||
1112 | .flags = GENL_ADMIN_PERM, | ||
1113 | }, | ||
377 | }; | 1114 | }; |
378 | 1115 | ||
379 | /* multicast groups */ | 1116 | /* multicast groups */ |
diff --git a/net/wireless/wext.c b/net/wireless/wext.c index 47e80cc2077c..2c569b63e7d8 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c | |||
@@ -417,20 +417,6 @@ static const int event_type_size[] = { | |||
417 | IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ | 417 | IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ |
418 | }; | 418 | }; |
419 | 419 | ||
420 | /* Size (in bytes) of various events, as packed */ | ||
421 | static const int event_type_pk_size[] = { | ||
422 | IW_EV_LCP_PK_LEN, /* IW_HEADER_TYPE_NULL */ | ||
423 | 0, | ||
424 | IW_EV_CHAR_PK_LEN, /* IW_HEADER_TYPE_CHAR */ | ||
425 | 0, | ||
426 | IW_EV_UINT_PK_LEN, /* IW_HEADER_TYPE_UINT */ | ||
427 | IW_EV_FREQ_PK_LEN, /* IW_HEADER_TYPE_FREQ */ | ||
428 | IW_EV_ADDR_PK_LEN, /* IW_HEADER_TYPE_ADDR */ | ||
429 | 0, | ||
430 | IW_EV_POINT_PK_LEN, /* Without variable payload */ | ||
431 | IW_EV_PARAM_PK_LEN, /* IW_HEADER_TYPE_PARAM */ | ||
432 | IW_EV_QUAL_PK_LEN, /* IW_HEADER_TYPE_QUAL */ | ||
433 | }; | ||
434 | 420 | ||
435 | /************************ COMMON SUBROUTINES ************************/ | 421 | /************************ COMMON SUBROUTINES ************************/ |
436 | /* | 422 | /* |
@@ -673,26 +659,8 @@ static const struct seq_operations wireless_seq_ops = { | |||
673 | 659 | ||
674 | static int wireless_seq_open(struct inode *inode, struct file *file) | 660 | static int wireless_seq_open(struct inode *inode, struct file *file) |
675 | { | 661 | { |
676 | struct seq_file *seq; | 662 | return seq_open_net(inode, file, &wireless_seq_ops, |
677 | int res; | 663 | sizeof(struct seq_net_private)); |
678 | res = seq_open(file, &wireless_seq_ops); | ||
679 | if (!res) { | ||
680 | seq = file->private_data; | ||
681 | seq->private = get_proc_net(inode); | ||
682 | if (!seq->private) { | ||
683 | seq_release(inode, file); | ||
684 | res = -ENXIO; | ||
685 | } | ||
686 | } | ||
687 | return res; | ||
688 | } | ||
689 | |||
690 | static int wireless_seq_release(struct inode *inode, struct file *file) | ||
691 | { | ||
692 | struct seq_file *seq = file->private_data; | ||
693 | struct net *net = seq->private; | ||
694 | put_net(net); | ||
695 | return seq_release(inode, file); | ||
696 | } | 664 | } |
697 | 665 | ||
698 | static const struct file_operations wireless_seq_fops = { | 666 | static const struct file_operations wireless_seq_fops = { |
@@ -700,7 +668,7 @@ static const struct file_operations wireless_seq_fops = { | |||
700 | .open = wireless_seq_open, | 668 | .open = wireless_seq_open, |
701 | .read = seq_read, | 669 | .read = seq_read, |
702 | .llseek = seq_lseek, | 670 | .llseek = seq_lseek, |
703 | .release = wireless_seq_release, | 671 | .release = seq_release_net, |
704 | }; | 672 | }; |
705 | 673 | ||
706 | int wext_proc_init(struct net *net) | 674 | int wext_proc_init(struct net *net) |
@@ -1137,7 +1105,7 @@ static void wireless_nlevent_process(unsigned long data) | |||
1137 | struct sk_buff *skb; | 1105 | struct sk_buff *skb; |
1138 | 1106 | ||
1139 | while ((skb = skb_dequeue(&wireless_nlevent_queue))) | 1107 | while ((skb = skb_dequeue(&wireless_nlevent_queue))) |
1140 | rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); | 1108 | rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); |
1141 | } | 1109 | } |
1142 | 1110 | ||
1143 | static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); | 1111 | static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); |
@@ -1189,6 +1157,9 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len) | |||
1189 | struct sk_buff *skb; | 1157 | struct sk_buff *skb; |
1190 | int err; | 1158 | int err; |
1191 | 1159 | ||
1160 | if (dev->nd_net != &init_net) | ||
1161 | return; | ||
1162 | |||
1192 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); | 1163 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); |
1193 | if (!skb) | 1164 | if (!skb) |
1194 | return; | 1165 | return; |