/* * Sigma Control API DUT (wlantest) * Copyright (c) 2010-2011, Atheros Communications, Inc. * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. * All Rights Reserved. * Licensed under the Clear BSD license. See README for more details. */ #include "sigma_dut.h" #include #include "wlantest_ctrl.h" #ifndef ETH_ALEN #define ETH_ALEN 6 #endif int hwaddr_aton(const char *txt, unsigned char *addr); static u8 * attr_get(u8 *buf, size_t buflen, enum wlantest_ctrl_attr attr, size_t *len) { u8 *pos = buf; while (pos + 8 <= buf + buflen) { enum wlantest_ctrl_attr a; size_t alen; a = WPA_GET_BE32(pos); pos += 4; alen = WPA_GET_BE32(pos); pos += 4; if (pos + alen > buf + buflen) return NULL; if (a == attr) { *len = alen; return pos; } pos += alen; } return NULL; } static u8 * attr_hdr_add(u8 *pos, u8 *end, enum wlantest_ctrl_attr attr, size_t len) { if (pos == NULL || end - pos < (int) (8 + len)) return NULL; WPA_PUT_BE32(pos, attr); pos += 4; WPA_PUT_BE32(pos, len); pos += 4; return pos; } static u8 * attr_add_str(u8 *pos, u8 *end, enum wlantest_ctrl_attr attr, const char *str) { size_t len = strlen(str); if (pos == NULL || end - pos < (int) (8 + len)) return NULL; WPA_PUT_BE32(pos, attr); pos += 4; WPA_PUT_BE32(pos, len); pos += 4; memcpy(pos, str, len); pos += len; return pos; } static u8 * attr_add_be32(u8 *pos, u8 *end, enum wlantest_ctrl_attr attr, u32 val) { if (pos == NULL || end - pos < 12) return NULL; WPA_PUT_BE32(pos, attr); pos += 4; WPA_PUT_BE32(pos, 4); pos += 4; WPA_PUT_BE32(pos, val); pos += 4; return pos; } static int open_wlantest(void) { int s; struct sockaddr_un addr; s = socket(AF_UNIX, SOCK_SEQPACKET, 0); if (s < 0) { perror("socket"); return -1; } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path + 1, WLANTEST_SOCK_NAME, sizeof(addr.sun_path) - 1); if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("connect"); close(s); return -1; } return s; } static int cmd_send_and_recv(int s, const u8 *cmd, size_t cmd_len, u8 *resp, size_t max_resp_len) { int res; enum wlantest_ctrl_cmd cmd_resp; if (send(s, cmd, cmd_len, 0) < 0) return -1; res = recv(s, resp, max_resp_len, 0); if (res < 4) return -1; cmd_resp = WPA_GET_BE32(resp); if (cmd_resp == WLANTEST_CTRL_SUCCESS) return res; return -1; } static int cmd_simple(int s, enum wlantest_ctrl_cmd cmd) { u8 buf[4]; int res; WPA_PUT_BE32(buf, cmd); res = cmd_send_and_recv(s, buf, sizeof(buf), buf, sizeof(buf)); return res < 0 ? -1 : 0; } static int run_wlantest_simple(struct sigma_dut *dut, struct sigma_conn *conn, enum wlantest_ctrl_cmd cmd) { int s, ret; s = open_wlantest(); if (s < 0) { send_resp(dut, conn, SIGMA_ERROR, "errorCode,wlantest not " "available"); return 0; } ret = cmd_simple(s, cmd); close(s); return ret < 0 ? -2 : 1; } static int cmd_wlantest_version(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { int s; u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; u8 buf[4]; char *version; size_t len; int rlen; char *rbuf; s = open_wlantest(); if (s < 0) { send_resp(dut, conn, SIGMA_ERROR, "errorCode,wlantest not " "available"); return 0; } WPA_PUT_BE32(buf, WLANTEST_CTRL_VERSION); rlen = cmd_send_and_recv(s, buf, sizeof(buf), resp, sizeof(resp)); close(s); if (rlen < 0) return -2; version = (char *) attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_VERSION, &len); if (version == NULL) return -2; rbuf = malloc(9 + len); if (rbuf == NULL) return -2; memcpy(rbuf, "version,", 8); memcpy(rbuf + 8, version, len); rbuf[8 + len] = '\0'; send_resp(dut, conn, SIGMA_COMPLETE, rbuf); free(rbuf); return 0; } int cmd_wlantest_set_channel(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { char buf[100]; const char *chan; if (dut->sniffer_ifname == NULL) { send_resp(dut, conn, SIGMA_ERROR, "errorCode,Sniffer " "interface not available"); return 0; } chan = get_param(cmd, "channel"); if (chan == NULL) return -1; snprintf(buf, sizeof(buf), "iw dev %s set type monitor", dut->sniffer_ifname); if (system(buf) != 0) { snprintf(buf, sizeof(buf), "ifconfig %s down", dut->sniffer_ifname); if (system(buf) != 0) { sigma_dut_print(dut, DUT_MSG_INFO, "Failed to run '%s'", buf); return -2; } snprintf(buf, sizeof(buf), "iw dev %s set type monitor", dut->sniffer_ifname); if (system(buf) != 0) { sigma_dut_print(dut, DUT_MSG_INFO, "Failed to run '%s'", buf); return -2; } } snprintf(buf, sizeof(buf), "iw dev %s set channel %d HT20", dut->sniffer_ifname, atoi(chan)); if (system(buf) != 0) { sigma_dut_print(dut, DUT_MSG_INFO, "Failed to run '%s'", buf); return -2; } snprintf(buf, sizeof(buf), "ifconfig %s up", dut->sniffer_ifname); if (system(buf) != 0) { sigma_dut_print(dut, DUT_MSG_INFO, "Failed to run '%s'", buf); return -2; } dut->mode = SIGMA_MODE_SNIFFER; return 1; } static int cmd_wlantest_flush(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { return run_wlantest_simple(dut, conn, WLANTEST_CTRL_FLUSH); } int cmd_wlantest_send_frame(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; u8 buf[100], *end, *pos; int rlen; enum wlantest_inject_frame frame; enum wlantest_inject_protection prot; const char *val; int s; /* wlantest_send_frame,PMFFrameType,disassoc,PMFProtected,Unprotected,sender,AP,bssid,00:11:22:33:44:55,stationID,00:66:77:88:99:aa */ if (dut->mode == SIGMA_MODE_STATION) { sigma_dut_print(dut, DUT_MSG_DEBUG, "Convert " "wlantest_send_frame to sta_send_frame"); return cmd_sta_send_frame(dut, conn, cmd); } if (dut->mode == SIGMA_MODE_AP) { sigma_dut_print(dut, DUT_MSG_DEBUG, "Convert " "wlantest_send_frame to ap_send_frame"); return cmd_ap_send_frame(dut, conn, cmd); } pos = buf; end = buf + sizeof(buf); WPA_PUT_BE32(pos, WLANTEST_CTRL_INJECT); pos += 4; val = get_param(cmd, "Type"); if (val == NULL) val = get_param(cmd, "PMFFrameType"); if (val == NULL) return -1; if (strcasecmp(val, "disassoc") == 0) frame = WLANTEST_FRAME_DISASSOC; else if (strcasecmp(val, "deauth") == 0) frame = WLANTEST_FRAME_DEAUTH; else if (strcasecmp(val, "saquery") == 0) frame = WLANTEST_FRAME_SAQUERYREQ; else if (strcasecmp(val, "auth") == 0) frame = WLANTEST_FRAME_AUTH; else if (strcasecmp(val, "assocreq") == 0) frame = WLANTEST_FRAME_ASSOCREQ; else if (strcasecmp(val, "reassocreq") == 0) frame = WLANTEST_FRAME_REASSOCREQ; else { send_resp(dut, conn, SIGMA_ERROR, "errorCode,Unsupported " "PMFFrameType"); return 0; } pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_FRAME, frame); val = get_param(cmd, "Protected"); if (val == NULL) val = get_param(cmd, "PMFProtected"); if (val == NULL) return -1; if (strcasecmp(val, "CorrectKey") == 0) prot = WLANTEST_INJECT_PROTECTED; else if (strcasecmp(val, "IncorrectKey") == 0) prot = WLANTEST_INJECT_INCORRECT_KEY; else if (strcasecmp(val, "Unprotected") == 0) prot = WLANTEST_INJECT_UNPROTECTED; else { send_resp(dut, conn, SIGMA_ERROR, "errorCode,Unsupported " "PMFProtected"); return 0; } pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_PROTECTION, prot); val = get_param(cmd, "sender"); if (val == NULL) return -1; if (strcasecmp(val, "ap") == 0) { pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_SENDER_AP, 1); } else if (strcasecmp(val, "sta") == 0) { pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_SENDER_AP, 0); } else { send_resp(dut, conn, SIGMA_ERROR, "errorCode,Unsupported " "sender"); return 0; } val = get_param(cmd, "bssid"); if (val == NULL) return -1; pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid bssid"); return 0; } pos += ETH_ALEN; val = get_param(cmd, "stationID"); if (val == NULL) return -1; pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid stationID"); return 0; } pos += ETH_ALEN; s = open_wlantest(); if (s < 0) { send_resp(dut, conn, SIGMA_ERROR, "errorCode,wlantest not " "available"); return 0; } rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp)); close(s); if (rlen < 0) return -2; return 1; } static int cmd_wlantest_add_passphrase(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; u8 buf[100], *end, *pos; int rlen; const char *val; int s; pos = buf; end = buf + sizeof(buf); WPA_PUT_BE32(pos, WLANTEST_CTRL_ADD_PASSPHRASE); pos += 4; val = get_param(cmd, "passphrase"); if (val) { if (strlen(val) < 8 || strlen(val) > 63) return -1; pos = attr_add_str(pos, end, WLANTEST_ATTR_PASSPHRASE, val); } else { val = get_param(cmd, "wepkey"); if (!val) return -1; pos = attr_add_str(pos, end, WLANTEST_ATTR_WEPKEY, val); } val = get_param(cmd, "bssid"); if (val) { pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid bssid"); return 0; } pos += ETH_ALEN; } s = open_wlantest(); if (s < 0) { send_resp(dut, conn, SIGMA_ERROR, "errorCode,wlantest not " "available"); return 0; } rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp)); close(s); if (rlen < 0) return -2; return 1; } static int cmd_wlantest_clear_sta_counters(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; u8 buf[100], *end, *pos; int rlen; const char *val; int s; pos = buf; end = buf + sizeof(buf); WPA_PUT_BE32(pos, WLANTEST_CTRL_CLEAR_STA_COUNTERS); pos += 4; val = get_param(cmd, "bssid"); if (val == NULL) return -1; if (val) { pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid bssid"); return 0; } pos += ETH_ALEN; } val = get_param(cmd, "stationID"); if (val == NULL) return -1; if (val) { pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid stationID"); return 0; } pos += ETH_ALEN; } s = open_wlantest(); if (s < 0) { send_resp(dut, conn, SIGMA_ERROR, "errorCode,wlantest not " "available"); return 0; } rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp)); close(s); if (rlen < 0) return -2; return 1; } static int cmd_wlantest_clear_bss_counters(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; u8 buf[100], *end, *pos; int rlen; const char *val; int s; pos = buf; end = buf + sizeof(buf); WPA_PUT_BE32(pos, WLANTEST_CTRL_CLEAR_BSS_COUNTERS); pos += 4; val = get_param(cmd, "bssid"); if (val == NULL) return -1; if (val) { pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid bssid"); return 0; } pos += ETH_ALEN; } s = open_wlantest(); if (s < 0) { send_resp(dut, conn, SIGMA_ERROR, "errorCode,wlantest not " "available"); return 0; } rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp)); close(s); if (rlen < 0) return -2; return 1; } static int cmd_wlantest_clear_tdls_counters(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; u8 buf[100], *end, *pos; int rlen; const char *val; int s; pos = buf; end = buf + sizeof(buf); WPA_PUT_BE32(pos, WLANTEST_CTRL_CLEAR_TDLS_COUNTERS); pos += 4; val = get_param(cmd, "bssid"); if (val == NULL) return -1; if (val) { pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid bssid"); return 0; } pos += ETH_ALEN; } val = get_param(cmd, "stationID"); if (val == NULL) return -1; if (val) { pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid stationID"); return 0; } pos += ETH_ALEN; } val = get_param(cmd, "stationID2"); if (val == NULL) return -1; if (val) { pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA2_ADDR, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid stationID2"); return 0; } pos += ETH_ALEN; } s = open_wlantest(); if (s < 0) { send_resp(dut, conn, SIGMA_ERROR, "errorCode,wlantest not " "available"); return 0; } rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp)); close(s); if (rlen < 0) return -2; return 1; } struct sta_counters { const char *name; enum wlantest_sta_counter num; }; static const struct sta_counters sta_counters[] = { { "auth_tx", WLANTEST_STA_COUNTER_AUTH_TX }, { "auth_rx", WLANTEST_STA_COUNTER_AUTH_RX }, { "assocreq_tx", WLANTEST_STA_COUNTER_ASSOCREQ_TX }, { "reassocreq_tx", WLANTEST_STA_COUNTER_REASSOCREQ_TX }, { "ptk_learned", WLANTEST_STA_COUNTER_PTK_LEARNED }, { "valid_deauth_tx", WLANTEST_STA_COUNTER_VALID_DEAUTH_TX }, { "valid_deauth_rx", WLANTEST_STA_COUNTER_VALID_DEAUTH_RX }, { "invalid_deauth_tx", WLANTEST_STA_COUNTER_INVALID_DEAUTH_TX }, { "invalid_deauth_rx", WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX }, { "valid_disassoc_tx", WLANTEST_STA_COUNTER_VALID_DISASSOC_TX }, { "valid_disassoc_rx", WLANTEST_STA_COUNTER_VALID_DISASSOC_RX }, { "invalid_disassoc_tx", WLANTEST_STA_COUNTER_INVALID_DISASSOC_TX }, { "invalid_disassoc_rx", WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX }, { "valid_saqueryreq_tx", WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_TX }, { "valid_saqueryreq_rx", WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_RX }, { "invalid_saqueryreq_tx", WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_TX }, { "invalid_saqueryreq_rx", WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_RX }, { "valid_saqueryresp_tx", WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX }, { "valid_saqueryresp_rx", WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_RX }, { "invalid_saqueryresp_tx", WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_TX }, { "invalid_saqueryresp_rx", WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_RX }, { "ping_ok", WLANTEST_STA_COUNTER_PING_OK }, { "assocresp_comeback", WLANTEST_STA_COUNTER_ASSOCRESP_COMEBACK }, { "reassocresp_comeback", WLANTEST_STA_COUNTER_REASSOCRESP_COMEBACK }, { "ping_ok_first_assoc", WLANTEST_STA_COUNTER_PING_OK_FIRST_ASSOC }, { "valid_deauth_rx_ack", WLANTEST_STA_COUNTER_VALID_DEAUTH_RX_ACK }, { "valid_disassoc_rx_ack", WLANTEST_STA_COUNTER_VALID_DISASSOC_RX_ACK }, { "invalid_deauth_rx_ack", WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX_ACK }, { "invalid_disassoc_rx_ack", WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX_ACK }, { "deauth_rx_asleep", WLANTEST_STA_COUNTER_DEAUTH_RX_ASLEEP }, { "deauth_rx_awake", WLANTEST_STA_COUNTER_DEAUTH_RX_AWAKE }, { "disassoc_rx_asleep", WLANTEST_STA_COUNTER_DISASSOC_RX_ASLEEP }, { "disassoc_rx_awake", WLANTEST_STA_COUNTER_DISASSOC_RX_AWAKE }, { "prot_data_tx", WLANTEST_STA_COUNTER_PROT_DATA_TX }, { "deauth_rx_rc6", WLANTEST_STA_COUNTER_DEAUTH_RX_RC6 }, { "deauth_rx_rc7", WLANTEST_STA_COUNTER_DEAUTH_RX_RC7 }, { "disassoc_rx_rc6", WLANTEST_STA_COUNTER_DISASSOC_RX_RC6 }, { "disassoc_rx_rc7", WLANTEST_STA_COUNTER_DISASSOC_RX_RC7 }, { NULL, 0 } }; static int cmd_wlantest_get_sta_counter(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; u8 buf[100], *end, *pos; int rlen; const char *val; int s, i; char ret[100]; size_t len; pos = buf; end = buf + sizeof(buf); WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_STA_COUNTER); pos += 4; val = get_param(cmd, "bssid"); if (val == NULL) return -1; if (val) { pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid bssid"); return 0; } pos += ETH_ALEN; } val = get_param(cmd, "stationID"); if (val == NULL) return -1; if (val) { pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid stationID"); return 0; } pos += ETH_ALEN; } val = get_param(cmd, "field"); if (val == NULL) return -1; for (i = 0; sta_counters[i].name; i++) { if (strcasecmp(sta_counters[i].name, val) == 0) break; } if (sta_counters[i].name == NULL) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid field"); return 0; } pos = attr_add_be32(pos, end, WLANTEST_ATTR_STA_COUNTER, sta_counters[i].num); s = open_wlantest(); if (s < 0) { send_resp(dut, conn, SIGMA_ERROR, "errorCode,wlantest not " "available"); return 0; } rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp)); close(s); pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_COUNTER, &len); if (pos == NULL || len != 4) return -2; snprintf(ret, sizeof(ret), "counter,%u", WPA_GET_BE32(pos)); send_resp(dut, conn, SIGMA_COMPLETE, ret); return 0; } struct bss_counters { const char *name; enum wlantest_bss_counter num; }; static const struct bss_counters bss_counters[] = { { "valid_bip_mmie", WLANTEST_BSS_COUNTER_VALID_BIP_MMIE }, { "invalid_bip_mmie", WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE }, { "missing_bip_mmie", WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE }, { "bip_deauth", WLANTEST_BSS_COUNTER_BIP_DEAUTH }, { "bip_disassoc", WLANTEST_BSS_COUNTER_BIP_DISASSOC }, { NULL, 0 } }; static int cmd_wlantest_get_bss_counter(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; u8 buf[100], *end, *pos; int rlen; const char *val; int s, i; char ret[100]; size_t len; pos = buf; end = buf + sizeof(buf); WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_BSS_COUNTER); pos += 4; val = get_param(cmd, "bssid"); if (val == NULL) return -1; if (val) { pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid bssid"); return 0; } pos += ETH_ALEN; } val = get_param(cmd, "field"); if (val == NULL) return -1; for (i = 0; bss_counters[i].name; i++) { if (strcasecmp(bss_counters[i].name, val) == 0) break; } if (bss_counters[i].name == NULL) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid field"); return 0; } pos = attr_add_be32(pos, end, WLANTEST_ATTR_BSS_COUNTER, bss_counters[i].num); s = open_wlantest(); if (s < 0) { send_resp(dut, conn, SIGMA_ERROR, "errorCode,wlantest not " "available"); return 0; } rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp)); close(s); pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_COUNTER, &len); if (pos == NULL || len != 4) return -2; snprintf(ret, sizeof(ret), "counter,%u", WPA_GET_BE32(pos)); send_resp(dut, conn, SIGMA_COMPLETE, ret); return 0; } struct tdls_counters { const char *name; enum wlantest_tdls_counter num; }; static const struct tdls_counters tdls_counters[] = { { "valid_direct_link", WLANTEST_TDLS_COUNTER_VALID_DIRECT_LINK }, { "invalid_direct_link", WLANTEST_TDLS_COUNTER_INVALID_DIRECT_LINK }, { "valid_ap_path", WLANTEST_TDLS_COUNTER_VALID_AP_PATH }, { "invalid_ap_path", WLANTEST_TDLS_COUNTER_INVALID_AP_PATH }, { "setup_req", WLANTEST_TDLS_COUNTER_SETUP_REQ }, { "setup_resp_ok", WLANTEST_TDLS_COUNTER_SETUP_RESP_OK }, { "setup_resp_fail", WLANTEST_TDLS_COUNTER_SETUP_RESP_FAIL }, { "setup_conf_ok", WLANTEST_TDLS_COUNTER_SETUP_CONF_OK }, { "setup_conf_fail", WLANTEST_TDLS_COUNTER_SETUP_CONF_FAIL }, { "teardown", WLANTEST_TDLS_COUNTER_TEARDOWN }, { NULL, 0 } }; static int cmd_wlantest_get_tdls_counter(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; u8 buf[100], *end, *pos; int rlen; const char *val; int s, i; char ret[100]; size_t len; pos = buf; end = buf + sizeof(buf); WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_TDLS_COUNTER); pos += 4; val = get_param(cmd, "bssid"); if (val == NULL) return -1; if (val) { pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid bssid"); return 0; } pos += ETH_ALEN; } val = get_param(cmd, "stationID"); if (val == NULL) return -1; if (val) { pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid stationID"); return 0; } pos += ETH_ALEN; } val = get_param(cmd, "stationID2"); if (val == NULL) return -1; if (val) { pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA2_ADDR, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid stationID"); return 0; } pos += ETH_ALEN; } val = get_param(cmd, "field"); if (val == NULL) return -1; for (i = 0; tdls_counters[i].name; i++) { if (strcasecmp(tdls_counters[i].name, val) == 0) break; } if (tdls_counters[i].name == NULL) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid field"); return 0; } pos = attr_add_be32(pos, end, WLANTEST_ATTR_TDLS_COUNTER, tdls_counters[i].num); s = open_wlantest(); if (s < 0) { send_resp(dut, conn, SIGMA_ERROR, "errorCode,wlantest not " "available"); return 0; } rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp)); close(s); pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_COUNTER, &len); if (pos == NULL || len != 4) return -2; snprintf(ret, sizeof(ret), "counter,%u", WPA_GET_BE32(pos)); send_resp(dut, conn, SIGMA_COMPLETE, ret); return 0; } struct sta_infos { const char *name; enum wlantest_sta_info num; }; static const struct sta_infos sta_infos[] = { { "proto", WLANTEST_STA_INFO_PROTO }, { "pairwise", WLANTEST_STA_INFO_PAIRWISE }, { "key_mgmt", WLANTEST_STA_INFO_KEY_MGMT }, { "rsn_capab", WLANTEST_STA_INFO_RSN_CAPAB }, { "state", WLANTEST_STA_INFO_STATE }, { NULL, 0 } }; static int cmd_wlantest_info_sta(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; u8 buf[100], *end, *pos; int rlen; const char *val; int s, i; char ret[120]; size_t len; char info[100]; pos = buf; end = buf + sizeof(buf); WPA_PUT_BE32(pos, WLANTEST_CTRL_INFO_STA); pos += 4; val = get_param(cmd, "bssid"); if (val == NULL) return -1; if (val) { pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid bssid"); return 0; } pos += ETH_ALEN; } val = get_param(cmd, "stationID"); if (val == NULL) return -1; if (val) { pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid stationID"); return 0; } pos += ETH_ALEN; } val = get_param(cmd, "field"); if (val == NULL) return -1; for (i = 0; sta_infos[i].name; i++) { if (strcasecmp(sta_infos[i].name, val) == 0) break; } if (sta_infos[i].name == NULL) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid field"); return 0; } pos = attr_add_be32(pos, end, WLANTEST_ATTR_STA_INFO, sta_infos[i].num); s = open_wlantest(); if (s < 0) { send_resp(dut, conn, SIGMA_ERROR, "errorCode,wlantest not " "available"); return 0; } rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp)); close(s); pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_INFO, &len); if (pos == NULL) return -2; if (len >= sizeof(info)) len = sizeof(info) - 1; memcpy(info, pos, len); info[len] = '\0'; snprintf(ret, sizeof(ret), "info,%s", info); send_resp(dut, conn, SIGMA_COMPLETE, ret); return 0; } struct bss_infos { const char *name; enum wlantest_bss_info num; }; static const struct bss_infos bss_infos[] = { { "proto", WLANTEST_BSS_INFO_PROTO }, { "pairwise", WLANTEST_BSS_INFO_PAIRWISE }, { "group", WLANTEST_BSS_INFO_GROUP }, { "group_mgmt", WLANTEST_BSS_INFO_GROUP_MGMT }, { "key_mgmt", WLANTEST_BSS_INFO_KEY_MGMT }, { "rsn_capab", WLANTEST_BSS_INFO_RSN_CAPAB }, { NULL, 0 } }; static int cmd_wlantest_info_bss(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; u8 buf[100], *end, *pos; int rlen; const char *val; int s, i; char ret[120]; size_t len; char info[100]; pos = buf; end = buf + sizeof(buf); WPA_PUT_BE32(pos, WLANTEST_CTRL_INFO_BSS); pos += 4; val = get_param(cmd, "bssid"); if (val == NULL) return -1; if (val) { pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN); if (hwaddr_aton(val, pos) < 0) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid bssid"); return 0; } pos += ETH_ALEN; } val = get_param(cmd, "field"); if (val == NULL) return -1; for (i = 0; bss_infos[i].name; i++) { if (strcasecmp(bss_infos[i].name, val) == 0) break; } if (bss_infos[i].name == NULL) { send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid field"); return 0; } pos = attr_add_be32(pos, end, WLANTEST_ATTR_BSS_INFO, bss_infos[i].num); s = open_wlantest(); if (s < 0) { send_resp(dut, conn, SIGMA_ERROR, "errorCode,wlantest not " "available"); return 0; } rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp)); close(s); pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_INFO, &len); if (pos == NULL) return -2; if (len >= sizeof(info)) len = sizeof(info) - 1; memcpy(info, pos, len); info[len] = '\0'; snprintf(ret, sizeof(ret), "info,%s", info); send_resp(dut, conn, SIGMA_COMPLETE, ret); return 0; } void wlantest_register_cmds(void) { sigma_dut_reg_cmd("wlantest_version", NULL, cmd_wlantest_version); sigma_dut_reg_cmd("wlantest_set_channel", NULL, cmd_wlantest_set_channel); sigma_dut_reg_cmd("wlantest_flush", NULL, cmd_wlantest_flush); sigma_dut_reg_cmd("wlantest_send_frame", NULL, cmd_wlantest_send_frame); sigma_dut_reg_cmd("wlantest_add_passphrase", NULL, cmd_wlantest_add_passphrase); sigma_dut_reg_cmd("wlantest_clear_sta_counters", NULL, cmd_wlantest_clear_sta_counters); sigma_dut_reg_cmd("wlantest_clear_bss_counters", NULL, cmd_wlantest_clear_bss_counters); sigma_dut_reg_cmd("wlantest_clear_tdls_counters", NULL, cmd_wlantest_clear_tdls_counters); sigma_dut_reg_cmd("wlantest_get_sta_counter", NULL, cmd_wlantest_get_sta_counter); sigma_dut_reg_cmd("wlantest_get_bss_counter", NULL, cmd_wlantest_get_bss_counter); sigma_dut_reg_cmd("wlantest_get_tdls_counter", NULL, cmd_wlantest_get_tdls_counter); sigma_dut_reg_cmd("wlantest_info_sta", NULL, cmd_wlantest_info_sta); sigma_dut_reg_cmd("wlantest_info_bss", NULL, cmd_wlantest_info_bss); }