diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-01-23 16:57:40 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-02-13 08:33:42 -0500 |
commit | 2a0e047ed62f20664005881b8e7f9328f910316a (patch) | |
tree | 166497ddbe4dea57a2d816d4fb928b3f8558b3aa /net/wireless | |
parent | a0497f9f57478c5a37c5628eb32833dd9729a821 (diff) |
cfg80211: configuration for WoWLAN over TCP
Intel Wireless devices are able to make a TCP connection
after suspending, sending some data and waking up when
the connection receives wakeup data (or breaks). Add the
WoWLAN configuration and feature advertising API for it.
Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.h | 3 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 295 |
2 files changed, 295 insertions, 3 deletions
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; |