xref: /aosp_15_r20/external/iw/phy.c (revision 92022041c981f431db0b590d0c3272306d0ea2a2)
1 #include <stdbool.h>
2 #include <errno.h>
3 #include <strings.h>
4 #include <unistd.h>
5 #include <sys/param.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 
9 #include <netlink/genl/genl.h>
10 #include <netlink/genl/family.h>
11 #include <netlink/genl/ctrl.h>
12 #include <netlink/msg.h>
13 #include <netlink/attr.h>
14 
15 #include "nl80211.h"
16 #include "iw.h"
17 
18 struct channels_ctx {
19 	int last_band;
20 	bool width_40;
21 	bool width_80;
22 	bool width_160;
23 };
24 
dfs_state_name(enum nl80211_dfs_state state)25 static char *dfs_state_name(enum nl80211_dfs_state state)
26 {
27 	switch (state) {
28 	case NL80211_DFS_USABLE:
29 		return "usable";
30 	case NL80211_DFS_AVAILABLE:
31 		return "available";
32 	case NL80211_DFS_UNAVAILABLE:
33 		return "unavailable";
34 	default:
35 		return "unknown";
36 	}
37 }
38 
print_channels_handler(struct nl_msg * msg,void * arg)39 static int print_channels_handler(struct nl_msg *msg, void *arg)
40 {
41 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
42 	struct channels_ctx *ctx = arg;
43 	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
44 	struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
45 	struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
46 	struct nlattr *nl_band;
47 	struct nlattr *nl_freq;
48 	int rem_band, rem_freq;
49 
50 	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
51 
52 	if (tb_msg[NL80211_ATTR_WIPHY_BANDS]) {
53 		nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
54 			if (ctx->last_band != nl_band->nla_type) {
55 				printf("Band %d:\n", nl_band->nla_type + 1);
56 				ctx->width_40 = false;
57 				ctx->width_80 = false;
58 				ctx->width_160 = false;
59 				ctx->last_band = nl_band->nla_type;
60 			}
61 
62 			nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), nla_len(nl_band), NULL);
63 
64 			if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
65 				__u16 cap = nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]);
66 
67 				if (cap & BIT(1))
68 					ctx->width_40 = true;
69 			}
70 
71 			if (tb_band[NL80211_BAND_ATTR_VHT_CAPA]) {
72 				__u32 capa;
73 
74 				ctx->width_80 = true;
75 
76 				capa = nla_get_u32(tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
77 				switch ((capa >> 2) & 3) {
78 				case 2:
79 					/* width_80p80 = true; */
80 					/* fall through */
81 				case 1:
82 					ctx->width_160 = true;
83 				break;
84 				}
85 			}
86 
87 			if (tb_band[NL80211_BAND_ATTR_FREQS]) {
88 				nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
89 					uint32_t freq;
90 
91 					nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), nla_len(nl_freq), NULL);
92 
93 					if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
94 						continue;
95 					freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
96 					printf("\t* %d MHz [%d] ", freq, ieee80211_frequency_to_channel(freq));
97 
98 					if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) {
99 						printf("(disabled)\n");
100 						continue;
101 					}
102 					printf("\n");
103 
104 					if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER])
105 						printf("\t  Maximum TX power: %.1f dBm\n", 0.01 * nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]));
106 
107 					/* If both flags are set assume an new kernel */
108 					if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR] && tb_freq[__NL80211_FREQUENCY_ATTR_NO_IBSS]) {
109 						printf("\t  No IR\n");
110 					} else if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) {
111 						printf("\t  Passive scan\n");
112 					} else if (tb_freq[__NL80211_FREQUENCY_ATTR_NO_IBSS]){
113 						printf("\t  No IBSS\n");
114 					}
115 
116 					if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
117 						printf("\t  Radar detection\n");
118 
119 					printf("\t  Channel widths:");
120 					if (!tb_freq[NL80211_FREQUENCY_ATTR_NO_20MHZ])
121 						printf(" 20MHz");
122 					if (ctx->width_40 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS])
123 						printf(" HT40-");
124 					if (ctx->width_40 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS])
125 						printf(" HT40+");
126 					if (ctx->width_80 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_80MHZ])
127 						printf(" VHT80");
128 					if (ctx->width_160 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_160MHZ])
129 						printf(" VHT160");
130 					printf("\n");
131 
132 					if (!tb_freq[NL80211_FREQUENCY_ATTR_DISABLED] && tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
133 						enum nl80211_dfs_state state = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
134 						unsigned long time;
135 
136 						printf("\t  DFS state: %s", dfs_state_name(state));
137 						if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]) {
138 							time = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]);
139 							printf(" (for %lu sec)", time / 1000);
140 						}
141 						printf("\n");
142 						if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME])
143 							printf("\t  DFS CAC time: %u ms\n",
144 							       nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]));
145 					}
146 				}
147 			}
148 		}
149 	}
150 
151 	return NL_SKIP;
152 }
153 
handle_channels(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)154 static int handle_channels(struct nl80211_state *state, struct nl_msg *msg,
155 			   int argc, char **argv, enum id_input id)
156 {
157 	static struct channels_ctx ctx = {
158 		.last_band = -1,
159 	};
160 
161 	nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
162 	nlmsg_hdr(msg)->nlmsg_flags |= NLM_F_DUMP;
163 
164 	register_handler(print_channels_handler, &ctx);
165 
166 	return 0;
167 }
168 TOPLEVEL(channels, NULL, NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_channels, "Show available channels.");
169 
handle_name(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)170 static int handle_name(struct nl80211_state *state,
171 		       struct nl_msg *msg,
172 		       int argc, char **argv,
173 		       enum id_input id)
174 {
175 	if (argc != 1)
176 		return 1;
177 
178 	NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, *argv);
179 
180 	return 0;
181  nla_put_failure:
182 	return -ENOBUFS;
183 }
184 COMMAND(set, name, "<new name>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_name,
185 	"Rename this wireless device.");
186 
handle_freq(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)187 static int handle_freq(struct nl80211_state *state, struct nl_msg *msg,
188 		       int argc, char **argv,
189 		       enum id_input id)
190 {
191 	struct chandef chandef;
192 	int res;
193 
194 	res = parse_freqchan(&chandef, false, argc, argv, NULL);
195 	if (res)
196 		return res;
197 
198 	return put_chandef(msg, &chandef);
199 }
200 
201 COMMAND(set, freq,
202 	"<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]\n"
203 	"<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
204 	NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq,
205 	"Set frequency/channel the hardware is using, including HT\n"
206 	"configuration.");
207 COMMAND(set, freq,
208 	"<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]\n"
209 	"<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
210 	NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL);
211 
handle_chan(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)212 static int handle_chan(struct nl80211_state *state, struct nl_msg *msg,
213 		       int argc, char **argv,
214 		       enum id_input id)
215 {
216 	struct chandef chandef;
217 	int res;
218 
219 	res = parse_freqchan(&chandef, true, argc, argv, NULL);
220 	if (res)
221 		return res;
222 
223 	return put_chandef(msg, &chandef);
224 }
225 COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]",
226 	NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL);
227 COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]",
228 	NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);
229 
230 
231 struct cac_event {
232 	int ret;
233 	uint32_t freq;
234 };
235 
print_cac_event(struct nl_msg * msg,void * arg)236 static int print_cac_event(struct nl_msg *msg, void *arg)
237 {
238 	struct nlattr *tb[NL80211_ATTR_MAX + 1];
239 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
240 	enum nl80211_radar_event event_type;
241 	struct cac_event *cac_event = arg;
242 	uint32_t freq;
243 
244 	if (gnlh->cmd != NL80211_CMD_RADAR_DETECT)
245 		return NL_SKIP;
246 
247 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
248 		  genlmsg_attrlen(gnlh, 0), NULL);
249 
250 	if (!tb[NL80211_ATTR_RADAR_EVENT] || !tb[NL80211_ATTR_WIPHY_FREQ])
251 		return NL_SKIP;
252 
253 	freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
254 	event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
255 	if (freq != cac_event->freq)
256 		return NL_SKIP;
257 
258 	switch (event_type) {
259 	case NL80211_RADAR_DETECTED:
260 		printf("%d MHz: radar detected\n", freq);
261 		break;
262 	case NL80211_RADAR_CAC_FINISHED:
263 		printf("%d MHz: CAC finished\n", freq);
264 		break;
265 	case NL80211_RADAR_CAC_ABORTED:
266 		printf("%d MHz: CAC was aborted\n", freq);
267 		break;
268 	case NL80211_RADAR_NOP_FINISHED:
269 		printf("%d MHz: NOP finished\n", freq);
270 		break;
271 	default:
272 		printf("%d MHz: unknown radar event\n", freq);
273 	}
274 	cac_event->ret = 0;
275 
276 	return NL_SKIP;
277 }
278 
handle_cac_trigger(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)279 static int handle_cac_trigger(struct nl80211_state *state,
280 			    struct nl_msg *msg,
281 			    int argc, char **argv,
282 			    enum id_input id)
283 {
284 	struct chandef chandef;
285 	int res;
286 
287 	if (argc < 2)
288 		return 1;
289 
290 	if (strcmp(argv[0], "channel") == 0) {
291 		res = parse_freqchan(&chandef, true, argc - 1, argv + 1, NULL);
292 	} else if (strcmp(argv[0], "freq") == 0) {
293 		res = parse_freqchan(&chandef, false, argc - 1, argv + 1, NULL);
294 	} else {
295 		return 1;
296 	}
297 
298 	if (res)
299 		return res;
300 
301 	return put_chandef(msg, &chandef);
302 }
303 
no_seq_check(struct nl_msg * msg,void * arg)304 static int no_seq_check(struct nl_msg *msg, void *arg)
305 {
306 	return NL_OK;
307 }
308 
handle_cac(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)309 static int handle_cac(struct nl80211_state *state,
310 		      struct nl_msg *msg,
311 		      int argc, char **argv,
312 		      enum id_input id)
313 {
314 	int err;
315 	struct nl_cb *radar_cb;
316 	struct chandef chandef;
317 	struct cac_event cac_event;
318 	char **cac_trigger_argv = NULL;
319 
320 	radar_cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
321 	if (!radar_cb)
322 		return 1;
323 
324 	if (argc < 3)
325 		return 1;
326 
327 	if (strcmp(argv[2], "channel") == 0) {
328 		err = parse_freqchan(&chandef, true, argc - 3, argv + 3, NULL);
329 	} else if (strcmp(argv[2], "freq") == 0) {
330 		err = parse_freqchan(&chandef, false, argc - 3, argv + 3, NULL);
331 	} else {
332 		err = 1;
333 	}
334 	if (err)
335 		goto err_out;
336 
337 	cac_trigger_argv = calloc(argc + 1, sizeof(char*));
338 	if (!cac_trigger_argv) {
339 		err = -ENOMEM;
340 		goto err_out;
341 	}
342 
343 	cac_trigger_argv[0] = argv[0];
344 	cac_trigger_argv[1] = "cac";
345 	cac_trigger_argv[2] = "trigger";
346 	memcpy(&cac_trigger_argv[3], &argv[2], (argc - 2) * sizeof(char*));
347 
348 	err = handle_cmd(state, id, argc + 1, cac_trigger_argv);
349 	if (err)
350 		goto err_out;
351 
352 	cac_event.ret = 1;
353 	cac_event.freq = chandef.control_freq;
354 
355 	__prepare_listen_events(state);
356 	nl_socket_set_cb(state->nl_sock, radar_cb);
357 
358 	/* need to turn off sequence number checking */
359 	nl_cb_set(radar_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
360 	nl_cb_set(radar_cb, NL_CB_VALID, NL_CB_CUSTOM, print_cac_event, &cac_event);
361 	while (cac_event.ret > 0)
362 		nl_recvmsgs(state->nl_sock, radar_cb);
363 
364 	err = 0;
365 err_out:
366 	if (radar_cb)
367 		nl_cb_put(radar_cb);
368 	if (cac_trigger_argv)
369 		free(cac_trigger_argv);
370 	return err;
371 }
372 TOPLEVEL(cac, "channel <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
373 	      "freq <freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
374 	      "freq <control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
375 	 0, 0, CIB_NETDEV, handle_cac, NULL);
376 COMMAND(cac, trigger,
377 	"channel <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
378 	"freq <frequency> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
379 	"freq <frequency> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
380 	NL80211_CMD_RADAR_DETECT, 0, CIB_NETDEV, handle_cac_trigger,
381 	"Start or trigger a channel availability check (CAC) looking to look for\n"
382 	"radars on the given channel.");
383 
handle_fragmentation(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)384 static int handle_fragmentation(struct nl80211_state *state,
385 				struct nl_msg *msg,
386 				int argc, char **argv,
387 				enum id_input id)
388 {
389 	unsigned int frag;
390 
391 	if (argc != 1)
392 		return 1;
393 
394 	if (strcmp("off", argv[0]) == 0)
395 		frag = -1;
396 	else {
397 		char *end;
398 
399 		if (!*argv[0])
400 			return 1;
401 		frag = strtoul(argv[0], &end, 10);
402 		if (*end != '\0')
403 			return 1;
404 	}
405 
406 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, frag);
407 
408 	return 0;
409  nla_put_failure:
410 	return -ENOBUFS;
411 }
412 COMMAND(set, frag, "<fragmentation threshold|off>",
413 	NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_fragmentation,
414 	"Set fragmentation threshold.");
415 
handle_rts(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)416 static int handle_rts(struct nl80211_state *state,
417 		      struct nl_msg *msg,
418 		      int argc, char **argv,
419 		      enum id_input id)
420 {
421 	unsigned int rts;
422 
423 	if (argc != 1)
424 		return 1;
425 
426 	if (strcmp("off", argv[0]) == 0)
427 		rts = -1;
428 	else {
429 		char *end;
430 
431 		if (!*argv[0])
432 			return 1;
433 		rts = strtoul(argv[0], &end, 10);
434 		if (*end != '\0')
435 			return 1;
436 	}
437 
438 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, rts);
439 
440 	return 0;
441  nla_put_failure:
442 	return -ENOBUFS;
443 }
444 COMMAND(set, rts, "<rts threshold|off>",
445 	NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_rts,
446 	"Set rts threshold.");
447 
handle_retry(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)448 static int handle_retry(struct nl80211_state *state,
449 			struct nl_msg *msg,
450 			int argc, char **argv, enum id_input id)
451 {
452 	unsigned int retry_short = 0, retry_long = 0;
453 	bool have_retry_s = false, have_retry_l = false;
454 	int i;
455 	enum {
456 		S_NONE,
457 		S_SHORT,
458 		S_LONG,
459 	} parser_state = S_NONE;
460 
461 	if (!argc || (argc != 2 && argc != 4))
462 		return 1;
463 
464 	for (i = 0; i < argc; i++) {
465 		char *end;
466 		unsigned int tmpul;
467 
468 		if (strcmp(argv[i], "short") == 0) {
469 			if (have_retry_s)
470 				return 1;
471 			parser_state = S_SHORT;
472 			have_retry_s = true;
473 		} else if (strcmp(argv[i], "long") == 0) {
474 			if (have_retry_l)
475 				return 1;
476 			parser_state = S_LONG;
477 			have_retry_l = true;
478 		} else {
479 			tmpul = strtoul(argv[i], &end, 10);
480 			if (*end != '\0')
481 				return 1;
482 			if (!tmpul || tmpul > 255)
483 				return -EINVAL;
484 			switch (parser_state) {
485 			case S_SHORT:
486 				retry_short = tmpul;
487 				break;
488 			case S_LONG:
489 				retry_long = tmpul;
490 				break;
491 			default:
492 				return 1;
493 			}
494 		}
495 	}
496 
497 	if (!have_retry_s && !have_retry_l)
498 		return 1;
499 	if (have_retry_s)
500 		NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, retry_short);
501 	if (have_retry_l)
502 		NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, retry_long);
503 
504 	return 0;
505  nla_put_failure:
506 	return -ENOBUFS;
507 }
508 COMMAND(set, retry, "[short <limit>] [long <limit>]",
509 	NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_retry,
510 	"Set retry limit.");
511 
512 #ifndef NETNS_RUN_DIR
513 #define NETNS_RUN_DIR "/var/run/netns"
514 #endif
netns_get_fd(const char * name)515 static int netns_get_fd(const char *name)
516 {
517 	char pathbuf[MAXPATHLEN];
518 	const char *path, *ptr;
519 
520 	path = name;
521 	ptr = strchr(name, '/');
522 	if (!ptr) {
523 		snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
524 			NETNS_RUN_DIR, name );
525 		path = pathbuf;
526 	}
527 	return open(path, O_RDONLY);
528 }
529 
handle_netns(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)530 static int handle_netns(struct nl80211_state *state,
531 			struct nl_msg *msg,
532 			int argc, char **argv,
533 			enum id_input id)
534 {
535 	char *end;
536 	int fd = -1;
537 
538 	if (argc < 1 || !*argv[0])
539 		return 1;
540 
541 	if (argc == 1) {
542 		NLA_PUT_U32(msg, NL80211_ATTR_PID,
543 				strtoul(argv[0], &end, 10));
544 		if (*end != '\0') {
545 			printf("Invalid parameter: pid(%s)\n", argv[0]);
546 			return 1;
547 		}
548 		return 0;
549 	}
550 
551 	if (argc != 2 || strcmp(argv[0], "name"))
552 		return 1;
553 
554 	if ((fd = netns_get_fd(argv[1])) >= 0) {
555 		NLA_PUT_U32(msg, NL80211_ATTR_NETNS_FD, fd);
556 		return 0;
557 	} else {
558 		printf("Invalid parameter: nsname(%s)\n", argv[0]);
559 	}
560 
561 	return 1;
562 
563  nla_put_failure:
564 	if (fd >= 0)
565 		close(fd);
566 	return -ENOBUFS;
567 }
568 COMMAND(set, netns, "{ <pid> | name <nsname> }",
569 	NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
570 	"Put this wireless device into a different network namespace:\n"
571 	"    <pid>    - change network namespace by process id\n"
572 	"    <nsname> - change network namespace by name from "NETNS_RUN_DIR"\n"
573 	"               or by absolute path (man ip-netns)\n");
574 
handle_coverage(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)575 static int handle_coverage(struct nl80211_state *state,
576 			struct nl_msg *msg,
577 			int argc, char **argv,
578 			enum id_input id)
579 {
580 	char *end;
581 	unsigned int coverage;
582 
583 	if (argc != 1)
584 		return 1;
585 
586 	if (!*argv[0])
587 		return 1;
588 	coverage = strtoul(argv[0], &end, 10);
589 	if (coverage > 255)
590 		return 1;
591 
592 	if (*end)
593 		return 1;
594 
595 	NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
596 
597 	return 0;
598  nla_put_failure:
599 	return -ENOBUFS;
600 }
601 COMMAND(set, coverage, "<coverage class>",
602 	NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_coverage,
603 	"Set coverage class (1 for every 3 usec of air propagation time).\n"
604 	"Valid values: 0 - 255.");
605 
handle_distance(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)606 static int handle_distance(struct nl80211_state *state,
607 			struct nl_msg *msg,
608 			int argc, char **argv,
609 			enum id_input id)
610 {
611 	if (argc != 1)
612 		return 1;
613 
614 	if (!*argv[0])
615 		return 1;
616 
617 	if (strcmp("auto", argv[0]) == 0) {
618 		NLA_PUT_FLAG(msg, NL80211_ATTR_WIPHY_DYN_ACK);
619 	} else {
620 		char *end;
621 		unsigned int distance, coverage;
622 
623 		distance = strtoul(argv[0], &end, 10);
624 
625 		if (*end)
626 			return 1;
627 
628 		/*
629 		 * Divide double the distance by the speed of light
630 		 * in m/usec (300) to get round-trip time in microseconds
631 		 * and then divide the result by three to get coverage class
632 		 * as specified in IEEE 802.11-2007 table 7-27.
633 		 * Values are rounded upwards.
634 		 */
635 		coverage = (distance + 449) / 450;
636 		if (coverage > 255)
637 			return 1;
638 
639 		NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
640 	}
641 
642 	return 0;
643  nla_put_failure:
644 	return -ENOBUFS;
645 }
646 COMMAND(set, distance, "<auto|distance>",
647 	NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
648 	"Enable ACK timeout estimation algorithm (dynack) or set appropriate\n"
649 	"coverage class for given link distance in meters.\n"
650 	"To disable dynack set valid value for coverage class.\n"
651 	"Valid values: 0 - 114750");
652 
handle_txpower(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)653 static int handle_txpower(struct nl80211_state *state,
654 			  struct nl_msg *msg,
655 			  int argc, char **argv,
656 			  enum id_input id)
657 {
658 	enum nl80211_tx_power_setting type;
659 	int mbm;
660 
661 	/* get the required args */
662 	if (argc != 1 && argc != 2)
663 		return 1;
664 
665 	if (!strcmp(argv[0], "auto"))
666 		type = NL80211_TX_POWER_AUTOMATIC;
667 	else if (!strcmp(argv[0], "fixed"))
668 		type = NL80211_TX_POWER_FIXED;
669 	else if (!strcmp(argv[0], "limit"))
670 		type = NL80211_TX_POWER_LIMITED;
671 	else {
672 		printf("Invalid parameter: %s\n", argv[0]);
673 		return 2;
674 	}
675 
676 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type);
677 
678 	if (type != NL80211_TX_POWER_AUTOMATIC) {
679 		char *endptr;
680 		if (argc != 2) {
681 			printf("Missing TX power level argument.\n");
682 			return 2;
683 		}
684 
685 		mbm = strtol(argv[1], &endptr, 10);
686 		if (*endptr)
687 			return 2;
688 		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mbm);
689 	} else if (argc != 1)
690 		return 1;
691 
692 	return 0;
693 
694  nla_put_failure:
695 	return -ENOBUFS;
696 }
697 COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
698 	NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_txpower,
699 	"Specify transmit power level and setting type.");
700 COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
701 	NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_txpower,
702 	"Specify transmit power level and setting type.");
703 
handle_antenna(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)704 static int handle_antenna(struct nl80211_state *state,
705 			  struct nl_msg *msg,
706 			  int argc, char **argv,
707 			  enum id_input id)
708 {
709 	char *end;
710 	uint32_t tx_ant = 0, rx_ant = 0;
711 
712 	if (argc == 1 && strcmp(argv[0], "all") == 0) {
713 		tx_ant = 0xffffffff;
714 		rx_ant = 0xffffffff;
715 	} else if (argc == 1) {
716 		tx_ant = rx_ant = strtoul(argv[0], &end, 0);
717 		if (*end)
718 			return 1;
719 	}
720 	else if (argc == 2) {
721 		tx_ant = strtoul(argv[0], &end, 0);
722 		if (*end)
723 			return 1;
724 		rx_ant = strtoul(argv[1], &end, 0);
725 		if (*end)
726 			return 1;
727 	} else
728 		return 1;
729 
730 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant);
731 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant);
732 
733 	return 0;
734 
735  nla_put_failure:
736 	return -ENOBUFS;
737 }
738 COMMAND(set, antenna, "<bitmap> | all | <tx bitmap> <rx bitmap>",
739 	NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna,
740 	"Set a bitmap of allowed antennas to use for TX and RX.\n"
741 	"The driver may reject antenna configurations it cannot support.");
742 
handle_set_txq(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)743 static int handle_set_txq(struct nl80211_state *state,
744 			  struct nl_msg *msg,
745 			  int argc, char **argv,
746 			  enum id_input id)
747 {
748 	unsigned int argval;
749 	char *end;
750 
751 	if (argc != 2)
752 		return 1;
753 
754 	if (!*argv[0] || !*argv[1])
755 		return 1;
756 
757 	argval = strtoul(argv[1], &end, 10);
758 
759 	if (*end)
760 		return 1;
761 
762 	if (!argval)
763 		return 1;
764 
765 	if (strcmp("limit", argv[0]) == 0)
766 		NLA_PUT_U32(msg, NL80211_ATTR_TXQ_LIMIT, argval);
767 	else if (strcmp("memory_limit", argv[0]) == 0)
768 		NLA_PUT_U32(msg, NL80211_ATTR_TXQ_MEMORY_LIMIT, argval);
769 	else if (strcmp("quantum", argv[0]) == 0)
770 		NLA_PUT_U32(msg, NL80211_ATTR_TXQ_QUANTUM, argval);
771 	else
772 		return -1;
773 
774 	return 0;
775  nla_put_failure:
776 	return -ENOBUFS;
777 }
778 COMMAND(set, txq, "limit <packets> | memory_limit <bytes> | quantum <bytes>",
779 	NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_set_txq,
780 	"Set TXQ parameters. The limit and memory_limit are global queue limits\n"
781 	"for the whole phy. The quantum is the DRR scheduler quantum setting.\n"
782 	"Valid values: 1 - 2**32");
783 
print_txq_handler(struct nl_msg * msg,void * arg)784 static int print_txq_handler(struct nl_msg *msg, void *arg)
785 {
786 	struct nlattr *attrs[NL80211_ATTR_MAX + 1];
787 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
788 	struct nlattr *txqstats_info[NL80211_TXQ_STATS_MAX + 1], *txqinfo;
789 	static struct nla_policy txqstats_policy[NL80211_TXQ_STATS_MAX + 1] = {
790 		[NL80211_TXQ_STATS_BACKLOG_PACKETS] = { .type = NLA_U32 },
791 		[NL80211_TXQ_STATS_BACKLOG_BYTES] = { .type = NLA_U32 },
792 		[NL80211_TXQ_STATS_OVERLIMIT] = { .type = NLA_U32 },
793 		[NL80211_TXQ_STATS_OVERMEMORY] = { .type = NLA_U32 },
794 		[NL80211_TXQ_STATS_COLLISIONS] = { .type = NLA_U32 },
795 		[NL80211_TXQ_STATS_MAX_FLOWS] = { .type = NLA_U32 },
796 	};
797 
798 	nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
799 		  genlmsg_attrlen(gnlh, 0), NULL);
800 
801 
802 	if (attrs[NL80211_ATTR_TXQ_LIMIT])
803 		printf("Packet limit:\t\t%u pkts\n",
804 			nla_get_u32(attrs[NL80211_ATTR_TXQ_LIMIT]));
805 	if (attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT])
806 		printf("Memory limit:\t\t%u bytes\n",
807 			nla_get_u32(attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]));
808 	if (attrs[NL80211_ATTR_TXQ_QUANTUM])
809 		printf("Quantum:\t\t%u bytes\n",
810 			nla_get_u32(attrs[NL80211_ATTR_TXQ_QUANTUM]));
811 
812 	if (attrs[NL80211_ATTR_TXQ_STATS]) {
813 		if (nla_parse_nested(txqstats_info, NL80211_TXQ_STATS_MAX,
814 				     attrs[NL80211_ATTR_TXQ_STATS],
815 				     txqstats_policy)) {
816 			printf("failed to parse nested TXQ stats attributes!");
817 			return 0;
818 		}
819 		txqinfo = txqstats_info[NL80211_TXQ_STATS_MAX_FLOWS];
820 		if (txqinfo)
821 			printf("Number of queues:\t%u\n", nla_get_u32(txqinfo));
822 
823 		txqinfo = txqstats_info[NL80211_TXQ_STATS_BACKLOG_PACKETS];
824 		if (txqinfo)
825 			printf("Backlog:\t\t%u pkts\n", nla_get_u32(txqinfo));
826 
827 		txqinfo = txqstats_info[NL80211_TXQ_STATS_BACKLOG_BYTES];
828 		if (txqinfo)
829 			printf("Memory usage:\t\t%u bytes\n", nla_get_u32(txqinfo));
830 
831 		txqinfo = txqstats_info[NL80211_TXQ_STATS_OVERLIMIT];
832 		if (txqinfo)
833 			printf("Packet limit overflows:\t%u\n", nla_get_u32(txqinfo));
834 
835 		txqinfo = txqstats_info[NL80211_TXQ_STATS_OVERMEMORY];
836 		if (txqinfo)
837 			printf("Memory limit overflows:\t%u\n", nla_get_u32(txqinfo));
838 		txqinfo = txqstats_info[NL80211_TXQ_STATS_COLLISIONS];
839 		if (txqinfo)
840 			printf("Hash collisions:\t%u\n", nla_get_u32(txqinfo));
841 	}
842 	return NL_SKIP;
843 }
844 
handle_get_txq(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)845 static int handle_get_txq(struct nl80211_state *state,
846 			  struct nl_msg *msg,
847 			  int argc, char **argv,
848 			  enum id_input id)
849 {
850 	nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
851 	nlmsg_hdr(msg)->nlmsg_flags |= NLM_F_DUMP;
852 	register_handler(print_txq_handler, NULL);
853 	return 0;
854 }
855 COMMAND(get, txq, "",
856 	NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_get_txq,
857 	"Get TXQ parameters.");
858