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 328112081358..b0495a1da22e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -148,6 +148,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
148 [NL80211_ATTR_FRAME] = { .type = NLA_BINARY, 148 [NL80211_ATTR_FRAME] = { .type = NLA_BINARY,
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}; 152};
152 153
153/* policy for the attributes */ 154/* policy for the attributes */
@@ -4663,6 +4664,124 @@ unlock_rtnl:
4663 return err; 4664 return err;
4664} 4665}
4665 4666
4667static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
4668{
4669 struct cfg80211_registered_device *rdev;
4670 struct wireless_dev *wdev;
4671 struct net_device *dev;
4672 u8 ps_state;
4673 bool state;
4674 int err;
4675
4676 if (!info->attrs[NL80211_ATTR_PS_STATE]) {
4677 err = -EINVAL;
4678 goto out;
4679 }
4680
4681 ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);
4682
4683 if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) {
4684 err = -EINVAL;
4685 goto out;
4686 }
4687
4688 rtnl_lock();
4689
4690 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4691 if (err)
4692 goto unlock_rdev;
4693
4694 wdev = dev->ieee80211_ptr;
4695
4696 if (!rdev->ops->set_power_mgmt) {
4697 err = -EOPNOTSUPP;
4698 goto unlock_rdev;
4699 }
4700
4701 state = (ps_state == NL80211_PS_ENABLED) ? true : false;
4702
4703 if (state == wdev->ps)
4704 goto unlock_rdev;
4705
4706 wdev->ps = state;
4707
4708 if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, wdev->ps,
4709 wdev->ps_timeout))
4710 /* assume this means it's off */
4711 wdev->ps = false;
4712
4713unlock_rdev:
4714 cfg80211_unlock_rdev(rdev);
4715 dev_put(dev);
4716 rtnl_unlock();
4717
4718out:
4719 return err;
4720}
4721
4722static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
4723{
4724 struct cfg80211_registered_device *rdev;
4725 enum nl80211_ps_state ps_state;
4726 struct wireless_dev *wdev;
4727 struct net_device *dev;
4728 struct sk_buff *msg;
4729 void *hdr;
4730 int err;
4731
4732 rtnl_lock();
4733
4734 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4735 if (err)
4736 goto unlock_rtnl;
4737
4738 wdev = dev->ieee80211_ptr;
4739
4740 if (!rdev->ops->set_power_mgmt) {
4741 err = -EOPNOTSUPP;
4742 goto out;
4743 }
4744
4745 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4746 if (!msg) {
4747 err = -ENOMEM;
4748 goto out;
4749 }
4750
4751 hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
4752 NL80211_CMD_GET_POWER_SAVE);
4753 if (!hdr) {
4754 err = -ENOMEM;
4755 goto free_msg;
4756 }
4757
4758 if (wdev->ps)
4759 ps_state = NL80211_PS_ENABLED;
4760 else
4761 ps_state = NL80211_PS_DISABLED;
4762
4763 NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state);
4764
4765 genlmsg_end(msg, hdr);
4766 err = genlmsg_reply(msg, info);
4767 goto out;
4768
4769nla_put_failure:
4770 err = -ENOBUFS;
4771
4772free_msg:
4773 nlmsg_free(msg);
4774
4775out:
4776 cfg80211_unlock_rdev(rdev);
4777 dev_put(dev);
4778
4779unlock_rtnl:
4780 rtnl_unlock();
4781
4782 return err;
4783}
4784
4666static struct genl_ops nl80211_ops[] = { 4785static struct genl_ops nl80211_ops[] = {
4667 { 4786 {
4668 .cmd = NL80211_CMD_GET_WIPHY, 4787 .cmd = NL80211_CMD_GET_WIPHY,
@@ -4955,6 +5074,18 @@ static struct genl_ops nl80211_ops[] = {
4955 .policy = nl80211_policy, 5074 .policy = nl80211_policy,
4956 .flags = GENL_ADMIN_PERM, 5075 .flags = GENL_ADMIN_PERM,
4957 }, 5076 },
5077 {
5078 .cmd = NL80211_CMD_SET_POWER_SAVE,
5079 .doit = nl80211_set_power_save,
5080 .policy = nl80211_policy,
5081 .flags = GENL_ADMIN_PERM,
5082 },
5083 {
5084 .cmd = NL80211_CMD_GET_POWER_SAVE,
5085 .doit = nl80211_get_power_save,
5086 .policy = nl80211_policy,
5087 /* can be retrieved by unprivileged users */
5088 },
4958}; 5089};
4959 5090
4960static struct genl_multicast_group nl80211_mlme_mcgrp = { 5091static struct genl_multicast_group nl80211_mlme_mcgrp = {