diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e447db04cf76..a7fc3d83f5f6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -149,6 +149,7 @@ 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, }, | ||
152 | }; | 153 | }; |
153 | 154 | ||
154 | /* policy for the attributes */ | 155 | /* policy for the attributes */ |
@@ -4778,6 +4779,84 @@ unlock_rtnl: | |||
4778 | return err; | 4779 | return err; |
4779 | } | 4780 | } |
4780 | 4781 | ||
4782 | static struct nla_policy | ||
4783 | nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { | ||
4784 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, | ||
4785 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, | ||
4786 | [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, | ||
4787 | }; | ||
4788 | |||
4789 | static int nl80211_set_cqm_rssi(struct genl_info *info, | ||
4790 | s32 threshold, u32 hysteresis) | ||
4791 | { | ||
4792 | struct cfg80211_registered_device *rdev; | ||
4793 | struct wireless_dev *wdev; | ||
4794 | struct net_device *dev; | ||
4795 | int err; | ||
4796 | |||
4797 | if (threshold > 0) | ||
4798 | return -EINVAL; | ||
4799 | |||
4800 | rtnl_lock(); | ||
4801 | |||
4802 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4803 | if (err) | ||
4804 | goto unlock_rdev; | ||
4805 | |||
4806 | wdev = dev->ieee80211_ptr; | ||
4807 | |||
4808 | if (!rdev->ops->set_cqm_rssi_config) { | ||
4809 | err = -EOPNOTSUPP; | ||
4810 | goto unlock_rdev; | ||
4811 | } | ||
4812 | |||
4813 | if (wdev->iftype != NL80211_IFTYPE_STATION) { | ||
4814 | err = -EOPNOTSUPP; | ||
4815 | goto unlock_rdev; | ||
4816 | } | ||
4817 | |||
4818 | err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, | ||
4819 | threshold, hysteresis); | ||
4820 | |||
4821 | unlock_rdev: | ||
4822 | cfg80211_unlock_rdev(rdev); | ||
4823 | dev_put(dev); | ||
4824 | rtnl_unlock(); | ||
4825 | |||
4826 | return err; | ||
4827 | } | ||
4828 | |||
4829 | static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) | ||
4830 | { | ||
4831 | struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1]; | ||
4832 | struct nlattr *cqm; | ||
4833 | int err; | ||
4834 | |||
4835 | cqm = info->attrs[NL80211_ATTR_CQM]; | ||
4836 | if (!cqm) { | ||
4837 | err = -EINVAL; | ||
4838 | goto out; | ||
4839 | } | ||
4840 | |||
4841 | err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, cqm, | ||
4842 | nl80211_attr_cqm_policy); | ||
4843 | if (err) | ||
4844 | goto out; | ||
4845 | |||
4846 | if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] && | ||
4847 | attrs[NL80211_ATTR_CQM_RSSI_HYST]) { | ||
4848 | s32 threshold; | ||
4849 | u32 hysteresis; | ||
4850 | threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); | ||
4851 | hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]); | ||
4852 | err = nl80211_set_cqm_rssi(info, threshold, hysteresis); | ||
4853 | } else | ||
4854 | err = -EINVAL; | ||
4855 | |||
4856 | out: | ||
4857 | return err; | ||
4858 | } | ||
4859 | |||
4781 | static struct genl_ops nl80211_ops[] = { | 4860 | static struct genl_ops nl80211_ops[] = { |
4782 | { | 4861 | { |
4783 | .cmd = NL80211_CMD_GET_WIPHY, | 4862 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -5082,6 +5161,12 @@ static struct genl_ops nl80211_ops[] = { | |||
5082 | .policy = nl80211_policy, | 5161 | .policy = nl80211_policy, |
5083 | /* can be retrieved by unprivileged users */ | 5162 | /* can be retrieved by unprivileged users */ |
5084 | }, | 5163 | }, |
5164 | { | ||
5165 | .cmd = NL80211_CMD_SET_CQM, | ||
5166 | .doit = nl80211_set_cqm, | ||
5167 | .policy = nl80211_policy, | ||
5168 | .flags = GENL_ADMIN_PERM, | ||
5169 | }, | ||
5085 | }; | 5170 | }; |
5086 | 5171 | ||
5087 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 5172 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
@@ -5832,6 +5917,52 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, | |||
5832 | nlmsg_free(msg); | 5917 | nlmsg_free(msg); |
5833 | } | 5918 | } |
5834 | 5919 | ||
5920 | void | ||
5921 | nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | ||
5922 | struct net_device *netdev, | ||
5923 | enum nl80211_cqm_rssi_threshold_event rssi_event, | ||
5924 | gfp_t gfp) | ||
5925 | { | ||
5926 | struct sk_buff *msg; | ||
5927 | struct nlattr *pinfoattr; | ||
5928 | void *hdr; | ||
5929 | |||
5930 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
5931 | if (!msg) | ||
5932 | return; | ||
5933 | |||
5934 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM); | ||
5935 | if (!hdr) { | ||
5936 | nlmsg_free(msg); | ||
5937 | return; | ||
5938 | } | ||
5939 | |||
5940 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
5941 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
5942 | |||
5943 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); | ||
5944 | if (!pinfoattr) | ||
5945 | goto nla_put_failure; | ||
5946 | |||
5947 | NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, | ||
5948 | rssi_event); | ||
5949 | |||
5950 | nla_nest_end(msg, pinfoattr); | ||
5951 | |||
5952 | if (genlmsg_end(msg, hdr) < 0) { | ||
5953 | nlmsg_free(msg); | ||
5954 | return; | ||
5955 | } | ||
5956 | |||
5957 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
5958 | nl80211_mlme_mcgrp.id, gfp); | ||
5959 | return; | ||
5960 | |||
5961 | nla_put_failure: | ||
5962 | genlmsg_cancel(msg, hdr); | ||
5963 | nlmsg_free(msg); | ||
5964 | } | ||
5965 | |||
5835 | static int nl80211_netlink_notify(struct notifier_block * nb, | 5966 | static int nl80211_netlink_notify(struct notifier_block * nb, |
5836 | unsigned long state, | 5967 | unsigned long state, |
5837 | void *_notify) | 5968 | void *_notify) |