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