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