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