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