diff options
-rw-r--r-- | include/net/cfg80211.h | 55 | ||||
-rw-r--r-- | include/uapi/linux/nl80211.h | 125 | ||||
-rw-r--r-- | net/wireless/core.h | 3 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 295 |
4 files changed, 474 insertions, 4 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d3a73818e44c..7e6569e1f16f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/nl80211.h> | 19 | #include <linux/nl80211.h> |
20 | #include <linux/if_ether.h> | 20 | #include <linux/if_ether.h> |
21 | #include <linux/ieee80211.h> | 21 | #include <linux/ieee80211.h> |
22 | #include <linux/net.h> | ||
22 | #include <net/regulatory.h> | 23 | #include <net/regulatory.h> |
23 | 24 | ||
24 | /** | 25 | /** |
@@ -1588,6 +1589,41 @@ struct cfg80211_wowlan_trig_pkt_pattern { | |||
1588 | }; | 1589 | }; |
1589 | 1590 | ||
1590 | /** | 1591 | /** |
1592 | * struct cfg80211_wowlan_tcp - TCP connection parameters | ||
1593 | * | ||
1594 | * @sock: (internal) socket for source port allocation | ||
1595 | * @src: source IP address | ||
1596 | * @dst: destination IP address | ||
1597 | * @dst_mac: destination MAC address | ||
1598 | * @src_port: source port | ||
1599 | * @dst_port: destination port | ||
1600 | * @payload_len: data payload length | ||
1601 | * @payload: data payload buffer | ||
1602 | * @payload_seq: payload sequence stamping configuration | ||
1603 | * @data_interval: interval at which to send data packets | ||
1604 | * @wake_len: wakeup payload match length | ||
1605 | * @wake_data: wakeup payload match data | ||
1606 | * @wake_mask: wakeup payload match mask | ||
1607 | * @tokens_size: length of the tokens buffer | ||
1608 | * @payload_tok: payload token usage configuration | ||
1609 | */ | ||
1610 | struct cfg80211_wowlan_tcp { | ||
1611 | struct socket *sock; | ||
1612 | __be32 src, dst; | ||
1613 | u16 src_port, dst_port; | ||
1614 | u8 dst_mac[ETH_ALEN]; | ||
1615 | int payload_len; | ||
1616 | const u8 *payload; | ||
1617 | struct nl80211_wowlan_tcp_data_seq payload_seq; | ||
1618 | u32 data_interval; | ||
1619 | u32 wake_len; | ||
1620 | const u8 *wake_data, *wake_mask; | ||
1621 | u32 tokens_size; | ||
1622 | /* must be last, variable member */ | ||
1623 | struct nl80211_wowlan_tcp_data_token payload_tok; | ||
1624 | }; | ||
1625 | |||
1626 | /** | ||
1591 | * struct cfg80211_wowlan - Wake on Wireless-LAN support info | 1627 | * struct cfg80211_wowlan - Wake on Wireless-LAN support info |
1592 | * | 1628 | * |
1593 | * This structure defines the enabled WoWLAN triggers for the device. | 1629 | * This structure defines the enabled WoWLAN triggers for the device. |
@@ -1601,12 +1637,15 @@ struct cfg80211_wowlan_trig_pkt_pattern { | |||
1601 | * @eap_identity_req: wake up on EAP identity request packet | 1637 | * @eap_identity_req: wake up on EAP identity request packet |
1602 | * @four_way_handshake: wake up on 4-way handshake | 1638 | * @four_way_handshake: wake up on 4-way handshake |
1603 | * @rfkill_release: wake up when rfkill is released | 1639 | * @rfkill_release: wake up when rfkill is released |
1640 | * @tcp: TCP connection establishment/wakeup parameters, see nl80211.h. | ||
1641 | * NULL if not configured. | ||
1604 | */ | 1642 | */ |
1605 | struct cfg80211_wowlan { | 1643 | struct cfg80211_wowlan { |
1606 | bool any, disconnect, magic_pkt, gtk_rekey_failure, | 1644 | bool any, disconnect, magic_pkt, gtk_rekey_failure, |
1607 | eap_identity_req, four_way_handshake, | 1645 | eap_identity_req, four_way_handshake, |
1608 | rfkill_release; | 1646 | rfkill_release; |
1609 | struct cfg80211_wowlan_trig_pkt_pattern *patterns; | 1647 | struct cfg80211_wowlan_trig_pkt_pattern *patterns; |
1648 | struct cfg80211_wowlan_tcp *tcp; | ||
1610 | int n_patterns; | 1649 | int n_patterns; |
1611 | }; | 1650 | }; |
1612 | 1651 | ||
@@ -1626,11 +1665,15 @@ struct cfg80211_wowlan { | |||
1626 | * frame triggers an 802.3 frame should be reported, for | 1665 | * frame triggers an 802.3 frame should be reported, for |
1627 | * disconnect due to deauth 802.11 frame. This indicates which | 1666 | * disconnect due to deauth 802.11 frame. This indicates which |
1628 | * it is. | 1667 | * it is. |
1668 | * @tcp_match: TCP wakeup packet received | ||
1669 | * @tcp_connlost: TCP connection lost or failed to establish | ||
1670 | * @tcp_nomoretokens: TCP data ran out of tokens | ||
1629 | */ | 1671 | */ |
1630 | struct cfg80211_wowlan_wakeup { | 1672 | struct cfg80211_wowlan_wakeup { |
1631 | bool disconnect, magic_pkt, gtk_rekey_failure, | 1673 | bool disconnect, magic_pkt, gtk_rekey_failure, |
1632 | eap_identity_req, four_way_handshake, | 1674 | eap_identity_req, four_way_handshake, |
1633 | rfkill_release, packet_80211; | 1675 | rfkill_release, packet_80211, |
1676 | tcp_match, tcp_connlost, tcp_nomoretokens; | ||
1634 | s32 pattern_idx; | 1677 | s32 pattern_idx; |
1635 | u32 packet_present_len, packet_len; | 1678 | u32 packet_present_len, packet_len; |
1636 | const void *packet; | 1679 | const void *packet; |
@@ -2285,6 +2328,14 @@ enum wiphy_wowlan_support_flags { | |||
2285 | WIPHY_WOWLAN_RFKILL_RELEASE = BIT(7), | 2328 | WIPHY_WOWLAN_RFKILL_RELEASE = BIT(7), |
2286 | }; | 2329 | }; |
2287 | 2330 | ||
2331 | struct wiphy_wowlan_tcp_support { | ||
2332 | const struct nl80211_wowlan_tcp_data_token_feature *tok; | ||
2333 | u32 data_payload_max; | ||
2334 | u32 data_interval_max; | ||
2335 | u32 wake_payload_max; | ||
2336 | bool seq; | ||
2337 | }; | ||
2338 | |||
2288 | /** | 2339 | /** |
2289 | * struct wiphy_wowlan_support - WoWLAN support data | 2340 | * struct wiphy_wowlan_support - WoWLAN support data |
2290 | * @flags: see &enum wiphy_wowlan_support_flags | 2341 | * @flags: see &enum wiphy_wowlan_support_flags |
@@ -2293,6 +2344,7 @@ enum wiphy_wowlan_support_flags { | |||
2293 | * @pattern_max_len: maximum length of each pattern | 2344 | * @pattern_max_len: maximum length of each pattern |
2294 | * @pattern_min_len: minimum length of each pattern | 2345 | * @pattern_min_len: minimum length of each pattern |
2295 | * @max_pkt_offset: maximum Rx packet offset | 2346 | * @max_pkt_offset: maximum Rx packet offset |
2347 | * @tcp: TCP wakeup support information | ||
2296 | */ | 2348 | */ |
2297 | struct wiphy_wowlan_support { | 2349 | struct wiphy_wowlan_support { |
2298 | u32 flags; | 2350 | u32 flags; |
@@ -2300,6 +2352,7 @@ struct wiphy_wowlan_support { | |||
2300 | int pattern_max_len; | 2352 | int pattern_max_len; |
2301 | int pattern_min_len; | 2353 | int pattern_min_len; |
2302 | int max_pkt_offset; | 2354 | int max_pkt_offset; |
2355 | const struct wiphy_wowlan_tcp_support *tcp; | ||
2303 | }; | 2356 | }; |
2304 | 2357 | ||
2305 | /** | 2358 | /** |
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index eb7b32247ec5..5309b34930ea 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -2991,6 +2991,17 @@ struct nl80211_wowlan_pattern_support { | |||
2991 | * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN: Original length of the 802.3 | 2991 | * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN: Original length of the 802.3 |
2992 | * packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023 | 2992 | * packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023 |
2993 | * attribute if the packet was truncated somewhere. | 2993 | * attribute if the packet was truncated somewhere. |
2994 | * @NL80211_WOWLAN_TRIG_TCP_CONNECTION: TCP connection wake, see DOC section | ||
2995 | * "TCP connection wakeup" for more details. This is a nested attribute | ||
2996 | * containing the exact information for establishing and keeping alive | ||
2997 | * the TCP connection. | ||
2998 | * @NL80211_WOWLAN_TRIG_TCP_WAKEUP_MATCH: For wakeup reporting only, the | ||
2999 | * wakeup packet was received on the TCP connection | ||
3000 | * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST: For wakeup reporting only, the | ||
3001 | * TCP connection was lost or failed to be established | ||
3002 | * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS: For wakeup reporting only, | ||
3003 | * the TCP connection ran out of tokens to use for data to send to the | ||
3004 | * service | ||
2994 | * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers | 3005 | * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers |
2995 | * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number | 3006 | * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number |
2996 | * | 3007 | * |
@@ -3012,6 +3023,10 @@ enum nl80211_wowlan_triggers { | |||
3012 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN, | 3023 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN, |
3013 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023, | 3024 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023, |
3014 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN, | 3025 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN, |
3026 | NL80211_WOWLAN_TRIG_TCP_CONNECTION, | ||
3027 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH, | ||
3028 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST, | ||
3029 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS, | ||
3015 | 3030 | ||
3016 | /* keep last */ | 3031 | /* keep last */ |
3017 | NUM_NL80211_WOWLAN_TRIG, | 3032 | NUM_NL80211_WOWLAN_TRIG, |
@@ -3019,6 +3034,116 @@ enum nl80211_wowlan_triggers { | |||
3019 | }; | 3034 | }; |
3020 | 3035 | ||
3021 | /** | 3036 | /** |
3037 | * DOC: TCP connection wakeup | ||
3038 | * | ||
3039 | * Some devices can establish a TCP connection in order to be woken up by a | ||
3040 | * packet coming in from outside their network segment, or behind NAT. If | ||
3041 | * configured, the device will establish a TCP connection to the given | ||
3042 | * service, and periodically send data to that service. The first data | ||
3043 | * packet is usually transmitted after SYN/ACK, also ACKing the SYN/ACK. | ||
3044 | * The data packets can optionally include a (little endian) sequence | ||
3045 | * number (in the TCP payload!) that is generated by the device, and, also | ||
3046 | * optionally, a token from a list of tokens. This serves as a keep-alive | ||
3047 | * with the service, and for NATed connections, etc. | ||
3048 | * | ||
3049 | * During this keep-alive period, the server doesn't send any data to the | ||
3050 | * client. When receiving data, it is compared against the wakeup pattern | ||
3051 | * (and mask) and if it matches, the host is woken up. Similarly, if the | ||
3052 | * connection breaks or cannot be established to start with, the host is | ||
3053 | * also woken up. | ||
3054 | * | ||
3055 | * Developer's note: ARP offload is required for this, otherwise TCP | ||
3056 | * response packets might not go through correctly. | ||
3057 | */ | ||
3058 | |||
3059 | /** | ||
3060 | * struct nl80211_wowlan_tcp_data_seq - WoWLAN TCP data sequence | ||
3061 | * @start: starting value | ||
3062 | * @offset: offset of sequence number in packet | ||
3063 | * @len: length of the sequence value to write, 1 through 4 | ||
3064 | * | ||
3065 | * Note: don't confuse with the TCP sequence number(s), this is for the | ||
3066 | * keepalive packet payload. The actual value is written into the packet | ||
3067 | * in little endian. | ||
3068 | */ | ||
3069 | struct nl80211_wowlan_tcp_data_seq { | ||
3070 | __u32 start, offset, len; | ||
3071 | }; | ||
3072 | |||
3073 | /** | ||
3074 | * struct nl80211_wowlan_tcp_data_token - WoWLAN TCP data token config | ||
3075 | * @offset: offset of token in packet | ||
3076 | * @len: length of each token | ||
3077 | * @token_stream: stream of data to be used for the tokens, the length must | ||
3078 | * be a multiple of @len for this to make sense | ||
3079 | */ | ||
3080 | struct nl80211_wowlan_tcp_data_token { | ||
3081 | __u32 offset, len; | ||
3082 | __u8 token_stream[]; | ||
3083 | }; | ||
3084 | |||
3085 | /** | ||
3086 | * struct nl80211_wowlan_tcp_data_token_feature - data token features | ||
3087 | * @min_len: minimum token length | ||
3088 | * @max_len: maximum token length | ||
3089 | * @bufsize: total available token buffer size (max size of @token_stream) | ||
3090 | */ | ||
3091 | struct nl80211_wowlan_tcp_data_token_feature { | ||
3092 | __u32 min_len, max_len, bufsize; | ||
3093 | }; | ||
3094 | |||
3095 | /** | ||
3096 | * enum nl80211_wowlan_tcp_attrs - WoWLAN TCP connection parameters | ||
3097 | * @__NL80211_WOWLAN_TCP_INVALID: invalid number for nested attributes | ||
3098 | * @NL80211_WOWLAN_TCP_SRC_IPV4: source IPv4 address (in network byte order) | ||
3099 | * @NL80211_WOWLAN_TCP_DST_IPV4: destination IPv4 address | ||
3100 | * (in network byte order) | ||
3101 | * @NL80211_WOWLAN_TCP_DST_MAC: destination MAC address, this is given because | ||
3102 | * route lookup when configured might be invalid by the time we suspend, | ||
3103 | * and doing a route lookup when suspending is no longer possible as it | ||
3104 | * might require ARP querying. | ||
3105 | * @NL80211_WOWLAN_TCP_SRC_PORT: source port (u16); optional, if not given a | ||
3106 | * socket and port will be allocated | ||
3107 | * @NL80211_WOWLAN_TCP_DST_PORT: destination port (u16) | ||
3108 | * @NL80211_WOWLAN_TCP_DATA_PAYLOAD: data packet payload, at least one byte. | ||
3109 | * For feature advertising, a u32 attribute holding the maximum length | ||
3110 | * of the data payload. | ||
3111 | * @NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ: data packet sequence configuration | ||
3112 | * (if desired), a &struct nl80211_wowlan_tcp_data_seq. For feature | ||
3113 | * advertising it is just a flag | ||
3114 | * @NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN: data packet token configuration, | ||
3115 | * see &struct nl80211_wowlan_tcp_data_token and for advertising see | ||
3116 | * &struct nl80211_wowlan_tcp_data_token_feature. | ||
3117 | * @NL80211_WOWLAN_TCP_DATA_INTERVAL: data interval in seconds, maximum | ||
3118 | * interval in feature advertising (u32) | ||
3119 | * @NL80211_WOWLAN_TCP_WAKE_PAYLOAD: wake packet payload, for advertising a | ||
3120 | * u32 attribute holding the maximum length | ||
3121 | * @NL80211_WOWLAN_TCP_WAKE_MASK: Wake packet payload mask, not used for | ||
3122 | * feature advertising. The mask works like @NL80211_WOWLAN_PKTPAT_MASK | ||
3123 | * but on the TCP payload only. | ||
3124 | * @NUM_NL80211_WOWLAN_TCP: number of TCP attributes | ||
3125 | * @MAX_NL80211_WOWLAN_TCP: highest attribute number | ||
3126 | */ | ||
3127 | enum nl80211_wowlan_tcp_attrs { | ||
3128 | __NL80211_WOWLAN_TCP_INVALID, | ||
3129 | NL80211_WOWLAN_TCP_SRC_IPV4, | ||
3130 | NL80211_WOWLAN_TCP_DST_IPV4, | ||
3131 | NL80211_WOWLAN_TCP_DST_MAC, | ||
3132 | NL80211_WOWLAN_TCP_SRC_PORT, | ||
3133 | NL80211_WOWLAN_TCP_DST_PORT, | ||
3134 | NL80211_WOWLAN_TCP_DATA_PAYLOAD, | ||
3135 | NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ, | ||
3136 | NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, | ||
3137 | NL80211_WOWLAN_TCP_DATA_INTERVAL, | ||
3138 | NL80211_WOWLAN_TCP_WAKE_PAYLOAD, | ||
3139 | NL80211_WOWLAN_TCP_WAKE_MASK, | ||
3140 | |||
3141 | /* keep last */ | ||
3142 | NUM_NL80211_WOWLAN_TCP, | ||
3143 | MAX_NL80211_WOWLAN_TCP = NUM_NL80211_WOWLAN_TCP - 1 | ||
3144 | }; | ||
3145 | |||
3146 | /** | ||
3022 | * enum nl80211_iface_limit_attrs - limit attributes | 3147 | * enum nl80211_iface_limit_attrs - limit attributes |
3023 | * @NL80211_IFACE_LIMIT_UNSPEC: (reserved) | 3148 | * @NL80211_IFACE_LIMIT_UNSPEC: (reserved) |
3024 | * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that | 3149 | * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 37d70dc2fe82..949c9573d8d7 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -108,6 +108,9 @@ cfg80211_rdev_free_wowlan(struct cfg80211_registered_device *rdev) | |||
108 | for (i = 0; i < rdev->wowlan->n_patterns; i++) | 108 | for (i = 0; i < rdev->wowlan->n_patterns; i++) |
109 | kfree(rdev->wowlan->patterns[i].mask); | 109 | kfree(rdev->wowlan->patterns[i].mask); |
110 | kfree(rdev->wowlan->patterns); | 110 | kfree(rdev->wowlan->patterns); |
111 | if (rdev->wowlan->tcp && rdev->wowlan->tcp->sock) | ||
112 | sock_release(rdev->wowlan->tcp->sock); | ||
113 | kfree(rdev->wowlan->tcp); | ||
111 | kfree(rdev->wowlan); | 114 | kfree(rdev->wowlan); |
112 | } | 115 | } |
113 | 116 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index cc0fad30b8c9..d29a461b4981 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <net/genetlink.h> | 19 | #include <net/genetlink.h> |
20 | #include <net/cfg80211.h> | 20 | #include <net/cfg80211.h> |
21 | #include <net/sock.h> | 21 | #include <net/sock.h> |
22 | #include <net/inet_connection_sock.h> | ||
22 | #include "core.h" | 23 | #include "core.h" |
23 | #include "nl80211.h" | 24 | #include "nl80211.h" |
24 | #include "reg.h" | 25 | #include "reg.h" |
@@ -399,6 +400,26 @@ nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { | |||
399 | [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG }, | 400 | [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG }, |
400 | [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, | 401 | [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, |
401 | [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, | 402 | [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, |
403 | [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED }, | ||
404 | }; | ||
405 | |||
406 | static const struct nla_policy | ||
407 | nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = { | ||
408 | [NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 }, | ||
409 | [NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 }, | ||
410 | [NL80211_WOWLAN_TCP_DST_MAC] = { .len = ETH_ALEN }, | ||
411 | [NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 }, | ||
412 | [NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 }, | ||
413 | [NL80211_WOWLAN_TCP_DATA_PAYLOAD] = { .len = 1 }, | ||
414 | [NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ] = { | ||
415 | .len = sizeof(struct nl80211_wowlan_tcp_data_seq) | ||
416 | }, | ||
417 | [NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN] = { | ||
418 | .len = sizeof(struct nl80211_wowlan_tcp_data_token) | ||
419 | }, | ||
420 | [NL80211_WOWLAN_TCP_DATA_INTERVAL] = { .type = NLA_U32 }, | ||
421 | [NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .len = 1 }, | ||
422 | [NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 }, | ||
402 | }; | 423 | }; |
403 | 424 | ||
404 | /* policy for GTK rekey offload attributes */ | 425 | /* policy for GTK rekey offload attributes */ |
@@ -872,6 +893,48 @@ nla_put_failure: | |||
872 | return -ENOBUFS; | 893 | return -ENOBUFS; |
873 | } | 894 | } |
874 | 895 | ||
896 | #ifdef CONFIG_PM | ||
897 | static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev, | ||
898 | struct sk_buff *msg) | ||
899 | { | ||
900 | const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan.tcp; | ||
901 | struct nlattr *nl_tcp; | ||
902 | |||
903 | if (!tcp) | ||
904 | return 0; | ||
905 | |||
906 | nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION); | ||
907 | if (!nl_tcp) | ||
908 | return -ENOBUFS; | ||
909 | |||
910 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, | ||
911 | tcp->data_payload_max)) | ||
912 | return -ENOBUFS; | ||
913 | |||
914 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, | ||
915 | tcp->data_payload_max)) | ||
916 | return -ENOBUFS; | ||
917 | |||
918 | if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ)) | ||
919 | return -ENOBUFS; | ||
920 | |||
921 | if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, | ||
922 | sizeof(*tcp->tok), tcp->tok)) | ||
923 | return -ENOBUFS; | ||
924 | |||
925 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL, | ||
926 | tcp->data_interval_max)) | ||
927 | return -ENOBUFS; | ||
928 | |||
929 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD, | ||
930 | tcp->wake_payload_max)) | ||
931 | return -ENOBUFS; | ||
932 | |||
933 | nla_nest_end(msg, nl_tcp); | ||
934 | return 0; | ||
935 | } | ||
936 | #endif | ||
937 | |||
875 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flags, | 938 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flags, |
876 | struct cfg80211_registered_device *dev) | 939 | struct cfg80211_registered_device *dev) |
877 | { | 940 | { |
@@ -1246,6 +1309,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag | |||
1246 | goto nla_put_failure; | 1309 | goto nla_put_failure; |
1247 | } | 1310 | } |
1248 | 1311 | ||
1312 | if (nl80211_send_wowlan_tcp_caps(dev, msg)) | ||
1313 | goto nla_put_failure; | ||
1314 | |||
1249 | nla_nest_end(msg, nl_wowlan); | 1315 | nla_nest_end(msg, nl_wowlan); |
1250 | } | 1316 | } |
1251 | #endif | 1317 | #endif |
@@ -6930,16 +6996,67 @@ static int nl80211_send_wowlan_patterns(struct sk_buff *msg, | |||
6930 | return 0; | 6996 | return 0; |
6931 | } | 6997 | } |
6932 | 6998 | ||
6999 | static int nl80211_send_wowlan_tcp(struct sk_buff *msg, | ||
7000 | struct cfg80211_wowlan_tcp *tcp) | ||
7001 | { | ||
7002 | struct nlattr *nl_tcp; | ||
7003 | |||
7004 | if (!tcp) | ||
7005 | return 0; | ||
7006 | |||
7007 | nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION); | ||
7008 | if (!nl_tcp) | ||
7009 | return -ENOBUFS; | ||
7010 | |||
7011 | if (nla_put_be32(msg, NL80211_WOWLAN_TCP_SRC_IPV4, tcp->src) || | ||
7012 | nla_put_be32(msg, NL80211_WOWLAN_TCP_DST_IPV4, tcp->dst) || | ||
7013 | nla_put(msg, NL80211_WOWLAN_TCP_DST_MAC, ETH_ALEN, tcp->dst_mac) || | ||
7014 | nla_put_u16(msg, NL80211_WOWLAN_TCP_SRC_PORT, tcp->src_port) || | ||
7015 | nla_put_u16(msg, NL80211_WOWLAN_TCP_DST_PORT, tcp->dst_port) || | ||
7016 | nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, | ||
7017 | tcp->payload_len, tcp->payload) || | ||
7018 | nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL, | ||
7019 | tcp->data_interval) || | ||
7020 | nla_put(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD, | ||
7021 | tcp->wake_len, tcp->wake_data) || | ||
7022 | nla_put(msg, NL80211_WOWLAN_TCP_WAKE_MASK, | ||
7023 | DIV_ROUND_UP(tcp->wake_len, 8), tcp->wake_mask)) | ||
7024 | return -ENOBUFS; | ||
7025 | |||
7026 | if (tcp->payload_seq.len && | ||
7027 | nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ, | ||
7028 | sizeof(tcp->payload_seq), &tcp->payload_seq)) | ||
7029 | return -ENOBUFS; | ||
7030 | |||
7031 | if (tcp->payload_tok.len && | ||
7032 | nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, | ||
7033 | sizeof(tcp->payload_tok) + tcp->tokens_size, | ||
7034 | &tcp->payload_tok)) | ||
7035 | return -ENOBUFS; | ||
7036 | |||
7037 | return 0; | ||
7038 | } | ||
7039 | |||
6933 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | 7040 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) |
6934 | { | 7041 | { |
6935 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 7042 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
6936 | struct sk_buff *msg; | 7043 | struct sk_buff *msg; |
6937 | void *hdr; | 7044 | void *hdr; |
7045 | u32 size = NLMSG_DEFAULT_SIZE; | ||
6938 | 7046 | ||
6939 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) | 7047 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns && |
7048 | !rdev->wiphy.wowlan.tcp) | ||
6940 | return -EOPNOTSUPP; | 7049 | return -EOPNOTSUPP; |
6941 | 7050 | ||
6942 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 7051 | if (rdev->wowlan && rdev->wowlan->tcp) { |
7052 | /* adjust size to have room for all the data */ | ||
7053 | size += rdev->wowlan->tcp->tokens_size + | ||
7054 | rdev->wowlan->tcp->payload_len + | ||
7055 | rdev->wowlan->tcp->wake_len + | ||
7056 | rdev->wowlan->tcp->wake_len / 8; | ||
7057 | } | ||
7058 | |||
7059 | msg = nlmsg_new(size, GFP_KERNEL); | ||
6943 | if (!msg) | 7060 | if (!msg) |
6944 | return -ENOMEM; | 7061 | return -ENOMEM; |
6945 | 7062 | ||
@@ -6970,8 +7087,13 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6970 | (rdev->wowlan->rfkill_release && | 7087 | (rdev->wowlan->rfkill_release && |
6971 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) | 7088 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) |
6972 | goto nla_put_failure; | 7089 | goto nla_put_failure; |
7090 | |||
6973 | if (nl80211_send_wowlan_patterns(msg, rdev)) | 7091 | if (nl80211_send_wowlan_patterns(msg, rdev)) |
6974 | goto nla_put_failure; | 7092 | goto nla_put_failure; |
7093 | |||
7094 | if (nl80211_send_wowlan_tcp(msg, rdev->wowlan->tcp)) | ||
7095 | goto nla_put_failure; | ||
7096 | |||
6975 | nla_nest_end(msg, nl_wowlan); | 7097 | nla_nest_end(msg, nl_wowlan); |
6976 | } | 7098 | } |
6977 | 7099 | ||
@@ -6983,6 +7105,150 @@ nla_put_failure: | |||
6983 | return -ENOBUFS; | 7105 | return -ENOBUFS; |
6984 | } | 7106 | } |
6985 | 7107 | ||
7108 | static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev, | ||
7109 | struct nlattr *attr, | ||
7110 | struct cfg80211_wowlan *trig) | ||
7111 | { | ||
7112 | struct nlattr *tb[NUM_NL80211_WOWLAN_TCP]; | ||
7113 | struct cfg80211_wowlan_tcp *cfg; | ||
7114 | struct nl80211_wowlan_tcp_data_token *tok = NULL; | ||
7115 | struct nl80211_wowlan_tcp_data_seq *seq = NULL; | ||
7116 | u32 size; | ||
7117 | u32 data_size, wake_size, tokens_size = 0, wake_mask_size; | ||
7118 | int err, port; | ||
7119 | |||
7120 | if (!rdev->wiphy.wowlan.tcp) | ||
7121 | return -EINVAL; | ||
7122 | |||
7123 | err = nla_parse(tb, MAX_NL80211_WOWLAN_TCP, | ||
7124 | nla_data(attr), nla_len(attr), | ||
7125 | nl80211_wowlan_tcp_policy); | ||
7126 | if (err) | ||
7127 | return err; | ||
7128 | |||
7129 | if (!tb[NL80211_WOWLAN_TCP_SRC_IPV4] || | ||
7130 | !tb[NL80211_WOWLAN_TCP_DST_IPV4] || | ||
7131 | !tb[NL80211_WOWLAN_TCP_DST_MAC] || | ||
7132 | !tb[NL80211_WOWLAN_TCP_DST_PORT] || | ||
7133 | !tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD] || | ||
7134 | !tb[NL80211_WOWLAN_TCP_DATA_INTERVAL] || | ||
7135 | !tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] || | ||
7136 | !tb[NL80211_WOWLAN_TCP_WAKE_MASK]) | ||
7137 | return -EINVAL; | ||
7138 | |||
7139 | data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]); | ||
7140 | if (data_size > rdev->wiphy.wowlan.tcp->data_payload_max) | ||
7141 | return -EINVAL; | ||
7142 | |||
7143 | if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) > | ||
7144 | rdev->wiphy.wowlan.tcp->data_interval_max) | ||
7145 | return -EINVAL; | ||
7146 | |||
7147 | wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]); | ||
7148 | if (wake_size > rdev->wiphy.wowlan.tcp->wake_payload_max) | ||
7149 | return -EINVAL; | ||
7150 | |||
7151 | wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]); | ||
7152 | if (wake_mask_size != DIV_ROUND_UP(wake_size, 8)) | ||
7153 | return -EINVAL; | ||
7154 | |||
7155 | if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]) { | ||
7156 | u32 tokln = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]); | ||
7157 | |||
7158 | tok = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]); | ||
7159 | tokens_size = tokln - sizeof(*tok); | ||
7160 | |||
7161 | if (!tok->len || tokens_size % tok->len) | ||
7162 | return -EINVAL; | ||
7163 | if (!rdev->wiphy.wowlan.tcp->tok) | ||
7164 | return -EINVAL; | ||
7165 | if (tok->len > rdev->wiphy.wowlan.tcp->tok->max_len) | ||
7166 | return -EINVAL; | ||
7167 | if (tok->len < rdev->wiphy.wowlan.tcp->tok->min_len) | ||
7168 | return -EINVAL; | ||
7169 | if (tokens_size > rdev->wiphy.wowlan.tcp->tok->bufsize) | ||
7170 | return -EINVAL; | ||
7171 | if (tok->offset + tok->len > data_size) | ||
7172 | return -EINVAL; | ||
7173 | } | ||
7174 | |||
7175 | if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) { | ||
7176 | seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]); | ||
7177 | if (!rdev->wiphy.wowlan.tcp->seq) | ||
7178 | return -EINVAL; | ||
7179 | if (seq->len == 0 || seq->len > 4) | ||
7180 | return -EINVAL; | ||
7181 | if (seq->len + seq->offset > data_size) | ||
7182 | return -EINVAL; | ||
7183 | } | ||
7184 | |||
7185 | size = sizeof(*cfg); | ||
7186 | size += data_size; | ||
7187 | size += wake_size + wake_mask_size; | ||
7188 | size += tokens_size; | ||
7189 | |||
7190 | cfg = kzalloc(size, GFP_KERNEL); | ||
7191 | if (!cfg) | ||
7192 | return -ENOMEM; | ||
7193 | cfg->src = nla_get_be32(tb[NL80211_WOWLAN_TCP_SRC_IPV4]); | ||
7194 | cfg->dst = nla_get_be32(tb[NL80211_WOWLAN_TCP_DST_IPV4]); | ||
7195 | memcpy(cfg->dst_mac, nla_data(tb[NL80211_WOWLAN_TCP_DST_MAC]), | ||
7196 | ETH_ALEN); | ||
7197 | if (tb[NL80211_WOWLAN_TCP_SRC_PORT]) | ||
7198 | port = nla_get_u16(tb[NL80211_WOWLAN_TCP_SRC_PORT]); | ||
7199 | else | ||
7200 | port = 0; | ||
7201 | #ifdef CONFIG_INET | ||
7202 | /* allocate a socket and port for it and use it */ | ||
7203 | err = __sock_create(wiphy_net(&rdev->wiphy), PF_INET, SOCK_STREAM, | ||
7204 | IPPROTO_TCP, &cfg->sock, 1); | ||
7205 | if (err) { | ||
7206 | kfree(cfg); | ||
7207 | return err; | ||
7208 | } | ||
7209 | if (inet_csk_get_port(cfg->sock->sk, port)) { | ||
7210 | sock_release(cfg->sock); | ||
7211 | kfree(cfg); | ||
7212 | return -EADDRINUSE; | ||
7213 | } | ||
7214 | cfg->src_port = inet_sk(cfg->sock->sk)->inet_num; | ||
7215 | #else | ||
7216 | if (!port) { | ||
7217 | kfree(cfg); | ||
7218 | return -EINVAL; | ||
7219 | } | ||
7220 | cfg->src_port = port; | ||
7221 | #endif | ||
7222 | |||
7223 | cfg->dst_port = nla_get_u16(tb[NL80211_WOWLAN_TCP_DST_PORT]); | ||
7224 | cfg->payload_len = data_size; | ||
7225 | cfg->payload = (u8 *)cfg + sizeof(*cfg) + tokens_size; | ||
7226 | memcpy((void *)cfg->payload, | ||
7227 | nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]), | ||
7228 | data_size); | ||
7229 | if (seq) | ||
7230 | cfg->payload_seq = *seq; | ||
7231 | cfg->data_interval = nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]); | ||
7232 | cfg->wake_len = wake_size; | ||
7233 | cfg->wake_data = (u8 *)cfg + sizeof(*cfg) + tokens_size + data_size; | ||
7234 | memcpy((void *)cfg->wake_data, | ||
7235 | nla_data(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]), | ||
7236 | wake_size); | ||
7237 | cfg->wake_mask = (u8 *)cfg + sizeof(*cfg) + tokens_size + | ||
7238 | data_size + wake_size; | ||
7239 | memcpy((void *)cfg->wake_mask, | ||
7240 | nla_data(tb[NL80211_WOWLAN_TCP_WAKE_MASK]), | ||
7241 | wake_mask_size); | ||
7242 | if (tok) { | ||
7243 | cfg->tokens_size = tokens_size; | ||
7244 | memcpy(&cfg->payload_tok, tok, sizeof(*tok) + tokens_size); | ||
7245 | } | ||
7246 | |||
7247 | trig->tcp = cfg; | ||
7248 | |||
7249 | return 0; | ||
7250 | } | ||
7251 | |||
6986 | static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | 7252 | static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) |
6987 | { | 7253 | { |
6988 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 7254 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -6993,7 +7259,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6993 | int err, i; | 7259 | int err, i; |
6994 | bool prev_enabled = rdev->wowlan; | 7260 | bool prev_enabled = rdev->wowlan; |
6995 | 7261 | ||
6996 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) | 7262 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns && |
7263 | !rdev->wiphy.wowlan.tcp) | ||
6997 | return -EOPNOTSUPP; | 7264 | return -EOPNOTSUPP; |
6998 | 7265 | ||
6999 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { | 7266 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { |
@@ -7120,6 +7387,14 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7120 | } | 7387 | } |
7121 | } | 7388 | } |
7122 | 7389 | ||
7390 | if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) { | ||
7391 | err = nl80211_parse_wowlan_tcp( | ||
7392 | rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION], | ||
7393 | &new_triggers); | ||
7394 | if (err) | ||
7395 | goto error; | ||
7396 | } | ||
7397 | |||
7123 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); | 7398 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); |
7124 | if (!ntrig) { | 7399 | if (!ntrig) { |
7125 | err = -ENOMEM; | 7400 | err = -ENOMEM; |
@@ -7137,6 +7412,9 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7137 | for (i = 0; i < new_triggers.n_patterns; i++) | 7412 | for (i = 0; i < new_triggers.n_patterns; i++) |
7138 | kfree(new_triggers.patterns[i].mask); | 7413 | kfree(new_triggers.patterns[i].mask); |
7139 | kfree(new_triggers.patterns); | 7414 | kfree(new_triggers.patterns); |
7415 | if (new_triggers.tcp && new_triggers.tcp->sock) | ||
7416 | sock_release(new_triggers.tcp->sock); | ||
7417 | kfree(new_triggers.tcp); | ||
7140 | return err; | 7418 | return err; |
7141 | } | 7419 | } |
7142 | #endif | 7420 | #endif |
@@ -9418,6 +9696,17 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, | |||
9418 | wakeup->pattern_idx)) | 9696 | wakeup->pattern_idx)) |
9419 | goto free_msg; | 9697 | goto free_msg; |
9420 | 9698 | ||
9699 | if (wakeup->tcp_match) | ||
9700 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH); | ||
9701 | |||
9702 | if (wakeup->tcp_connlost) | ||
9703 | nla_put_flag(msg, | ||
9704 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST); | ||
9705 | |||
9706 | if (wakeup->tcp_nomoretokens) | ||
9707 | nla_put_flag(msg, | ||
9708 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS); | ||
9709 | |||
9421 | if (wakeup->packet) { | 9710 | if (wakeup->packet) { |
9422 | u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211; | 9711 | u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211; |
9423 | u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN; | 9712 | u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN; |