diff options
-rw-r--r-- | include/linux/nl80211.h | 10 | ||||
-rw-r--r-- | include/net/cfg80211.h | 7 | ||||
-rw-r--r-- | net/wireless/core.c | 16 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 131 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 10 |
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 | ||
1581 | enum 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 | ||
4667 | static 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 | |||
4713 | unlock_rdev: | ||
4714 | cfg80211_unlock_rdev(rdev); | ||
4715 | dev_put(dev); | ||
4716 | rtnl_unlock(); | ||
4717 | |||
4718 | out: | ||
4719 | return err; | ||
4720 | } | ||
4721 | |||
4722 | static 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 | |||
4769 | nla_put_failure: | ||
4770 | err = -ENOBUFS; | ||
4771 | |||
4772 | free_msg: | ||
4773 | nlmsg_free(msg); | ||
4774 | |||
4775 | out: | ||
4776 | cfg80211_unlock_rdev(rdev); | ||
4777 | dev_put(dev); | ||
4778 | |||
4779 | unlock_rtnl: | ||
4780 | rtnl_unlock(); | ||
4781 | |||
4782 | return err; | ||
4783 | } | ||
4784 | |||
4666 | static struct genl_ops nl80211_ops[] = { | 4785 | static 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 | ||
4960 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 5091 | static 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 | } |