diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 824 |
1 files changed, 666 insertions, 158 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ab9d8f14e151..353e1a4ece83 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -111,6 +111,11 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
111 | .len = IEEE80211_MAX_DATA_LEN }, | 111 | .len = IEEE80211_MAX_DATA_LEN }, |
112 | [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED }, | 112 | [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED }, |
113 | [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED }, | 113 | [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED }, |
114 | |||
115 | [NL80211_ATTR_SSID] = { .type = NLA_BINARY, | ||
116 | .len = IEEE80211_MAX_SSID_LEN }, | ||
117 | [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 }, | ||
118 | [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, | ||
114 | }; | 119 | }; |
115 | 120 | ||
116 | /* message building helper */ | 121 | /* message building helper */ |
@@ -131,6 +136,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
131 | struct nlattr *nl_freqs, *nl_freq; | 136 | struct nlattr *nl_freqs, *nl_freq; |
132 | struct nlattr *nl_rates, *nl_rate; | 137 | struct nlattr *nl_rates, *nl_rate; |
133 | struct nlattr *nl_modes; | 138 | struct nlattr *nl_modes; |
139 | struct nlattr *nl_cmds; | ||
134 | enum ieee80211_band band; | 140 | enum ieee80211_band band; |
135 | struct ieee80211_channel *chan; | 141 | struct ieee80211_channel *chan; |
136 | struct ieee80211_rate *rate; | 142 | struct ieee80211_rate *rate; |
@@ -242,6 +248,35 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
242 | } | 248 | } |
243 | nla_nest_end(msg, nl_bands); | 249 | nla_nest_end(msg, nl_bands); |
244 | 250 | ||
251 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); | ||
252 | if (!nl_cmds) | ||
253 | goto nla_put_failure; | ||
254 | |||
255 | i = 0; | ||
256 | #define CMD(op, n) \ | ||
257 | do { \ | ||
258 | if (dev->ops->op) { \ | ||
259 | i++; \ | ||
260 | NLA_PUT_U32(msg, i, NL80211_CMD_ ## n); \ | ||
261 | } \ | ||
262 | } while (0) | ||
263 | |||
264 | CMD(add_virtual_intf, NEW_INTERFACE); | ||
265 | CMD(change_virtual_intf, SET_INTERFACE); | ||
266 | CMD(add_key, NEW_KEY); | ||
267 | CMD(add_beacon, NEW_BEACON); | ||
268 | CMD(add_station, NEW_STATION); | ||
269 | CMD(add_mpath, NEW_MPATH); | ||
270 | CMD(set_mesh_params, SET_MESH_PARAMS); | ||
271 | CMD(change_bss, SET_BSS); | ||
272 | CMD(auth, AUTHENTICATE); | ||
273 | CMD(assoc, ASSOCIATE); | ||
274 | CMD(deauth, DEAUTHENTICATE); | ||
275 | CMD(disassoc, DISASSOCIATE); | ||
276 | |||
277 | #undef CMD | ||
278 | nla_nest_end(msg, nl_cmds); | ||
279 | |||
245 | return genlmsg_end(msg, hdr); | 280 | return genlmsg_end(msg, hdr); |
246 | 281 | ||
247 | nla_put_failure: | 282 | nla_put_failure: |
@@ -331,16 +366,26 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
331 | int result = 0, rem_txq_params = 0; | 366 | int result = 0, rem_txq_params = 0; |
332 | struct nlattr *nl_txq_params; | 367 | struct nlattr *nl_txq_params; |
333 | 368 | ||
334 | rdev = cfg80211_get_dev_from_info(info); | 369 | rtnl_lock(); |
335 | if (IS_ERR(rdev)) | 370 | |
336 | return PTR_ERR(rdev); | 371 | mutex_lock(&cfg80211_mutex); |
337 | 372 | ||
338 | if (info->attrs[NL80211_ATTR_WIPHY_NAME]) { | 373 | rdev = __cfg80211_drv_from_info(info); |
374 | if (IS_ERR(rdev)) { | ||
375 | result = PTR_ERR(rdev); | ||
376 | goto unlock; | ||
377 | } | ||
378 | |||
379 | mutex_lock(&rdev->mtx); | ||
380 | |||
381 | if (info->attrs[NL80211_ATTR_WIPHY_NAME]) | ||
339 | result = cfg80211_dev_rename( | 382 | result = cfg80211_dev_rename( |
340 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); | 383 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); |
341 | if (result) | 384 | |
342 | goto bad_res; | 385 | mutex_unlock(&cfg80211_mutex); |
343 | } | 386 | |
387 | if (result) | ||
388 | goto bad_res; | ||
344 | 389 | ||
345 | if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { | 390 | if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { |
346 | struct ieee80211_txq_params txq_params; | 391 | struct ieee80211_txq_params txq_params; |
@@ -436,7 +481,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
436 | 481 | ||
437 | 482 | ||
438 | bad_res: | 483 | bad_res: |
439 | cfg80211_put_dev(rdev); | 484 | mutex_unlock(&rdev->mtx); |
485 | unlock: | ||
486 | rtnl_unlock(); | ||
440 | return result; | 487 | return result; |
441 | } | 488 | } |
442 | 489 | ||
@@ -572,21 +619,31 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
572 | enum nl80211_iftype type; | 619 | enum nl80211_iftype type; |
573 | struct net_device *dev; | 620 | struct net_device *dev; |
574 | u32 _flags, *flags = NULL; | 621 | u32 _flags, *flags = NULL; |
622 | bool change = false; | ||
575 | 623 | ||
576 | memset(¶ms, 0, sizeof(params)); | 624 | memset(¶ms, 0, sizeof(params)); |
577 | 625 | ||
626 | rtnl_lock(); | ||
627 | |||
578 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 628 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
579 | if (err) | 629 | if (err) |
580 | return err; | 630 | goto unlock_rtnl; |
631 | |||
581 | ifindex = dev->ifindex; | 632 | ifindex = dev->ifindex; |
582 | type = dev->ieee80211_ptr->iftype; | 633 | type = dev->ieee80211_ptr->iftype; |
583 | dev_put(dev); | 634 | dev_put(dev); |
584 | 635 | ||
585 | err = -EINVAL; | ||
586 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | 636 | if (info->attrs[NL80211_ATTR_IFTYPE]) { |
587 | type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | 637 | enum nl80211_iftype ntype; |
588 | if (type > NL80211_IFTYPE_MAX) | 638 | |
639 | ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | ||
640 | if (type != ntype) | ||
641 | change = true; | ||
642 | type = ntype; | ||
643 | if (type > NL80211_IFTYPE_MAX) { | ||
644 | err = -EINVAL; | ||
589 | goto unlock; | 645 | goto unlock; |
646 | } | ||
590 | } | 647 | } |
591 | 648 | ||
592 | if (!drv->ops->change_virtual_intf || | 649 | if (!drv->ops->change_virtual_intf || |
@@ -602,6 +659,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
602 | } | 659 | } |
603 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | 660 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); |
604 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 661 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); |
662 | change = true; | ||
605 | } | 663 | } |
606 | 664 | ||
607 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { | 665 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { |
@@ -611,20 +669,26 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
611 | } | 669 | } |
612 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], | 670 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], |
613 | &_flags); | 671 | &_flags); |
614 | if (!err) | 672 | if (err) |
615 | flags = &_flags; | 673 | goto unlock; |
674 | |||
675 | flags = &_flags; | ||
676 | change = true; | ||
616 | } | 677 | } |
617 | rtnl_lock(); | 678 | |
618 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, | 679 | if (change) |
619 | type, flags, ¶ms); | 680 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, |
681 | type, flags, ¶ms); | ||
682 | else | ||
683 | err = 0; | ||
620 | 684 | ||
621 | dev = __dev_get_by_index(&init_net, ifindex); | 685 | dev = __dev_get_by_index(&init_net, ifindex); |
622 | WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type)); | 686 | WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type)); |
623 | 687 | ||
624 | rtnl_unlock(); | ||
625 | |||
626 | unlock: | 688 | unlock: |
627 | cfg80211_put_dev(drv); | 689 | cfg80211_put_dev(drv); |
690 | unlock_rtnl: | ||
691 | rtnl_unlock(); | ||
628 | return err; | 692 | return err; |
629 | } | 693 | } |
630 | 694 | ||
@@ -647,9 +711,13 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
647 | return -EINVAL; | 711 | return -EINVAL; |
648 | } | 712 | } |
649 | 713 | ||
714 | rtnl_lock(); | ||
715 | |||
650 | drv = cfg80211_get_dev_from_info(info); | 716 | drv = cfg80211_get_dev_from_info(info); |
651 | if (IS_ERR(drv)) | 717 | if (IS_ERR(drv)) { |
652 | return PTR_ERR(drv); | 718 | err = PTR_ERR(drv); |
719 | goto unlock_rtnl; | ||
720 | } | ||
653 | 721 | ||
654 | if (!drv->ops->add_virtual_intf || | 722 | if (!drv->ops->add_virtual_intf || |
655 | !(drv->wiphy.interface_modes & (1 << type))) { | 723 | !(drv->wiphy.interface_modes & (1 << type))) { |
@@ -663,18 +731,17 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
663 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 731 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); |
664 | } | 732 | } |
665 | 733 | ||
666 | rtnl_lock(); | ||
667 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 734 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
668 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 735 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
669 | &flags); | 736 | &flags); |
670 | err = drv->ops->add_virtual_intf(&drv->wiphy, | 737 | err = drv->ops->add_virtual_intf(&drv->wiphy, |
671 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 738 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
672 | type, err ? NULL : &flags, ¶ms); | 739 | type, err ? NULL : &flags, ¶ms); |
673 | rtnl_unlock(); | ||
674 | |||
675 | 740 | ||
676 | unlock: | 741 | unlock: |
677 | cfg80211_put_dev(drv); | 742 | cfg80211_put_dev(drv); |
743 | unlock_rtnl: | ||
744 | rtnl_unlock(); | ||
678 | return err; | 745 | return err; |
679 | } | 746 | } |
680 | 747 | ||
@@ -684,9 +751,11 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | |||
684 | int ifindex, err; | 751 | int ifindex, err; |
685 | struct net_device *dev; | 752 | struct net_device *dev; |
686 | 753 | ||
754 | rtnl_lock(); | ||
755 | |||
687 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 756 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
688 | if (err) | 757 | if (err) |
689 | return err; | 758 | goto unlock_rtnl; |
690 | ifindex = dev->ifindex; | 759 | ifindex = dev->ifindex; |
691 | dev_put(dev); | 760 | dev_put(dev); |
692 | 761 | ||
@@ -695,12 +764,12 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | |||
695 | goto out; | 764 | goto out; |
696 | } | 765 | } |
697 | 766 | ||
698 | rtnl_lock(); | ||
699 | err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex); | 767 | err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex); |
700 | rtnl_unlock(); | ||
701 | 768 | ||
702 | out: | 769 | out: |
703 | cfg80211_put_dev(drv); | 770 | cfg80211_put_dev(drv); |
771 | unlock_rtnl: | ||
772 | rtnl_unlock(); | ||
704 | return err; | 773 | return err; |
705 | } | 774 | } |
706 | 775 | ||
@@ -752,9 +821,11 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
752 | if (info->attrs[NL80211_ATTR_MAC]) | 821 | if (info->attrs[NL80211_ATTR_MAC]) |
753 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 822 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
754 | 823 | ||
824 | rtnl_lock(); | ||
825 | |||
755 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 826 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
756 | if (err) | 827 | if (err) |
757 | return err; | 828 | goto unlock_rtnl; |
758 | 829 | ||
759 | if (!drv->ops->get_key) { | 830 | if (!drv->ops->get_key) { |
760 | err = -EOPNOTSUPP; | 831 | err = -EOPNOTSUPP; |
@@ -782,10 +853,8 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
782 | if (mac_addr) | 853 | if (mac_addr) |
783 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 854 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
784 | 855 | ||
785 | rtnl_lock(); | ||
786 | err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr, | 856 | err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr, |
787 | &cookie, get_key_callback); | 857 | &cookie, get_key_callback); |
788 | rtnl_unlock(); | ||
789 | 858 | ||
790 | if (err) | 859 | if (err) |
791 | goto out; | 860 | goto out; |
@@ -803,6 +872,9 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
803 | out: | 872 | out: |
804 | cfg80211_put_dev(drv); | 873 | cfg80211_put_dev(drv); |
805 | dev_put(dev); | 874 | dev_put(dev); |
875 | unlock_rtnl: | ||
876 | rtnl_unlock(); | ||
877 | |||
806 | return err; | 878 | return err; |
807 | } | 879 | } |
808 | 880 | ||
@@ -831,9 +903,11 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
831 | !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) | 903 | !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) |
832 | return -EINVAL; | 904 | return -EINVAL; |
833 | 905 | ||
906 | rtnl_lock(); | ||
907 | |||
834 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 908 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
835 | if (err) | 909 | if (err) |
836 | return err; | 910 | goto unlock_rtnl; |
837 | 911 | ||
838 | if (info->attrs[NL80211_ATTR_KEY_DEFAULT]) | 912 | if (info->attrs[NL80211_ATTR_KEY_DEFAULT]) |
839 | func = drv->ops->set_default_key; | 913 | func = drv->ops->set_default_key; |
@@ -845,13 +919,15 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
845 | goto out; | 919 | goto out; |
846 | } | 920 | } |
847 | 921 | ||
848 | rtnl_lock(); | ||
849 | err = func(&drv->wiphy, dev, key_idx); | 922 | err = func(&drv->wiphy, dev, key_idx); |
850 | rtnl_unlock(); | ||
851 | 923 | ||
852 | out: | 924 | out: |
853 | cfg80211_put_dev(drv); | 925 | cfg80211_put_dev(drv); |
854 | dev_put(dev); | 926 | dev_put(dev); |
927 | |||
928 | unlock_rtnl: | ||
929 | rtnl_unlock(); | ||
930 | |||
855 | return err; | 931 | return err; |
856 | } | 932 | } |
857 | 933 | ||
@@ -921,22 +997,25 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
921 | return -EINVAL; | 997 | return -EINVAL; |
922 | } | 998 | } |
923 | 999 | ||
1000 | rtnl_lock(); | ||
1001 | |||
924 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1002 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
925 | if (err) | 1003 | if (err) |
926 | return err; | 1004 | goto unlock_rtnl; |
927 | 1005 | ||
928 | if (!drv->ops->add_key) { | 1006 | if (!drv->ops->add_key) { |
929 | err = -EOPNOTSUPP; | 1007 | err = -EOPNOTSUPP; |
930 | goto out; | 1008 | goto out; |
931 | } | 1009 | } |
932 | 1010 | ||
933 | rtnl_lock(); | ||
934 | err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, ¶ms); | 1011 | err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, ¶ms); |
935 | rtnl_unlock(); | ||
936 | 1012 | ||
937 | out: | 1013 | out: |
938 | cfg80211_put_dev(drv); | 1014 | cfg80211_put_dev(drv); |
939 | dev_put(dev); | 1015 | dev_put(dev); |
1016 | unlock_rtnl: | ||
1017 | rtnl_unlock(); | ||
1018 | |||
940 | return err; | 1019 | return err; |
941 | } | 1020 | } |
942 | 1021 | ||
@@ -957,22 +1036,26 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
957 | if (info->attrs[NL80211_ATTR_MAC]) | 1036 | if (info->attrs[NL80211_ATTR_MAC]) |
958 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1037 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
959 | 1038 | ||
1039 | rtnl_lock(); | ||
1040 | |||
960 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1041 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
961 | if (err) | 1042 | if (err) |
962 | return err; | 1043 | goto unlock_rtnl; |
963 | 1044 | ||
964 | if (!drv->ops->del_key) { | 1045 | if (!drv->ops->del_key) { |
965 | err = -EOPNOTSUPP; | 1046 | err = -EOPNOTSUPP; |
966 | goto out; | 1047 | goto out; |
967 | } | 1048 | } |
968 | 1049 | ||
969 | rtnl_lock(); | ||
970 | err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); | 1050 | err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); |
971 | rtnl_unlock(); | ||
972 | 1051 | ||
973 | out: | 1052 | out: |
974 | cfg80211_put_dev(drv); | 1053 | cfg80211_put_dev(drv); |
975 | dev_put(dev); | 1054 | dev_put(dev); |
1055 | |||
1056 | unlock_rtnl: | ||
1057 | rtnl_unlock(); | ||
1058 | |||
976 | return err; | 1059 | return err; |
977 | } | 1060 | } |
978 | 1061 | ||
@@ -986,9 +1069,16 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
986 | struct beacon_parameters params; | 1069 | struct beacon_parameters params; |
987 | int haveinfo = 0; | 1070 | int haveinfo = 0; |
988 | 1071 | ||
1072 | rtnl_lock(); | ||
1073 | |||
989 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1074 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
990 | if (err) | 1075 | if (err) |
991 | return err; | 1076 | goto unlock_rtnl; |
1077 | |||
1078 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { | ||
1079 | err = -EOPNOTSUPP; | ||
1080 | goto out; | ||
1081 | } | ||
992 | 1082 | ||
993 | switch (info->genlhdr->cmd) { | 1083 | switch (info->genlhdr->cmd) { |
994 | case NL80211_CMD_NEW_BEACON: | 1084 | case NL80211_CMD_NEW_BEACON: |
@@ -1049,13 +1139,14 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1049 | goto out; | 1139 | goto out; |
1050 | } | 1140 | } |
1051 | 1141 | ||
1052 | rtnl_lock(); | ||
1053 | err = call(&drv->wiphy, dev, ¶ms); | 1142 | err = call(&drv->wiphy, dev, ¶ms); |
1054 | rtnl_unlock(); | ||
1055 | 1143 | ||
1056 | out: | 1144 | out: |
1057 | cfg80211_put_dev(drv); | 1145 | cfg80211_put_dev(drv); |
1058 | dev_put(dev); | 1146 | dev_put(dev); |
1147 | unlock_rtnl: | ||
1148 | rtnl_unlock(); | ||
1149 | |||
1059 | return err; | 1150 | return err; |
1060 | } | 1151 | } |
1061 | 1152 | ||
@@ -1065,22 +1156,29 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1065 | int err; | 1156 | int err; |
1066 | struct net_device *dev; | 1157 | struct net_device *dev; |
1067 | 1158 | ||
1159 | rtnl_lock(); | ||
1160 | |||
1068 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1161 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1069 | if (err) | 1162 | if (err) |
1070 | return err; | 1163 | goto unlock_rtnl; |
1071 | 1164 | ||
1072 | if (!drv->ops->del_beacon) { | 1165 | if (!drv->ops->del_beacon) { |
1073 | err = -EOPNOTSUPP; | 1166 | err = -EOPNOTSUPP; |
1074 | goto out; | 1167 | goto out; |
1075 | } | 1168 | } |
1076 | 1169 | ||
1077 | rtnl_lock(); | 1170 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { |
1171 | err = -EOPNOTSUPP; | ||
1172 | goto out; | ||
1173 | } | ||
1078 | err = drv->ops->del_beacon(&drv->wiphy, dev); | 1174 | err = drv->ops->del_beacon(&drv->wiphy, dev); |
1079 | rtnl_unlock(); | ||
1080 | 1175 | ||
1081 | out: | 1176 | out: |
1082 | cfg80211_put_dev(drv); | 1177 | cfg80211_put_dev(drv); |
1083 | dev_put(dev); | 1178 | dev_put(dev); |
1179 | unlock_rtnl: | ||
1180 | rtnl_unlock(); | ||
1181 | |||
1084 | return err; | 1182 | return err; |
1085 | } | 1183 | } |
1086 | 1184 | ||
@@ -1246,30 +1344,32 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
1246 | return -EINVAL; | 1344 | return -EINVAL; |
1247 | } | 1345 | } |
1248 | 1346 | ||
1249 | netdev = dev_get_by_index(&init_net, ifidx); | 1347 | rtnl_lock(); |
1250 | if (!netdev) | 1348 | |
1251 | return -ENODEV; | 1349 | netdev = __dev_get_by_index(&init_net, ifidx); |
1350 | if (!netdev) { | ||
1351 | err = -ENODEV; | ||
1352 | goto out_rtnl; | ||
1353 | } | ||
1252 | 1354 | ||
1253 | dev = cfg80211_get_dev_from_ifindex(ifidx); | 1355 | dev = cfg80211_get_dev_from_ifindex(ifidx); |
1254 | if (IS_ERR(dev)) { | 1356 | if (IS_ERR(dev)) { |
1255 | err = PTR_ERR(dev); | 1357 | err = PTR_ERR(dev); |
1256 | goto out_put_netdev; | 1358 | goto out_rtnl; |
1257 | } | 1359 | } |
1258 | 1360 | ||
1259 | if (!dev->ops->dump_station) { | 1361 | if (!dev->ops->dump_station) { |
1260 | err = -ENOSYS; | 1362 | err = -EOPNOTSUPP; |
1261 | goto out_err; | 1363 | goto out_err; |
1262 | } | 1364 | } |
1263 | 1365 | ||
1264 | rtnl_lock(); | ||
1265 | |||
1266 | while (1) { | 1366 | while (1) { |
1267 | err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx, | 1367 | err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx, |
1268 | mac_addr, &sinfo); | 1368 | mac_addr, &sinfo); |
1269 | if (err == -ENOENT) | 1369 | if (err == -ENOENT) |
1270 | break; | 1370 | break; |
1271 | if (err) | 1371 | if (err) |
1272 | goto out_err_rtnl; | 1372 | goto out_err; |
1273 | 1373 | ||
1274 | if (nl80211_send_station(skb, | 1374 | if (nl80211_send_station(skb, |
1275 | NETLINK_CB(cb->skb).pid, | 1375 | NETLINK_CB(cb->skb).pid, |
@@ -1285,12 +1385,10 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
1285 | out: | 1385 | out: |
1286 | cb->args[1] = sta_idx; | 1386 | cb->args[1] = sta_idx; |
1287 | err = skb->len; | 1387 | err = skb->len; |
1288 | out_err_rtnl: | ||
1289 | rtnl_unlock(); | ||
1290 | out_err: | 1388 | out_err: |
1291 | cfg80211_put_dev(dev); | 1389 | cfg80211_put_dev(dev); |
1292 | out_put_netdev: | 1390 | out_rtnl: |
1293 | dev_put(netdev); | 1391 | rtnl_unlock(); |
1294 | 1392 | ||
1295 | return err; | 1393 | return err; |
1296 | } | 1394 | } |
@@ -1311,19 +1409,18 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
1311 | 1409 | ||
1312 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1410 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1313 | 1411 | ||
1412 | rtnl_lock(); | ||
1413 | |||
1314 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1414 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1315 | if (err) | 1415 | if (err) |
1316 | return err; | 1416 | goto out_rtnl; |
1317 | 1417 | ||
1318 | if (!drv->ops->get_station) { | 1418 | if (!drv->ops->get_station) { |
1319 | err = -EOPNOTSUPP; | 1419 | err = -EOPNOTSUPP; |
1320 | goto out; | 1420 | goto out; |
1321 | } | 1421 | } |
1322 | 1422 | ||
1323 | rtnl_lock(); | ||
1324 | err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo); | 1423 | err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo); |
1325 | rtnl_unlock(); | ||
1326 | |||
1327 | if (err) | 1424 | if (err) |
1328 | goto out; | 1425 | goto out; |
1329 | 1426 | ||
@@ -1340,10 +1437,12 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
1340 | 1437 | ||
1341 | out_free: | 1438 | out_free: |
1342 | nlmsg_free(msg); | 1439 | nlmsg_free(msg); |
1343 | |||
1344 | out: | 1440 | out: |
1345 | cfg80211_put_dev(drv); | 1441 | cfg80211_put_dev(drv); |
1346 | dev_put(dev); | 1442 | dev_put(dev); |
1443 | out_rtnl: | ||
1444 | rtnl_unlock(); | ||
1445 | |||
1347 | return err; | 1446 | return err; |
1348 | } | 1447 | } |
1349 | 1448 | ||
@@ -1411,9 +1510,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
1411 | params.plink_action = | 1510 | params.plink_action = |
1412 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 1511 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
1413 | 1512 | ||
1513 | rtnl_lock(); | ||
1514 | |||
1414 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1515 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1415 | if (err) | 1516 | if (err) |
1416 | return err; | 1517 | goto out_rtnl; |
1417 | 1518 | ||
1418 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); | 1519 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); |
1419 | if (err) | 1520 | if (err) |
@@ -1424,15 +1525,16 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
1424 | goto out; | 1525 | goto out; |
1425 | } | 1526 | } |
1426 | 1527 | ||
1427 | rtnl_lock(); | ||
1428 | err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, ¶ms); | 1528 | err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, ¶ms); |
1429 | rtnl_unlock(); | ||
1430 | 1529 | ||
1431 | out: | 1530 | out: |
1432 | if (params.vlan) | 1531 | if (params.vlan) |
1433 | dev_put(params.vlan); | 1532 | dev_put(params.vlan); |
1434 | cfg80211_put_dev(drv); | 1533 | cfg80211_put_dev(drv); |
1435 | dev_put(dev); | 1534 | dev_put(dev); |
1535 | out_rtnl: | ||
1536 | rtnl_unlock(); | ||
1537 | |||
1436 | return err; | 1538 | return err; |
1437 | } | 1539 | } |
1438 | 1540 | ||
@@ -1474,9 +1576,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
1474 | ¶ms.station_flags)) | 1576 | ¶ms.station_flags)) |
1475 | return -EINVAL; | 1577 | return -EINVAL; |
1476 | 1578 | ||
1579 | rtnl_lock(); | ||
1580 | |||
1477 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1581 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1478 | if (err) | 1582 | if (err) |
1479 | return err; | 1583 | goto out_rtnl; |
1480 | 1584 | ||
1481 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); | 1585 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); |
1482 | if (err) | 1586 | if (err) |
@@ -1487,15 +1591,21 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
1487 | goto out; | 1591 | goto out; |
1488 | } | 1592 | } |
1489 | 1593 | ||
1490 | rtnl_lock(); | 1594 | if (!netif_running(dev)) { |
1595 | err = -ENETDOWN; | ||
1596 | goto out; | ||
1597 | } | ||
1598 | |||
1491 | err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, ¶ms); | 1599 | err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, ¶ms); |
1492 | rtnl_unlock(); | ||
1493 | 1600 | ||
1494 | out: | 1601 | out: |
1495 | if (params.vlan) | 1602 | if (params.vlan) |
1496 | dev_put(params.vlan); | 1603 | dev_put(params.vlan); |
1497 | cfg80211_put_dev(drv); | 1604 | cfg80211_put_dev(drv); |
1498 | dev_put(dev); | 1605 | dev_put(dev); |
1606 | out_rtnl: | ||
1607 | rtnl_unlock(); | ||
1608 | |||
1499 | return err; | 1609 | return err; |
1500 | } | 1610 | } |
1501 | 1611 | ||
@@ -1509,22 +1619,25 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | |||
1509 | if (info->attrs[NL80211_ATTR_MAC]) | 1619 | if (info->attrs[NL80211_ATTR_MAC]) |
1510 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1620 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1511 | 1621 | ||
1622 | rtnl_lock(); | ||
1623 | |||
1512 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1624 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1513 | if (err) | 1625 | if (err) |
1514 | return err; | 1626 | goto out_rtnl; |
1515 | 1627 | ||
1516 | if (!drv->ops->del_station) { | 1628 | if (!drv->ops->del_station) { |
1517 | err = -EOPNOTSUPP; | 1629 | err = -EOPNOTSUPP; |
1518 | goto out; | 1630 | goto out; |
1519 | } | 1631 | } |
1520 | 1632 | ||
1521 | rtnl_lock(); | ||
1522 | err = drv->ops->del_station(&drv->wiphy, dev, mac_addr); | 1633 | err = drv->ops->del_station(&drv->wiphy, dev, mac_addr); |
1523 | rtnl_unlock(); | ||
1524 | 1634 | ||
1525 | out: | 1635 | out: |
1526 | cfg80211_put_dev(drv); | 1636 | cfg80211_put_dev(drv); |
1527 | dev_put(dev); | 1637 | dev_put(dev); |
1638 | out_rtnl: | ||
1639 | rtnl_unlock(); | ||
1640 | |||
1528 | return err; | 1641 | return err; |
1529 | } | 1642 | } |
1530 | 1643 | ||
@@ -1605,22 +1718,29 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
1605 | return -EINVAL; | 1718 | return -EINVAL; |
1606 | } | 1719 | } |
1607 | 1720 | ||
1608 | netdev = dev_get_by_index(&init_net, ifidx); | 1721 | rtnl_lock(); |
1609 | if (!netdev) | 1722 | |
1610 | return -ENODEV; | 1723 | netdev = __dev_get_by_index(&init_net, ifidx); |
1724 | if (!netdev) { | ||
1725 | err = -ENODEV; | ||
1726 | goto out_rtnl; | ||
1727 | } | ||
1611 | 1728 | ||
1612 | dev = cfg80211_get_dev_from_ifindex(ifidx); | 1729 | dev = cfg80211_get_dev_from_ifindex(ifidx); |
1613 | if (IS_ERR(dev)) { | 1730 | if (IS_ERR(dev)) { |
1614 | err = PTR_ERR(dev); | 1731 | err = PTR_ERR(dev); |
1615 | goto out_put_netdev; | 1732 | goto out_rtnl; |
1616 | } | 1733 | } |
1617 | 1734 | ||
1618 | if (!dev->ops->dump_mpath) { | 1735 | if (!dev->ops->dump_mpath) { |
1619 | err = -ENOSYS; | 1736 | err = -EOPNOTSUPP; |
1620 | goto out_err; | 1737 | goto out_err; |
1621 | } | 1738 | } |
1622 | 1739 | ||
1623 | rtnl_lock(); | 1740 | if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { |
1741 | err = -EOPNOTSUPP; | ||
1742 | goto out; | ||
1743 | } | ||
1624 | 1744 | ||
1625 | while (1) { | 1745 | while (1) { |
1626 | err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx, | 1746 | err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx, |
@@ -1628,7 +1748,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
1628 | if (err == -ENOENT) | 1748 | if (err == -ENOENT) |
1629 | break; | 1749 | break; |
1630 | if (err) | 1750 | if (err) |
1631 | goto out_err_rtnl; | 1751 | goto out_err; |
1632 | 1752 | ||
1633 | if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid, | 1753 | if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid, |
1634 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 1754 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
@@ -1643,12 +1763,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
1643 | out: | 1763 | out: |
1644 | cb->args[1] = path_idx; | 1764 | cb->args[1] = path_idx; |
1645 | err = skb->len; | 1765 | err = skb->len; |
1646 | out_err_rtnl: | ||
1647 | rtnl_unlock(); | ||
1648 | out_err: | 1766 | out_err: |
1649 | cfg80211_put_dev(dev); | 1767 | cfg80211_put_dev(dev); |
1650 | out_put_netdev: | 1768 | out_rtnl: |
1651 | dev_put(netdev); | 1769 | rtnl_unlock(); |
1652 | 1770 | ||
1653 | return err; | 1771 | return err; |
1654 | } | 1772 | } |
@@ -1670,19 +1788,23 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | |||
1670 | 1788 | ||
1671 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1789 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1672 | 1790 | ||
1791 | rtnl_lock(); | ||
1792 | |||
1673 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1793 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1674 | if (err) | 1794 | if (err) |
1675 | return err; | 1795 | goto out_rtnl; |
1676 | 1796 | ||
1677 | if (!drv->ops->get_mpath) { | 1797 | if (!drv->ops->get_mpath) { |
1678 | err = -EOPNOTSUPP; | 1798 | err = -EOPNOTSUPP; |
1679 | goto out; | 1799 | goto out; |
1680 | } | 1800 | } |
1681 | 1801 | ||
1682 | rtnl_lock(); | 1802 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { |
1683 | err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo); | 1803 | err = -EOPNOTSUPP; |
1684 | rtnl_unlock(); | 1804 | goto out; |
1805 | } | ||
1685 | 1806 | ||
1807 | err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo); | ||
1686 | if (err) | 1808 | if (err) |
1687 | goto out; | 1809 | goto out; |
1688 | 1810 | ||
@@ -1699,10 +1821,12 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | |||
1699 | 1821 | ||
1700 | out_free: | 1822 | out_free: |
1701 | nlmsg_free(msg); | 1823 | nlmsg_free(msg); |
1702 | |||
1703 | out: | 1824 | out: |
1704 | cfg80211_put_dev(drv); | 1825 | cfg80211_put_dev(drv); |
1705 | dev_put(dev); | 1826 | dev_put(dev); |
1827 | out_rtnl: | ||
1828 | rtnl_unlock(); | ||
1829 | |||
1706 | return err; | 1830 | return err; |
1707 | } | 1831 | } |
1708 | 1832 | ||
@@ -1723,22 +1847,35 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | |||
1723 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1847 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1724 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 1848 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
1725 | 1849 | ||
1850 | rtnl_lock(); | ||
1851 | |||
1726 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1852 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1727 | if (err) | 1853 | if (err) |
1728 | return err; | 1854 | goto out_rtnl; |
1729 | 1855 | ||
1730 | if (!drv->ops->change_mpath) { | 1856 | if (!drv->ops->change_mpath) { |
1731 | err = -EOPNOTSUPP; | 1857 | err = -EOPNOTSUPP; |
1732 | goto out; | 1858 | goto out; |
1733 | } | 1859 | } |
1734 | 1860 | ||
1735 | rtnl_lock(); | 1861 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { |
1862 | err = -EOPNOTSUPP; | ||
1863 | goto out; | ||
1864 | } | ||
1865 | |||
1866 | if (!netif_running(dev)) { | ||
1867 | err = -ENETDOWN; | ||
1868 | goto out; | ||
1869 | } | ||
1870 | |||
1736 | err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop); | 1871 | err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop); |
1737 | rtnl_unlock(); | ||
1738 | 1872 | ||
1739 | out: | 1873 | out: |
1740 | cfg80211_put_dev(drv); | 1874 | cfg80211_put_dev(drv); |
1741 | dev_put(dev); | 1875 | dev_put(dev); |
1876 | out_rtnl: | ||
1877 | rtnl_unlock(); | ||
1878 | |||
1742 | return err; | 1879 | return err; |
1743 | } | 1880 | } |
1744 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | 1881 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) |
@@ -1758,22 +1895,35 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | |||
1758 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1895 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1759 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 1896 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
1760 | 1897 | ||
1898 | rtnl_lock(); | ||
1899 | |||
1761 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1900 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1762 | if (err) | 1901 | if (err) |
1763 | return err; | 1902 | goto out_rtnl; |
1764 | 1903 | ||
1765 | if (!drv->ops->add_mpath) { | 1904 | if (!drv->ops->add_mpath) { |
1766 | err = -EOPNOTSUPP; | 1905 | err = -EOPNOTSUPP; |
1767 | goto out; | 1906 | goto out; |
1768 | } | 1907 | } |
1769 | 1908 | ||
1770 | rtnl_lock(); | 1909 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { |
1910 | err = -EOPNOTSUPP; | ||
1911 | goto out; | ||
1912 | } | ||
1913 | |||
1914 | if (!netif_running(dev)) { | ||
1915 | err = -ENETDOWN; | ||
1916 | goto out; | ||
1917 | } | ||
1918 | |||
1771 | err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop); | 1919 | err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop); |
1772 | rtnl_unlock(); | ||
1773 | 1920 | ||
1774 | out: | 1921 | out: |
1775 | cfg80211_put_dev(drv); | 1922 | cfg80211_put_dev(drv); |
1776 | dev_put(dev); | 1923 | dev_put(dev); |
1924 | out_rtnl: | ||
1925 | rtnl_unlock(); | ||
1926 | |||
1777 | return err; | 1927 | return err; |
1778 | } | 1928 | } |
1779 | 1929 | ||
@@ -1787,22 +1937,25 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) | |||
1787 | if (info->attrs[NL80211_ATTR_MAC]) | 1937 | if (info->attrs[NL80211_ATTR_MAC]) |
1788 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1938 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1789 | 1939 | ||
1940 | rtnl_lock(); | ||
1941 | |||
1790 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1942 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1791 | if (err) | 1943 | if (err) |
1792 | return err; | 1944 | goto out_rtnl; |
1793 | 1945 | ||
1794 | if (!drv->ops->del_mpath) { | 1946 | if (!drv->ops->del_mpath) { |
1795 | err = -EOPNOTSUPP; | 1947 | err = -EOPNOTSUPP; |
1796 | goto out; | 1948 | goto out; |
1797 | } | 1949 | } |
1798 | 1950 | ||
1799 | rtnl_lock(); | ||
1800 | err = drv->ops->del_mpath(&drv->wiphy, dev, dst); | 1951 | err = drv->ops->del_mpath(&drv->wiphy, dev, dst); |
1801 | rtnl_unlock(); | ||
1802 | 1952 | ||
1803 | out: | 1953 | out: |
1804 | cfg80211_put_dev(drv); | 1954 | cfg80211_put_dev(drv); |
1805 | dev_put(dev); | 1955 | dev_put(dev); |
1956 | out_rtnl: | ||
1957 | rtnl_unlock(); | ||
1958 | |||
1806 | return err; | 1959 | return err; |
1807 | } | 1960 | } |
1808 | 1961 | ||
@@ -1835,22 +1988,30 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
1835 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | 1988 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); |
1836 | } | 1989 | } |
1837 | 1990 | ||
1991 | rtnl_lock(); | ||
1992 | |||
1838 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1993 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1839 | if (err) | 1994 | if (err) |
1840 | return err; | 1995 | goto out_rtnl; |
1841 | 1996 | ||
1842 | if (!drv->ops->change_bss) { | 1997 | if (!drv->ops->change_bss) { |
1843 | err = -EOPNOTSUPP; | 1998 | err = -EOPNOTSUPP; |
1844 | goto out; | 1999 | goto out; |
1845 | } | 2000 | } |
1846 | 2001 | ||
1847 | rtnl_lock(); | 2002 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { |
2003 | err = -EOPNOTSUPP; | ||
2004 | goto out; | ||
2005 | } | ||
2006 | |||
1848 | err = drv->ops->change_bss(&drv->wiphy, dev, ¶ms); | 2007 | err = drv->ops->change_bss(&drv->wiphy, dev, ¶ms); |
1849 | rtnl_unlock(); | ||
1850 | 2008 | ||
1851 | out: | 2009 | out: |
1852 | cfg80211_put_dev(drv); | 2010 | cfg80211_put_dev(drv); |
1853 | dev_put(dev); | 2011 | dev_put(dev); |
2012 | out_rtnl: | ||
2013 | rtnl_unlock(); | ||
2014 | |||
1854 | return err; | 2015 | return err; |
1855 | } | 2016 | } |
1856 | 2017 | ||
@@ -1945,10 +2106,12 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
1945 | struct nlattr *pinfoattr; | 2106 | struct nlattr *pinfoattr; |
1946 | struct sk_buff *msg; | 2107 | struct sk_buff *msg; |
1947 | 2108 | ||
2109 | rtnl_lock(); | ||
2110 | |||
1948 | /* Look up our device */ | 2111 | /* Look up our device */ |
1949 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 2112 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1950 | if (err) | 2113 | if (err) |
1951 | return err; | 2114 | goto out_rtnl; |
1952 | 2115 | ||
1953 | if (!drv->ops->get_mesh_params) { | 2116 | if (!drv->ops->get_mesh_params) { |
1954 | err = -EOPNOTSUPP; | 2117 | err = -EOPNOTSUPP; |
@@ -1956,9 +2119,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
1956 | } | 2119 | } |
1957 | 2120 | ||
1958 | /* Get the mesh params */ | 2121 | /* Get the mesh params */ |
1959 | rtnl_lock(); | ||
1960 | err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params); | 2122 | err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params); |
1961 | rtnl_unlock(); | ||
1962 | if (err) | 2123 | if (err) |
1963 | goto out; | 2124 | goto out; |
1964 | 2125 | ||
@@ -2007,13 +2168,16 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2007 | err = genlmsg_unicast(msg, info->snd_pid); | 2168 | err = genlmsg_unicast(msg, info->snd_pid); |
2008 | goto out; | 2169 | goto out; |
2009 | 2170 | ||
2010 | nla_put_failure: | 2171 | nla_put_failure: |
2011 | genlmsg_cancel(msg, hdr); | 2172 | genlmsg_cancel(msg, hdr); |
2012 | err = -EMSGSIZE; | 2173 | err = -EMSGSIZE; |
2013 | out: | 2174 | out: |
2014 | /* Cleanup */ | 2175 | /* Cleanup */ |
2015 | cfg80211_put_dev(drv); | 2176 | cfg80211_put_dev(drv); |
2016 | dev_put(dev); | 2177 | dev_put(dev); |
2178 | out_rtnl: | ||
2179 | rtnl_unlock(); | ||
2180 | |||
2017 | return err; | 2181 | return err; |
2018 | } | 2182 | } |
2019 | 2183 | ||
@@ -2060,9 +2224,11 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2060 | parent_attr, nl80211_meshconf_params_policy)) | 2224 | parent_attr, nl80211_meshconf_params_policy)) |
2061 | return -EINVAL; | 2225 | return -EINVAL; |
2062 | 2226 | ||
2227 | rtnl_lock(); | ||
2228 | |||
2063 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 2229 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
2064 | if (err) | 2230 | if (err) |
2065 | return err; | 2231 | goto out_rtnl; |
2066 | 2232 | ||
2067 | if (!drv->ops->set_mesh_params) { | 2233 | if (!drv->ops->set_mesh_params) { |
2068 | err = -EOPNOTSUPP; | 2234 | err = -EOPNOTSUPP; |
@@ -2109,14 +2275,15 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2109 | nla_get_u16); | 2275 | nla_get_u16); |
2110 | 2276 | ||
2111 | /* Apply changes */ | 2277 | /* Apply changes */ |
2112 | rtnl_lock(); | ||
2113 | err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask); | 2278 | err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask); |
2114 | rtnl_unlock(); | ||
2115 | 2279 | ||
2116 | out: | 2280 | out: |
2117 | /* cleanup */ | 2281 | /* cleanup */ |
2118 | cfg80211_put_dev(drv); | 2282 | cfg80211_put_dev(drv); |
2119 | dev_put(dev); | 2283 | dev_put(dev); |
2284 | out_rtnl: | ||
2285 | rtnl_unlock(); | ||
2286 | |||
2120 | return err; | 2287 | return err; |
2121 | } | 2288 | } |
2122 | 2289 | ||
@@ -2262,43 +2429,6 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2262 | return -EINVAL; | 2429 | return -EINVAL; |
2263 | } | 2430 | } |
2264 | 2431 | ||
2265 | static int nl80211_set_mgmt_extra_ie(struct sk_buff *skb, | ||
2266 | struct genl_info *info) | ||
2267 | { | ||
2268 | struct cfg80211_registered_device *drv; | ||
2269 | int err; | ||
2270 | struct net_device *dev; | ||
2271 | struct mgmt_extra_ie_params params; | ||
2272 | |||
2273 | memset(¶ms, 0, sizeof(params)); | ||
2274 | |||
2275 | if (!info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) | ||
2276 | return -EINVAL; | ||
2277 | params.subtype = nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]); | ||
2278 | if (params.subtype > 15) | ||
2279 | return -EINVAL; /* FC Subtype field is 4 bits (0..15) */ | ||
2280 | |||
2281 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2282 | params.ies = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2283 | params.ies_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2284 | } | ||
2285 | |||
2286 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2287 | if (err) | ||
2288 | return err; | ||
2289 | |||
2290 | if (drv->ops->set_mgmt_extra_ie) { | ||
2291 | rtnl_lock(); | ||
2292 | err = drv->ops->set_mgmt_extra_ie(&drv->wiphy, dev, ¶ms); | ||
2293 | rtnl_unlock(); | ||
2294 | } else | ||
2295 | err = -EOPNOTSUPP; | ||
2296 | |||
2297 | cfg80211_put_dev(drv); | ||
2298 | dev_put(dev); | ||
2299 | return err; | ||
2300 | } | ||
2301 | |||
2302 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | 2432 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) |
2303 | { | 2433 | { |
2304 | struct cfg80211_registered_device *drv; | 2434 | struct cfg80211_registered_device *drv; |
@@ -2312,9 +2442,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2312 | enum ieee80211_band band; | 2442 | enum ieee80211_band band; |
2313 | size_t ie_len; | 2443 | size_t ie_len; |
2314 | 2444 | ||
2445 | rtnl_lock(); | ||
2446 | |||
2315 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 2447 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
2316 | if (err) | 2448 | if (err) |
2317 | return err; | 2449 | goto out_rtnl; |
2318 | 2450 | ||
2319 | wiphy = &drv->wiphy; | 2451 | wiphy = &drv->wiphy; |
2320 | 2452 | ||
@@ -2323,11 +2455,14 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2323 | goto out; | 2455 | goto out; |
2324 | } | 2456 | } |
2325 | 2457 | ||
2326 | rtnl_lock(); | 2458 | if (!netif_running(dev)) { |
2459 | err = -ENETDOWN; | ||
2460 | goto out; | ||
2461 | } | ||
2327 | 2462 | ||
2328 | if (drv->scan_req) { | 2463 | if (drv->scan_req) { |
2329 | err = -EBUSY; | 2464 | err = -EBUSY; |
2330 | goto out_unlock; | 2465 | goto out; |
2331 | } | 2466 | } |
2332 | 2467 | ||
2333 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | 2468 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { |
@@ -2335,7 +2470,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2335 | n_channels++; | 2470 | n_channels++; |
2336 | if (!n_channels) { | 2471 | if (!n_channels) { |
2337 | err = -EINVAL; | 2472 | err = -EINVAL; |
2338 | goto out_unlock; | 2473 | goto out; |
2339 | } | 2474 | } |
2340 | } else { | 2475 | } else { |
2341 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | 2476 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) |
@@ -2349,7 +2484,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2349 | 2484 | ||
2350 | if (n_ssids > wiphy->max_scan_ssids) { | 2485 | if (n_ssids > wiphy->max_scan_ssids) { |
2351 | err = -EINVAL; | 2486 | err = -EINVAL; |
2352 | goto out_unlock; | 2487 | goto out; |
2353 | } | 2488 | } |
2354 | 2489 | ||
2355 | if (info->attrs[NL80211_ATTR_IE]) | 2490 | if (info->attrs[NL80211_ATTR_IE]) |
@@ -2363,7 +2498,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2363 | + ie_len, GFP_KERNEL); | 2498 | + ie_len, GFP_KERNEL); |
2364 | if (!request) { | 2499 | if (!request) { |
2365 | err = -ENOMEM; | 2500 | err = -ENOMEM; |
2366 | goto out_unlock; | 2501 | goto out; |
2367 | } | 2502 | } |
2368 | 2503 | ||
2369 | request->channels = (void *)((char *)request + sizeof(*request)); | 2504 | request->channels = (void *)((char *)request + sizeof(*request)); |
@@ -2434,11 +2569,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2434 | drv->scan_req = NULL; | 2569 | drv->scan_req = NULL; |
2435 | kfree(request); | 2570 | kfree(request); |
2436 | } | 2571 | } |
2437 | out_unlock: | ||
2438 | rtnl_unlock(); | ||
2439 | out: | 2572 | out: |
2440 | cfg80211_put_dev(drv); | 2573 | cfg80211_put_dev(drv); |
2441 | dev_put(dev); | 2574 | dev_put(dev); |
2575 | out_rtnl: | ||
2576 | rtnl_unlock(); | ||
2577 | |||
2442 | return err; | 2578 | return err; |
2443 | } | 2579 | } |
2444 | 2580 | ||
@@ -2558,6 +2694,288 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
2558 | return err; | 2694 | return err; |
2559 | } | 2695 | } |
2560 | 2696 | ||
2697 | static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) | ||
2698 | { | ||
2699 | return auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM || | ||
2700 | auth_type == NL80211_AUTHTYPE_SHARED_KEY || | ||
2701 | auth_type == NL80211_AUTHTYPE_FT || | ||
2702 | auth_type == NL80211_AUTHTYPE_NETWORK_EAP; | ||
2703 | } | ||
2704 | |||
2705 | static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | ||
2706 | { | ||
2707 | struct cfg80211_registered_device *drv; | ||
2708 | struct net_device *dev; | ||
2709 | struct cfg80211_auth_request req; | ||
2710 | struct wiphy *wiphy; | ||
2711 | int err; | ||
2712 | |||
2713 | rtnl_lock(); | ||
2714 | |||
2715 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2716 | if (err) | ||
2717 | goto unlock_rtnl; | ||
2718 | |||
2719 | if (!drv->ops->auth) { | ||
2720 | err = -EOPNOTSUPP; | ||
2721 | goto out; | ||
2722 | } | ||
2723 | |||
2724 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
2725 | err = -EOPNOTSUPP; | ||
2726 | goto out; | ||
2727 | } | ||
2728 | |||
2729 | if (!netif_running(dev)) { | ||
2730 | err = -ENETDOWN; | ||
2731 | goto out; | ||
2732 | } | ||
2733 | |||
2734 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2735 | err = -EINVAL; | ||
2736 | goto out; | ||
2737 | } | ||
2738 | |||
2739 | wiphy = &drv->wiphy; | ||
2740 | memset(&req, 0, sizeof(req)); | ||
2741 | |||
2742 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
2743 | |||
2744 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
2745 | req.chan = ieee80211_get_channel( | ||
2746 | wiphy, | ||
2747 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | ||
2748 | if (!req.chan) { | ||
2749 | err = -EINVAL; | ||
2750 | goto out; | ||
2751 | } | ||
2752 | } | ||
2753 | |||
2754 | if (info->attrs[NL80211_ATTR_SSID]) { | ||
2755 | req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | ||
2756 | req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | ||
2757 | } | ||
2758 | |||
2759 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2760 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2761 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2762 | } | ||
2763 | |||
2764 | if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { | ||
2765 | req.auth_type = | ||
2766 | nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); | ||
2767 | if (!nl80211_valid_auth_type(req.auth_type)) { | ||
2768 | err = -EINVAL; | ||
2769 | goto out; | ||
2770 | } | ||
2771 | } | ||
2772 | |||
2773 | err = drv->ops->auth(&drv->wiphy, dev, &req); | ||
2774 | |||
2775 | out: | ||
2776 | cfg80211_put_dev(drv); | ||
2777 | dev_put(dev); | ||
2778 | unlock_rtnl: | ||
2779 | rtnl_unlock(); | ||
2780 | return err; | ||
2781 | } | ||
2782 | |||
2783 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | ||
2784 | { | ||
2785 | struct cfg80211_registered_device *drv; | ||
2786 | struct net_device *dev; | ||
2787 | struct cfg80211_assoc_request req; | ||
2788 | struct wiphy *wiphy; | ||
2789 | int err; | ||
2790 | |||
2791 | rtnl_lock(); | ||
2792 | |||
2793 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2794 | if (err) | ||
2795 | goto unlock_rtnl; | ||
2796 | |||
2797 | if (!drv->ops->assoc) { | ||
2798 | err = -EOPNOTSUPP; | ||
2799 | goto out; | ||
2800 | } | ||
2801 | |||
2802 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
2803 | err = -EOPNOTSUPP; | ||
2804 | goto out; | ||
2805 | } | ||
2806 | |||
2807 | if (!netif_running(dev)) { | ||
2808 | err = -ENETDOWN; | ||
2809 | goto out; | ||
2810 | } | ||
2811 | |||
2812 | if (!info->attrs[NL80211_ATTR_MAC] || | ||
2813 | !info->attrs[NL80211_ATTR_SSID]) { | ||
2814 | err = -EINVAL; | ||
2815 | goto out; | ||
2816 | } | ||
2817 | |||
2818 | wiphy = &drv->wiphy; | ||
2819 | memset(&req, 0, sizeof(req)); | ||
2820 | |||
2821 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
2822 | |||
2823 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
2824 | req.chan = ieee80211_get_channel( | ||
2825 | wiphy, | ||
2826 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | ||
2827 | if (!req.chan) { | ||
2828 | err = -EINVAL; | ||
2829 | goto out; | ||
2830 | } | ||
2831 | } | ||
2832 | |||
2833 | req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | ||
2834 | req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | ||
2835 | |||
2836 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2837 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2838 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2839 | } | ||
2840 | |||
2841 | err = drv->ops->assoc(&drv->wiphy, dev, &req); | ||
2842 | |||
2843 | out: | ||
2844 | cfg80211_put_dev(drv); | ||
2845 | dev_put(dev); | ||
2846 | unlock_rtnl: | ||
2847 | rtnl_unlock(); | ||
2848 | return err; | ||
2849 | } | ||
2850 | |||
2851 | static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | ||
2852 | { | ||
2853 | struct cfg80211_registered_device *drv; | ||
2854 | struct net_device *dev; | ||
2855 | struct cfg80211_deauth_request req; | ||
2856 | struct wiphy *wiphy; | ||
2857 | int err; | ||
2858 | |||
2859 | rtnl_lock(); | ||
2860 | |||
2861 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2862 | if (err) | ||
2863 | goto unlock_rtnl; | ||
2864 | |||
2865 | if (!drv->ops->deauth) { | ||
2866 | err = -EOPNOTSUPP; | ||
2867 | goto out; | ||
2868 | } | ||
2869 | |||
2870 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
2871 | err = -EOPNOTSUPP; | ||
2872 | goto out; | ||
2873 | } | ||
2874 | |||
2875 | if (!netif_running(dev)) { | ||
2876 | err = -ENETDOWN; | ||
2877 | goto out; | ||
2878 | } | ||
2879 | |||
2880 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2881 | err = -EINVAL; | ||
2882 | goto out; | ||
2883 | } | ||
2884 | |||
2885 | wiphy = &drv->wiphy; | ||
2886 | memset(&req, 0, sizeof(req)); | ||
2887 | |||
2888 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
2889 | |||
2890 | if (info->attrs[NL80211_ATTR_REASON_CODE]) { | ||
2891 | req.reason_code = | ||
2892 | nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | ||
2893 | if (req.reason_code == 0) { | ||
2894 | /* Reason Code 0 is reserved */ | ||
2895 | err = -EINVAL; | ||
2896 | goto out; | ||
2897 | } | ||
2898 | } | ||
2899 | |||
2900 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2901 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2902 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2903 | } | ||
2904 | |||
2905 | err = drv->ops->deauth(&drv->wiphy, dev, &req); | ||
2906 | |||
2907 | out: | ||
2908 | cfg80211_put_dev(drv); | ||
2909 | dev_put(dev); | ||
2910 | unlock_rtnl: | ||
2911 | rtnl_unlock(); | ||
2912 | return err; | ||
2913 | } | ||
2914 | |||
2915 | static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | ||
2916 | { | ||
2917 | struct cfg80211_registered_device *drv; | ||
2918 | struct net_device *dev; | ||
2919 | struct cfg80211_disassoc_request req; | ||
2920 | struct wiphy *wiphy; | ||
2921 | int err; | ||
2922 | |||
2923 | rtnl_lock(); | ||
2924 | |||
2925 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2926 | if (err) | ||
2927 | goto unlock_rtnl; | ||
2928 | |||
2929 | if (!drv->ops->disassoc) { | ||
2930 | err = -EOPNOTSUPP; | ||
2931 | goto out; | ||
2932 | } | ||
2933 | |||
2934 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
2935 | err = -EOPNOTSUPP; | ||
2936 | goto out; | ||
2937 | } | ||
2938 | |||
2939 | if (!netif_running(dev)) { | ||
2940 | err = -ENETDOWN; | ||
2941 | goto out; | ||
2942 | } | ||
2943 | |||
2944 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2945 | err = -EINVAL; | ||
2946 | goto out; | ||
2947 | } | ||
2948 | |||
2949 | wiphy = &drv->wiphy; | ||
2950 | memset(&req, 0, sizeof(req)); | ||
2951 | |||
2952 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
2953 | |||
2954 | if (info->attrs[NL80211_ATTR_REASON_CODE]) { | ||
2955 | req.reason_code = | ||
2956 | nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | ||
2957 | if (req.reason_code == 0) { | ||
2958 | /* Reason Code 0 is reserved */ | ||
2959 | err = -EINVAL; | ||
2960 | goto out; | ||
2961 | } | ||
2962 | } | ||
2963 | |||
2964 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2965 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2966 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2967 | } | ||
2968 | |||
2969 | err = drv->ops->disassoc(&drv->wiphy, dev, &req); | ||
2970 | |||
2971 | out: | ||
2972 | cfg80211_put_dev(drv); | ||
2973 | dev_put(dev); | ||
2974 | unlock_rtnl: | ||
2975 | rtnl_unlock(); | ||
2976 | return err; | ||
2977 | } | ||
2978 | |||
2561 | static struct genl_ops nl80211_ops[] = { | 2979 | static struct genl_ops nl80211_ops[] = { |
2562 | { | 2980 | { |
2563 | .cmd = NL80211_CMD_GET_WIPHY, | 2981 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -2725,12 +3143,6 @@ static struct genl_ops nl80211_ops[] = { | |||
2725 | .flags = GENL_ADMIN_PERM, | 3143 | .flags = GENL_ADMIN_PERM, |
2726 | }, | 3144 | }, |
2727 | { | 3145 | { |
2728 | .cmd = NL80211_CMD_SET_MGMT_EXTRA_IE, | ||
2729 | .doit = nl80211_set_mgmt_extra_ie, | ||
2730 | .policy = nl80211_policy, | ||
2731 | .flags = GENL_ADMIN_PERM, | ||
2732 | }, | ||
2733 | { | ||
2734 | .cmd = NL80211_CMD_TRIGGER_SCAN, | 3146 | .cmd = NL80211_CMD_TRIGGER_SCAN, |
2735 | .doit = nl80211_trigger_scan, | 3147 | .doit = nl80211_trigger_scan, |
2736 | .policy = nl80211_policy, | 3148 | .policy = nl80211_policy, |
@@ -2741,6 +3153,33 @@ static struct genl_ops nl80211_ops[] = { | |||
2741 | .policy = nl80211_policy, | 3153 | .policy = nl80211_policy, |
2742 | .dumpit = nl80211_dump_scan, | 3154 | .dumpit = nl80211_dump_scan, |
2743 | }, | 3155 | }, |
3156 | { | ||
3157 | .cmd = NL80211_CMD_AUTHENTICATE, | ||
3158 | .doit = nl80211_authenticate, | ||
3159 | .policy = nl80211_policy, | ||
3160 | .flags = GENL_ADMIN_PERM, | ||
3161 | }, | ||
3162 | { | ||
3163 | .cmd = NL80211_CMD_ASSOCIATE, | ||
3164 | .doit = nl80211_associate, | ||
3165 | .policy = nl80211_policy, | ||
3166 | .flags = GENL_ADMIN_PERM, | ||
3167 | }, | ||
3168 | { | ||
3169 | .cmd = NL80211_CMD_DEAUTHENTICATE, | ||
3170 | .doit = nl80211_deauthenticate, | ||
3171 | .policy = nl80211_policy, | ||
3172 | .flags = GENL_ADMIN_PERM, | ||
3173 | }, | ||
3174 | { | ||
3175 | .cmd = NL80211_CMD_DISASSOCIATE, | ||
3176 | .doit = nl80211_disassociate, | ||
3177 | .policy = nl80211_policy, | ||
3178 | .flags = GENL_ADMIN_PERM, | ||
3179 | }, | ||
3180 | }; | ||
3181 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | ||
3182 | .name = "mlme", | ||
2744 | }; | 3183 | }; |
2745 | 3184 | ||
2746 | /* multicast groups */ | 3185 | /* multicast groups */ |
@@ -2887,6 +3326,71 @@ nla_put_failure: | |||
2887 | nlmsg_free(msg); | 3326 | nlmsg_free(msg); |
2888 | } | 3327 | } |
2889 | 3328 | ||
3329 | static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, | ||
3330 | struct net_device *netdev, | ||
3331 | const u8 *buf, size_t len, | ||
3332 | enum nl80211_commands cmd) | ||
3333 | { | ||
3334 | struct sk_buff *msg; | ||
3335 | void *hdr; | ||
3336 | |||
3337 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
3338 | if (!msg) | ||
3339 | return; | ||
3340 | |||
3341 | hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); | ||
3342 | if (!hdr) { | ||
3343 | nlmsg_free(msg); | ||
3344 | return; | ||
3345 | } | ||
3346 | |||
3347 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
3348 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
3349 | NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); | ||
3350 | |||
3351 | if (genlmsg_end(msg, hdr) < 0) { | ||
3352 | nlmsg_free(msg); | ||
3353 | return; | ||
3354 | } | ||
3355 | |||
3356 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); | ||
3357 | return; | ||
3358 | |||
3359 | nla_put_failure: | ||
3360 | genlmsg_cancel(msg, hdr); | ||
3361 | nlmsg_free(msg); | ||
3362 | } | ||
3363 | |||
3364 | void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, | ||
3365 | struct net_device *netdev, const u8 *buf, size_t len) | ||
3366 | { | ||
3367 | nl80211_send_mlme_event(rdev, netdev, buf, len, | ||
3368 | NL80211_CMD_AUTHENTICATE); | ||
3369 | } | ||
3370 | |||
3371 | void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, | ||
3372 | struct net_device *netdev, const u8 *buf, | ||
3373 | size_t len) | ||
3374 | { | ||
3375 | nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE); | ||
3376 | } | ||
3377 | |||
3378 | void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev, | ||
3379 | struct net_device *netdev, const u8 *buf, | ||
3380 | size_t len) | ||
3381 | { | ||
3382 | nl80211_send_mlme_event(rdev, netdev, buf, len, | ||
3383 | NL80211_CMD_DEAUTHENTICATE); | ||
3384 | } | ||
3385 | |||
3386 | void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev, | ||
3387 | struct net_device *netdev, const u8 *buf, | ||
3388 | size_t len) | ||
3389 | { | ||
3390 | nl80211_send_mlme_event(rdev, netdev, buf, len, | ||
3391 | NL80211_CMD_DISASSOCIATE); | ||
3392 | } | ||
3393 | |||
2890 | /* initialisation/exit functions */ | 3394 | /* initialisation/exit functions */ |
2891 | 3395 | ||
2892 | int nl80211_init(void) | 3396 | int nl80211_init(void) |
@@ -2915,6 +3419,10 @@ int nl80211_init(void) | |||
2915 | if (err) | 3419 | if (err) |
2916 | goto err_out; | 3420 | goto err_out; |
2917 | 3421 | ||
3422 | err = genl_register_mc_group(&nl80211_fam, &nl80211_mlme_mcgrp); | ||
3423 | if (err) | ||
3424 | goto err_out; | ||
3425 | |||
2918 | return 0; | 3426 | return 0; |
2919 | err_out: | 3427 | err_out: |
2920 | genl_unregister_family(&nl80211_fam); | 3428 | genl_unregister_family(&nl80211_fam); |