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.c153
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
3476out: 3483out:
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
3698out: 3709out:
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
3760out: 3775out:
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
4796static struct nla_policy
4797nl80211_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
4803static 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
4835unlock_rdev:
4836 cfg80211_unlock_rdev(rdev);
4837 dev_put(dev);
4838 rtnl_unlock();
4839
4840 return err;
4841}
4842
4843static 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
4870out:
4871 return err;
4872}
4873
4781static struct genl_ops nl80211_ops[] = { 4874static 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
5087static struct genl_multicast_group nl80211_mlme_mcgrp = { 5186static 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
5934void
5935nl80211_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
5835static int nl80211_netlink_notify(struct notifier_block * nb, 5980static int nl80211_netlink_notify(struct notifier_block * nb,
5836 unsigned long state, 5981 unsigned long state,
5837 void *_notify) 5982 void *_notify)