Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 1 | #include <net/if.h> |
| 2 | #include <errno.h> |
| 3 | #include <string.h> |
Johannes Berg | 819b78c | 2013-02-19 23:31:27 +0100 | [diff] [blame] | 4 | #include <stdio.h> |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 5 | |
| 6 | #include <netlink/genl/genl.h> |
| 7 | #include <netlink/genl/family.h> |
| 8 | #include <netlink/genl/ctrl.h> |
| 9 | #include <netlink/msg.h> |
| 10 | #include <netlink/attr.h> |
| 11 | |
Johannes Berg | 819b78c | 2013-02-19 23:31:27 +0100 | [diff] [blame] | 12 | #include <arpa/inet.h> |
| 13 | |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 14 | #include "nl80211.h" |
| 15 | #include "iw.h" |
| 16 | |
| 17 | SECTION(wowlan); |
| 18 | |
Johannes Berg | 819b78c | 2013-02-19 23:31:27 +0100 | [diff] [blame] | 19 | static int wowlan_parse_tcp_file(struct nl_msg *msg, const char *fn) |
| 20 | { |
| 21 | char buf[16768]; |
| 22 | int err = 1; |
| 23 | FILE *f = fopen(fn, "r"); |
| 24 | struct nlattr *tcp; |
| 25 | |
| 26 | if (!f) |
| 27 | return 1; |
| 28 | tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION); |
| 29 | if (!tcp) |
| 30 | goto nla_put_failure; |
| 31 | |
| 32 | while (!feof(f)) { |
| 33 | char *eol; |
| 34 | |
| 35 | if (!fgets(buf, sizeof(buf), f)) |
| 36 | break; |
| 37 | |
| 38 | eol = strchr(buf + 5, '\r'); |
| 39 | if (eol) |
| 40 | *eol = 0; |
| 41 | eol = strchr(buf + 5, '\n'); |
| 42 | if (eol) |
| 43 | *eol = 0; |
| 44 | |
| 45 | if (strncmp(buf, "source=", 7) == 0) { |
| 46 | struct in_addr in_addr; |
| 47 | char *addr = buf + 7; |
| 48 | char *port = strchr(buf + 7, ':'); |
| 49 | |
| 50 | if (port) { |
| 51 | *port = 0; |
| 52 | port++; |
| 53 | } |
| 54 | if (inet_aton(addr, &in_addr) == 0) |
| 55 | goto close; |
| 56 | NLA_PUT_U32(msg, NL80211_WOWLAN_TCP_SRC_IPV4, |
| 57 | in_addr.s_addr); |
| 58 | if (port) |
| 59 | NLA_PUT_U16(msg, NL80211_WOWLAN_TCP_SRC_PORT, |
| 60 | atoi(port)); |
| 61 | } else if (strncmp(buf, "dest=", 5) == 0) { |
| 62 | struct in_addr in_addr; |
| 63 | char *addr = buf + 5; |
| 64 | char *port = strchr(buf + 5, ':'); |
| 65 | char *mac; |
| 66 | unsigned char macbuf[6]; |
| 67 | |
| 68 | if (!port) |
| 69 | goto close; |
| 70 | *port = 0; |
| 71 | port++; |
| 72 | mac = strchr(port, '@'); |
| 73 | if (!mac) |
| 74 | goto close; |
| 75 | *mac = 0; |
| 76 | mac++; |
| 77 | if (inet_aton(addr, &in_addr) == 0) |
| 78 | goto close; |
| 79 | NLA_PUT_U32(msg, NL80211_WOWLAN_TCP_DST_IPV4, |
| 80 | in_addr.s_addr); |
| 81 | NLA_PUT_U16(msg, NL80211_WOWLAN_TCP_DST_PORT, |
| 82 | atoi(port)); |
| 83 | if (mac_addr_a2n(macbuf, mac)) |
| 84 | goto close; |
| 85 | NLA_PUT(msg, NL80211_WOWLAN_TCP_DST_MAC, |
| 86 | 6, macbuf); |
| 87 | } else if (strncmp(buf, "data=", 5) == 0) { |
| 88 | size_t len; |
| 89 | unsigned char *pkt = parse_hex(buf + 5, &len); |
| 90 | |
| 91 | if (!pkt) |
| 92 | goto close; |
| 93 | NLA_PUT(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, len, pkt); |
| 94 | free(pkt); |
| 95 | } else if (strncmp(buf, "data.interval=", 14) == 0) { |
| 96 | NLA_PUT_U32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL, |
Johannes Berg | 509a5e5 | 2013-02-26 13:54:32 +0100 | [diff] [blame] | 97 | atoi(buf + 14)); |
Johannes Berg | 819b78c | 2013-02-19 23:31:27 +0100 | [diff] [blame] | 98 | } else if (strncmp(buf, "wake=", 5) == 0) { |
| 99 | unsigned char *pat, *mask; |
| 100 | size_t patlen; |
| 101 | |
| 102 | if (parse_hex_mask(buf + 5, &pat, &patlen, &mask)) |
| 103 | goto close; |
| 104 | NLA_PUT(msg, NL80211_WOWLAN_TCP_WAKE_MASK, |
| 105 | DIV_ROUND_UP(patlen, 8), mask); |
| 106 | NLA_PUT(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD, |
| 107 | patlen, pat); |
| 108 | free(mask); |
| 109 | free(pat); |
| 110 | } else if (strncmp(buf, "data.seq=", 9) == 0) { |
| 111 | struct nl80211_wowlan_tcp_data_seq seq = {}; |
| 112 | char *len, *offs, *start; |
| 113 | |
| 114 | len = buf + 9; |
| 115 | offs = strchr(len, ','); |
| 116 | if (!offs) |
| 117 | goto close; |
| 118 | *offs = 0; |
| 119 | offs++; |
| 120 | start = strchr(offs, ','); |
| 121 | if (start) { |
| 122 | *start = 0; |
| 123 | start++; |
| 124 | seq.start = atoi(start); |
| 125 | } |
| 126 | seq.len = atoi(len); |
| 127 | seq.offset = atoi(offs); |
| 128 | |
| 129 | NLA_PUT(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ, |
| 130 | sizeof(seq), &seq); |
| 131 | } else if (strncmp(buf, "data.tok=", 9) == 0) { |
| 132 | struct nl80211_wowlan_tcp_data_token *tok; |
| 133 | size_t stream_len; |
| 134 | char *len, *offs, *toks; |
| 135 | unsigned char *stream; |
| 136 | |
| 137 | len = buf + 9; |
| 138 | offs = strchr(len, ','); |
| 139 | if (!offs) |
| 140 | goto close; |
| 141 | *offs = 0; |
| 142 | offs++; |
| 143 | toks = strchr(offs, ','); |
| 144 | if (!toks) |
| 145 | goto close; |
| 146 | *toks = 0; |
| 147 | toks++; |
| 148 | |
| 149 | stream = parse_hex(toks, &stream_len); |
| 150 | if (!stream) |
| 151 | goto close; |
| 152 | tok = malloc(sizeof(*tok) + stream_len); |
| 153 | if (!tok) { |
| 154 | free(stream); |
| 155 | err = -ENOMEM; |
| 156 | goto close; |
| 157 | } |
| 158 | |
| 159 | tok->len = atoi(len); |
| 160 | tok->offset = atoi(offs); |
| 161 | memcpy(tok->token_stream, stream, stream_len); |
| 162 | |
| 163 | NLA_PUT(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, |
| 164 | sizeof(*tok) + stream_len, tok); |
| 165 | free(stream); |
| 166 | free(tok); |
| 167 | } else { |
| 168 | if (buf[0] == '#') |
| 169 | continue; |
| 170 | goto close; |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | err = 0; |
| 175 | goto close; |
| 176 | nla_put_failure: |
| 177 | err = -ENOBUFS; |
| 178 | close: |
| 179 | fclose(f); |
| 180 | nla_nest_end(msg, tcp); |
| 181 | return err; |
| 182 | } |
| 183 | |
Luciano Coelho | d516c5b | 2014-11-28 23:05:55 +0200 | [diff] [blame] | 184 | static int wowlan_parse_net_detect(struct nl_msg *msg, int *argc, char ***argv) |
| 185 | { |
Luciano Coelho | b162228 | 2015-03-17 16:11:47 +0200 | [diff] [blame] | 186 | struct nlattr *nd; |
| 187 | int err = 0; |
Luciano Coelho | d516c5b | 2014-11-28 23:05:55 +0200 | [diff] [blame] | 188 | |
| 189 | nd = nla_nest_start(msg, NL80211_WOWLAN_TRIG_NET_DETECT); |
Luciano Coelho | b162228 | 2015-03-17 16:11:47 +0200 | [diff] [blame] | 190 | if (!nd) |
| 191 | return -ENOBUFS; |
Luciano Coelho | d516c5b | 2014-11-28 23:05:55 +0200 | [diff] [blame] | 192 | |
Luciano Coelho | b162228 | 2015-03-17 16:11:47 +0200 | [diff] [blame] | 193 | err = parse_sched_scan(msg, argc, argv); |
Luciano Coelho | d516c5b | 2014-11-28 23:05:55 +0200 | [diff] [blame] | 194 | |
Luciano Coelho | d516c5b | 2014-11-28 23:05:55 +0200 | [diff] [blame] | 195 | nla_nest_end(msg, nd); |
Luciano Coelho | b162228 | 2015-03-17 16:11:47 +0200 | [diff] [blame] | 196 | |
Luciano Coelho | d516c5b | 2014-11-28 23:05:55 +0200 | [diff] [blame] | 197 | return err; |
| 198 | } |
| 199 | |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 200 | static int handle_wowlan_enable(struct nl80211_state *state, struct nl_cb *cb, |
Johannes Berg | 05514f9 | 2012-07-19 11:50:50 +0200 | [diff] [blame] | 201 | struct nl_msg *msg, int argc, char **argv, |
| 202 | enum id_input id) |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 203 | { |
| 204 | struct nlattr *wowlan, *pattern; |
| 205 | struct nl_msg *patterns = NULL; |
| 206 | enum { |
| 207 | PS_REG, |
| 208 | PS_PAT, |
| 209 | } parse_state = PS_REG; |
| 210 | int err = -ENOBUFS; |
| 211 | unsigned char *pat, *mask; |
| 212 | size_t patlen; |
Amitkumar Karwar | 1c8f49c | 2013-02-19 16:44:44 -0800 | [diff] [blame] | 213 | int patnum = 0, pkt_offset; |
| 214 | char *eptr, *value1, *value2, *sptr = NULL; |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 215 | |
| 216 | wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS); |
| 217 | if (!wowlan) |
| 218 | return -ENOBUFS; |
| 219 | |
| 220 | while (argc) { |
| 221 | switch (parse_state) { |
| 222 | case PS_REG: |
| 223 | if (strcmp(argv[0], "any") == 0) |
| 224 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY); |
| 225 | else if (strcmp(argv[0], "disconnect") == 0) |
| 226 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); |
| 227 | else if (strcmp(argv[0], "magic-packet") == 0) |
| 228 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); |
Johannes Berg | 3a6636b | 2011-07-12 13:08:37 +0200 | [diff] [blame] | 229 | else if (strcmp(argv[0], "gtk-rekey-failure") == 0) |
| 230 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE); |
| 231 | else if (strcmp(argv[0], "eap-identity-request") == 0) |
| 232 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST); |
| 233 | else if (strcmp(argv[0], "4way-handshake") == 0) |
| 234 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE); |
| 235 | else if (strcmp(argv[0], "rfkill-release") == 0) |
| 236 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE); |
Johannes Berg | 819b78c | 2013-02-19 23:31:27 +0100 | [diff] [blame] | 237 | else if (strcmp(argv[0], "tcp") == 0) { |
| 238 | argv++; |
| 239 | argc--; |
| 240 | if (!argc) { |
| 241 | err = 1; |
| 242 | goto nla_put_failure; |
| 243 | } |
| 244 | err = wowlan_parse_tcp_file(msg, argv[0]); |
| 245 | if (err) |
| 246 | goto nla_put_failure; |
| 247 | } else if (strcmp(argv[0], "patterns") == 0) { |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 248 | parse_state = PS_PAT; |
| 249 | patterns = nlmsg_alloc(); |
| 250 | if (!patterns) { |
| 251 | err = -ENOMEM; |
| 252 | goto nla_put_failure; |
| 253 | } |
Luciano Coelho | d516c5b | 2014-11-28 23:05:55 +0200 | [diff] [blame] | 254 | } else if (strcmp(argv[0], "net-detect") == 0) { |
| 255 | argv++; |
| 256 | argc--; |
| 257 | if (!argc) { |
| 258 | err = 1; |
| 259 | goto nla_put_failure; |
| 260 | } |
| 261 | err = wowlan_parse_net_detect(msg, &argc, &argv); |
| 262 | if (err) |
| 263 | goto nla_put_failure; |
| 264 | continue; |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 265 | } else { |
| 266 | err = 1; |
| 267 | goto nla_put_failure; |
| 268 | } |
| 269 | break; |
| 270 | case PS_PAT: |
Amitkumar Karwar | 1c8f49c | 2013-02-19 16:44:44 -0800 | [diff] [blame] | 271 | value1 = strtok_r(argv[0], "+", &sptr); |
| 272 | value2 = strtok_r(NULL, "+", &sptr); |
| 273 | |
| 274 | if (!value2) { |
| 275 | pkt_offset = 0; |
| 276 | value2 = value1; |
| 277 | } else { |
| 278 | pkt_offset = strtoul(value1, &eptr, 10); |
| 279 | if (eptr != value1 + strlen(value1)) { |
| 280 | err = 1; |
| 281 | goto nla_put_failure; |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | if (parse_hex_mask(value2, &pat, &patlen, &mask)) { |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 286 | err = 1; |
| 287 | goto nla_put_failure; |
| 288 | } |
Amitkumar Karwar | 1c8f49c | 2013-02-19 16:44:44 -0800 | [diff] [blame] | 289 | |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 290 | pattern = nla_nest_start(patterns, ++patnum); |
Amitkumar Karwar | c82868d | 2013-06-28 12:53:44 -0700 | [diff] [blame] | 291 | NLA_PUT(patterns, NL80211_PKTPAT_MASK, |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 292 | DIV_ROUND_UP(patlen, 8), mask); |
Amitkumar Karwar | c82868d | 2013-06-28 12:53:44 -0700 | [diff] [blame] | 293 | NLA_PUT(patterns, NL80211_PKTPAT_PATTERN, patlen, pat); |
| 294 | NLA_PUT_U32(patterns, NL80211_PKTPAT_OFFSET, |
| 295 | pkt_offset); |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 296 | nla_nest_end(patterns, pattern); |
| 297 | free(mask); |
| 298 | free(pat); |
| 299 | break; |
| 300 | } |
| 301 | argv++; |
| 302 | argc--; |
| 303 | } |
| 304 | |
| 305 | if (patterns) |
| 306 | nla_put_nested(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, |
| 307 | patterns); |
| 308 | |
| 309 | nla_nest_end(msg, wowlan); |
| 310 | err = 0; |
| 311 | nla_put_failure: |
| 312 | nlmsg_free(patterns); |
| 313 | return err; |
| 314 | } |
Johannes Berg | 3a6636b | 2011-07-12 13:08:37 +0200 | [diff] [blame] | 315 | COMMAND(wowlan, enable, "[any] [disconnect] [magic-packet] [gtk-rekey-failure] [eap-identity-request]" |
Luciano Coelho | b162228 | 2015-03-17 16:11:47 +0200 | [diff] [blame] | 316 | " [4way-handshake] [rfkill-release] [net-detect " SCHED_SCAN_OPTIONS "]" |
Luciano Coelho | d516c5b | 2014-11-28 23:05:55 +0200 | [diff] [blame] | 317 | " [tcp <config-file>] [patterns [offset1+]<pattern1> ...]", |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 318 | NL80211_CMD_SET_WOWLAN, 0, CIB_PHY, handle_wowlan_enable, |
| 319 | "Enable WoWLAN with the given triggers.\n" |
| 320 | "Each pattern is given as a bytestring with '-' in places where any byte\n" |
| 321 | "may be present, e.g. 00:11:22:-:44 will match 00:11:22:33:44 and\n" |
Amitkumar Karwar | 1c8f49c | 2013-02-19 16:44:44 -0800 | [diff] [blame] | 322 | "00:11:22:33:ff:44 etc.\n" |
| 323 | "Offset and pattern should be separated by '+', e.g. 18+43:34:00:12 will match " |
| 324 | "'43:34:00:12' after 18 bytes of offset in Rx packet.\n\n" |
Johannes Berg | 819b78c | 2013-02-19 23:31:27 +0100 | [diff] [blame] | 325 | "The TCP configuration file contains:\n" |
| 326 | " source=ip[:port]\n" |
| 327 | " dest=ip:port@mac\n" |
| 328 | " data=<hex data packet>\n" |
| 329 | " data.interval=seconds\n" |
| 330 | " [wake=<hex packet with masked out bytes indicated by '-'>]\n" |
| 331 | " [data.seq=len,offset[,start]]\n" |
Luciano Coelho | d516c5b | 2014-11-28 23:05:55 +0200 | [diff] [blame] | 332 | " [data.tok=len,offset,<token stream>]\n\n" |
| 333 | "Net-detect configuration example:\n" |
Luciano Coelho | 29af201 | 2015-03-13 14:17:07 +0200 | [diff] [blame] | 334 | " iw phy0 wowlan enable net-detect interval 5000 delay 30 freqs 2412 2422 matches ssid foo ssid bar"); |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 335 | |
| 336 | |
| 337 | static int handle_wowlan_disable(struct nl80211_state *state, struct nl_cb *cb, |
Johannes Berg | 05514f9 | 2012-07-19 11:50:50 +0200 | [diff] [blame] | 338 | struct nl_msg *msg, int argc, char **argv, |
| 339 | enum id_input id) |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 340 | { |
| 341 | /* just a set w/o wowlan attribute */ |
| 342 | return 0; |
| 343 | } |
| 344 | COMMAND(wowlan, disable, "", NL80211_CMD_SET_WOWLAN, 0, CIB_PHY, handle_wowlan_disable, |
| 345 | "Disable WoWLAN."); |
| 346 | |
| 347 | |
| 348 | static int print_wowlan_handler(struct nl_msg *msg, void *arg) |
| 349 | { |
| 350 | struct nlattr *attrs[NL80211_ATTR_MAX + 1]; |
| 351 | struct nlattr *trig[NUM_NL80211_WOWLAN_TRIG]; |
| 352 | struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); |
| 353 | struct nlattr *pattern; |
| 354 | int rem_pattern; |
| 355 | |
| 356 | nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), |
| 357 | genlmsg_attrlen(gnlh, 0), NULL); |
| 358 | |
| 359 | if (!attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { |
| 360 | printf("WoWLAN is disabled.\n"); |
| 361 | return NL_SKIP; |
| 362 | } |
| 363 | |
| 364 | /* XXX: use policy */ |
| 365 | nla_parse(trig, MAX_NL80211_WOWLAN_TRIG, |
| 366 | nla_data(attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), |
| 367 | nla_len(attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), |
| 368 | NULL); |
| 369 | |
| 370 | printf("WoWLAN is enabled:\n"); |
| 371 | if (trig[NL80211_WOWLAN_TRIG_ANY]) |
| 372 | printf(" * wake up on special any trigger\n"); |
| 373 | if (trig[NL80211_WOWLAN_TRIG_DISCONNECT]) |
| 374 | printf(" * wake up on disconnect\n"); |
| 375 | if (trig[NL80211_WOWLAN_TRIG_MAGIC_PKT]) |
| 376 | printf(" * wake up on magic packet\n"); |
Johannes Berg | 3a6636b | 2011-07-12 13:08:37 +0200 | [diff] [blame] | 377 | if (trig[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) |
| 378 | printf(" * wake up on GTK rekeying failure\n"); |
| 379 | if (trig[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) |
| 380 | printf(" * wake up on EAP identity request\n"); |
| 381 | if (trig[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) |
| 382 | printf(" * wake up on 4-way handshake\n"); |
| 383 | if (trig[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) |
| 384 | printf(" * wake up on RF-kill release\n"); |
Luciano Coelho | d7d3928 | 2014-11-28 23:05:56 +0200 | [diff] [blame] | 385 | if (trig[NL80211_WOWLAN_TRIG_NET_DETECT]) { |
| 386 | struct nlattr *match, *freq, |
| 387 | *nd[NUM_NL80211_ATTR], *tb[NUM_NL80211_ATTR]; |
| 388 | int rem_match; |
| 389 | |
Luciano Coelho | d516c5b | 2014-11-28 23:05:55 +0200 | [diff] [blame] | 390 | printf(" * wake up on network detection\n"); |
David Ng | 5b32c1a | 2017-08-24 17:48:38 -0700 | [diff] [blame] | 391 | nla_parse(nd, NL80211_ATTR_MAX, |
Luciano Coelho | d7d3928 | 2014-11-28 23:05:56 +0200 | [diff] [blame] | 392 | nla_data(trig[NL80211_WOWLAN_TRIG_NET_DETECT]), |
| 393 | nla_len(trig[NL80211_WOWLAN_TRIG_NET_DETECT]), NULL); |
| 394 | |
| 395 | if (nd[NL80211_ATTR_SCHED_SCAN_INTERVAL]) |
Luciano Coelho | 29af201 | 2015-03-13 14:17:07 +0200 | [diff] [blame] | 396 | printf("\tscan interval: %u msecs\n", |
Luciano Coelho | d7d3928 | 2014-11-28 23:05:56 +0200 | [diff] [blame] | 397 | nla_get_u32(nd[NL80211_ATTR_SCHED_SCAN_INTERVAL])); |
| 398 | |
Luciano Coelho | 29af201 | 2015-03-13 14:17:07 +0200 | [diff] [blame] | 399 | if (nd[NL80211_ATTR_SCHED_SCAN_DELAY]) |
Stefan Lippers-Hollmann | f66320a | 2015-04-28 04:45:09 +0200 | [diff] [blame] | 400 | printf("\tinitial scan delay: %u secs\n", |
Luciano Coelho | 29af201 | 2015-03-13 14:17:07 +0200 | [diff] [blame] | 401 | nla_get_u32(nd[NL80211_ATTR_SCHED_SCAN_DELAY])); |
| 402 | |
Luciano Coelho | d7d3928 | 2014-11-28 23:05:56 +0200 | [diff] [blame] | 403 | if (nd[NL80211_ATTR_SCHED_SCAN_MATCH]) { |
| 404 | printf("\tmatches:\n"); |
| 405 | nla_for_each_nested(match, |
| 406 | nd[NL80211_ATTR_SCHED_SCAN_MATCH], |
| 407 | rem_match) { |
David Ng | 5b32c1a | 2017-08-24 17:48:38 -0700 | [diff] [blame] | 408 | nla_parse(tb, NL80211_ATTR_MAX, nla_data(match), |
Luciano Coelho | d7d3928 | 2014-11-28 23:05:56 +0200 | [diff] [blame] | 409 | nla_len(match), |
| 410 | NULL); |
| 411 | printf("\t\tSSID: "); |
| 412 | print_ssid_escaped( |
| 413 | nla_len(tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]), |
| 414 | nla_data(tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID])); |
| 415 | printf("\n"); |
| 416 | } |
| 417 | } |
| 418 | if (nd[NL80211_ATTR_SCAN_FREQUENCIES]) { |
| 419 | printf("\tfrequencies:"); |
| 420 | nla_for_each_nested(freq, |
| 421 | nd[NL80211_ATTR_SCAN_FREQUENCIES], |
| 422 | rem_match) { |
| 423 | printf(" %d", nla_get_u32(freq)); |
| 424 | } |
| 425 | printf("\n"); |
| 426 | } |
| 427 | } |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 428 | if (trig[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { |
| 429 | nla_for_each_nested(pattern, |
| 430 | trig[NL80211_WOWLAN_TRIG_PKT_PATTERN], |
| 431 | rem_pattern) { |
Amitkumar Karwar | c82868d | 2013-06-28 12:53:44 -0700 | [diff] [blame] | 432 | struct nlattr *patattr[NUM_NL80211_PKTPAT]; |
Johannes Berg | 19195f3 | 2014-04-10 09:42:30 +0200 | [diff] [blame] | 433 | int i, patlen, masklen; |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 434 | uint8_t *mask, *pat; |
Amitkumar Karwar | c82868d | 2013-06-28 12:53:44 -0700 | [diff] [blame] | 435 | nla_parse(patattr, MAX_NL80211_PKTPAT, |
| 436 | nla_data(pattern), nla_len(pattern), NULL); |
| 437 | if (!patattr[NL80211_PKTPAT_MASK] || |
Johannes Berg | 19195f3 | 2014-04-10 09:42:30 +0200 | [diff] [blame] | 438 | !patattr[NL80211_PKTPAT_PATTERN]) { |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 439 | printf(" * (invalid pattern specification)\n"); |
| 440 | continue; |
| 441 | } |
Amitkumar Karwar | c82868d | 2013-06-28 12:53:44 -0700 | [diff] [blame] | 442 | masklen = nla_len(patattr[NL80211_PKTPAT_MASK]); |
| 443 | patlen = nla_len(patattr[NL80211_PKTPAT_PATTERN]); |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 444 | if (DIV_ROUND_UP(patlen, 8) != masklen) { |
| 445 | printf(" * (invalid pattern specification)\n"); |
| 446 | continue; |
| 447 | } |
Johannes Berg | 19195f3 | 2014-04-10 09:42:30 +0200 | [diff] [blame] | 448 | if (patattr[NL80211_PKTPAT_OFFSET]) { |
| 449 | int pkt_offset = |
| 450 | nla_get_u32(patattr[NL80211_PKTPAT_OFFSET]); |
| 451 | printf(" * wake up on packet offset: %d", pkt_offset); |
| 452 | } |
Amitkumar Karwar | 1c8f49c | 2013-02-19 16:44:44 -0800 | [diff] [blame] | 453 | printf(" pattern: "); |
Amitkumar Karwar | c82868d | 2013-06-28 12:53:44 -0700 | [diff] [blame] | 454 | pat = nla_data(patattr[NL80211_PKTPAT_PATTERN]); |
| 455 | mask = nla_data(patattr[NL80211_PKTPAT_MASK]); |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 456 | for (i = 0; i < patlen; i++) { |
| 457 | if (mask[i / 8] & (1 << (i % 8))) |
| 458 | printf("%.2x", pat[i]); |
| 459 | else |
| 460 | printf("--"); |
| 461 | if (i != patlen - 1) |
| 462 | printf(":"); |
| 463 | } |
| 464 | printf("\n"); |
| 465 | } |
| 466 | } |
Johannes Berg | 819b78c | 2013-02-19 23:31:27 +0100 | [diff] [blame] | 467 | if (trig[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) |
| 468 | printf(" * wake up on TCP connection\n"); |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 469 | |
| 470 | return NL_SKIP; |
| 471 | } |
| 472 | |
| 473 | static int handle_wowlan_show(struct nl80211_state *state, struct nl_cb *cb, |
Johannes Berg | 05514f9 | 2012-07-19 11:50:50 +0200 | [diff] [blame] | 474 | struct nl_msg *msg, int argc, char **argv, |
| 475 | enum id_input id) |
Johannes Berg | 3ff2456 | 2011-04-12 13:04:50 +0200 | [diff] [blame] | 476 | { |
| 477 | nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, |
| 478 | print_wowlan_handler, NULL); |
| 479 | |
| 480 | return 0; |
| 481 | } |
| 482 | COMMAND(wowlan, show, "", NL80211_CMD_GET_WOWLAN, 0, CIB_PHY, handle_wowlan_show, |
| 483 | "Show WoWLAN status."); |