1*92022041SSam Saccone #include <errno.h>
2*92022041SSam Saccone
3*92022041SSam Saccone #include <netlink/genl/genl.h>
4*92022041SSam Saccone #include <netlink/genl/family.h>
5*92022041SSam Saccone #include <netlink/genl/ctrl.h>
6*92022041SSam Saccone #include <netlink/msg.h>
7*92022041SSam Saccone #include <netlink/attr.h>
8*92022041SSam Saccone #include <inttypes.h>
9*92022041SSam Saccone
10*92022041SSam Saccone #include "nl80211.h"
11*92022041SSam Saccone #include "iw.h"
12*92022041SSam Saccone
13*92022041SSam Saccone SECTION(ftm);
14*92022041SSam Saccone
handle_ftm_stats(struct nl_msg * msg,void * arg)15*92022041SSam Saccone static int handle_ftm_stats(struct nl_msg *msg, void *arg)
16*92022041SSam Saccone {
17*92022041SSam Saccone struct nlattr *tb[NL80211_ATTR_MAX + 1];
18*92022041SSam Saccone struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
19*92022041SSam Saccone struct nlattr *info[NL80211_FTM_STATS_MAX + 1];
20*92022041SSam Saccone static struct nla_policy info_policy[NL80211_FTM_STATS_MAX + 1] = {
21*92022041SSam Saccone [NL80211_FTM_STATS_SUCCESS_NUM] = { .type = NLA_U32 },
22*92022041SSam Saccone [NL80211_FTM_STATS_PARTIAL_NUM] = { .type = NLA_U32 },
23*92022041SSam Saccone [NL80211_FTM_STATS_FAILED_NUM] = { .type = NLA_U32 },
24*92022041SSam Saccone [NL80211_FTM_STATS_ASAP_NUM] = { .type = NLA_U32 },
25*92022041SSam Saccone [NL80211_FTM_STATS_NON_ASAP_NUM] = { .type = NLA_U32 },
26*92022041SSam Saccone [NL80211_FTM_STATS_TOTAL_DURATION_MSEC] = { .type = NLA_U64 },
27*92022041SSam Saccone [NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM] = { .type = NLA_U32 },
28*92022041SSam Saccone [NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM]
29*92022041SSam Saccone = { .type = NLA_U32 },
30*92022041SSam Saccone [NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM]
31*92022041SSam Saccone = { .type = NLA_U32 },
32*92022041SSam Saccone };
33*92022041SSam Saccone
34*92022041SSam Saccone nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
35*92022041SSam Saccone genlmsg_attrlen(gnlh, 0), NULL);
36*92022041SSam Saccone
37*92022041SSam Saccone if (!tb[NL80211_ATTR_FTM_RESPONDER_STATS]) {
38*92022041SSam Saccone fprintf(stderr, "FTM responder statistics are missing");
39*92022041SSam Saccone return NL_SKIP;
40*92022041SSam Saccone }
41*92022041SSam Saccone
42*92022041SSam Saccone nla_parse(info, NL80211_REG_RULE_ATTR_MAX,
43*92022041SSam Saccone nla_data(tb[NL80211_ATTR_FTM_RESPONDER_STATS]),
44*92022041SSam Saccone nla_len(tb[NL80211_ATTR_FTM_RESPONDER_STATS]),
45*92022041SSam Saccone info_policy);
46*92022041SSam Saccone
47*92022041SSam Saccone printf("FTM responder stats:\n");
48*92022041SSam Saccone
49*92022041SSam Saccone if (info[NL80211_FTM_STATS_SUCCESS_NUM])
50*92022041SSam Saccone printf("\tSuccess num %u\n",
51*92022041SSam Saccone nla_get_u32(info[NL80211_FTM_STATS_SUCCESS_NUM]));
52*92022041SSam Saccone
53*92022041SSam Saccone if (info[NL80211_FTM_STATS_PARTIAL_NUM])
54*92022041SSam Saccone printf("\tPartial success num %u\n",
55*92022041SSam Saccone nla_get_u32(info[NL80211_FTM_STATS_PARTIAL_NUM]));
56*92022041SSam Saccone
57*92022041SSam Saccone if (info[NL80211_FTM_STATS_FAILED_NUM])
58*92022041SSam Saccone printf("\tFailed num %u\n",
59*92022041SSam Saccone nla_get_u32(info[NL80211_FTM_STATS_FAILED_NUM]));
60*92022041SSam Saccone
61*92022041SSam Saccone if (info[NL80211_FTM_STATS_ASAP_NUM])
62*92022041SSam Saccone printf("\tASAP success num %u\n",
63*92022041SSam Saccone nla_get_u32(info[NL80211_FTM_STATS_ASAP_NUM]));
64*92022041SSam Saccone
65*92022041SSam Saccone if (info[NL80211_FTM_STATS_NON_ASAP_NUM])
66*92022041SSam Saccone printf("\tNon ASAP num %u\n",
67*92022041SSam Saccone nla_get_u32(info[NL80211_FTM_STATS_NON_ASAP_NUM]));
68*92022041SSam Saccone
69*92022041SSam Saccone if (info[NL80211_FTM_STATS_TOTAL_DURATION_MSEC])
70*92022041SSam Saccone printf("\tTotal duration %" PRIu64 "\n",
71*92022041SSam Saccone nla_get_u64(info[NL80211_FTM_STATS_TOTAL_DURATION_MSEC]));
72*92022041SSam Saccone
73*92022041SSam Saccone if (info[NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM])
74*92022041SSam Saccone printf("\tUnknown triggers num %u\n",
75*92022041SSam Saccone nla_get_u32(info[NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM]));
76*92022041SSam Saccone
77*92022041SSam Saccone if (info[NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM])
78*92022041SSam Saccone printf("\tRescheduled requests num %u\n",
79*92022041SSam Saccone nla_get_u32(info[NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM]));
80*92022041SSam Saccone
81*92022041SSam Saccone if (info[NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM])
82*92022041SSam Saccone printf("\tOut of window num %u\n",
83*92022041SSam Saccone nla_get_u32(info[NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM]));
84*92022041SSam Saccone
85*92022041SSam Saccone return NL_SKIP;
86*92022041SSam Saccone }
87*92022041SSam Saccone
handle_ftm_get_stats(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)88*92022041SSam Saccone static int handle_ftm_get_stats(struct nl80211_state *state,
89*92022041SSam Saccone struct nl_msg *msg, int argc, char **argv,
90*92022041SSam Saccone enum id_input id)
91*92022041SSam Saccone {
92*92022041SSam Saccone register_handler(handle_ftm_stats, NULL);
93*92022041SSam Saccone return 0;
94*92022041SSam Saccone }
95*92022041SSam Saccone
96*92022041SSam Saccone COMMAND(ftm, get_stats, "",
97*92022041SSam Saccone NL80211_CMD_GET_FTM_RESPONDER_STATS, 0, CIB_NETDEV, handle_ftm_get_stats,
98*92022041SSam Saccone "Get FTM responder statistics.\n");
99*92022041SSam Saccone
handle_ftm_start_responder(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)100*92022041SSam Saccone static int handle_ftm_start_responder(struct nl80211_state *state,
101*92022041SSam Saccone struct nl_msg *msg, int argc, char **argv,
102*92022041SSam Saccone enum id_input id)
103*92022041SSam Saccone {
104*92022041SSam Saccone int i;
105*92022041SSam Saccone char buf[256];
106*92022041SSam Saccone bool lci_present = false, civic_present = false;
107*92022041SSam Saccone struct nlattr *ftm = nla_nest_start(msg, NL80211_ATTR_FTM_RESPONDER);
108*92022041SSam Saccone
109*92022041SSam Saccone if (!ftm)
110*92022041SSam Saccone return -ENOBUFS;
111*92022041SSam Saccone
112*92022041SSam Saccone nla_put_flag(msg, NL80211_FTM_RESP_ATTR_ENABLED);
113*92022041SSam Saccone
114*92022041SSam Saccone for (i = 0; i < argc; i++) {
115*92022041SSam Saccone if (strncmp(argv[i], "lci=", 4) == 0) {
116*92022041SSam Saccone size_t lci_len = strlen(argv[i] + 4);
117*92022041SSam Saccone
118*92022041SSam Saccone if (lci_present || !lci_len || lci_len % 2 ||
119*92022041SSam Saccone !hex2bin(argv[i] + 4, buf)) {
120*92022041SSam Saccone printf("Illegal LCI buffer!\n");
121*92022041SSam Saccone return HANDLER_RET_USAGE;
122*92022041SSam Saccone }
123*92022041SSam Saccone
124*92022041SSam Saccone lci_present = true;
125*92022041SSam Saccone NLA_PUT(msg, NL80211_FTM_RESP_ATTR_LCI,
126*92022041SSam Saccone lci_len / 2, buf);
127*92022041SSam Saccone } else if (strncmp(argv[i], "civic=", 6) == 0) {
128*92022041SSam Saccone size_t civic_len = strlen(argv[i] + 6);
129*92022041SSam Saccone
130*92022041SSam Saccone if (civic_present || !civic_len || civic_len % 2 ||
131*92022041SSam Saccone !hex2bin(argv[i] + 6, buf)) {
132*92022041SSam Saccone printf("Illegal CIVIC buffer!\n");
133*92022041SSam Saccone return HANDLER_RET_USAGE;
134*92022041SSam Saccone }
135*92022041SSam Saccone
136*92022041SSam Saccone civic_present = true;
137*92022041SSam Saccone NLA_PUT(msg, NL80211_FTM_RESP_ATTR_CIVICLOC,
138*92022041SSam Saccone civic_len / 2, buf);
139*92022041SSam Saccone } else {
140*92022041SSam Saccone printf("Illegal argument: %s\n", argv[i]);
141*92022041SSam Saccone return HANDLER_RET_USAGE;
142*92022041SSam Saccone }
143*92022041SSam Saccone }
144*92022041SSam Saccone
145*92022041SSam Saccone nla_nest_end(msg, ftm);
146*92022041SSam Saccone
147*92022041SSam Saccone return 0;
148*92022041SSam Saccone
149*92022041SSam Saccone nla_put_failure:
150*92022041SSam Saccone return -ENOMEM;
151*92022041SSam Saccone }
152*92022041SSam Saccone
153*92022041SSam Saccone COMMAND(ftm, start_responder,
154*92022041SSam Saccone "[lci=<lci buffer in hex>] [civic=<civic buffer in hex>]",
155*92022041SSam Saccone NL80211_CMD_SET_BEACON, 0, CIB_NETDEV,
156*92022041SSam Saccone handle_ftm_start_responder,
157*92022041SSam Saccone "Start an FTM responder. Needs a running ap interface\n");
158