aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorKalle Valo <kalle.valo@nokia.com>2010-02-17 10:58:10 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-02-19 15:52:40 -0500
commitffb9eb3d8b450c22bbbc688c6b630141ac476fd9 (patch)
tree0e9677ea9df5b86fedf814236bf049a0f0435f6a /net
parent088ea189c4c75cdf211146faa4b341a0f7476be6 (diff)
nl80211: add power save commands
The most needed command from nl80211, which Wireless Extensions had, is support for power save mode. Add a simple command to make it possible to enable and disable power save via nl80211. I was also planning about extending the interface, for example adding the timeout value, but after thinking more about this I decided not to do it. Basically there were three reasons: Firstly, the parameters for power save are very much hardware dependent. Trying to find a unified interface which would work with all hardware, and still make sense to users, will be very difficult. Secondly, IEEE 802.11 power save implementation in Linux is still in state of flux. We have a long way to still to go and there is no way to predict what kind of implementation we will have after few years. And because we need to support nl80211 interface a long time, practically forever, adding now parameters to nl80211 might create maintenance problems later on. Third issue are the users. Power save parameters are mostly used for debugging, so debugfs is better, more flexible, interface for this. For example, wpa_supplicant currently doesn't configure anything related to power save mode. It's better to strive that kernel can automatically optimise the power save parameters, like with help of pm qos network and other traffic parameters. Later on, when we have better understanding of power save, we can extend this command with more features, if there's a need for that. Signed-off-by: Kalle Valo <kalle.valo@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/wireless/core.c16
-rw-r--r--net/wireless/nl80211.c131
-rw-r--r--net/wireless/wext-compat.c10
3 files changed, 145 insertions, 12 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 51908dc2ea00..7fdb9409ad2a 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -698,19 +698,21 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
698 wdev->wext.default_key = -1; 698 wdev->wext.default_key = -1;
699 wdev->wext.default_mgmt_key = -1; 699 wdev->wext.default_mgmt_key = -1;
700 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; 700 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
701#endif
702
701 if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT) 703 if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT)
702 wdev->wext.ps = true; 704 wdev->ps = true;
703 else 705 else
704 wdev->wext.ps = false; 706 wdev->ps = false;
705 wdev->wext.ps_timeout = 100; 707 wdev->ps_timeout = 100;
706 if (rdev->ops->set_power_mgmt) 708 if (rdev->ops->set_power_mgmt)
707 if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, 709 if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
708 wdev->wext.ps, 710 wdev->ps,
709 wdev->wext.ps_timeout)) { 711 wdev->ps_timeout)) {
710 /* assume this means it's off */ 712 /* assume this means it's off */
711 wdev->wext.ps = false; 713 wdev->ps = false;
712 } 714 }
713#endif 715
714 if (!dev->ethtool_ops) 716 if (!dev->ethtool_ops)
715 dev->ethtool_ops = &cfg80211_ethtool_ops; 717 dev->ethtool_ops = &cfg80211_ethtool_ops;
716 718
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 = {
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index b17eeae448d5..9ab51838849e 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -1099,8 +1099,8 @@ int cfg80211_wext_siwpower(struct net_device *dev,
1099{ 1099{
1100 struct wireless_dev *wdev = dev->ieee80211_ptr; 1100 struct wireless_dev *wdev = dev->ieee80211_ptr;
1101 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 1101 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
1102 bool ps = wdev->wext.ps; 1102 bool ps = wdev->ps;
1103 int timeout = wdev->wext.ps_timeout; 1103 int timeout = wdev->ps_timeout;
1104 int err; 1104 int err;
1105 1105
1106 if (wdev->iftype != NL80211_IFTYPE_STATION) 1106 if (wdev->iftype != NL80211_IFTYPE_STATION)
@@ -1133,8 +1133,8 @@ int cfg80211_wext_siwpower(struct net_device *dev,
1133 if (err) 1133 if (err)
1134 return err; 1134 return err;
1135 1135
1136 wdev->wext.ps = ps; 1136 wdev->ps = ps;
1137 wdev->wext.ps_timeout = timeout; 1137 wdev->ps_timeout = timeout;
1138 1138
1139 return 0; 1139 return 0;
1140 1140
@@ -1147,7 +1147,7 @@ int cfg80211_wext_giwpower(struct net_device *dev,
1147{ 1147{
1148 struct wireless_dev *wdev = dev->ieee80211_ptr; 1148 struct wireless_dev *wdev = dev->ieee80211_ptr;
1149 1149
1150 wrq->disabled = !wdev->wext.ps; 1150 wrq->disabled = !wdev->ps;
1151 1151
1152 return 0; 1152 return 0;
1153} 1153}