diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 153 |
1 files changed, 149 insertions, 4 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e447db04cf76..df5505b3930c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -149,6 +149,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
149 | .len = IEEE80211_MAX_DATA_LEN }, | 149 | .len = IEEE80211_MAX_DATA_LEN }, |
150 | [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, }, | 150 | [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, }, |
151 | [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 }, | 151 | [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 }, |
152 | [NL80211_ATTR_CQM] = { .type = NLA_NESTED, }, | ||
153 | [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG }, | ||
152 | }; | 154 | }; |
153 | 155 | ||
154 | /* policy for the attributes */ | 156 | /* policy for the attributes */ |
@@ -2095,7 +2097,8 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | |||
2095 | goto out_rtnl; | 2097 | goto out_rtnl; |
2096 | 2098 | ||
2097 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2099 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2098 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { | 2100 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
2101 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | ||
2099 | err = -EINVAL; | 2102 | err = -EINVAL; |
2100 | goto out; | 2103 | goto out; |
2101 | } | 2104 | } |
@@ -3391,6 +3394,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3391 | int err, ssid_len, ie_len = 0; | 3394 | int err, ssid_len, ie_len = 0; |
3392 | enum nl80211_auth_type auth_type; | 3395 | enum nl80211_auth_type auth_type; |
3393 | struct key_parse key; | 3396 | struct key_parse key; |
3397 | bool local_state_change; | ||
3394 | 3398 | ||
3395 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 3399 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3396 | return -EINVAL; | 3400 | return -EINVAL; |
@@ -3469,9 +3473,12 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3469 | goto out; | 3473 | goto out; |
3470 | } | 3474 | } |
3471 | 3475 | ||
3476 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; | ||
3477 | |||
3472 | err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, | 3478 | err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, |
3473 | ssid, ssid_len, ie, ie_len, | 3479 | ssid, ssid_len, ie, ie_len, |
3474 | key.p.key, key.p.key_len, key.idx); | 3480 | key.p.key, key.p.key_len, key.idx, |
3481 | local_state_change); | ||
3475 | 3482 | ||
3476 | out: | 3483 | out: |
3477 | cfg80211_unlock_rdev(rdev); | 3484 | cfg80211_unlock_rdev(rdev); |
@@ -3648,6 +3655,7 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
3648 | const u8 *ie = NULL, *bssid; | 3655 | const u8 *ie = NULL, *bssid; |
3649 | int err, ie_len = 0; | 3656 | int err, ie_len = 0; |
3650 | u16 reason_code; | 3657 | u16 reason_code; |
3658 | bool local_state_change; | ||
3651 | 3659 | ||
3652 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 3660 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3653 | return -EINVAL; | 3661 | return -EINVAL; |
@@ -3693,7 +3701,10 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
3693 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 3701 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3694 | } | 3702 | } |
3695 | 3703 | ||
3696 | err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code); | 3704 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; |
3705 | |||
3706 | err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, | ||
3707 | local_state_change); | ||
3697 | 3708 | ||
3698 | out: | 3709 | out: |
3699 | cfg80211_unlock_rdev(rdev); | 3710 | cfg80211_unlock_rdev(rdev); |
@@ -3710,6 +3721,7 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
3710 | const u8 *ie = NULL, *bssid; | 3721 | const u8 *ie = NULL, *bssid; |
3711 | int err, ie_len = 0; | 3722 | int err, ie_len = 0; |
3712 | u16 reason_code; | 3723 | u16 reason_code; |
3724 | bool local_state_change; | ||
3713 | 3725 | ||
3714 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 3726 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3715 | return -EINVAL; | 3727 | return -EINVAL; |
@@ -3755,7 +3767,10 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
3755 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 3767 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3756 | } | 3768 | } |
3757 | 3769 | ||
3758 | err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code); | 3770 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; |
3771 | |||
3772 | err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, | ||
3773 | local_state_change); | ||
3759 | 3774 | ||
3760 | out: | 3775 | out: |
3761 | cfg80211_unlock_rdev(rdev); | 3776 | cfg80211_unlock_rdev(rdev); |
@@ -4778,6 +4793,84 @@ unlock_rtnl: | |||
4778 | return err; | 4793 | return err; |
4779 | } | 4794 | } |
4780 | 4795 | ||
4796 | static struct nla_policy | ||
4797 | nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { | ||
4798 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, | ||
4799 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, | ||
4800 | [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, | ||
4801 | }; | ||
4802 | |||
4803 | static int nl80211_set_cqm_rssi(struct genl_info *info, | ||
4804 | s32 threshold, u32 hysteresis) | ||
4805 | { | ||
4806 | struct cfg80211_registered_device *rdev; | ||
4807 | struct wireless_dev *wdev; | ||
4808 | struct net_device *dev; | ||
4809 | int err; | ||
4810 | |||
4811 | if (threshold > 0) | ||
4812 | return -EINVAL; | ||
4813 | |||
4814 | rtnl_lock(); | ||
4815 | |||
4816 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4817 | if (err) | ||
4818 | goto unlock_rdev; | ||
4819 | |||
4820 | wdev = dev->ieee80211_ptr; | ||
4821 | |||
4822 | if (!rdev->ops->set_cqm_rssi_config) { | ||
4823 | err = -EOPNOTSUPP; | ||
4824 | goto unlock_rdev; | ||
4825 | } | ||
4826 | |||
4827 | if (wdev->iftype != NL80211_IFTYPE_STATION) { | ||
4828 | err = -EOPNOTSUPP; | ||
4829 | goto unlock_rdev; | ||
4830 | } | ||
4831 | |||
4832 | err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, | ||
4833 | threshold, hysteresis); | ||
4834 | |||
4835 | unlock_rdev: | ||
4836 | cfg80211_unlock_rdev(rdev); | ||
4837 | dev_put(dev); | ||
4838 | rtnl_unlock(); | ||
4839 | |||
4840 | return err; | ||
4841 | } | ||
4842 | |||
4843 | static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) | ||
4844 | { | ||
4845 | struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1]; | ||
4846 | struct nlattr *cqm; | ||
4847 | int err; | ||
4848 | |||
4849 | cqm = info->attrs[NL80211_ATTR_CQM]; | ||
4850 | if (!cqm) { | ||
4851 | err = -EINVAL; | ||
4852 | goto out; | ||
4853 | } | ||
4854 | |||
4855 | err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, cqm, | ||
4856 | nl80211_attr_cqm_policy); | ||
4857 | if (err) | ||
4858 | goto out; | ||
4859 | |||
4860 | if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] && | ||
4861 | attrs[NL80211_ATTR_CQM_RSSI_HYST]) { | ||
4862 | s32 threshold; | ||
4863 | u32 hysteresis; | ||
4864 | threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); | ||
4865 | hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]); | ||
4866 | err = nl80211_set_cqm_rssi(info, threshold, hysteresis); | ||
4867 | } else | ||
4868 | err = -EINVAL; | ||
4869 | |||
4870 | out: | ||
4871 | return err; | ||
4872 | } | ||
4873 | |||
4781 | static struct genl_ops nl80211_ops[] = { | 4874 | static struct genl_ops nl80211_ops[] = { |
4782 | { | 4875 | { |
4783 | .cmd = NL80211_CMD_GET_WIPHY, | 4876 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -5082,6 +5175,12 @@ static struct genl_ops nl80211_ops[] = { | |||
5082 | .policy = nl80211_policy, | 5175 | .policy = nl80211_policy, |
5083 | /* can be retrieved by unprivileged users */ | 5176 | /* can be retrieved by unprivileged users */ |
5084 | }, | 5177 | }, |
5178 | { | ||
5179 | .cmd = NL80211_CMD_SET_CQM, | ||
5180 | .doit = nl80211_set_cqm, | ||
5181 | .policy = nl80211_policy, | ||
5182 | .flags = GENL_ADMIN_PERM, | ||
5183 | }, | ||
5085 | }; | 5184 | }; |
5086 | 5185 | ||
5087 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 5186 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
@@ -5832,6 +5931,52 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, | |||
5832 | nlmsg_free(msg); | 5931 | nlmsg_free(msg); |
5833 | } | 5932 | } |
5834 | 5933 | ||
5934 | void | ||
5935 | nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | ||
5936 | struct net_device *netdev, | ||
5937 | enum nl80211_cqm_rssi_threshold_event rssi_event, | ||
5938 | gfp_t gfp) | ||
5939 | { | ||
5940 | struct sk_buff *msg; | ||
5941 | struct nlattr *pinfoattr; | ||
5942 | void *hdr; | ||
5943 | |||
5944 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
5945 | if (!msg) | ||
5946 | return; | ||
5947 | |||
5948 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM); | ||
5949 | if (!hdr) { | ||
5950 | nlmsg_free(msg); | ||
5951 | return; | ||
5952 | } | ||
5953 | |||
5954 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
5955 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
5956 | |||
5957 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); | ||
5958 | if (!pinfoattr) | ||
5959 | goto nla_put_failure; | ||
5960 | |||
5961 | NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, | ||
5962 | rssi_event); | ||
5963 | |||
5964 | nla_nest_end(msg, pinfoattr); | ||
5965 | |||
5966 | if (genlmsg_end(msg, hdr) < 0) { | ||
5967 | nlmsg_free(msg); | ||
5968 | return; | ||
5969 | } | ||
5970 | |||
5971 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
5972 | nl80211_mlme_mcgrp.id, gfp); | ||
5973 | return; | ||
5974 | |||
5975 | nla_put_failure: | ||
5976 | genlmsg_cancel(msg, hdr); | ||
5977 | nlmsg_free(msg); | ||
5978 | } | ||
5979 | |||
5835 | static int nl80211_netlink_notify(struct notifier_block * nb, | 5980 | static int nl80211_netlink_notify(struct notifier_block * nb, |
5836 | unsigned long state, | 5981 | unsigned long state, |
5837 | void *_notify) | 5982 | void *_notify) |