3 * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
15 #include "utils/includes.h"
18 #include "utils/common.h"
19 #include "wlantest_ctrl.h"
22 static u8
* attr_get(u8
*buf
, size_t buflen
, enum wlantest_ctrl_attr attr
,
27 while (pos
+ 8 <= buf
+ buflen
) {
28 enum wlantest_ctrl_attr a
;
30 a
= WPA_GET_BE32(pos
);
32 alen
= WPA_GET_BE32(pos
);
34 if (pos
+ alen
> buf
+ buflen
) {
35 printf("Invalid control message attribute\n");
49 static u8
* attr_hdr_add(u8
*pos
, u8
*end
, enum wlantest_ctrl_attr attr
,
52 if (pos
== NULL
|| end
- pos
< 8 + len
)
54 WPA_PUT_BE32(pos
, attr
);
56 WPA_PUT_BE32(pos
, len
);
62 static u8
* attr_add_be32(u8
*pos
, u8
*end
, enum wlantest_ctrl_attr attr
,
65 if (pos
== NULL
|| end
- pos
< 12)
67 WPA_PUT_BE32(pos
, attr
);
71 WPA_PUT_BE32(pos
, val
);
77 static int cmd_send_and_recv(int s
, const u8
*cmd
, size_t cmd_len
,
78 u8
*resp
, size_t max_resp_len
)
81 enum wlantest_ctrl_cmd cmd_resp
;
83 if (send(s
, cmd
, cmd_len
, 0) < 0)
85 res
= recv(s
, resp
, max_resp_len
, 0);
89 cmd_resp
= WPA_GET_BE32(resp
);
90 if (cmd_resp
== WLANTEST_CTRL_SUCCESS
)
93 if (cmd_resp
== WLANTEST_CTRL_UNKNOWN_CMD
)
94 printf("Unknown command\n");
95 else if (cmd_resp
== WLANTEST_CTRL_INVALID_CMD
)
96 printf("Invalid command\n");
102 static int cmd_simple(int s
, enum wlantest_ctrl_cmd cmd
)
106 WPA_PUT_BE32(buf
, cmd
);
107 res
= cmd_send_and_recv(s
, buf
, sizeof(buf
), buf
, sizeof(buf
));
108 return res
< 0 ? -1 : 0;
112 static int cmd_ping(int s
, int argc
, char *argv
[])
114 int res
= cmd_simple(s
, WLANTEST_CTRL_PING
);
121 static int cmd_terminate(int s
, int argc
, char *argv
[])
123 return cmd_simple(s
, WLANTEST_CTRL_TERMINATE
);
127 static int cmd_list_bss(int s
, int argc
, char *argv
[])
129 u8 resp
[WLANTEST_CTRL_MAX_RESP_LEN
];
135 WPA_PUT_BE32(buf
, WLANTEST_CTRL_LIST_BSS
);
136 rlen
= cmd_send_and_recv(s
, buf
, sizeof(buf
), resp
, sizeof(resp
));
140 bssid
= attr_get(resp
+ 4, rlen
- 4, WLANTEST_ATTR_BSSID
, &len
);
144 for (i
= 0; i
< len
/ ETH_ALEN
; i
++)
145 printf(MACSTR
" ", MAC2STR(bssid
+ ETH_ALEN
* i
));
152 static int cmd_list_sta(int s
, int argc
, char *argv
[])
154 u8 resp
[WLANTEST_CTRL_MAX_RESP_LEN
];
161 printf("list_sta needs one argument: BSSID\n");
166 WPA_PUT_BE32(pos
, WLANTEST_CTRL_LIST_STA
);
168 WPA_PUT_BE32(pos
, WLANTEST_ATTR_BSSID
);
170 WPA_PUT_BE32(pos
, ETH_ALEN
);
172 if (hwaddr_aton(argv
[0], pos
) < 0) {
173 printf("Invalid BSSID '%s'\n", argv
[0]);
178 rlen
= cmd_send_and_recv(s
, buf
, pos
- buf
, resp
, sizeof(resp
));
182 addr
= attr_get(resp
+ 4, rlen
- 4, WLANTEST_ATTR_STA_ADDR
, &len
);
186 for (i
= 0; i
< len
/ ETH_ALEN
; i
++)
187 printf(MACSTR
" ", MAC2STR(addr
+ ETH_ALEN
* i
));
194 static int cmd_flush(int s
, int argc
, char *argv
[])
196 return cmd_simple(s
, WLANTEST_CTRL_FLUSH
);
200 static int cmd_clear_sta_counters(int s
, int argc
, char *argv
[])
202 u8 resp
[WLANTEST_CTRL_MAX_RESP_LEN
];
207 printf("clear_sta_counters needs two arguments: BSSID and "
213 WPA_PUT_BE32(pos
, WLANTEST_CTRL_CLEAR_STA_COUNTERS
);
215 WPA_PUT_BE32(pos
, WLANTEST_ATTR_BSSID
);
217 WPA_PUT_BE32(pos
, ETH_ALEN
);
219 if (hwaddr_aton(argv
[0], pos
) < 0) {
220 printf("Invalid BSSID '%s'\n", argv
[0]);
225 WPA_PUT_BE32(pos
, WLANTEST_ATTR_STA_ADDR
);
227 WPA_PUT_BE32(pos
, ETH_ALEN
);
229 if (hwaddr_aton(argv
[1], pos
) < 0) {
230 printf("Invalid STA address '%s'\n", argv
[1]);
235 rlen
= cmd_send_and_recv(s
, buf
, pos
- buf
, resp
, sizeof(resp
));
243 static int cmd_clear_bss_counters(int s
, int argc
, char *argv
[])
245 u8 resp
[WLANTEST_CTRL_MAX_RESP_LEN
];
250 printf("clear_bss_counters needs one argument: BSSID\n");
255 WPA_PUT_BE32(pos
, WLANTEST_CTRL_CLEAR_BSS_COUNTERS
);
257 WPA_PUT_BE32(pos
, WLANTEST_ATTR_BSSID
);
259 WPA_PUT_BE32(pos
, ETH_ALEN
);
261 if (hwaddr_aton(argv
[0], pos
) < 0) {
262 printf("Invalid BSSID '%s'\n", argv
[0]);
267 rlen
= cmd_send_and_recv(s
, buf
, pos
- buf
, resp
, sizeof(resp
));
275 struct sta_counters
{
277 enum wlantest_sta_counter num
;
280 static const struct sta_counters sta_counters
[] = {
281 { "auth_tx", WLANTEST_STA_COUNTER_AUTH_TX
},
282 { "auth_rx", WLANTEST_STA_COUNTER_AUTH_RX
},
283 { "assocreq_tx", WLANTEST_STA_COUNTER_ASSOCREQ_TX
},
284 { "reassocreq_tx", WLANTEST_STA_COUNTER_REASSOCREQ_TX
},
285 { "ptk_learned", WLANTEST_STA_COUNTER_PTK_LEARNED
},
286 { "valid_deauth_tx", WLANTEST_STA_COUNTER_VALID_DEAUTH_TX
},
287 { "valid_deauth_rx", WLANTEST_STA_COUNTER_VALID_DEAUTH_RX
},
288 { "invalid_deauth_tx", WLANTEST_STA_COUNTER_INVALID_DEAUTH_TX
},
289 { "invalid_deauth_rx", WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX
},
290 { "valid_disassoc_tx", WLANTEST_STA_COUNTER_VALID_DISASSOC_TX
},
291 { "valid_disassoc_rx", WLANTEST_STA_COUNTER_VALID_DISASSOC_RX
},
292 { "invalid_disassoc_tx", WLANTEST_STA_COUNTER_INVALID_DISASSOC_TX
},
293 { "invalid_disassoc_rx", WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX
},
294 { "valid_saqueryreq_tx", WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_TX
},
295 { "valid_saqueryreq_rx", WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_RX
},
296 { "invalid_saqueryreq_tx",
297 WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_TX
},
298 { "invalid_saqueryreq_rx",
299 WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_RX
},
300 { "valid_saqueryresp_tx", WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX
},
301 { "valid_saqueryresp_rx", WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_RX
},
302 { "invalid_saqueryresp_tx",
303 WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_TX
},
304 { "invalid_saqueryresp_rx",
305 WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_RX
},
309 static int cmd_get_sta_counter(int s
, int argc
, char *argv
[])
311 u8 resp
[WLANTEST_CTRL_MAX_RESP_LEN
];
312 u8 buf
[100], *end
, *pos
;
317 printf("get_sta_counter needs at three arguments: "
318 "counter name, BSSID, and STA address\n");
323 end
= buf
+ sizeof(buf
);
324 WPA_PUT_BE32(pos
, WLANTEST_CTRL_GET_STA_COUNTER
);
327 for (i
= 0; sta_counters
[i
].name
; i
++) {
328 if (os_strcasecmp(sta_counters
[i
].name
, argv
[0]) == 0)
331 if (sta_counters
[i
].name
== NULL
) {
332 printf("Unknown STA counter '%s'\n", argv
[0]);
334 for (i
= 0; sta_counters
[i
].name
; i
++)
335 printf(" %s", sta_counters
[i
].name
);
340 pos
= attr_add_be32(pos
, end
, WLANTEST_ATTR_STA_COUNTER
,
341 sta_counters
[i
].num
);
342 pos
= attr_hdr_add(pos
, end
, WLANTEST_ATTR_BSSID
, ETH_ALEN
);
343 if (hwaddr_aton(argv
[1], pos
) < 0) {
344 printf("Invalid BSSID '%s'\n", argv
[1]);
349 pos
= attr_hdr_add(pos
, end
, WLANTEST_ATTR_STA_ADDR
, ETH_ALEN
);
350 if (hwaddr_aton(argv
[2], pos
) < 0) {
351 printf("Invalid STA address '%s'\n", argv
[2]);
356 rlen
= cmd_send_and_recv(s
, buf
, pos
- buf
, resp
, sizeof(resp
));
360 pos
= attr_get(resp
+ 4, rlen
- 4, WLANTEST_ATTR_COUNTER
, &len
);
361 if (pos
== NULL
|| len
!= 4)
363 printf("%u\n", WPA_GET_BE32(pos
));
368 struct bss_counters
{
370 enum wlantest_bss_counter num
;
373 static const struct bss_counters bss_counters
[] = {
374 { "valid_bip_mmie", WLANTEST_BSS_COUNTER_VALID_BIP_MMIE
},
375 { "invalid_bip_mmie", WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE
},
376 { "missing_bip_mmie", WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE
},
380 static int cmd_get_bss_counter(int s
, int argc
, char *argv
[])
382 u8 resp
[WLANTEST_CTRL_MAX_RESP_LEN
];
383 u8 buf
[100], *end
, *pos
;
388 printf("get_bss_counter needs at three arguments: "
389 "counter name and BSSID\n");
394 end
= buf
+ sizeof(buf
);
395 WPA_PUT_BE32(pos
, WLANTEST_CTRL_GET_BSS_COUNTER
);
398 for (i
= 0; bss_counters
[i
].name
; i
++) {
399 if (os_strcasecmp(bss_counters
[i
].name
, argv
[0]) == 0)
402 if (bss_counters
[i
].name
== NULL
) {
403 printf("Unknown BSS counter '%s'\n", argv
[0]);
405 for (i
= 0; bss_counters
[i
].name
; i
++)
406 printf(" %s", bss_counters
[i
].name
);
411 pos
= attr_add_be32(pos
, end
, WLANTEST_ATTR_BSS_COUNTER
,
412 bss_counters
[i
].num
);
413 pos
= attr_hdr_add(pos
, end
, WLANTEST_ATTR_BSSID
, ETH_ALEN
);
414 if (hwaddr_aton(argv
[1], pos
) < 0) {
415 printf("Invalid BSSID '%s'\n", argv
[1]);
420 rlen
= cmd_send_and_recv(s
, buf
, pos
- buf
, resp
, sizeof(resp
));
424 pos
= attr_get(resp
+ 4, rlen
- 4, WLANTEST_ATTR_COUNTER
, &len
);
425 if (pos
== NULL
|| len
!= 4)
427 printf("%u\n", WPA_GET_BE32(pos
));
432 struct inject_frames
{
434 enum wlantest_inject_frame frame
;
437 static const struct inject_frames inject_frames
[] = {
438 { "auth", WLANTEST_FRAME_AUTH
},
439 { "assocreq", WLANTEST_FRAME_ASSOCREQ
},
440 { "reassocreq", WLANTEST_FRAME_REASSOCREQ
},
441 { "deauth", WLANTEST_FRAME_DEAUTH
},
442 { "disassoc", WLANTEST_FRAME_DISASSOC
},
443 { "saqueryreq", WLANTEST_FRAME_SAQUERYREQ
},
447 static int cmd_inject(int s
, int argc
, char *argv
[])
449 u8 resp
[WLANTEST_CTRL_MAX_RESP_LEN
];
450 u8 buf
[100], *end
, *pos
;
452 enum wlantest_inject_protection prot
;
454 /* <frame> <prot> <sender> <BSSID> <STA/ff:ff:ff:ff:ff:ff> */
457 printf("inject needs five arguments: frame, protection, "
458 "sender, BSSID, STA/ff:ff:ff:ff:ff:ff\n");
463 end
= buf
+ sizeof(buf
);
464 WPA_PUT_BE32(pos
, WLANTEST_CTRL_INJECT
);
467 for (i
= 0; inject_frames
[i
].name
; i
++) {
468 if (os_strcasecmp(inject_frames
[i
].name
, argv
[0]) == 0)
471 if (inject_frames
[i
].name
== NULL
) {
472 printf("Unknown inject frame '%s'\n", argv
[0]);
474 for (i
= 0; inject_frames
[i
].name
; i
++)
475 printf(" %s", inject_frames
[i
].name
);
480 pos
= attr_add_be32(pos
, end
, WLANTEST_ATTR_INJECT_FRAME
,
481 inject_frames
[i
].frame
);
483 if (os_strcasecmp(argv
[1], "normal") == 0)
484 prot
= WLANTEST_INJECT_NORMAL
;
485 else if (os_strcasecmp(argv
[1], "protected") == 0)
486 prot
= WLANTEST_INJECT_PROTECTED
;
487 else if (os_strcasecmp(argv
[1], "unprotected") == 0)
488 prot
= WLANTEST_INJECT_UNPROTECTED
;
489 else if (os_strcasecmp(argv
[1], "incorrect") == 0)
490 prot
= WLANTEST_INJECT_INCORRECT_KEY
;
492 printf("Unknown protection type '%s'\n", argv
[1]);
493 printf("Protection types: normal protected unprotected "
497 pos
= attr_add_be32(pos
, end
, WLANTEST_ATTR_INJECT_PROTECTION
, prot
);
499 if (os_strcasecmp(argv
[2], "ap") == 0) {
500 pos
= attr_add_be32(pos
, end
, WLANTEST_ATTR_INJECT_SENDER_AP
,
502 } else if (os_strcasecmp(argv
[2], "sta") == 0) {
503 pos
= attr_add_be32(pos
, end
, WLANTEST_ATTR_INJECT_SENDER_AP
,
506 printf("Unknown sender '%s'\n", argv
[2]);
507 printf("Sender types: ap sta\n");
511 pos
= attr_hdr_add(pos
, end
, WLANTEST_ATTR_BSSID
, ETH_ALEN
);
512 if (hwaddr_aton(argv
[3], pos
) < 0) {
513 printf("Invalid BSSID '%s'\n", argv
[3]);
518 pos
= attr_hdr_add(pos
, end
, WLANTEST_ATTR_STA_ADDR
, ETH_ALEN
);
519 if (hwaddr_aton(argv
[4], pos
) < 0) {
520 printf("Invalid STA '%s'\n", argv
[4]);
525 rlen
= cmd_send_and_recv(s
, buf
, pos
- buf
, resp
, sizeof(resp
));
533 struct wlantest_cli_cmd
{
535 int (*handler
)(int s
, int argc
, char *argv
[]);
539 static const struct wlantest_cli_cmd wlantest_cli_commands
[] = {
540 { "ping", cmd_ping
, "= test connection to wlantest" },
541 { "terminate", cmd_terminate
, "= terminate wlantest" },
542 { "list_bss", cmd_list_bss
, "= get BSS list" },
543 { "list_sta", cmd_list_sta
, "<BSSID> = get STA list" },
544 { "flush", cmd_flush
, "= drop all collected BSS data" },
545 { "clear_sta_counters", cmd_clear_sta_counters
,
546 "<BSSID> <STA> = clear STA counters" },
547 { "clear_bss_counters", cmd_clear_bss_counters
,
548 "<BSSID> = clear BSS counters" },
549 { "get_sta_counter", cmd_get_sta_counter
,
550 "<counter> <BSSID> <STA> = get STA counter value" },
551 { "get_bss_counter", cmd_get_bss_counter
,
552 "<counter> <BSSID> = get BSS counter value" },
553 { "inject", cmd_inject
,
554 "<frame> <prot> <sender> <BSSID> <STA/ff:ff:ff:ff:ff:ff>" },
559 static int ctrl_command(int s
, int argc
, char *argv
[])
561 const struct wlantest_cli_cmd
*cmd
, *match
= NULL
;
565 for (cmd
= wlantest_cli_commands
; cmd
->cmd
; cmd
++) {
566 if (os_strncasecmp(cmd
->cmd
, argv
[0], os_strlen(argv
[0])) == 0)
569 if (os_strcasecmp(cmd
->cmd
, argv
[0]) == 0) {
579 printf("Ambiguous command '%s'; possible commands:", argv
[0]);
580 for (cmd
= wlantest_cli_commands
; cmd
->cmd
; cmd
++) {
581 if (os_strncasecmp(cmd
->cmd
, argv
[0],
582 os_strlen(argv
[0])) == 0) {
583 printf(" %s", cmd
->cmd
);
588 } else if (count
== 0) {
589 printf("Unknown command '%s'\n", argv
[0]);
592 ret
= match
->handler(s
, argc
- 1, &argv
[1]);
599 int main(int argc
, char *argv
[])
602 struct sockaddr_un addr
;
605 s
= socket(AF_UNIX
, SOCK_SEQPACKET
, 0);
611 os_memset(&addr
, 0, sizeof(addr
));
612 addr
.sun_family
= AF_UNIX
;
613 os_strlcpy(addr
.sun_path
+ 1, WLANTEST_SOCK_NAME
,
614 sizeof(addr
.sun_path
) - 1);
615 if (connect(s
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
622 ret
= ctrl_command(s
, argc
- 1, &argv
[1]);
626 /* TODO: interactive */