aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-01-23 16:57:40 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-02-13 08:33:42 -0500
commit2a0e047ed62f20664005881b8e7f9328f910316a (patch)
tree166497ddbe4dea57a2d816d4fb928b3f8558b3aa /net/wireless
parenta0497f9f57478c5a37c5628eb32833dd9729a821 (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.h3
-rw-r--r--net/wireless/nl80211.c295
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
406static const struct nla_policy
407nl80211_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
897static 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
875static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flags, 938static 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
6999static 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
6933static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) 7040static 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
7108static 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
6986static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) 7252static 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;