158 lines
4.6 KiB
C
158 lines
4.6 KiB
C
#include <errno.h>
|
|
|
|
#include <netlink/genl/genl.h>
|
|
#include <netlink/genl/family.h>
|
|
#include <netlink/genl/ctrl.h>
|
|
#include <netlink/msg.h>
|
|
#include <netlink/attr.h>
|
|
#include <inttypes.h>
|
|
|
|
#include "nl80211.h"
|
|
#include "iw.h"
|
|
|
|
SECTION(ftm);
|
|
|
|
static int handle_ftm_stats(struct nl_msg *msg, void *arg)
|
|
{
|
|
struct nlattr *tb[NL80211_ATTR_MAX + 1];
|
|
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
|
|
struct nlattr *info[NL80211_FTM_STATS_MAX + 1];
|
|
static struct nla_policy info_policy[NL80211_FTM_STATS_MAX + 1] = {
|
|
[NL80211_FTM_STATS_SUCCESS_NUM] = { .type = NLA_U32 },
|
|
[NL80211_FTM_STATS_PARTIAL_NUM] = { .type = NLA_U32 },
|
|
[NL80211_FTM_STATS_FAILED_NUM] = { .type = NLA_U32 },
|
|
[NL80211_FTM_STATS_ASAP_NUM] = { .type = NLA_U32 },
|
|
[NL80211_FTM_STATS_NON_ASAP_NUM] = { .type = NLA_U32 },
|
|
[NL80211_FTM_STATS_TOTAL_DURATION_MSEC] = { .type = NLA_U64 },
|
|
[NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM] = { .type = NLA_U32 },
|
|
[NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM]
|
|
= { .type = NLA_U32 },
|
|
[NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM]
|
|
= { .type = NLA_U32 },
|
|
};
|
|
|
|
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
|
|
genlmsg_attrlen(gnlh, 0), NULL);
|
|
|
|
if (!tb[NL80211_ATTR_FTM_RESPONDER_STATS]) {
|
|
fprintf(stderr, "FTM responder statistics are missing");
|
|
return NL_SKIP;
|
|
}
|
|
|
|
nla_parse(info, NL80211_REG_RULE_ATTR_MAX,
|
|
nla_data(tb[NL80211_ATTR_FTM_RESPONDER_STATS]),
|
|
nla_len(tb[NL80211_ATTR_FTM_RESPONDER_STATS]),
|
|
info_policy);
|
|
|
|
printf("FTM responder stats:\n");
|
|
|
|
if (info[NL80211_FTM_STATS_SUCCESS_NUM])
|
|
printf("\tSuccess num %u\n",
|
|
nla_get_u32(info[NL80211_FTM_STATS_SUCCESS_NUM]));
|
|
|
|
if (info[NL80211_FTM_STATS_PARTIAL_NUM])
|
|
printf("\tPartial success num %u\n",
|
|
nla_get_u32(info[NL80211_FTM_STATS_PARTIAL_NUM]));
|
|
|
|
if (info[NL80211_FTM_STATS_FAILED_NUM])
|
|
printf("\tFailed num %u\n",
|
|
nla_get_u32(info[NL80211_FTM_STATS_FAILED_NUM]));
|
|
|
|
if (info[NL80211_FTM_STATS_ASAP_NUM])
|
|
printf("\tASAP success num %u\n",
|
|
nla_get_u32(info[NL80211_FTM_STATS_ASAP_NUM]));
|
|
|
|
if (info[NL80211_FTM_STATS_NON_ASAP_NUM])
|
|
printf("\tNon ASAP num %u\n",
|
|
nla_get_u32(info[NL80211_FTM_STATS_NON_ASAP_NUM]));
|
|
|
|
if (info[NL80211_FTM_STATS_TOTAL_DURATION_MSEC])
|
|
printf("\tTotal duration %" PRIu64 "\n",
|
|
nla_get_u64(info[NL80211_FTM_STATS_TOTAL_DURATION_MSEC]));
|
|
|
|
if (info[NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM])
|
|
printf("\tUnknown triggers num %u\n",
|
|
nla_get_u32(info[NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM]));
|
|
|
|
if (info[NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM])
|
|
printf("\tRescheduled requests num %u\n",
|
|
nla_get_u32(info[NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM]));
|
|
|
|
if (info[NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM])
|
|
printf("\tOut of window num %u\n",
|
|
nla_get_u32(info[NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM]));
|
|
|
|
return NL_SKIP;
|
|
}
|
|
|
|
static int handle_ftm_get_stats(struct nl80211_state *state,
|
|
struct nl_msg *msg, int argc, char **argv,
|
|
enum id_input id)
|
|
{
|
|
register_handler(handle_ftm_stats, NULL);
|
|
return 0;
|
|
}
|
|
|
|
COMMAND(ftm, get_stats, "",
|
|
NL80211_CMD_GET_FTM_RESPONDER_STATS, 0, CIB_NETDEV, handle_ftm_get_stats,
|
|
"Get FTM responder statistics.\n");
|
|
|
|
static int handle_ftm_start_responder(struct nl80211_state *state,
|
|
struct nl_msg *msg, int argc, char **argv,
|
|
enum id_input id)
|
|
{
|
|
int i;
|
|
char buf[256];
|
|
bool lci_present = false, civic_present = false;
|
|
struct nlattr *ftm = nla_nest_start(msg, NL80211_ATTR_FTM_RESPONDER);
|
|
|
|
if (!ftm)
|
|
return -ENOBUFS;
|
|
|
|
nla_put_flag(msg, NL80211_FTM_RESP_ATTR_ENABLED);
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
if (strncmp(argv[i], "lci=", 4) == 0) {
|
|
size_t lci_len = strlen(argv[i] + 4);
|
|
|
|
if (lci_present || !lci_len || lci_len % 2 ||
|
|
!hex2bin(argv[i] + 4, buf)) {
|
|
printf("Illegal LCI buffer!\n");
|
|
return HANDLER_RET_USAGE;
|
|
}
|
|
|
|
lci_present = true;
|
|
NLA_PUT(msg, NL80211_FTM_RESP_ATTR_LCI,
|
|
lci_len / 2, buf);
|
|
} else if (strncmp(argv[i], "civic=", 6) == 0) {
|
|
size_t civic_len = strlen(argv[i] + 6);
|
|
|
|
if (civic_present || !civic_len || civic_len % 2 ||
|
|
!hex2bin(argv[i] + 6, buf)) {
|
|
printf("Illegal CIVIC buffer!\n");
|
|
return HANDLER_RET_USAGE;
|
|
}
|
|
|
|
civic_present = true;
|
|
NLA_PUT(msg, NL80211_FTM_RESP_ATTR_CIVICLOC,
|
|
civic_len / 2, buf);
|
|
} else {
|
|
printf("Illegal argument: %s\n", argv[i]);
|
|
return HANDLER_RET_USAGE;
|
|
}
|
|
}
|
|
|
|
nla_nest_end(msg, ftm);
|
|
|
|
return 0;
|
|
|
|
nla_put_failure:
|
|
return -ENOMEM;
|
|
}
|
|
|
|
COMMAND(ftm, start_responder,
|
|
"[lci=<lci buffer in hex>] [civic=<civic buffer in hex>]",
|
|
NL80211_CMD_SET_BEACON, 0, CIB_NETDEV,
|
|
handle_ftm_start_responder,
|
|
"Start an FTM responder. Needs a running ap interface\n");
|