aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/nl80211.h10
-rw-r--r--include/net/cfg80211.h7
-rw-r--r--net/wireless/core.c16
-rw-r--r--net/wireless/nl80211.c131
-rw-r--r--net/wireless/wext-compat.c10
5 files changed, 159 insertions, 15 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 8e6384f8fda6..28ba20fda3e2 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -416,6 +416,9 @@ enum nl80211_commands {
416 NL80211_CMD_ACTION, 416 NL80211_CMD_ACTION,
417 NL80211_CMD_ACTION_TX_STATUS, 417 NL80211_CMD_ACTION_TX_STATUS,
418 418
419 NL80211_CMD_SET_POWER_SAVE,
420 NL80211_CMD_GET_POWER_SAVE,
421
419 /* add new commands above here */ 422 /* add new commands above here */
420 423
421 /* used to define NL80211_CMD_MAX below */ 424 /* used to define NL80211_CMD_MAX below */
@@ -837,6 +840,8 @@ enum nl80211_attrs {
837 840
838 NL80211_ATTR_ACK, 841 NL80211_ATTR_ACK,
839 842
843 NL80211_ATTR_PS_STATE,
844
840 /* add attributes here, update the policy in nl80211.c */ 845 /* add attributes here, update the policy in nl80211.c */
841 846
842 __NL80211_ATTR_AFTER_LAST, 847 __NL80211_ATTR_AFTER_LAST,
@@ -1573,4 +1578,9 @@ enum nl80211_band {
1573 NL80211_BAND_5GHZ, 1578 NL80211_BAND_5GHZ,
1574}; 1579};
1575 1580
1581enum nl80211_ps_state {
1582 NL80211_PS_DISABLED,
1583 NL80211_PS_ENABLED,
1584};
1585
1576#endif /* __LINUX_NL80211_H */ 1586#endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7188934b64d3..3d134a1fb96b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1150,7 +1150,6 @@ struct cfg80211_ops {
1150 enum nl80211_channel_type channel_type, 1150 enum nl80211_channel_type channel_type,
1151 const u8 *buf, size_t len, u64 *cookie); 1151 const u8 *buf, size_t len, u64 *cookie);
1152 1152
1153 /* some temporary stuff to finish wext */
1154 int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, 1153 int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
1155 bool enabled, int timeout); 1154 bool enabled, int timeout);
1156}; 1155};
@@ -1489,6 +1488,9 @@ struct wireless_dev {
1489 struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES]; 1488 struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES];
1490 struct cfg80211_internal_bss *current_bss; /* associated / joined */ 1489 struct cfg80211_internal_bss *current_bss; /* associated / joined */
1491 1490
1491 bool ps;
1492 int ps_timeout;
1493
1492#ifdef CONFIG_CFG80211_WEXT 1494#ifdef CONFIG_CFG80211_WEXT
1493 /* wext data */ 1495 /* wext data */
1494 struct { 1496 struct {
@@ -1500,8 +1502,7 @@ struct wireless_dev {
1500 u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; 1502 u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
1501 u8 ssid[IEEE80211_MAX_SSID_LEN]; 1503 u8 ssid[IEEE80211_MAX_SSID_LEN];
1502 s8 default_key, default_mgmt_key; 1504 s8 default_key, default_mgmt_key;
1503 bool ps, prev_bssid_valid; 1505 bool prev_bssid_valid;
1504 int ps_timeout;
1505 } wext; 1506 } wext;
1506#endif 1507#endif
1507}; 1508};
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}