aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c334
1 files changed, 289 insertions, 45 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 030cf153bea2..db71150b8040 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -150,6 +150,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
150 .len = IEEE80211_MAX_DATA_LEN }, 150 .len = IEEE80211_MAX_DATA_LEN },
151 [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, }, 151 [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
152 [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 }, 152 [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 },
153 [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
154 [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
155 [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
153}; 156};
154 157
155/* policy for the attributes */ 158/* policy for the attributes */
@@ -586,6 +589,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
586 i++; 589 i++;
587 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); 590 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
588 } 591 }
592 CMD(set_channel, SET_CHANNEL);
589 593
590#undef CMD 594#undef CMD
591 595
@@ -686,10 +690,90 @@ static int parse_txq_params(struct nlattr *tb[],
686 return 0; 690 return 0;
687} 691}
688 692
693static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
694{
695 /*
696 * You can only set the channel explicitly for AP, mesh
697 * and WDS type interfaces; all others have their channel
698 * managed via their respective "establish a connection"
699 * command (connect, join, ...)
700 *
701 * Monitors are special as they are normally slaved to
702 * whatever else is going on, so they behave as though
703 * you tried setting the wiphy channel itself.
704 */
705 return !wdev ||
706 wdev->iftype == NL80211_IFTYPE_AP ||
707 wdev->iftype == NL80211_IFTYPE_WDS ||
708 wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
709 wdev->iftype == NL80211_IFTYPE_MONITOR;
710}
711
712static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
713 struct wireless_dev *wdev,
714 struct genl_info *info)
715{
716 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
717 u32 freq;
718 int result;
719
720 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
721 return -EINVAL;
722
723 if (!nl80211_can_set_dev_channel(wdev))
724 return -EOPNOTSUPP;
725
726 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
727 channel_type = nla_get_u32(info->attrs[
728 NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
729 if (channel_type != NL80211_CHAN_NO_HT &&
730 channel_type != NL80211_CHAN_HT20 &&
731 channel_type != NL80211_CHAN_HT40PLUS &&
732 channel_type != NL80211_CHAN_HT40MINUS)
733 return -EINVAL;
734 }
735
736 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
737
738 mutex_lock(&rdev->devlist_mtx);
739 if (wdev) {
740 wdev_lock(wdev);
741 result = cfg80211_set_freq(rdev, wdev, freq, channel_type);
742 wdev_unlock(wdev);
743 } else {
744 result = cfg80211_set_freq(rdev, NULL, freq, channel_type);
745 }
746 mutex_unlock(&rdev->devlist_mtx);
747
748 return result;
749}
750
751static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
752{
753 struct cfg80211_registered_device *rdev;
754 struct net_device *netdev;
755 int result;
756
757 rtnl_lock();
758
759 result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev);
760 if (result)
761 goto unlock;
762
763 result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info);
764
765 unlock:
766 rtnl_unlock();
767
768 return result;
769}
770
689static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) 771static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
690{ 772{
691 struct cfg80211_registered_device *rdev; 773 struct cfg80211_registered_device *rdev;
692 int result = 0, rem_txq_params = 0; 774 struct net_device *netdev = NULL;
775 struct wireless_dev *wdev;
776 int result, rem_txq_params = 0;
693 struct nlattr *nl_txq_params; 777 struct nlattr *nl_txq_params;
694 u32 changed; 778 u32 changed;
695 u8 retry_short = 0, retry_long = 0; 779 u8 retry_short = 0, retry_long = 0;
@@ -698,16 +782,50 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
698 782
699 rtnl_lock(); 783 rtnl_lock();
700 784
785 /*
786 * Try to find the wiphy and netdev. Normally this
787 * function shouldn't need the netdev, but this is
788 * done for backward compatibility -- previously
789 * setting the channel was done per wiphy, but now
790 * it is per netdev. Previous userland like hostapd
791 * also passed a netdev to set_wiphy, so that it is
792 * possible to let that go to the right netdev!
793 */
701 mutex_lock(&cfg80211_mutex); 794 mutex_lock(&cfg80211_mutex);
702 795
703 rdev = __cfg80211_rdev_from_info(info); 796 if (info->attrs[NL80211_ATTR_IFINDEX]) {
704 if (IS_ERR(rdev)) { 797 int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
705 mutex_unlock(&cfg80211_mutex); 798
706 result = PTR_ERR(rdev); 799 netdev = dev_get_by_index(genl_info_net(info), ifindex);
707 goto unlock; 800 if (netdev && netdev->ieee80211_ptr) {
801 rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy);
802 mutex_lock(&rdev->mtx);
803 } else
804 netdev = NULL;
708 } 805 }
709 806
710 mutex_lock(&rdev->mtx); 807 if (!netdev) {
808 rdev = __cfg80211_rdev_from_info(info);
809 if (IS_ERR(rdev)) {
810 mutex_unlock(&cfg80211_mutex);
811 result = PTR_ERR(rdev);
812 goto unlock;
813 }
814 wdev = NULL;
815 netdev = NULL;
816 result = 0;
817
818 mutex_lock(&rdev->mtx);
819 } else if (netif_running(netdev) &&
820 nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
821 wdev = netdev->ieee80211_ptr;
822 else
823 wdev = NULL;
824
825 /*
826 * end workaround code, by now the rdev is available
827 * and locked, and wdev may or may not be NULL.
828 */
711 829
712 if (info->attrs[NL80211_ATTR_WIPHY_NAME]) 830 if (info->attrs[NL80211_ATTR_WIPHY_NAME])
713 result = cfg80211_dev_rename( 831 result = cfg80211_dev_rename(
@@ -746,26 +864,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
746 } 864 }
747 865
748 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { 866 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
749 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; 867 result = __nl80211_set_channel(rdev, wdev, info);
750 u32 freq;
751
752 result = -EINVAL;
753
754 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
755 channel_type = nla_get_u32(info->attrs[
756 NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
757 if (channel_type != NL80211_CHAN_NO_HT &&
758 channel_type != NL80211_CHAN_HT20 &&
759 channel_type != NL80211_CHAN_HT40PLUS &&
760 channel_type != NL80211_CHAN_HT40MINUS)
761 goto bad_res;
762 }
763
764 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
765
766 mutex_lock(&rdev->devlist_mtx);
767 result = rdev_set_freq(rdev, NULL, freq, channel_type);
768 mutex_unlock(&rdev->devlist_mtx);
769 if (result) 868 if (result)
770 goto bad_res; 869 goto bad_res;
771 } 870 }
@@ -862,6 +961,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
862 961
863 bad_res: 962 bad_res:
864 mutex_unlock(&rdev->mtx); 963 mutex_unlock(&rdev->mtx);
964 if (netdev)
965 dev_put(netdev);
865 unlock: 966 unlock:
866 rtnl_unlock(); 967 rtnl_unlock();
867 return result; 968 return result;
@@ -2096,7 +2197,8 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
2096 goto out_rtnl; 2197 goto out_rtnl;
2097 2198
2098 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && 2199 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
2099 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { 2200 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
2201 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
2100 err = -EINVAL; 2202 err = -EINVAL;
2101 goto out; 2203 goto out;
2102 } 2204 }
@@ -2439,6 +2541,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
2439 params.use_cts_prot = -1; 2541 params.use_cts_prot = -1;
2440 params.use_short_preamble = -1; 2542 params.use_short_preamble = -1;
2441 params.use_short_slot_time = -1; 2543 params.use_short_slot_time = -1;
2544 params.ap_isolate = -1;
2442 2545
2443 if (info->attrs[NL80211_ATTR_BSS_CTS_PROT]) 2546 if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
2444 params.use_cts_prot = 2547 params.use_cts_prot =
@@ -2455,6 +2558,8 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
2455 params.basic_rates_len = 2558 params.basic_rates_len =
2456 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); 2559 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
2457 } 2560 }
2561 if (info->attrs[NL80211_ATTR_AP_ISOLATE])
2562 params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
2458 2563
2459 rtnl_lock(); 2564 rtnl_lock();
2460 2565
@@ -3392,6 +3497,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
3392 int err, ssid_len, ie_len = 0; 3497 int err, ssid_len, ie_len = 0;
3393 enum nl80211_auth_type auth_type; 3498 enum nl80211_auth_type auth_type;
3394 struct key_parse key; 3499 struct key_parse key;
3500 bool local_state_change;
3395 3501
3396 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3502 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3397 return -EINVAL; 3503 return -EINVAL;
@@ -3470,9 +3576,12 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
3470 goto out; 3576 goto out;
3471 } 3577 }
3472 3578
3579 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
3580
3473 err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, 3581 err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
3474 ssid, ssid_len, ie, ie_len, 3582 ssid, ssid_len, ie, ie_len,
3475 key.p.key, key.p.key_len, key.idx); 3583 key.p.key, key.p.key_len, key.idx,
3584 local_state_change);
3476 3585
3477out: 3586out:
3478 cfg80211_unlock_rdev(rdev); 3587 cfg80211_unlock_rdev(rdev);
@@ -3551,9 +3660,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
3551{ 3660{
3552 struct cfg80211_registered_device *rdev; 3661 struct cfg80211_registered_device *rdev;
3553 struct net_device *dev; 3662 struct net_device *dev;
3554 struct wireless_dev *wdev;
3555 struct cfg80211_crypto_settings crypto; 3663 struct cfg80211_crypto_settings crypto;
3556 struct ieee80211_channel *chan, *fixedchan; 3664 struct ieee80211_channel *chan;
3557 const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; 3665 const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
3558 int err, ssid_len, ie_len = 0; 3666 int err, ssid_len, ie_len = 0;
3559 bool use_mfp = false; 3667 bool use_mfp = false;
@@ -3596,16 +3704,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
3596 goto out; 3704 goto out;
3597 } 3705 }
3598 3706
3599 mutex_lock(&rdev->devlist_mtx);
3600 wdev = dev->ieee80211_ptr;
3601 fixedchan = rdev_fixed_channel(rdev, wdev);
3602 if (fixedchan && chan != fixedchan) {
3603 err = -EBUSY;
3604 mutex_unlock(&rdev->devlist_mtx);
3605 goto out;
3606 }
3607 mutex_unlock(&rdev->devlist_mtx);
3608
3609 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); 3707 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
3610 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); 3708 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
3611 3709
@@ -3649,6 +3747,7 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
3649 const u8 *ie = NULL, *bssid; 3747 const u8 *ie = NULL, *bssid;
3650 int err, ie_len = 0; 3748 int err, ie_len = 0;
3651 u16 reason_code; 3749 u16 reason_code;
3750 bool local_state_change;
3652 3751
3653 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3752 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3654 return -EINVAL; 3753 return -EINVAL;
@@ -3694,7 +3793,10 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
3694 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3793 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
3695 } 3794 }
3696 3795
3697 err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code); 3796 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
3797
3798 err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
3799 local_state_change);
3698 3800
3699out: 3801out:
3700 cfg80211_unlock_rdev(rdev); 3802 cfg80211_unlock_rdev(rdev);
@@ -3711,6 +3813,7 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
3711 const u8 *ie = NULL, *bssid; 3813 const u8 *ie = NULL, *bssid;
3712 int err, ie_len = 0; 3814 int err, ie_len = 0;
3713 u16 reason_code; 3815 u16 reason_code;
3816 bool local_state_change;
3714 3817
3715 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3818 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3716 return -EINVAL; 3819 return -EINVAL;
@@ -3756,7 +3859,10 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
3756 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3859 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
3757 } 3860 }
3758 3861
3759 err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code); 3862 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
3863
3864 err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
3865 local_state_change);
3760 3866
3761out: 3867out:
3762 cfg80211_unlock_rdev(rdev); 3868 cfg80211_unlock_rdev(rdev);
@@ -4337,9 +4443,10 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
4337 if (channel_type != NL80211_CHAN_NO_HT && 4443 if (channel_type != NL80211_CHAN_NO_HT &&
4338 channel_type != NL80211_CHAN_HT20 && 4444 channel_type != NL80211_CHAN_HT20 &&
4339 channel_type != NL80211_CHAN_HT40PLUS && 4445 channel_type != NL80211_CHAN_HT40PLUS &&
4340 channel_type != NL80211_CHAN_HT40MINUS) 4446 channel_type != NL80211_CHAN_HT40MINUS) {
4341 err = -EINVAL; 4447 err = -EINVAL;
4342 goto out; 4448 goto out;
4449 }
4343 } 4450 }
4344 4451
4345 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); 4452 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
@@ -4611,9 +4718,10 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
4611 if (channel_type != NL80211_CHAN_NO_HT && 4718 if (channel_type != NL80211_CHAN_NO_HT &&
4612 channel_type != NL80211_CHAN_HT20 && 4719 channel_type != NL80211_CHAN_HT20 &&
4613 channel_type != NL80211_CHAN_HT40PLUS && 4720 channel_type != NL80211_CHAN_HT40PLUS &&
4614 channel_type != NL80211_CHAN_HT40MINUS) 4721 channel_type != NL80211_CHAN_HT40MINUS) {
4615 err = -EINVAL; 4722 err = -EINVAL;
4616 goto out; 4723 goto out;
4724 }
4617 } 4725 }
4618 4726
4619 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); 4727 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
@@ -4779,6 +4887,84 @@ unlock_rtnl:
4779 return err; 4887 return err;
4780} 4888}
4781 4889
4890static struct nla_policy
4891nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = {
4892 [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
4893 [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
4894 [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
4895};
4896
4897static int nl80211_set_cqm_rssi(struct genl_info *info,
4898 s32 threshold, u32 hysteresis)
4899{
4900 struct cfg80211_registered_device *rdev;
4901 struct wireless_dev *wdev;
4902 struct net_device *dev;
4903 int err;
4904
4905 if (threshold > 0)
4906 return -EINVAL;
4907
4908 rtnl_lock();
4909
4910 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4911 if (err)
4912 goto unlock_rdev;
4913
4914 wdev = dev->ieee80211_ptr;
4915
4916 if (!rdev->ops->set_cqm_rssi_config) {
4917 err = -EOPNOTSUPP;
4918 goto unlock_rdev;
4919 }
4920
4921 if (wdev->iftype != NL80211_IFTYPE_STATION) {
4922 err = -EOPNOTSUPP;
4923 goto unlock_rdev;
4924 }
4925
4926 err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev,
4927 threshold, hysteresis);
4928
4929unlock_rdev:
4930 cfg80211_unlock_rdev(rdev);
4931 dev_put(dev);
4932 rtnl_unlock();
4933
4934 return err;
4935}
4936
4937static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
4938{
4939 struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
4940 struct nlattr *cqm;
4941 int err;
4942
4943 cqm = info->attrs[NL80211_ATTR_CQM];
4944 if (!cqm) {
4945 err = -EINVAL;
4946 goto out;
4947 }
4948
4949 err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, cqm,
4950 nl80211_attr_cqm_policy);
4951 if (err)
4952 goto out;
4953
4954 if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
4955 attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
4956 s32 threshold;
4957 u32 hysteresis;
4958 threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
4959 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
4960 err = nl80211_set_cqm_rssi(info, threshold, hysteresis);
4961 } else
4962 err = -EINVAL;
4963
4964out:
4965 return err;
4966}
4967
4782static struct genl_ops nl80211_ops[] = { 4968static struct genl_ops nl80211_ops[] = {
4783 { 4969 {
4784 .cmd = NL80211_CMD_GET_WIPHY, 4970 .cmd = NL80211_CMD_GET_WIPHY,
@@ -5083,6 +5269,18 @@ static struct genl_ops nl80211_ops[] = {
5083 .policy = nl80211_policy, 5269 .policy = nl80211_policy,
5084 /* can be retrieved by unprivileged users */ 5270 /* can be retrieved by unprivileged users */
5085 }, 5271 },
5272 {
5273 .cmd = NL80211_CMD_SET_CQM,
5274 .doit = nl80211_set_cqm,
5275 .policy = nl80211_policy,
5276 .flags = GENL_ADMIN_PERM,
5277 },
5278 {
5279 .cmd = NL80211_CMD_SET_CHANNEL,
5280 .doit = nl80211_set_channel,
5281 .policy = nl80211_policy,
5282 .flags = GENL_ADMIN_PERM,
5283 },
5086}; 5284};
5087 5285
5088static struct genl_multicast_group nl80211_mlme_mcgrp = { 5286static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -5833,6 +6031,52 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
5833 nlmsg_free(msg); 6031 nlmsg_free(msg);
5834} 6032}
5835 6033
6034void
6035nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
6036 struct net_device *netdev,
6037 enum nl80211_cqm_rssi_threshold_event rssi_event,
6038 gfp_t gfp)
6039{
6040 struct sk_buff *msg;
6041 struct nlattr *pinfoattr;
6042 void *hdr;
6043
6044 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
6045 if (!msg)
6046 return;
6047
6048 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
6049 if (!hdr) {
6050 nlmsg_free(msg);
6051 return;
6052 }
6053
6054 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
6055 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
6056
6057 pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
6058 if (!pinfoattr)
6059 goto nla_put_failure;
6060
6061 NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
6062 rssi_event);
6063
6064 nla_nest_end(msg, pinfoattr);
6065
6066 if (genlmsg_end(msg, hdr) < 0) {
6067 nlmsg_free(msg);
6068 return;
6069 }
6070
6071 genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
6072 nl80211_mlme_mcgrp.id, gfp);
6073 return;
6074
6075 nla_put_failure:
6076 genlmsg_cancel(msg, hdr);
6077 nlmsg_free(msg);
6078}
6079
5836static int nl80211_netlink_notify(struct notifier_block * nb, 6080static int nl80211_netlink_notify(struct notifier_block * nb,
5837 unsigned long state, 6081 unsigned long state,
5838 void *_notify) 6082 void *_notify)