blob: 23be38e2ddd3beab5f2409f799a7e586f163819b [file] [log] [blame]
#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");