]> git.ipfire.org Git - thirdparty/iw.git/blob - station.c
add #include <string.h>
[thirdparty/iw.git] / station.c
1 #include <linux/nl80211.h>
2 #include <net/if.h>
3 #include <errno.h>
4 #include <string.h>
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
12 #include "iw.h"
13
14 enum plink_state {
15 LISTEN,
16 OPN_SNT,
17 OPN_RCVD,
18 CNF_RCVD,
19 ESTAB,
20 HOLDING,
21 BLOCKED
22 };
23
24 enum plink_actions {
25 PLINK_ACTION_UNDEFINED,
26 PLINK_ACTION_OPEN,
27 PLINK_ACTION_BLOCK,
28 };
29
30
31 static int wait_handler(struct nl_msg *msg, void *arg)
32 {
33 int *finished = arg;
34
35 *finished = 1;
36 return NL_STOP;
37 }
38
39 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
40 void *arg)
41 {
42 fprintf(stderr, "nl80211 error %d\n", err->error);
43 exit(err->error);
44 }
45
46 static int print_sta_handler(struct nl_msg *msg, void *arg)
47 {
48 struct nlattr *tb[NL80211_ATTR_MAX + 1];
49 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
50 struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
51 char mac_addr[20], state_name[10], dev[20];
52 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
53 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
54 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
55 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
56 [NL80211_STA_INFO_LLID] = { .type = NLA_U16 },
57 [NL80211_STA_INFO_PLID] = { .type = NLA_U16 },
58 [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
59 };
60
61 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
62 genlmsg_attrlen(gnlh, 0), NULL);
63
64 /*
65 * TODO: validate the interface and mac address!
66 * Otherwise, there's a race condition as soon as
67 * the kernel starts sending station notifications.
68 */
69
70 if (!tb[NL80211_ATTR_STA_INFO]) {
71 fprintf(stderr, "sta stats missing!");
72 return NL_SKIP;
73 }
74 if (nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
75 tb[NL80211_ATTR_STA_INFO],
76 stats_policy)) {
77 fprintf(stderr, "failed to parse nested attributes!");
78 return NL_SKIP;
79 }
80
81 mac_addr_n2a(mac_addr, nla_data(tb[NL80211_ATTR_MAC]));
82 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
83 printf("Station %s (on %s)", mac_addr, dev);
84
85 if (sinfo[NL80211_STA_INFO_INACTIVE_TIME])
86 printf("\n\tinactive time:\t%d ms",
87 nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME]));
88 if (sinfo[NL80211_STA_INFO_RX_BYTES])
89 printf("\n\trx bytes:\t%d",
90 nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES]));
91 if (sinfo[NL80211_STA_INFO_TX_BYTES])
92 printf("\n\ttx bytes:\t%d",
93 nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES]));
94 if (sinfo[NL80211_STA_INFO_LLID])
95 printf("\n\tmesh llid:\t%d",
96 nla_get_u16(sinfo[NL80211_STA_INFO_LLID]));
97 if (sinfo[NL80211_STA_INFO_PLID])
98 printf("\n\tmesh plid:\t%d",
99 nla_get_u16(sinfo[NL80211_STA_INFO_PLID]));
100 if (sinfo[NL80211_STA_INFO_PLINK_STATE]) {
101 switch (nla_get_u16(sinfo[NL80211_STA_INFO_PLINK_STATE])) {
102 case LISTEN:
103 strcpy(state_name, "LISTEN");
104 break;
105 case OPN_SNT:
106 strcpy(state_name, "OPN_SNT");
107 break;
108 case OPN_RCVD:
109 strcpy(state_name, "OPN_RCVD");
110 break;
111 case CNF_RCVD:
112 strcpy(state_name, "CNF_RCVD");
113 break;
114 case ESTAB:
115 strcpy(state_name, "ESTAB");
116 break;
117 case HOLDING:
118 strcpy(state_name, "HOLDING");
119 break;
120 case BLOCKED:
121 strcpy(state_name, "BLOCKED");
122 break;
123 default:
124 strcpy(state_name, "UNKNOWN");
125 break;
126 }
127 printf("\n\tmesh plink:\t%s", state_name);
128 }
129
130 printf("\n");
131 return NL_SKIP;
132 }
133
134 static int handle_station_get(struct nl80211_state *state,
135 char *dev, int argc, char **argv)
136 {
137 struct nl_msg *msg;
138 struct nl_cb *cb = NULL;
139 int ret = -1;
140 int err;
141 int finished = 0;
142 unsigned char mac_addr[ETH_ALEN];
143
144 if (argc < 1) {
145 fprintf(stderr, "not enough arguments\n");
146 return -1;
147 }
148
149 if (mac_addr_a2n(mac_addr, argv[0])) {
150 fprintf(stderr, "invalid mac address\n");
151 return -1;
152 }
153
154 argc--;
155 argv++;
156
157 if (argc) {
158 fprintf(stderr, "too many arguments\n");
159 return -1;
160 }
161
162 msg = nlmsg_alloc();
163 if (!msg)
164 goto out;
165
166 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
167 0, NL80211_CMD_GET_STATION, 0);
168
169 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
170 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(dev));
171
172 cb = nl_cb_alloc(NL_CB_CUSTOM);
173 if (!cb)
174 goto out;
175
176 if (nl_send_auto_complete(state->nl_handle, msg) < 0)
177 goto out;
178
179 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_sta_handler, NULL);
180 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished);
181 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, NULL);
182
183 err = nl_recvmsgs(state->nl_handle, cb);
184
185 if (!finished)
186 err = nl_wait_for_ack(state->nl_handle);
187
188 if (err < 0)
189 goto out;
190
191 ret = 0;
192
193 out:
194 nl_cb_put(cb);
195 nla_put_failure:
196 nlmsg_free(msg);
197 return ret;
198 }
199
200 static int handle_station_set(struct nl80211_state *state,
201 char *dev, int argc, char **argv)
202 {
203 struct nl_msg *msg;
204 struct nl_cb *cb = NULL;
205 int ret = -1;
206 int err;
207 int finished = 0;
208 unsigned char plink_action;
209 unsigned char mac_addr[ETH_ALEN];
210
211 if (argc < 3) {
212 fprintf(stderr, "not enough arguments\n");
213 return -1;
214 }
215
216 if (mac_addr_a2n(mac_addr, argv[0])) {
217 fprintf(stderr, "invalid mac address\n");
218 return -1;
219 }
220 argc--;
221 argv++;
222
223 if (strcmp("plink_action", argv[0]) != 0) {
224 fprintf(stderr, "parameter not supported\n");
225 return -1;
226 }
227 argc--;
228 argv++;
229
230 if (strcmp("open", argv[0]) == 0)
231 plink_action = PLINK_ACTION_OPEN;
232 else if (strcmp("block", argv[0]) == 0)
233 plink_action = PLINK_ACTION_BLOCK;
234 else {
235 fprintf(stderr, "plink action not supported\n");
236 return -1;
237 }
238 argc--;
239 argv++;
240
241 if (argc) {
242 fprintf(stderr, "too many arguments\n");
243 return -1;
244 }
245
246 msg = nlmsg_alloc();
247 if (!msg)
248 goto out;
249
250 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
251 0, NL80211_CMD_SET_STATION, 0);
252
253 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
254 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(dev));
255 NLA_PUT_U8(msg, NL80211_ATTR_STA_PLINK_ACTION, plink_action);
256
257 cb = nl_cb_alloc(NL_CB_CUSTOM);
258 if (!cb)
259 goto out;
260
261 if (nl_send_auto_complete(state->nl_handle, msg) < 0)
262 goto out;
263
264 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_sta_handler, NULL);
265 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished);
266 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, NULL);
267
268 err = nl_recvmsgs(state->nl_handle, cb);
269
270 if (!finished)
271 err = nl_wait_for_ack(state->nl_handle);
272
273 if (err < 0)
274 goto out;
275
276 ret = 0;
277
278 out:
279 nl_cb_put(cb);
280 nla_put_failure:
281 nlmsg_free(msg);
282 return ret;
283 }
284 static int handle_station_dump(struct nl80211_state *state,
285 char *dev, int argc, char **argv)
286 {
287 struct nl_msg *msg;
288 struct nl_cb *cb = NULL;
289 int ret = -1;
290 int err;
291 int finished = 0;
292
293 if (argc) {
294 fprintf(stderr, "too many arguments\n");
295 return -1;
296 }
297
298 msg = nlmsg_alloc();
299 if (!msg)
300 goto out;
301
302 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
303 NLM_F_DUMP, NL80211_CMD_GET_STATION, 0);
304
305 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(dev));
306
307 cb = nl_cb_alloc(NL_CB_CUSTOM);
308 if (!cb)
309 goto out;
310
311 if (nl_send_auto_complete(state->nl_handle, msg) < 0)
312 goto out;
313
314 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_sta_handler, NULL);
315 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, wait_handler, &finished);
316
317 err = nl_recvmsgs(state->nl_handle, cb);
318
319 if (err < 0)
320 goto out;
321
322 ret = 0;
323
324 out:
325 nl_cb_put(cb);
326 nla_put_failure:
327 nlmsg_free(msg);
328 return ret;
329 }
330
331 static int handle_station_del(struct nl80211_state *state,
332 char *dev, int argc, char **argv)
333 {
334 struct nl_msg *msg;
335 struct nl_cb *cb = NULL;
336 int ret = -1;
337 int err;
338 int finished = 0;
339 unsigned char mac[ETH_ALEN];
340
341 if (argc > 1) {
342 fprintf(stderr, "too many arguments\n");
343 return -1;
344 }
345
346 if (argc && mac_addr_a2n(mac, argv[0])) {
347 fprintf(stderr, "invalid mac address\n");
348 return -1;
349 }
350
351 msg = nlmsg_alloc();
352 if (!msg)
353 goto out;
354
355 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 0,
356 NL80211_CMD_DEL_STATION, 0);
357
358 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(dev));
359 if (argc)
360 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac);
361
362 cb = nl_cb_alloc(NL_CB_CUSTOM);
363 if (!cb)
364 goto out;
365
366 if (nl_send_auto_complete(state->nl_handle, msg) < 0)
367 goto out;
368
369 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_sta_handler, NULL);
370 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished);
371 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, NULL);
372
373 err = nl_recvmsgs(state->nl_handle, cb);
374
375 if (!finished)
376 err = nl_wait_for_ack(state->nl_handle);
377
378 if (err < 0)
379 goto out;
380
381 ret = 0;
382
383 out:
384 nl_cb_put(cb);
385 nla_put_failure:
386 nlmsg_free(msg);
387 return ret;
388 }
389
390 int handle_station(struct nl80211_state *state,
391 char *dev, int argc, char **argv)
392 {
393 char *cmd = argv[0];
394
395 if (argc < 1) {
396 fprintf(stderr, "you must specify an station command\n");
397 return -1;
398 }
399
400 argc--;
401 argv++;
402
403 if (strcmp(cmd, "del") == 0)
404 return handle_station_del(state, dev, argc, argv);
405 if (strcmp(cmd, "get") == 0)
406 return handle_station_get(state, dev, argc, argv);
407 if (strcmp(cmd, "set") == 0)
408 return handle_station_set(state, dev, argc, argv);
409 if (strcmp(cmd, "dump") == 0)
410 return handle_station_dump(state, dev, argc, argv);
411
412 printf("invalid interface command %s\n", cmd);
413 return -1;
414 }