]> git.ipfire.org Git - thirdparty/iw.git/blob - wowlan.c
update nl80211.h
[thirdparty/iw.git] / wowlan.c
1 #include <net/if.h>
2 #include <errno.h>
3 #include <string.h>
4
5 #include <netlink/genl/genl.h>
6 #include <netlink/genl/family.h>
7 #include <netlink/genl/ctrl.h>
8 #include <netlink/msg.h>
9 #include <netlink/attr.h>
10
11 #include "nl80211.h"
12 #include "iw.h"
13
14 SECTION(wowlan);
15
16 static int handle_wowlan_enable(struct nl80211_state *state, struct nl_cb *cb,
17 struct nl_msg *msg, int argc, char **argv)
18 {
19 struct nlattr *wowlan, *pattern;
20 struct nl_msg *patterns = NULL;
21 enum {
22 PS_REG,
23 PS_PAT,
24 } parse_state = PS_REG;
25 int err = -ENOBUFS;
26 unsigned char *pat, *mask;
27 size_t patlen;
28 int patnum = 0;
29
30 wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
31 if (!wowlan)
32 return -ENOBUFS;
33
34 while (argc) {
35 switch (parse_state) {
36 case PS_REG:
37 if (strcmp(argv[0], "any") == 0)
38 NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY);
39 else if (strcmp(argv[0], "disconnect") == 0)
40 NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT);
41 else if (strcmp(argv[0], "magic-packet") == 0)
42 NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT);
43 else if (strcmp(argv[0], "gtk-rekey-failure") == 0)
44 NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE);
45 else if (strcmp(argv[0], "eap-identity-request") == 0)
46 NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST);
47 else if (strcmp(argv[0], "4way-handshake") == 0)
48 NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE);
49 else if (strcmp(argv[0], "rfkill-release") == 0)
50 NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE);
51 else if (strcmp(argv[0], "patterns") == 0) {
52 parse_state = PS_PAT;
53 patterns = nlmsg_alloc();
54 if (!patterns) {
55 err = -ENOMEM;
56 goto nla_put_failure;
57 }
58 } else {
59 err = 1;
60 goto nla_put_failure;
61 }
62 break;
63 case PS_PAT:
64 if (parse_hex_mask(argv[0], &pat, &patlen, &mask)) {
65 err = 1;
66 goto nla_put_failure;
67 }
68 pattern = nla_nest_start(patterns, ++patnum);
69 NLA_PUT(patterns, NL80211_WOWLAN_PKTPAT_MASK,
70 DIV_ROUND_UP(patlen, 8), mask);
71 NLA_PUT(patterns, NL80211_WOWLAN_PKTPAT_PATTERN,
72 patlen, pat);
73 nla_nest_end(patterns, pattern);
74 free(mask);
75 free(pat);
76 break;
77 }
78 argv++;
79 argc--;
80 }
81
82 if (patterns)
83 nla_put_nested(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
84 patterns);
85
86 nla_nest_end(msg, wowlan);
87 err = 0;
88 nla_put_failure:
89 nlmsg_free(patterns);
90 return err;
91 }
92 COMMAND(wowlan, enable, "[any] [disconnect] [magic-packet] [gtk-rekey-failure] [eap-identity-request]"
93 " [4way-handshake] [rfkill-release] [patterns <pattern>*]",
94 NL80211_CMD_SET_WOWLAN, 0, CIB_PHY, handle_wowlan_enable,
95 "Enable WoWLAN with the given triggers.\n"
96 "Each pattern is given as a bytestring with '-' in places where any byte\n"
97 "may be present, e.g. 00:11:22:-:44 will match 00:11:22:33:44 and\n"
98 "00:11:22:33:ff:44 etc.");
99
100
101 static int handle_wowlan_disable(struct nl80211_state *state, struct nl_cb *cb,
102 struct nl_msg *msg, int argc, char **argv)
103 {
104 /* just a set w/o wowlan attribute */
105 return 0;
106 }
107 COMMAND(wowlan, disable, "", NL80211_CMD_SET_WOWLAN, 0, CIB_PHY, handle_wowlan_disable,
108 "Disable WoWLAN.");
109
110
111 static int print_wowlan_handler(struct nl_msg *msg, void *arg)
112 {
113 struct nlattr *attrs[NL80211_ATTR_MAX + 1];
114 struct nlattr *trig[NUM_NL80211_WOWLAN_TRIG];
115 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
116 struct nlattr *pattern;
117 int rem_pattern;
118
119 nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
120 genlmsg_attrlen(gnlh, 0), NULL);
121
122 if (!attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
123 printf("WoWLAN is disabled.\n");
124 return NL_SKIP;
125 }
126
127 /* XXX: use policy */
128 nla_parse(trig, MAX_NL80211_WOWLAN_TRIG,
129 nla_data(attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
130 nla_len(attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
131 NULL);
132
133 printf("WoWLAN is enabled:\n");
134 if (trig[NL80211_WOWLAN_TRIG_ANY])
135 printf(" * wake up on special any trigger\n");
136 if (trig[NL80211_WOWLAN_TRIG_DISCONNECT])
137 printf(" * wake up on disconnect\n");
138 if (trig[NL80211_WOWLAN_TRIG_MAGIC_PKT])
139 printf(" * wake up on magic packet\n");
140 if (trig[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE])
141 printf(" * wake up on GTK rekeying failure\n");
142 if (trig[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST])
143 printf(" * wake up on EAP identity request\n");
144 if (trig[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE])
145 printf(" * wake up on 4-way handshake\n");
146 if (trig[NL80211_WOWLAN_TRIG_RFKILL_RELEASE])
147 printf(" * wake up on RF-kill release\n");
148 if (trig[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
149 nla_for_each_nested(pattern,
150 trig[NL80211_WOWLAN_TRIG_PKT_PATTERN],
151 rem_pattern) {
152 struct nlattr *patattr[NUM_NL80211_WOWLAN_PKTPAT];
153 int i, patlen, masklen;
154 uint8_t *mask, *pat;
155 nla_parse(patattr, MAX_NL80211_WOWLAN_PKTPAT,
156 nla_data(pattern), nla_len(pattern),
157 NULL);
158 if (!patattr[NL80211_WOWLAN_PKTPAT_MASK] ||
159 !patattr[NL80211_WOWLAN_PKTPAT_PATTERN]) {
160 printf(" * (invalid pattern specification)\n");
161 continue;
162 }
163 masklen = nla_len(patattr[NL80211_WOWLAN_PKTPAT_MASK]);
164 patlen = nla_len(patattr[NL80211_WOWLAN_PKTPAT_PATTERN]);
165 if (DIV_ROUND_UP(patlen, 8) != masklen) {
166 printf(" * (invalid pattern specification)\n");
167 continue;
168 }
169 printf(" * wake up on pattern: ");
170 pat = nla_data(patattr[NL80211_WOWLAN_PKTPAT_PATTERN]);
171 mask = nla_data(patattr[NL80211_WOWLAN_PKTPAT_MASK]);
172 for (i = 0; i < patlen; i++) {
173 if (mask[i / 8] & (1 << (i % 8)))
174 printf("%.2x", pat[i]);
175 else
176 printf("--");
177 if (i != patlen - 1)
178 printf(":");
179 }
180 printf("\n");
181 }
182 }
183
184 return NL_SKIP;
185 }
186
187 static int handle_wowlan_show(struct nl80211_state *state, struct nl_cb *cb,
188 struct nl_msg *msg, int argc, char **argv)
189 {
190 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
191 print_wowlan_handler, NULL);
192
193 return 0;
194 }
195 COMMAND(wowlan, show, "", NL80211_CMD_GET_WOWLAN, 0, CIB_PHY, handle_wowlan_show,
196 "Show WoWLAN status.");