1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
#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");
|