aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-05-04 09:37:28 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-05-05 14:59:19 -0400
commitff1b6e69ad4f31fb3c9c6da2665655f2e798dd70 (patch)
tree6fc049fd0389ffb382ea401096d7bd665642af5c
parent8f7f3b2fcc4ccbba0be776049df41a2f96c986ac (diff)
nl80211/cfg80211: WoWLAN support
This is based on (but now quite far from) the original work from Luis and Eliad. Add support for configuring WoWLAN triggers, and getting the configuration out again. Changes from the original patchset are too numerous to list, but one important change needs highlighting: the suspend() callback is passed NULL for the trigger configuration if userspace has not configured WoWLAN at all. Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com> Signed-off-by: Eliad Peller <eliad@wizery.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/linux/nl80211.h99
-rw-r--r--include/net/cfg80211.h74
-rw-r--r--net/mac80211/cfg.c3
-rw-r--r--net/wireless/core.c8
-rw-r--r--net/wireless/core.h14
-rw-r--r--net/wireless/nl80211.c243
-rw-r--r--net/wireless/sysfs.c2
7 files changed, 439 insertions, 4 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index be8df57b789d..a75dea9c416e 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -420,6 +420,14 @@
420 * new station with the AUTHENTICATED flag unset and maybe change it later 420 * new station with the AUTHENTICATED flag unset and maybe change it later
421 * depending on the authentication result. 421 * depending on the authentication result.
422 * 422 *
423 * @NL80211_CMD_GET_WOWLAN: get Wake-on-Wireless-LAN (WoWLAN) settings.
424 * @NL80211_CMD_SET_WOWLAN: set Wake-on-Wireless-LAN (WoWLAN) settings.
425 * Since wireless is more complex than wired ethernet, it supports
426 * various triggers. These triggers can be configured through this
427 * command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For
428 * more background information, see
429 * http://wireless.kernel.org/en/users/Documentation/WoWLAN.
430 *
423 * @NL80211_CMD_MAX: highest used command number 431 * @NL80211_CMD_MAX: highest used command number
424 * @__NL80211_CMD_AFTER_LAST: internal use 432 * @__NL80211_CMD_AFTER_LAST: internal use
425 */ 433 */
@@ -534,6 +542,9 @@ enum nl80211_commands {
534 542
535 NL80211_CMD_NEW_PEER_CANDIDATE, 543 NL80211_CMD_NEW_PEER_CANDIDATE,
536 544
545 NL80211_CMD_GET_WOWLAN,
546 NL80211_CMD_SET_WOWLAN,
547
537 /* add new commands above here */ 548 /* add new commands above here */
538 549
539 /* used to define NL80211_CMD_MAX below */ 550 /* used to define NL80211_CMD_MAX below */
@@ -903,6 +914,13 @@ enum nl80211_commands {
903 * allows auth frames in a mesh to be passed to userspace for processing via 914 * allows auth frames in a mesh to be passed to userspace for processing via
904 * the @NL80211_MESH_SETUP_USERSPACE_AUTH flag. 915 * the @NL80211_MESH_SETUP_USERSPACE_AUTH flag.
905 * 916 *
917 * @NL80211_ATTR_WOWLAN_SUPPORTED: indicates, as part of the wiphy capabilities,
918 * the supported WoWLAN triggers
919 * @NL80211_ATTR_WOWLAN_TRIGGERS: used by %NL80211_CMD_SET_WOWLAN to
920 * indicate which WoW triggers should be enabled. This is also
921 * used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN
922 * triggers.
923 *
906 * @NL80211_ATTR_MAX: highest attribute number currently defined 924 * @NL80211_ATTR_MAX: highest attribute number currently defined
907 * @__NL80211_ATTR_AFTER_LAST: internal use 925 * @__NL80211_ATTR_AFTER_LAST: internal use
908 */ 926 */
@@ -1092,6 +1110,9 @@ enum nl80211_attrs {
1092 1110
1093 NL80211_ATTR_SUPPORT_MESH_AUTH, 1111 NL80211_ATTR_SUPPORT_MESH_AUTH,
1094 1112
1113 NL80211_ATTR_WOWLAN_TRIGGERS,
1114 NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED,
1115
1095 /* add attributes here, update the policy in nl80211.c */ 1116 /* add attributes here, update the policy in nl80211.c */
1096 1117
1097 __NL80211_ATTR_AFTER_LAST, 1118 __NL80211_ATTR_AFTER_LAST,
@@ -2061,4 +2082,82 @@ enum nl80211_tx_power_setting {
2061 NL80211_TX_POWER_FIXED, 2082 NL80211_TX_POWER_FIXED,
2062}; 2083};
2063 2084
2085/**
2086 * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute
2087 * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute
2088 * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has
2089 * a zero bit are ignored
2090 * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have
2091 * a bit for each byte in the pattern. The lowest-order bit corresponds
2092 * to the first byte of the pattern, but the bytes of the pattern are
2093 * in a little-endian-like format, i.e. the 9th byte of the pattern
2094 * corresponds to the lowest-order bit in the second byte of the mask.
2095 * For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where
2096 * xx indicates "don't care") would be represented by a pattern of
2097 * twelve zero bytes, and a mask of "0xed,0x07".
2098 * Note that the pattern matching is done as though frames were not
2099 * 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked
2100 * first (including SNAP header unpacking) and then matched.
2101 * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes
2102 * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number
2103 */
2104enum nl80211_wowlan_packet_pattern_attr {
2105 __NL80211_WOWLAN_PKTPAT_INVALID,
2106 NL80211_WOWLAN_PKTPAT_MASK,
2107 NL80211_WOWLAN_PKTPAT_PATTERN,
2108
2109 NUM_NL80211_WOWLAN_PKTPAT,
2110 MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1,
2111};
2112
2113/**
2114 * struct nl80211_wowlan_pattern_support - pattern support information
2115 * @max_patterns: maximum number of patterns supported
2116 * @min_pattern_len: minimum length of each pattern
2117 * @max_pattern_len: maximum length of each pattern
2118 *
2119 * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when
2120 * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the
2121 * capability information given by the kernel to userspace.
2122 */
2123struct nl80211_wowlan_pattern_support {
2124 __u32 max_patterns;
2125 __u32 min_pattern_len;
2126 __u32 max_pattern_len;
2127} __attribute__((packed));
2128
2129/**
2130 * enum nl80211_wowlan_triggers - WoWLAN trigger definitions
2131 * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes
2132 * @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put
2133 * the chip into a special state -- works best with chips that have
2134 * support for low-power operation already (flag)
2135 * @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect
2136 * is detected is implementation-specific (flag)
2137 * @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed
2138 * by 16 repetitions of MAC addr, anywhere in payload) (flag)
2139 * @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns
2140 * which are passed in an array of nested attributes, each nested attribute
2141 * defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern.
2142 * Each pattern defines a wakeup packet. The matching is done on the MSDU,
2143 * i.e. as though the packet was an 802.3 packet, so the pattern matching
2144 * is done after the packet is converted to the MSDU.
2145 *
2146 * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
2147 * carrying a &struct nl80211_wowlan_pattern_support.
2148 * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
2149 * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
2150 */
2151enum nl80211_wowlan_triggers {
2152 __NL80211_WOWLAN_TRIG_INVALID,
2153 NL80211_WOWLAN_TRIG_ANY,
2154 NL80211_WOWLAN_TRIG_DISCONNECT,
2155 NL80211_WOWLAN_TRIG_MAGIC_PKT,
2156 NL80211_WOWLAN_TRIG_PKT_PATTERN,
2157
2158 /* keep last */
2159 NUM_NL80211_WOWLAN_TRIG,
2160 MAX_NL80211_WOWLAN_TRIG = NUM_NL80211_WOWLAN_TRIG - 1
2161};
2162
2064#endif /* __LINUX_NL80211_H */ 2163#endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 4932dfcb72b4..0920daf36807 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1088,6 +1088,38 @@ struct cfg80211_pmksa {
1088}; 1088};
1089 1089
1090/** 1090/**
1091 * struct cfg80211_wowlan_trig_pkt_pattern - packet pattern
1092 * @mask: bitmask where to match pattern and where to ignore bytes,
1093 * one bit per byte, in same format as nl80211
1094 * @pattern: bytes to match where bitmask is 1
1095 * @pattern_len: length of pattern (in bytes)
1096 *
1097 * Internal note: @mask and @pattern are allocated in one chunk of
1098 * memory, free @mask only!
1099 */
1100struct cfg80211_wowlan_trig_pkt_pattern {
1101 u8 *mask, *pattern;
1102 int pattern_len;
1103};
1104
1105/**
1106 * struct cfg80211_wowlan - Wake on Wireless-LAN support info
1107 *
1108 * This structure defines the enabled WoWLAN triggers for the device.
1109 * @any: wake up on any activity -- special trigger if device continues
1110 * operating as normal during suspend
1111 * @disconnect: wake up if getting disconnected
1112 * @magic_pkt: wake up on receiving magic packet
1113 * @patterns: wake up on receiving packet matching a pattern
1114 * @n_patterns: number of patterns
1115 */
1116struct cfg80211_wowlan {
1117 bool any, disconnect, magic_pkt;
1118 struct cfg80211_wowlan_trig_pkt_pattern *patterns;
1119 int n_patterns;
1120};
1121
1122/**
1091 * struct cfg80211_ops - backend description for wireless configuration 1123 * struct cfg80211_ops - backend description for wireless configuration
1092 * 1124 *
1093 * This struct is registered by fullmac card drivers and/or wireless stacks 1125 * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -1100,7 +1132,9 @@ struct cfg80211_pmksa {
1100 * wireless extensions but this is subject to reevaluation as soon as this 1132 * wireless extensions but this is subject to reevaluation as soon as this
1101 * code is used more widely and we have a first user without wext. 1133 * code is used more widely and we have a first user without wext.
1102 * 1134 *
1103 * @suspend: wiphy device needs to be suspended 1135 * @suspend: wiphy device needs to be suspended. The variable @wow will
1136 * be %NULL or contain the enabled Wake-on-Wireless triggers that are
1137 * configured for the device.
1104 * @resume: wiphy device needs to be resumed 1138 * @resume: wiphy device needs to be resumed
1105 * 1139 *
1106 * @add_virtual_intf: create a new virtual interface with the given name, 1140 * @add_virtual_intf: create a new virtual interface with the given name,
@@ -1244,7 +1278,7 @@ struct cfg80211_pmksa {
1244 * @get_ringparam: Get tx and rx ring current and maximum sizes. 1278 * @get_ringparam: Get tx and rx ring current and maximum sizes.
1245 */ 1279 */
1246struct cfg80211_ops { 1280struct cfg80211_ops {
1247 int (*suspend)(struct wiphy *wiphy); 1281 int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
1248 int (*resume)(struct wiphy *wiphy); 1282 int (*resume)(struct wiphy *wiphy);
1249 1283
1250 struct net_device * (*add_virtual_intf)(struct wiphy *wiphy, 1284 struct net_device * (*add_virtual_intf)(struct wiphy *wiphy,
@@ -1480,6 +1514,38 @@ struct ieee80211_txrx_stypes {
1480}; 1514};
1481 1515
1482/** 1516/**
1517 * enum wiphy_wowlan_support_flags - WoWLAN support flags
1518 * @WIPHY_WOWLAN_ANY: supports wakeup for the special "any"
1519 * trigger that keeps the device operating as-is and
1520 * wakes up the host on any activity, for example a
1521 * received packet that passed filtering; note that the
1522 * packet should be preserved in that case
1523 * @WIPHY_WOWLAN_MAGIC_PKT: supports wakeup on magic packet
1524 * (see nl80211.h)
1525 * @WIPHY_WOWLAN_DISCONNECT: supports wakeup on disconnect
1526 */
1527enum wiphy_wowlan_support_flags {
1528 WIPHY_WOWLAN_ANY = BIT(0),
1529 WIPHY_WOWLAN_MAGIC_PKT = BIT(1),
1530 WIPHY_WOWLAN_DISCONNECT = BIT(2),
1531};
1532
1533/**
1534 * struct wiphy_wowlan_support - WoWLAN support data
1535 * @flags: see &enum wiphy_wowlan_support_flags
1536 * @n_patterns: number of supported wakeup patterns
1537 * (see nl80211.h for the pattern definition)
1538 * @pattern_max_len: maximum length of each pattern
1539 * @pattern_min_len: minimum length of each pattern
1540 */
1541struct wiphy_wowlan_support {
1542 u32 flags;
1543 int n_patterns;
1544 int pattern_max_len;
1545 int pattern_min_len;
1546};
1547
1548/**
1483 * struct wiphy - wireless hardware description 1549 * struct wiphy - wireless hardware description
1484 * @reg_notifier: the driver's regulatory notification callback, 1550 * @reg_notifier: the driver's regulatory notification callback,
1485 * note that if your driver uses wiphy_apply_custom_regulatory() 1551 * note that if your driver uses wiphy_apply_custom_regulatory()
@@ -1546,6 +1612,8 @@ struct ieee80211_txrx_stypes {
1546 * 1612 *
1547 * @max_remain_on_channel_duration: Maximum time a remain-on-channel operation 1613 * @max_remain_on_channel_duration: Maximum time a remain-on-channel operation
1548 * may request, if implemented. 1614 * may request, if implemented.
1615 *
1616 * @wowlan: WoWLAN support information
1549 */ 1617 */
1550struct wiphy { 1618struct wiphy {
1551 /* assign these fields before you register the wiphy */ 1619 /* assign these fields before you register the wiphy */
@@ -1583,6 +1651,8 @@ struct wiphy {
1583 char fw_version[ETHTOOL_BUSINFO_LEN]; 1651 char fw_version[ETHTOOL_BUSINFO_LEN];
1584 u32 hw_version; 1652 u32 hw_version;
1585 1653
1654 struct wiphy_wowlan_support wowlan;
1655
1586 u16 max_remain_on_channel_duration; 1656 u16 max_remain_on_channel_duration;
1587 1657
1588 u8 max_num_pmkids; 1658 u8 max_num_pmkids;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 12d52cec9515..321d598eb8cb 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1297,7 +1297,8 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
1297} 1297}
1298 1298
1299#ifdef CONFIG_PM 1299#ifdef CONFIG_PM
1300static int ieee80211_suspend(struct wiphy *wiphy) 1300static int ieee80211_suspend(struct wiphy *wiphy,
1301 struct cfg80211_wowlan *wowlan)
1301{ 1302{
1302 return __ieee80211_suspend(wiphy_priv(wiphy)); 1303 return __ieee80211_suspend(wiphy_priv(wiphy));
1303} 1304}
diff --git a/net/wireless/core.c b/net/wireless/core.c
index bbf1fa11107a..bea0d80710c8 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -493,6 +493,13 @@ int wiphy_register(struct wiphy *wiphy)
493 return -EINVAL; 493 return -EINVAL;
494 } 494 }
495 495
496 if (rdev->wiphy.wowlan.n_patterns) {
497 if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len ||
498 rdev->wiphy.wowlan.pattern_min_len >
499 rdev->wiphy.wowlan.pattern_max_len))
500 return -EINVAL;
501 }
502
496 /* check and set up bitrates */ 503 /* check and set up bitrates */
497 ieee80211_set_bitrate_flags(wiphy); 504 ieee80211_set_bitrate_flags(wiphy);
498 505
@@ -631,6 +638,7 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
631 mutex_destroy(&rdev->devlist_mtx); 638 mutex_destroy(&rdev->devlist_mtx);
632 list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) 639 list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
633 cfg80211_put_bss(&scan->pub); 640 cfg80211_put_bss(&scan->pub);
641 cfg80211_rdev_free_wowlan(rdev);
634 kfree(rdev); 642 kfree(rdev);
635} 643}
636 644
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 26a0a084e16b..7a18c10a7fb6 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -70,6 +70,8 @@ struct cfg80211_registered_device {
70 struct work_struct conn_work; 70 struct work_struct conn_work;
71 struct work_struct event_work; 71 struct work_struct event_work;
72 72
73 struct cfg80211_wowlan *wowlan;
74
73 /* must be last because of the way we do wiphy_priv(), 75 /* must be last because of the way we do wiphy_priv(),
74 * and it should at least be aligned to NETDEV_ALIGN */ 76 * and it should at least be aligned to NETDEV_ALIGN */
75 struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); 77 struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
@@ -89,6 +91,18 @@ bool wiphy_idx_valid(int wiphy_idx)
89 return wiphy_idx >= 0; 91 return wiphy_idx >= 0;
90} 92}
91 93
94static inline void
95cfg80211_rdev_free_wowlan(struct cfg80211_registered_device *rdev)
96{
97 int i;
98
99 if (!rdev->wowlan)
100 return;
101 for (i = 0; i < rdev->wowlan->n_patterns; i++)
102 kfree(rdev->wowlan->patterns[i].mask);
103 kfree(rdev->wowlan->patterns);
104 kfree(rdev->wowlan);
105}
92 106
93extern struct workqueue_struct *cfg80211_wq; 107extern struct workqueue_struct *cfg80211_wq;
94extern struct mutex cfg80211_mutex; 108extern struct mutex cfg80211_mutex;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ab77f943dc04..0a199a1ca9b6 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -173,6 +173,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
173 [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 }, 173 [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 },
174 [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG }, 174 [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG },
175 [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, 175 [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
176 [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
176}; 177};
177 178
178/* policy for the key attributes */ 179/* policy for the key attributes */
@@ -194,6 +195,15 @@ nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = {
194 [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG }, 195 [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG },
195}; 196};
196 197
198/* policy for WoWLAN attributes */
199static const struct nla_policy
200nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = {
201 [NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG },
202 [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG },
203 [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG },
204 [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED },
205};
206
197/* ifidx get helper */ 207/* ifidx get helper */
198static int nl80211_get_ifidx(struct netlink_callback *cb) 208static int nl80211_get_ifidx(struct netlink_callback *cb)
199{ 209{
@@ -821,6 +831,35 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
821 nla_nest_end(msg, nl_ifs); 831 nla_nest_end(msg, nl_ifs);
822 } 832 }
823 833
834 if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) {
835 struct nlattr *nl_wowlan;
836
837 nl_wowlan = nla_nest_start(msg,
838 NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
839 if (!nl_wowlan)
840 goto nla_put_failure;
841
842 if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY)
843 NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY);
844 if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT)
845 NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT);
846 if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT)
847 NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT);
848 if (dev->wiphy.wowlan.n_patterns) {
849 struct nl80211_wowlan_pattern_support pat = {
850 .max_patterns = dev->wiphy.wowlan.n_patterns,
851 .min_pattern_len =
852 dev->wiphy.wowlan.pattern_min_len,
853 .max_pattern_len =
854 dev->wiphy.wowlan.pattern_max_len,
855 };
856 NLA_PUT(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
857 sizeof(pat), &pat);
858 }
859
860 nla_nest_end(msg, nl_wowlan);
861 }
862
824 return genlmsg_end(msg, hdr); 863 return genlmsg_end(msg, hdr);
825 864
826 nla_put_failure: 865 nla_put_failure:
@@ -4808,6 +4847,194 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
4808 return cfg80211_leave_mesh(rdev, dev); 4847 return cfg80211_leave_mesh(rdev, dev);
4809} 4848}
4810 4849
4850static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
4851{
4852 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4853 struct sk_buff *msg;
4854 void *hdr;
4855
4856 if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns)
4857 return -EOPNOTSUPP;
4858
4859 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4860 if (!msg)
4861 return -ENOMEM;
4862
4863 hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
4864 NL80211_CMD_GET_WOWLAN);
4865 if (!hdr)
4866 goto nla_put_failure;
4867
4868 if (rdev->wowlan) {
4869 struct nlattr *nl_wowlan;
4870
4871 nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
4872 if (!nl_wowlan)
4873 goto nla_put_failure;
4874
4875 if (rdev->wowlan->any)
4876 NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY);
4877 if (rdev->wowlan->disconnect)
4878 NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT);
4879 if (rdev->wowlan->magic_pkt)
4880 NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT);
4881 if (rdev->wowlan->n_patterns) {
4882 struct nlattr *nl_pats, *nl_pat;
4883 int i, pat_len;
4884
4885 nl_pats = nla_nest_start(msg,
4886 NL80211_WOWLAN_TRIG_PKT_PATTERN);
4887 if (!nl_pats)
4888 goto nla_put_failure;
4889
4890 for (i = 0; i < rdev->wowlan->n_patterns; i++) {
4891 nl_pat = nla_nest_start(msg, i + 1);
4892 if (!nl_pat)
4893 goto nla_put_failure;
4894 pat_len = rdev->wowlan->patterns[i].pattern_len;
4895 NLA_PUT(msg, NL80211_WOWLAN_PKTPAT_MASK,
4896 DIV_ROUND_UP(pat_len, 8),
4897 rdev->wowlan->patterns[i].mask);
4898 NLA_PUT(msg, NL80211_WOWLAN_PKTPAT_PATTERN,
4899 pat_len,
4900 rdev->wowlan->patterns[i].pattern);
4901 nla_nest_end(msg, nl_pat);
4902 }
4903 nla_nest_end(msg, nl_pats);
4904 }
4905
4906 nla_nest_end(msg, nl_wowlan);
4907 }
4908
4909 genlmsg_end(msg, hdr);
4910 return genlmsg_reply(msg, info);
4911
4912nla_put_failure:
4913 nlmsg_free(msg);
4914 return -ENOBUFS;
4915}
4916
4917static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
4918{
4919 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4920 struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
4921 struct cfg80211_wowlan no_triggers = {};
4922 struct cfg80211_wowlan new_triggers = {};
4923 struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan;
4924 int err, i;
4925
4926 if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns)
4927 return -EOPNOTSUPP;
4928
4929 if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS])
4930 goto no_triggers;
4931
4932 err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG,
4933 nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
4934 nla_len(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
4935 nl80211_wowlan_policy);
4936 if (err)
4937 return err;
4938
4939 if (tb[NL80211_WOWLAN_TRIG_ANY]) {
4940 if (!(wowlan->flags & WIPHY_WOWLAN_ANY))
4941 return -EINVAL;
4942 new_triggers.any = true;
4943 }
4944
4945 if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) {
4946 if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
4947 return -EINVAL;
4948 new_triggers.disconnect = true;
4949 }
4950
4951 if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
4952 if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
4953 return -EINVAL;
4954 new_triggers.magic_pkt = true;
4955 }
4956
4957 if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
4958 struct nlattr *pat;
4959 int n_patterns = 0;
4960 int rem, pat_len, mask_len;
4961 struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT];
4962
4963 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
4964 rem)
4965 n_patterns++;
4966 if (n_patterns > wowlan->n_patterns)
4967 return -EINVAL;
4968
4969 new_triggers.patterns = kcalloc(n_patterns,
4970 sizeof(new_triggers.patterns[0]),
4971 GFP_KERNEL);
4972 if (!new_triggers.patterns)
4973 return -ENOMEM;
4974
4975 new_triggers.n_patterns = n_patterns;
4976 i = 0;
4977
4978 nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
4979 rem) {
4980 nla_parse(pat_tb, MAX_NL80211_WOWLAN_PKTPAT,
4981 nla_data(pat), nla_len(pat), NULL);
4982 err = -EINVAL;
4983 if (!pat_tb[NL80211_WOWLAN_PKTPAT_MASK] ||
4984 !pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN])
4985 goto error;
4986 pat_len = nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]);
4987 mask_len = DIV_ROUND_UP(pat_len, 8);
4988 if (nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]) !=
4989 mask_len)
4990 goto error;
4991 if (pat_len > wowlan->pattern_max_len ||
4992 pat_len < wowlan->pattern_min_len)
4993 goto error;
4994
4995 new_triggers.patterns[i].mask =
4996 kmalloc(mask_len + pat_len, GFP_KERNEL);
4997 if (!new_triggers.patterns[i].mask) {
4998 err = -ENOMEM;
4999 goto error;
5000 }
5001 new_triggers.patterns[i].pattern =
5002 new_triggers.patterns[i].mask + mask_len;
5003 memcpy(new_triggers.patterns[i].mask,
5004 nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]),
5005 mask_len);
5006 new_triggers.patterns[i].pattern_len = pat_len;
5007 memcpy(new_triggers.patterns[i].pattern,
5008 nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]),
5009 pat_len);
5010 i++;
5011 }
5012 }
5013
5014 if (memcmp(&new_triggers, &no_triggers, sizeof(new_triggers))) {
5015 struct cfg80211_wowlan *ntrig;
5016 ntrig = kmemdup(&new_triggers, sizeof(new_triggers),
5017 GFP_KERNEL);
5018 if (!ntrig) {
5019 err = -ENOMEM;
5020 goto error;
5021 }
5022 cfg80211_rdev_free_wowlan(rdev);
5023 rdev->wowlan = ntrig;
5024 } else {
5025 no_triggers:
5026 cfg80211_rdev_free_wowlan(rdev);
5027 rdev->wowlan = NULL;
5028 }
5029
5030 return 0;
5031 error:
5032 for (i = 0; i < new_triggers.n_patterns; i++)
5033 kfree(new_triggers.patterns[i].mask);
5034 kfree(new_triggers.patterns);
5035 return err;
5036}
5037
4811#define NL80211_FLAG_NEED_WIPHY 0x01 5038#define NL80211_FLAG_NEED_WIPHY 0x01
4812#define NL80211_FLAG_NEED_NETDEV 0x02 5039#define NL80211_FLAG_NEED_NETDEV 0x02
4813#define NL80211_FLAG_NEED_RTNL 0x04 5040#define NL80211_FLAG_NEED_RTNL 0x04
@@ -5306,6 +5533,22 @@ static struct genl_ops nl80211_ops[] = {
5306 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | 5533 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
5307 NL80211_FLAG_NEED_RTNL, 5534 NL80211_FLAG_NEED_RTNL,
5308 }, 5535 },
5536 {
5537 .cmd = NL80211_CMD_GET_WOWLAN,
5538 .doit = nl80211_get_wowlan,
5539 .policy = nl80211_policy,
5540 /* can be retrieved by unprivileged users */
5541 .internal_flags = NL80211_FLAG_NEED_WIPHY |
5542 NL80211_FLAG_NEED_RTNL,
5543 },
5544 {
5545 .cmd = NL80211_CMD_SET_WOWLAN,
5546 .doit = nl80211_set_wowlan,
5547 .policy = nl80211_policy,
5548 .flags = GENL_ADMIN_PERM,
5549 .internal_flags = NL80211_FLAG_NEED_WIPHY |
5550 NL80211_FLAG_NEED_RTNL,
5551 },
5309}; 5552};
5310 5553
5311static struct genl_multicast_group nl80211_mlme_mcgrp = { 5554static struct genl_multicast_group nl80211_mlme_mcgrp = {
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index 4294fa22bb2d..c6e4ca6a7d2e 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -93,7 +93,7 @@ static int wiphy_suspend(struct device *dev, pm_message_t state)
93 93
94 if (rdev->ops->suspend) { 94 if (rdev->ops->suspend) {
95 rtnl_lock(); 95 rtnl_lock();
96 ret = rdev->ops->suspend(&rdev->wiphy); 96 ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan);
97 rtnl_unlock(); 97 rtnl_unlock();
98 } 98 }
99 99