diff options
-rw-r--r-- | include/linux/nl80211.h | 99 | ||||
-rw-r--r-- | include/net/cfg80211.h | 74 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 3 | ||||
-rw-r--r-- | net/wireless/core.c | 8 | ||||
-rw-r--r-- | net/wireless/core.h | 14 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 243 | ||||
-rw-r--r-- | net/wireless/sysfs.c | 2 |
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 | */ | ||
2104 | enum 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 | */ | ||
2123 | struct 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 | */ | ||
2151 | enum 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 | */ | ||
1100 | struct 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 | */ | ||
1116 | struct 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 | */ |
1246 | struct cfg80211_ops { | 1280 | struct 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 | */ | ||
1527 | enum 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 | */ | ||
1541 | struct 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 | */ |
1550 | struct wiphy { | 1618 | struct 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 |
1300 | static int ieee80211_suspend(struct wiphy *wiphy) | 1300 | static 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 | ||
94 | static inline void | ||
95 | cfg80211_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 | ||
93 | extern struct workqueue_struct *cfg80211_wq; | 107 | extern struct workqueue_struct *cfg80211_wq; |
94 | extern struct mutex cfg80211_mutex; | 108 | extern 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 */ | ||
199 | static const struct nla_policy | ||
200 | nl80211_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 */ |
198 | static int nl80211_get_ifidx(struct netlink_callback *cb) | 208 | static 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 | ||
4850 | static 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 | |||
4912 | nla_put_failure: | ||
4913 | nlmsg_free(msg); | ||
4914 | return -ENOBUFS; | ||
4915 | } | ||
4916 | |||
4917 | static 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 | ||
5311 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 5554 | static 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 | ||