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 wlantest_cli_cmd {
434 int (*handler)(int s, int argc, char *argv[]);
438 static const struct wlantest_cli_cmd wlantest_cli_commands[] = {
439 { "ping", cmd_ping, "= test connection to wlantest" },
440 { "terminate", cmd_terminate, "= terminate wlantest" },
441 { "list_bss", cmd_list_bss, "= get BSS list" },
442 { "list_sta", cmd_list_sta, "<BSSID> = get STA list" },
443 { "flush", cmd_flush, "= drop all collected BSS data" },
444 { "clear_sta_counters", cmd_clear_sta_counters,
445 "<BSSID> <STA> = clear STA counters" },
446 { "clear_bss_counters", cmd_clear_bss_counters,
447 "<BSSID> = clear BSS counters" },
448 { "get_sta_counter", cmd_get_sta_counter,
449 "<counter> <BSSID> <STA> = get STA counter value" },
450 { "get_bss_counter", cmd_get_bss_counter,
451 "<counter> <BSSID> = get BSS counter value" },
456 static int ctrl_command(int s, int argc, char *argv[])
458 const struct wlantest_cli_cmd *cmd, *match = NULL;
462 for (cmd = wlantest_cli_commands; cmd->cmd; cmd++) {
463 if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0)
466 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
476 printf("Ambiguous command '%s'; possible commands:", argv[0]);
477 for (cmd = wlantest_cli_commands; cmd->cmd; cmd++) {
478 if (os_strncasecmp(cmd->cmd, argv[0],
479 os_strlen(argv[0])) == 0) {
480 printf(" %s", cmd->cmd);
485 } else if (count == 0) {
486 printf("Unknown command '%s'\n", argv[0]);
489 ret = match->handler(s, argc - 1, &argv[1]);
496 int main(int argc, char *argv[])
499 struct sockaddr_un addr;
502 s = socket(AF_UNIX, SOCK_SEQPACKET, 0);
508 os_memset(&addr, 0, sizeof(addr));
509 addr.sun_family = AF_UNIX;
510 os_strlcpy(addr.sun_path + 1, WLANTEST_SOCK_NAME,
511 sizeof(addr.sun_path) - 1);
512 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
519 ret = ctrl_command(s, argc - 1, &argv[1]);
523 /* TODO: interactive */