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.c131
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
4782static struct nla_policy
4783nl80211_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
4789static 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
4821unlock_rdev:
4822 cfg80211_unlock_rdev(rdev);
4823 dev_put(dev);
4824 rtnl_unlock();
4825
4826 return err;
4827}
4828
4829static 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
4856out:
4857 return err;
4858}
4859
4781static struct genl_ops nl80211_ops[] = { 4860static 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
5087static struct genl_multicast_group nl80211_mlme_mcgrp = { 5172static 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
5920void
5921nl80211_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
5835static int nl80211_netlink_notify(struct notifier_block * nb, 5966static int nl80211_netlink_notify(struct notifier_block * nb,
5836 unsigned long state, 5967 unsigned long state,
5837 void *_notify) 5968 void *_notify)