]> git.ipfire.org Git - thirdparty/iw.git/blame - util.c
iw: scan: parse 'supported Operating Classes element'
[thirdparty/iw.git] / util.c
CommitLineData
748f8489 1#include <ctype.h>
51e9bd80
JB
2#include <netlink/attr.h>
3#include <errno.h>
4#include <stdbool.h>
3d1e8704 5#include "iw.h"
f5f7b1d0 6#include "nl80211.h"
3d1e8704 7
7f87d3cf 8void mac_addr_n2a(char *mac_addr, const unsigned char *arg)
3d1e8704 9{
53e5ce7a 10 int i, l;
3d1e8704
LCC
11
12 l = 0;
13 for (i = 0; i < ETH_ALEN ; i++) {
14 if (i == 0) {
53e5ce7a 15 sprintf(mac_addr+l, "%02x", arg[i]);
3d1e8704
LCC
16 l += 2;
17 } else {
53e5ce7a 18 sprintf(mac_addr+l, ":%02x", arg[i]);
3d1e8704
LCC
19 l += 3;
20 }
21 }
3d1e8704
LCC
22}
23
24int mac_addr_a2n(unsigned char *mac_addr, char *arg)
25{
26 int i;
27
28 for (i = 0; i < ETH_ALEN ; i++) {
29 int temp;
30 char *cp = strchr(arg, ':');
31 if (cp) {
32 *cp = 0;
33 cp++;
34 }
35 if (sscanf(arg, "%x", &temp) != 1)
36 return -1;
37 if (temp < 0 || temp > 255)
38 return -1;
39
40 mac_addr[i] = temp;
41 if (!cp)
42 break;
43 arg = cp;
44 }
45 if (i < ETH_ALEN - 1)
46 return -1;
47
48 return 0;
49}
541ef425 50
3ff24563
JB
51int parse_hex_mask(char *hexmask, unsigned char **result, size_t *result_len,
52 unsigned char **mask)
236d4191 53{
3ff24563
JB
54 size_t len = strlen(hexmask) / 2;
55 unsigned char *result_val;
56 unsigned char *result_mask = NULL;
57
236d4191
JB
58 int pos = 0;
59
3ff24563 60 *result_len = 0;
236d4191 61
3ff24563
JB
62 result_val = calloc(len + 2, 1);
63 if (!result_val)
64 goto error;
65 *result = result_val;
66 if (mask) {
67 result_mask = calloc(DIV_ROUND_UP(len, 8) + 2, 1);
68 if (!result_mask)
69 goto error;
70 *mask = result_mask;
71 }
236d4191
JB
72
73 while (1) {
3ff24563 74 char *cp = strchr(hexmask, ':');
236d4191
JB
75 if (cp) {
76 *cp = 0;
77 cp++;
78 }
236d4191 79
3ff24563
JB
80 if (result_mask && (strcmp(hexmask, "-") == 0 ||
81 strcmp(hexmask, "xx") == 0 ||
82 strcmp(hexmask, "--") == 0)) {
83 /* skip this byte and leave mask bit unset */
84 } else {
85 int temp, mask_pos;
86 char *end;
87
88 temp = strtoul(hexmask, &end, 16);
89 if (*end)
90 goto error;
91 if (temp < 0 || temp > 255)
92 goto error;
93 result_val[pos] = temp;
94
95 mask_pos = pos / 8;
96 if (result_mask)
97 result_mask[mask_pos] |= 1 << (pos % 8);
98 }
99
100 (*result_len)++;
101 pos++;
236d4191 102
236d4191
JB
103 if (!cp)
104 break;
3ff24563 105 hexmask = cp;
236d4191
JB
106 }
107
3ff24563 108 return 0;
236d4191 109 error:
3ff24563
JB
110 free(result_val);
111 free(result_mask);
112 return -1;
113}
114
115unsigned char *parse_hex(char *hex, size_t *outlen)
116{
117 unsigned char *result;
118
119 if (parse_hex_mask(hex, &result, outlen, NULL))
120 return NULL;
121 return result;
236d4191
JB
122}
123
541ef425
JB
124static const char *ifmodes[NL80211_IFTYPE_MAX + 1] = {
125 "unspecified",
126 "IBSS",
34e78ed0 127 "managed",
541ef425 128 "AP",
34e78ed0 129 "AP/VLAN",
541ef425 130 "WDS",
34e78ed0 131 "monitor",
a4464243
JB
132 "mesh point",
133 "P2P-client",
134 "P2P-GO",
add40bbd 135 "P2P-device",
3955e524 136 "outside context of a BSS",
ed9b77ec 137 "NAN",
541ef425
JB
138};
139
140static char modebuf[100];
141
142const char *iftype_name(enum nl80211_iftype iftype)
143{
a66b3a35 144 if (iftype <= NL80211_IFTYPE_MAX && ifmodes[iftype])
541ef425
JB
145 return ifmodes[iftype];
146 sprintf(modebuf, "Unknown mode (%d)", iftype);
147 return modebuf;
148}
379f8397 149
9990c1e9 150static const char *commands[NL80211_CMD_MAX + 1] = {
dc1f3fe8 151#include "nl80211-commands.inc"
9990c1e9
MH
152};
153
154static char cmdbuf[100];
155
156const char *command_name(enum nl80211_commands cmd)
157{
73780397 158 if (cmd <= NL80211_CMD_MAX && commands[cmd])
9990c1e9
MH
159 return commands[cmd];
160 sprintf(cmdbuf, "Unknown command (%d)", cmd);
161 return cmdbuf;
162}
163
58b46da2 164int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
379f8397 165{
58b46da2
BR
166 /* see 802.11 17.3.8.3.2 and Annex J
167 * there are overlapping channel numbers in 5GHz and 2GHz bands */
168 if (chan <= 0)
169 return 0; /* not supported */
170 switch (band) {
171 case NL80211_BAND_2GHZ:
172 if (chan == 14)
173 return 2484;
174 else if (chan < 14)
175 return 2407 + chan * 5;
176 break;
177 case NL80211_BAND_5GHZ:
178 if (chan >= 182 && chan <= 196)
179 return 4000 + chan * 5;
180 else
181 return 5000 + chan * 5;
182 break;
183 case NL80211_BAND_60GHZ:
184 if (chan < 5)
185 return 56160 + chan * 2160;
186 break;
187 default:
188 ;
189 }
190 return 0; /* not supported */
379f8397
JB
191}
192
193int ieee80211_frequency_to_channel(int freq)
194{
58b46da2 195 /* see 802.11-2007 17.3.8.3.2 and Annex J */
379f8397
JB
196 if (freq == 2484)
197 return 14;
58b46da2 198 else if (freq < 2484)
379f8397 199 return (freq - 2407) / 5;
58b46da2
BR
200 else if (freq >= 4910 && freq <= 4980)
201 return (freq - 4000) / 5;
202 else if (freq <= 45000) /* DMG band lower limit */
203 return (freq - 5000) / 5;
204 else if (freq >= 58320 && freq <= 64800)
d56e86bc 205 return (freq - 56160) / 2160;
58b46da2
BR
206 else
207 return 0;
379f8397 208}
748f8489
JB
209
210void print_ssid_escaped(const uint8_t len, const uint8_t *data)
211{
212 int i;
213
214 for (i = 0; i < len; i++) {
3f612733 215 if (isprint(data[i]) && data[i] != ' ' && data[i] != '\\')
748f8489 216 printf("%c", data[i]);
3f612733
JB
217 else if (data[i] == ' ' &&
218 (i != 0 && i != len -1))
219 printf(" ");
748f8489
JB
220 else
221 printf("\\x%.2x", data[i]);
222 }
223}
51e9bd80
JB
224
225static int hex2num(char digit)
226{
227 if (!isxdigit(digit))
228 return -1;
229 if (isdigit(digit))
230 return digit - '0';
231 return tolower(digit) - 'a' + 10;
232}
233
9ad3cc24 234static int hex2byte(const char *hex)
51e9bd80
JB
235{
236 int d1, d2;
237
238 d1 = hex2num(hex[0]);
239 if (d1 < 0)
240 return -1;
241 d2 = hex2num(hex[1]);
242 if (d2 < 0)
243 return -1;
244 return (d1 << 4) | d2;
245}
246
60b6c638 247char *hex2bin(const char *hex, char *buf)
51e9bd80
JB
248{
249 char *result = buf;
250 int d;
251
252 while (hex[0]) {
253 d = hex2byte(hex);
254 if (d < 0)
255 return NULL;
256 buf[0] = d;
257 buf++;
258 hex += 2;
259 }
260
261 return result;
262}
263
6c2a0121
EG
264static int parse_akm_suite(const char *cipher_str)
265{
266
267 if (!strcmp(cipher_str, "PSK"))
268 return 0x000FAC02;
269 if (!strcmp(cipher_str, "FT/PSK"))
270 return 0x000FAC03;
271 if (!strcmp(cipher_str, "PSK/SHA-256"))
272 return 0x000FAC06;
273 return -EINVAL;
274}
275
276static int parse_cipher_suite(const char *cipher_str)
277{
278
279 if (!strcmp(cipher_str, "TKIP"))
280 return 0x000FAC02;
d7924705 281 if (!strcmp(cipher_str, "CCMP") || !strcmp(cipher_str, "CCMP-128"))
6c2a0121 282 return 0x000FAC04;
d7924705 283 if (!strcmp(cipher_str, "GCMP") || !strcmp(cipher_str, "GCMP-128"))
6c2a0121
EG
284 return 0x000FAC08;
285 if (!strcmp(cipher_str, "GCMP-256"))
286 return 0x000FAC09;
287 if (!strcmp(cipher_str, "CCMP-256"))
288 return 0x000FAC0A;
289 return -EINVAL;
290}
291
0e39f109 292int parse_keys(struct nl_msg *msg, char **argv[], int *argc)
51e9bd80
JB
293{
294 struct nlattr *keys;
295 int i = 0;
041581ce 296 bool have_default = false;
0e39f109 297 char *arg = **argv;
51e9bd80 298 char keybuf[13];
6c2a0121 299 int pos = 0;
51e9bd80 300
0e39f109 301 if (!*argc)
51e9bd80
JB
302 return 1;
303
6c2a0121
EG
304 if (!memcmp(&arg[pos], "psk", 3)) {
305 char psk_keybuf[32];
306 int cipher_suite, akm_suite;
307
0e39f109 308 if (*argc < 4)
6c2a0121
EG
309 goto explain;
310
311 pos+=3;
312 if (arg[pos] != ':')
313 goto explain;
314 pos++;
315
316 NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, NL80211_WPA_VERSION_2);
317
318 if (strlen(&arg[pos]) != (sizeof(psk_keybuf) * 2) || !hex2bin(&arg[pos], psk_keybuf)) {
319 printf("Bad PSK\n");
320 return -EINVAL;
321 }
322
323 NLA_PUT(msg, NL80211_ATTR_PMK, 32, psk_keybuf);
324 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, NL80211_AUTHTYPE_OPEN_SYSTEM);
325
0e39f109
EG
326 *argv += 1;
327 *argc -= 1;
328 arg = **argv;
6c2a0121
EG
329
330 akm_suite = parse_akm_suite(arg);
331 if (akm_suite < 0)
332 goto explain;
333
334 NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, akm_suite);
335
0e39f109
EG
336 *argv += 1;
337 *argc -= 1;
338 arg = **argv;
6c2a0121
EG
339
340 cipher_suite = parse_cipher_suite(arg);
341 if (cipher_suite < 0)
342 goto explain;
343
344 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher_suite);
345
0e39f109
EG
346 *argv += 1;
347 *argc -= 1;
348 arg = **argv;
6c2a0121
EG
349
350 cipher_suite = parse_cipher_suite(arg);
351 if (cipher_suite < 0)
352 goto explain;
353
354 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher_suite);
355
d4f1ea11
IP
356 *argv += 1;
357 *argc -= 1;
6c2a0121
EG
358 return 0;
359 }
360
51e9bd80
JB
361 NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
362
363 keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
364 if (!keys)
365 return -ENOBUFS;
366
367 do {
6c2a0121 368 int keylen;
51e9bd80
JB
369 struct nlattr *key = nla_nest_start(msg, ++i);
370 char *keydata;
371
0e39f109 372 arg = **argv;
6c2a0121
EG
373 pos = 0;
374
51e9bd80
JB
375 if (!key)
376 return -ENOBUFS;
377
378 if (arg[pos] == 'd') {
379 NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
380 pos++;
381 if (arg[pos] == ':')
382 pos++;
041581ce 383 have_default = true;
51e9bd80
JB
384 }
385
386 if (!isdigit(arg[pos]))
387 goto explain;
388 NLA_PUT_U8(msg, NL80211_KEY_IDX, arg[pos++] - '0');
389 if (arg[pos++] != ':')
390 goto explain;
391 keydata = arg + pos;
392 switch (strlen(keydata)) {
393 case 10:
394 keydata = hex2bin(keydata, keybuf);
6ab936f0 395 /* fall through */
51e9bd80
JB
396 case 5:
397 NLA_PUT_U32(msg, NL80211_KEY_CIPHER, 0x000FAC01);
398 keylen = 5;
399 break;
400 case 26:
401 keydata = hex2bin(keydata, keybuf);
6ab936f0 402 /* fall through */
51e9bd80
JB
403 case 13:
404 NLA_PUT_U32(msg, NL80211_KEY_CIPHER, 0x000FAC05);
405 keylen = 13;
406 break;
407 default:
408 goto explain;
409 }
410
411 if (!keydata)
412 goto explain;
413
414 NLA_PUT(msg, NL80211_KEY_DATA, keylen, keydata);
415
0e39f109
EG
416 *argv += 1;
417 *argc -= 1;
041581ce
JB
418
419 /* one key should be TX key */
0e39f109 420 if (!have_default && !*argc)
041581ce
JB
421 NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
422
423 nla_nest_end(msg, key);
0e39f109 424 } while (*argc);
51e9bd80
JB
425
426 nla_nest_end(msg, keys);
427
428 return 0;
429 nla_put_failure:
430 return -ENOBUFS;
431 explain:
432 fprintf(stderr, "key must be [d:]index:data where\n"
433 " 'd:' means default (transmit) key\n"
434 " 'index:' is a single digit (0-3)\n"
435 " 'data' must be 5 or 13 ascii chars\n"
436 " or 10 or 26 hex digits\n"
6c2a0121
EG
437 "for example: d:2:6162636465 is the same as d:2:abcde\n"
438 "or psk:data <AKM Suite> <pairwise CIPHER> <groupwise CIPHER> where\n"
439 " 'data' is the PSK (output of wpa_passphrase and the CIPHER can be CCMP or GCMP\n"
440 "for example: psk:0123456789abcdef PSK CCMP CCMP\n"
441 "The allowed AKM suites are PSK, FT/PSK, PSK/SHA-256\n"
442 "The allowed Cipher suites are TKIP, CCMP, GCMP, GCMP-256, CCMP-256\n");
51e9bd80
JB
443 return 2;
444}
deb3501c 445
c37f6c64 446enum nl80211_chan_width str_to_bw(const char *str)
997c60fd
BB
447{
448 static const struct {
449 const char *name;
450 unsigned int val;
451 } bwmap[] = {
452 { .name = "5", .val = NL80211_CHAN_WIDTH_5, },
453 { .name = "10", .val = NL80211_CHAN_WIDTH_10, },
454 { .name = "20", .val = NL80211_CHAN_WIDTH_20, },
455 { .name = "40", .val = NL80211_CHAN_WIDTH_40, },
456 { .name = "80", .val = NL80211_CHAN_WIDTH_80, },
457 { .name = "80+80", .val = NL80211_CHAN_WIDTH_80P80, },
458 { .name = "160", .val = NL80211_CHAN_WIDTH_160, },
459 };
c37f6c64
JB
460 unsigned int i;
461
462 for (i = 0; i < ARRAY_SIZE(bwmap); i++) {
463 if (strcasecmp(bwmap[i].name, str) == 0)
464 return bwmap[i].val;
465 }
466
467 return NL80211_CHAN_WIDTH_20_NOHT;
468}
469
470static int parse_freqs(struct chandef *chandef, int argc, char **argv,
471 int *parsed)
472{
997c60fd 473 uint32_t freq;
997c60fd 474 char *end;
4871fcf5 475 bool need_cf1 = false, need_cf2 = false;
997c60fd
BB
476
477 if (argc < 1)
478 return 0;
479
c37f6c64 480 chandef->width = str_to_bw(argv[0]);
997c60fd 481
4871fcf5
JB
482 switch (chandef->width) {
483 case NL80211_CHAN_WIDTH_20_NOHT:
484 /* First argument was not understood, give up gracefully. */
997c60fd 485 return 0;
4871fcf5
JB
486 case NL80211_CHAN_WIDTH_20:
487 case NL80211_CHAN_WIDTH_5:
488 case NL80211_CHAN_WIDTH_10:
489 break;
490 case NL80211_CHAN_WIDTH_80P80:
491 need_cf2 = true;
492 /* fall through */
493 case NL80211_CHAN_WIDTH_40:
494 case NL80211_CHAN_WIDTH_80:
495 case NL80211_CHAN_WIDTH_160:
496 need_cf1 = true;
497 break;
498 }
997c60fd 499
c37f6c64
JB
500 *parsed += 1;
501
4871fcf5 502 if (!need_cf1)
997c60fd
BB
503 return 0;
504
4871fcf5
JB
505 if (argc < 2)
506 return 1;
507
997c60fd
BB
508 /* center freq 1 */
509 if (!*argv[1])
4871fcf5 510 return 1;
997c60fd
BB
511 freq = strtoul(argv[1], &end, 10);
512 if (*end)
4871fcf5 513 return 1;
997c60fd
BB
514 *parsed += 1;
515
516 chandef->center_freq1 = freq;
517
4871fcf5 518 if (!need_cf2)
997c60fd
BB
519 return 0;
520
4871fcf5
JB
521 if (argc < 3)
522 return 1;
523
997c60fd
BB
524 /* center freq 2 */
525 if (!*argv[2])
4871fcf5 526 return 1;
997c60fd
BB
527 freq = strtoul(argv[2], &end, 10);
528 if (*end)
4871fcf5 529 return 1;
997c60fd
BB
530 chandef->center_freq2 = freq;
531
532 *parsed += 1;
533
534 return 0;
535}
536
537
538/**
539 * parse_freqchan - Parse frequency or channel definition
540 *
541 * @chandef: chandef structure to be filled in
542 * @chan: Boolean whether to parse a channel or frequency based specifier
543 * @argc: Number of arguments
544 * @argv: Array of string arguments
545 * @parsed: Pointer to return the number of used arguments, or NULL to error
546 * out if any argument is left unused.
547 *
548 * The given chandef structure will be filled in from the command line
549 * arguments. argc/argv will be updated so that further arguments from the
550 * command line can be parsed.
551 *
4871fcf5
JB
552 * Note that despite the fact that the function knows how many center freqs
553 * are needed, there's an ambiguity if the next argument after this is an
554 * integer argument, since the valid channel width values are interpreted
555 * as such, rather than a following argument. This can be avoided by the
556 * user by giving "NOHT" instead.
997c60fd
BB
557 *
558 * The working specifier if chan is set are:
559 * <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]
560 *
561 * And if frequency is set:
562 * <freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]
563 * <control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]
564 *
565 * If the mode/channel width is not given the NOHT is assumed.
566 *
567 * Return: Number of used arguments, zero or negative error number otherwise
568 */
569int parse_freqchan(struct chandef *chandef, bool chan, int argc, char **argv,
570 int *parsed)
571{
572 char *end;
573 static const struct chanmode chanmode[] = {
574 { .name = "HT20",
575 .width = NL80211_CHAN_WIDTH_20,
576 .freq1_diff = 0,
577 .chantype = NL80211_CHAN_HT20 },
578 { .name = "HT40+",
579 .width = NL80211_CHAN_WIDTH_40,
580 .freq1_diff = 10,
581 .chantype = NL80211_CHAN_HT40PLUS },
582 { .name = "HT40-",
583 .width = NL80211_CHAN_WIDTH_40,
584 .freq1_diff = -10,
585 .chantype = NL80211_CHAN_HT40MINUS },
586 { .name = "NOHT",
587 .width = NL80211_CHAN_WIDTH_20_NOHT,
588 .freq1_diff = 0,
589 .chantype = NL80211_CHAN_NO_HT },
590 { .name = "5MHz",
591 .width = NL80211_CHAN_WIDTH_5,
592 .freq1_diff = 0,
593 .chantype = -1 },
594 { .name = "10MHz",
595 .width = NL80211_CHAN_WIDTH_10,
596 .freq1_diff = 0,
597 .chantype = -1 },
598 { .name = "80MHz",
599 .width = NL80211_CHAN_WIDTH_80,
600 .freq1_diff = 0,
601 .chantype = -1 },
602 };
603 const struct chanmode *chanmode_selected = NULL;
604 unsigned int freq;
605 unsigned int i;
606 int _parsed = 0;
607 int res = 0;
608
609 if (argc < 1)
610 return 1;
611
612 if (!argv[0])
613 goto out;
614 freq = strtoul(argv[0], &end, 10);
615 if (*end) {
616 res = 1;
617 goto out;
618 }
619
620 _parsed += 1;
621
622 memset(chandef, 0, sizeof(struct chandef));
623
624 if (chan) {
625 enum nl80211_band band;
626
627 band = freq <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
628 freq = ieee80211_channel_to_frequency(freq, band);
629 }
630 chandef->control_freq = freq;
631 /* Assume 20MHz NOHT channel for now. */
632 chandef->center_freq1 = freq;
633
634 /* Try to parse HT mode definitions */
635 if (argc > 1) {
636 for (i = 0; i < ARRAY_SIZE(chanmode); i++) {
637 if (strcasecmp(chanmode[i].name, argv[1]) == 0) {
638 chanmode_selected = &chanmode[i];
639 _parsed += 1;
640 break;
641 }
642 }
643 }
644
645 /* channel mode given, use it and return. */
646 if (chanmode_selected) {
647 chandef->center_freq1 = get_cf1(chanmode_selected, freq);
648 chandef->width = chanmode_selected->width;
649 goto out;
650 }
651
652 /* This was a only a channel definition, nothing further may follow. */
653 if (chan)
654 goto out;
655
656 res = parse_freqs(chandef, argc - 1, argv + 1, &_parsed);
657
658 out:
659 /* Error out if parsed is NULL. */
660 if (!parsed && _parsed != argc)
661 return 1;
662
663 if (parsed)
664 *parsed = _parsed;
665
666 return res;
667}
668
669int put_chandef(struct nl_msg *msg, struct chandef *chandef)
670{
671 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, chandef->control_freq);
672 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width);
673
674 switch (chandef->width) {
675 case NL80211_CHAN_WIDTH_20_NOHT:
676 NLA_PUT_U32(msg,
677 NL80211_ATTR_WIPHY_CHANNEL_TYPE,
678 NL80211_CHAN_NO_HT);
679 break;
680 case NL80211_CHAN_WIDTH_20:
681 NLA_PUT_U32(msg,
682 NL80211_ATTR_WIPHY_CHANNEL_TYPE,
683 NL80211_CHAN_HT20);
684 break;
685 case NL80211_CHAN_WIDTH_40:
686 if (chandef->control_freq > chandef->center_freq1)
687 NLA_PUT_U32(msg,
688 NL80211_ATTR_WIPHY_CHANNEL_TYPE,
689 NL80211_CHAN_HT40MINUS);
690 else
691 NLA_PUT_U32(msg,
692 NL80211_ATTR_WIPHY_CHANNEL_TYPE,
693 NL80211_CHAN_HT40PLUS);
694 break;
695 default:
696 break;
697 }
698
699 if (chandef->center_freq1)
700 NLA_PUT_U32(msg,
701 NL80211_ATTR_CENTER_FREQ1,
702 chandef->center_freq1);
703
704 if (chandef->center_freq2)
705 NLA_PUT_U32(msg,
706 NL80211_ATTR_CENTER_FREQ2,
707 chandef->center_freq2);
708
709 return 0;
710
711 nla_put_failure:
712 return -ENOBUFS;
713}
714
7ddfb679 715static void print_mcs_index(const __u8 *mcs)
deb3501c 716{
9fea9777 717 int mcs_bit, prev_bit = -2, prev_cont = 0;
04953e90
JB
718
719 for (mcs_bit = 0; mcs_bit <= 76; mcs_bit++) {
720 unsigned int mcs_octet = mcs_bit/8;
721 unsigned int MCS_RATE_BIT = 1 << mcs_bit % 8;
722 bool mcs_rate_idx_set;
723
724 mcs_rate_idx_set = !!(mcs[mcs_octet] & MCS_RATE_BIT);
725
726 if (!mcs_rate_idx_set)
727 continue;
728
729 if (prev_bit != mcs_bit - 1) {
730 if (prev_bit != -2)
731 printf("%d, ", prev_bit);
732 else
733 printf(" ");
734 printf("%d", mcs_bit);
735 prev_cont = 0;
736 } else if (!prev_cont) {
737 printf("-");
738 prev_cont = 1;
739 }
740
741 prev_bit = mcs_bit;
742 }
deb3501c 743
04953e90
JB
744 if (prev_cont)
745 printf("%d", prev_bit);
746 printf("\n");
deb3501c 747}
0950993f
LR
748
749/*
750 * There are only 4 possible values, we just use a case instead of computing it,
751 * but technically this can also be computed through the formula:
752 *
753 * Max AMPDU length = (2 ^ (13 + exponent)) - 1 bytes
754 */
755static __u32 compute_ampdu_length(__u8 exponent)
756{
757 switch (exponent) {
758 case 0: return 8191; /* (2 ^(13 + 0)) -1 */
759 case 1: return 16383; /* (2 ^(13 + 1)) -1 */
760 case 2: return 32767; /* (2 ^(13 + 2)) -1 */
761 case 3: return 65535; /* (2 ^(13 + 3)) -1 */
762 default: return 0;
763 }
764}
765
766static const char *print_ampdu_space(__u8 space)
767{
768 switch (space) {
769 case 0: return "No restriction";
770 case 1: return "1/4 usec";
771 case 2: return "1/2 usec";
772 case 3: return "1 usec";
773 case 4: return "2 usec";
774 case 5: return "4 usec";
775 case 6: return "8 usec";
776 case 7: return "16 usec";
777 default:
7ae93cd5 778 return "BUG (spacing more than 3 bits!)";
0950993f
LR
779 }
780}
781
782void print_ampdu_length(__u8 exponent)
783{
04953e90 784 __u32 max_ampdu_length;
0950993f
LR
785
786 max_ampdu_length = compute_ampdu_length(exponent);
787
788 if (max_ampdu_length) {
789 printf("\t\tMaximum RX AMPDU length %d bytes (exponent: 0x0%02x)\n",
790 max_ampdu_length, exponent);
3f362f8b 791 } else {
0950993f
LR
792 printf("\t\tMaximum RX AMPDU length: unrecognized bytes "
793 "(exponent: %d)\n", exponent);
794 }
795}
796
797void print_ampdu_spacing(__u8 spacing)
798{
3f362f8b
NB
799 printf("\t\tMinimum RX AMPDU time spacing: %s (0x%02x)\n",
800 print_ampdu_space(spacing), spacing);
0950993f 801}
357c1a5d
LR
802
803void print_ht_capability(__u16 cap)
804{
805#define PRINT_HT_CAP(_cond, _str) \
806 do { \
807 if (_cond) \
808 printf("\t\t\t" _str "\n"); \
809 } while (0)
810
811 printf("\t\tCapabilities: 0x%02x\n", cap);
812
028c0de5 813 PRINT_HT_CAP((cap & BIT(0)), "RX LDPC");
357c1a5d
LR
814 PRINT_HT_CAP((cap & BIT(1)), "HT20/HT40");
815 PRINT_HT_CAP(!(cap & BIT(1)), "HT20");
816
817 PRINT_HT_CAP(((cap >> 2) & 0x3) == 0, "Static SM Power Save");
818 PRINT_HT_CAP(((cap >> 2) & 0x3) == 1, "Dynamic SM Power Save");
819 PRINT_HT_CAP(((cap >> 2) & 0x3) == 3, "SM Power Save disabled");
820
821 PRINT_HT_CAP((cap & BIT(4)), "RX Greenfield");
822 PRINT_HT_CAP((cap & BIT(5)), "RX HT20 SGI");
823 PRINT_HT_CAP((cap & BIT(6)), "RX HT40 SGI");
824 PRINT_HT_CAP((cap & BIT(7)), "TX STBC");
825
826 PRINT_HT_CAP(((cap >> 8) & 0x3) == 0, "No RX STBC");
827 PRINT_HT_CAP(((cap >> 8) & 0x3) == 1, "RX STBC 1-stream");
828 PRINT_HT_CAP(((cap >> 8) & 0x3) == 2, "RX STBC 2-streams");
829 PRINT_HT_CAP(((cap >> 8) & 0x3) == 3, "RX STBC 3-streams");
830
831 PRINT_HT_CAP((cap & BIT(10)), "HT Delayed Block Ack");
832
c79c7464
CL
833 PRINT_HT_CAP(!(cap & BIT(11)), "Max AMSDU length: 3839 bytes");
834 PRINT_HT_CAP((cap & BIT(11)), "Max AMSDU length: 7935 bytes");
357c1a5d
LR
835
836 /*
837 * For beacons and probe response this would mean the BSS
838 * does or does not allow the usage of DSSS/CCK HT40.
839 * Otherwise it means the STA does or does not use
840 * DSSS/CCK HT40.
841 */
842 PRINT_HT_CAP((cap & BIT(12)), "DSSS/CCK HT40");
843 PRINT_HT_CAP(!(cap & BIT(12)), "No DSSS/CCK HT40");
844
845 /* BIT(13) is reserved */
846
847 PRINT_HT_CAP((cap & BIT(14)), "40 MHz Intolerant");
848
849 PRINT_HT_CAP((cap & BIT(15)), "L-SIG TXOP protection");
850#undef PRINT_HT_CAP
851}
7ddfb679
JB
852
853void print_ht_mcs(const __u8 *mcs)
854{
855 /* As defined in 7.3.2.57.4 Supported MCS Set field */
856 unsigned int tx_max_num_spatial_streams, max_rx_supp_data_rate;
857 bool tx_mcs_set_defined, tx_mcs_set_equal, tx_unequal_modulation;
858
5ba6a62b 859 max_rx_supp_data_rate = (mcs[10] | ((mcs[11] & 0x3) << 8));
7ddfb679
JB
860 tx_mcs_set_defined = !!(mcs[12] & (1 << 0));
861 tx_mcs_set_equal = !(mcs[12] & (1 << 1));
862 tx_max_num_spatial_streams = ((mcs[12] >> 2) & 3) + 1;
863 tx_unequal_modulation = !!(mcs[12] & (1 << 4));
864
865 if (max_rx_supp_data_rate)
866 printf("\t\tHT Max RX data rate: %d Mbps\n", max_rx_supp_data_rate);
867 /* XXX: else see 9.6.0e.5.3 how to get this I think */
868
869 if (tx_mcs_set_defined) {
870 if (tx_mcs_set_equal) {
2a79feb0 871 printf("\t\tHT TX/RX MCS rate indexes supported:");
7ddfb679
JB
872 print_mcs_index(mcs);
873 } else {
874 printf("\t\tHT RX MCS rate indexes supported:");
875 print_mcs_index(mcs);
876
877 if (tx_unequal_modulation)
878 printf("\t\tTX unequal modulation supported\n");
879 else
880 printf("\t\tTX unequal modulation not supported\n");
881
882 printf("\t\tHT TX Max spatial streams: %d\n",
883 tx_max_num_spatial_streams);
884
885 printf("\t\tHT TX MCS rate indexes supported may differ\n");
886 }
887 } else {
888 printf("\t\tHT RX MCS rate indexes supported:");
889 print_mcs_index(mcs);
089bb35d 890 printf("\t\tHT TX MCS rate indexes are undefined\n");
7ddfb679
JB
891 }
892}
54eb1613
JB
893
894void print_vht_info(__u32 capa, const __u8 *mcs)
895{
896 __u16 tmp;
897 int i;
898
899 printf("\t\tVHT Capabilities (0x%.8x):\n", capa);
900
901#define PRINT_VHT_CAPA(_bit, _str) \
902 do { \
903 if (capa & BIT(_bit)) \
904 printf("\t\t\t" _str "\n"); \
905 } while (0)
906
907 printf("\t\t\tMax MPDU length: ");
908 switch (capa & 3) {
909 case 0: printf("3895\n"); break;
910 case 1: printf("7991\n"); break;
911 case 2: printf("11454\n"); break;
912 case 3: printf("(reserved)\n");
913 }
914 printf("\t\t\tSupported Channel Width: ");
915 switch ((capa >> 2) & 3) {
916 case 0: printf("neither 160 nor 80+80\n"); break;
917 case 1: printf("160 MHz\n"); break;
918 case 2: printf("160 MHz, 80+80 MHz\n"); break;
919 case 3: printf("(reserved)\n");
920 }
921 PRINT_VHT_CAPA(4, "RX LDPC");
922 PRINT_VHT_CAPA(5, "short GI (80 MHz)");
923 PRINT_VHT_CAPA(6, "short GI (160/80+80 MHz)");
924 PRINT_VHT_CAPA(7, "TX STBC");
925 /* RX STBC */
926 PRINT_VHT_CAPA(11, "SU Beamformer");
927 PRINT_VHT_CAPA(12, "SU Beamformee");
928 /* compressed steering */
929 /* # of sounding dimensions */
930 PRINT_VHT_CAPA(19, "MU Beamformer");
931 PRINT_VHT_CAPA(20, "MU Beamformee");
932 PRINT_VHT_CAPA(21, "VHT TXOP PS");
933 PRINT_VHT_CAPA(22, "+HTC-VHT");
934 /* max A-MPDU */
935 /* VHT link adaptation */
75271051
MB
936 PRINT_VHT_CAPA(28, "RX antenna pattern consistency");
937 PRINT_VHT_CAPA(29, "TX antenna pattern consistency");
54eb1613
JB
938
939 printf("\t\tVHT RX MCS set:\n");
940 tmp = mcs[0] | (mcs[1] << 8);
941 for (i = 1; i <= 8; i++) {
942 printf("\t\t\t%d streams: ", i);
943 switch ((tmp >> ((i-1)*2) ) & 3) {
944 case 0: printf("MCS 0-7\n"); break;
945 case 1: printf("MCS 0-8\n"); break;
946 case 2: printf("MCS 0-9\n"); break;
947 case 3: printf("not supported\n"); break;
948 }
949 }
950 tmp = mcs[2] | (mcs[3] << 8);
951 printf("\t\tVHT RX highest supported: %d Mbps\n", tmp & 0x1fff);
952
953 printf("\t\tVHT TX MCS set:\n");
954 tmp = mcs[4] | (mcs[5] << 8);
955 for (i = 1; i <= 8; i++) {
956 printf("\t\t\t%d streams: ", i);
957 switch ((tmp >> ((i-1)*2) ) & 3) {
958 case 0: printf("MCS 0-7\n"); break;
959 case 1: printf("MCS 0-8\n"); break;
960 case 2: printf("MCS 0-9\n"); break;
961 case 3: printf("not supported\n"); break;
962 }
963 }
964 tmp = mcs[6] | (mcs[7] << 8);
965 printf("\t\tVHT TX highest supported: %d Mbps\n", tmp & 0x1fff);
966}
492354de 967
c741be9f
JC
968void print_he_info(struct nlattr *nl_iftype)
969{
970 struct nlattr *tb[NL80211_BAND_IFTYPE_ATTR_MAX + 1];
971 struct nlattr *tb_flags[NL80211_IFTYPE_MAX + 1];
972 char *iftypes[NUM_NL80211_IFTYPES] = {
973 "Unspec", "Adhoc", "Station", "AP", "AP/VLAN", "WDS", "Monitor",
974 "Mesh", "P2P/Client", "P2P/Go", "P2P/Device", "OCB", "NAN",
975 };
976 __u16 mac_cap[3] = { 0 };
977 __u16 phy_cap[6] = { 0 };
978 __u16 mcs_set[6] = { 0 };
979 __u8 ppet[25] = { 0 };
980 size_t len;
981 int i;
982
983 #define PRINT_HE_CAP(_var, _idx, _bit, _str) \
984 do { \
985 if (_var[_idx] & BIT(_bit)) \
986 printf("\t\t\t\t" _str "\n"); \
987 } while (0)
988
989 #define PRINT_HE_CAP_MASK(_var, _idx, _shift, _mask, _str) \
990 do { \
991 if ((_var[_idx] >> _shift) & _mask) \
992 printf("\t\t\t\t" _str ": %d\n", (_var[_idx] >> _shift) & _mask); \
993 } while (0)
994
995 #define PRINT_HE_MAC_CAP(...) PRINT_HE_CAP(mac_cap, __VA_ARGS__)
996 #define PRINT_HE_MAC_CAP_MASK(...) PRINT_HE_CAP_MASK(mac_cap, __VA_ARGS__)
997 #define PRINT_HE_PHY_CAP(...) PRINT_HE_CAP(phy_cap, __VA_ARGS__)
998 #define PRINT_HE_PHY_CAP0(_idx, _bit, ...) PRINT_HE_CAP(phy_cap, _idx, _bit + 8, __VA_ARGS__)
999 #define PRINT_HE_PHY_CAP_MASK(...) PRINT_HE_CAP_MASK(phy_cap, __VA_ARGS__)
1000
1001 nla_parse(tb, NL80211_BAND_IFTYPE_ATTR_MAX,
1002 nla_data(nl_iftype), nla_len(nl_iftype), NULL);
1003
1004 if (!tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES])
1005 return;
1006
1007 if (nla_parse_nested(tb_flags, NL80211_IFTYPE_MAX,
1008 tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES], NULL))
1009 return;
1010
1011 printf("\t\tHE Iftypes:");
1012 for (i = 0; i < NUM_NL80211_IFTYPES; i++)
1013 if (nla_get_flag(tb_flags[i]) && iftypes[i])
1014 printf(" %s", iftypes[i]);
1015 printf("\n");
1016
1017 if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]) {
1018 len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]);
1019 if (len > sizeof(mac_cap))
1020 len = sizeof(mac_cap);
1021 memcpy(mac_cap,
1022 nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]),
1023 len);
1024 }
1025 printf("\t\t\tHE MAC Capabilities (0x");
1026 for (i = 0; i < 3; i++)
1027 printf("%04x", mac_cap[i]);
1028 printf("):\n");
1029
1030 PRINT_HE_MAC_CAP(0, 0, "+HTC HE Supported");
1031 PRINT_HE_MAC_CAP(0, 1, "TWT Requester");
1032 PRINT_HE_MAC_CAP(0, 2, "TWT Responder");
1033 PRINT_HE_MAC_CAP_MASK(0, 3, 0x3, "Dynamic BA Fragementation Level");
1034 PRINT_HE_MAC_CAP_MASK(0, 5, 0x7, "Maximum number of MSDUS Fragments");
1035 PRINT_HE_MAC_CAP_MASK(0, 8, 0x3, "Minimum Payload size of 128 bytes");
1036 PRINT_HE_MAC_CAP_MASK(0, 10, 0x3, "Trigger Frame MAC Padding Duration");
1037 PRINT_HE_MAC_CAP_MASK(0, 12, 0x7, "Multi-TID Aggregation Support");
1038
1039 PRINT_HE_MAC_CAP(1, 1, "All Ack");
1040 PRINT_HE_MAC_CAP(1, 2, "TRS");
1041 PRINT_HE_MAC_CAP(1, 3, "BSR");
1042 PRINT_HE_MAC_CAP(1, 4, "Broadcast TWT");
1043 PRINT_HE_MAC_CAP(1, 5, "32-bit BA Bitmap");
1044 PRINT_HE_MAC_CAP(1, 6, "MU Cascading");
1045 PRINT_HE_MAC_CAP(1, 7, "Ack-Enabled Aggregation");
1046 PRINT_HE_MAC_CAP(1, 9, "OM Control");
1047 PRINT_HE_MAC_CAP(1, 10, "OFDMA RA");
1048 PRINT_HE_MAC_CAP_MASK(1, 11, 0x3, "Maximum A-MPDU Length Exponent");
1049 PRINT_HE_MAC_CAP(1, 13, "A-MSDU Fragmentation");
1050 PRINT_HE_MAC_CAP(1, 14, "Flexible TWT Scheduling");
1051 PRINT_HE_MAC_CAP(1, 15, "RX Control Frame to MultiBSS");
1052
1053 PRINT_HE_MAC_CAP(2, 0, "BSRP BQRP A-MPDU Aggregation");
1054 PRINT_HE_MAC_CAP(2, 1, "QTP");
1055 PRINT_HE_MAC_CAP(2, 2, "BQR");
1056 PRINT_HE_MAC_CAP(2, 3, "SRP Responder Role");
1057 PRINT_HE_MAC_CAP(2, 4, "NDP Feedback Report");
1058 PRINT_HE_MAC_CAP(2, 5, "OPS");
1059 PRINT_HE_MAC_CAP(2, 6, "A-MSDU in A-MPDU");
1060 PRINT_HE_MAC_CAP_MASK(2, 7, 7, "Multi-TID Aggregation TX");
1061 PRINT_HE_MAC_CAP(2, 10, "HE Subchannel Selective Transmission");
1062 PRINT_HE_MAC_CAP(2, 11, "UL 2x996-Tone RU");
1063 PRINT_HE_MAC_CAP(2, 12, "OM Control UL MU Data Disable RX");
1064
1065 if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]) {
1066 len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]);
1067
1068 if (len > sizeof(phy_cap) - 1)
1069 len = sizeof(phy_cap) - 1;
1070 memcpy(&((__u8 *)phy_cap)[1],
1071 nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]),
1072 len);
1073 }
1074 printf("\t\t\tHE PHY Capabilities: (0x");
1075 for (i = 0; i < 11; i++)
1076 printf("%02x", ((__u8 *)phy_cap)[i + 1]);
1077 printf("):\n");
1078
1079 PRINT_HE_PHY_CAP0(0, 1, "HE40/2.4GHz");
1080 PRINT_HE_PHY_CAP0(0, 2, "HE40/HE80/5GHz");
1081 PRINT_HE_PHY_CAP0(0, 3, "HE160/5GHz");
1082 PRINT_HE_PHY_CAP0(0, 4, "HE160/HE80+80/5GHz");
1083 PRINT_HE_PHY_CAP0(0, 5, "242 tone RUs/2.4GHz");
1084 PRINT_HE_PHY_CAP0(0, 6, "242 tone RUs/5GHz");
1085
1086 PRINT_HE_PHY_CAP_MASK(1, 0, 0xf, "Punctured Preamble RX");
1087 PRINT_HE_PHY_CAP_MASK(1, 4, 0x1, "Device Class");
1088 PRINT_HE_PHY_CAP(1, 5, "LDPC Coding in Payload");
1089 PRINT_HE_PHY_CAP(1, 6, "HE SU PPDU with 1x HE-LTF and 0.8us GI");
1090 PRINT_HE_PHY_CAP_MASK(1, 7, 0x3, "Midamble Rx Max NSTS");
1091 PRINT_HE_PHY_CAP(1, 9, "NDP with 4x HE-LTF and 3.2us GI");
1092 PRINT_HE_PHY_CAP(1, 10, "STBC Tx <= 80MHz");
1093 PRINT_HE_PHY_CAP(1, 11, "STBC Rx <= 80MHz");
1094 PRINT_HE_PHY_CAP(1, 12, "Doppler Tx");
1095 PRINT_HE_PHY_CAP(1, 13, "Doppler Rx");
1096 PRINT_HE_PHY_CAP(1, 14, "Full Bandwidth UL MU-MIMO");
1097 PRINT_HE_PHY_CAP(1, 15, "Partial Bandwidth UL MU-MIMO");
1098
1099 PRINT_HE_PHY_CAP_MASK(2, 0, 0x3, "DCM Max Constellation");
1100 PRINT_HE_PHY_CAP_MASK(2, 2, 0x1, "DCM Max NSS Tx");
1101 PRINT_HE_PHY_CAP_MASK(2, 3, 0x3, "DCM Max Constellation Rx");
1102 PRINT_HE_PHY_CAP_MASK(2, 5, 0x1, "DCM Max NSS Rx");
1103 PRINT_HE_PHY_CAP(2, 6, "Rx HE MU PPDU from Non-AP STA");
1104 PRINT_HE_PHY_CAP(2, 7, "SU Beamformer");
1105 PRINT_HE_PHY_CAP(2, 8, "SU Beamformee");
1106 PRINT_HE_PHY_CAP(2, 9, "MU Beamformer");
1107 PRINT_HE_PHY_CAP_MASK(2, 10, 0x7, "Beamformee STS <= 80Mhz");
1108 PRINT_HE_PHY_CAP_MASK(2, 13, 0x7, "Beamformee STS > 80Mhz");
1109
1110 PRINT_HE_PHY_CAP_MASK(3, 0, 0x7, "Sounding Dimensions <= 80Mhz");
1111 PRINT_HE_PHY_CAP_MASK(3, 3, 0x7, "Sounding Dimensions > 80Mhz");
1112 PRINT_HE_PHY_CAP(3, 6, "Ng = 16 SU Feedback");
1113 PRINT_HE_PHY_CAP(3, 7, "Ng = 16 MU Feedback");
1114 PRINT_HE_PHY_CAP(3, 8, "Codebook Size SU Feedback");
1115 PRINT_HE_PHY_CAP(3, 9, "Codebook Size MU Feedback");
1116 PRINT_HE_PHY_CAP(3, 10, "Triggered SU Beamforming Feedback");
1117 PRINT_HE_PHY_CAP(3, 11, "Triggered MU Beamforming Feedback");
1118 PRINT_HE_PHY_CAP(3, 12, "Triggered CQI Feedback");
1119 PRINT_HE_PHY_CAP(3, 13, "Partial Bandwidth Extended Range");
1120 PRINT_HE_PHY_CAP(3, 14, "Partial Bandwidth DL MU-MIMO");
1121 PRINT_HE_PHY_CAP(3, 15, "PPE Threshold Present");
1122
1123 PRINT_HE_PHY_CAP(4, 0, "SRP-based SR");
1124 PRINT_HE_PHY_CAP(4, 1, "Power Boost Factor ar");
1125 PRINT_HE_PHY_CAP(4, 2, "HE SU PPDU & HE PPDU 4x HE-LTF 0.8us GI");
1126 PRINT_HE_PHY_CAP_MASK(4, 3, 0x7, "Max NC");
1127 PRINT_HE_PHY_CAP(4, 6, "STBC Tx > 80MHz");
1128 PRINT_HE_PHY_CAP(4, 7, "STBC Rx > 80MHz");
1129 PRINT_HE_PHY_CAP(4, 8, "HE ER SU PPDU 4x HE-LTF 0.8us GI");
1130 PRINT_HE_PHY_CAP(4, 9, "20MHz in 40MHz HE PPDU 2.4GHz");
1131 PRINT_HE_PHY_CAP(4, 10, "20MHz in 160/80+80MHz HE PPDU");
1132 PRINT_HE_PHY_CAP(4, 11, "80MHz in 160/80+80MHz HE PPDU");
1133 PRINT_HE_PHY_CAP(4, 12, "HE ER SU PPDU 1x HE-LTF 0.8us GI");
1134 PRINT_HE_PHY_CAP(4, 13, "Midamble Rx 2x & 1x HE-LTF");
1135 PRINT_HE_PHY_CAP_MASK(4, 14, 0x3, "DCM Max BW");
1136
1137 PRINT_HE_PHY_CAP(5, 0, "Longer Than 16HE SIG-B OFDM Symbols");
1138 PRINT_HE_PHY_CAP(5, 1, "Non-Triggered CQI Feedback");
1139 PRINT_HE_PHY_CAP(5, 2, "TX 1024-QAM");
1140 PRINT_HE_PHY_CAP(5, 3, "RX 1024-QAM");
1141 PRINT_HE_PHY_CAP(5, 4, "RX Full BW SU Using HE MU PPDU with Compression SIGB");
1142 PRINT_HE_PHY_CAP(5, 5, "RX Full BW SU Using HE MU PPDU with Non-Compression SIGB");
1143
1144 if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]) {
1145 len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]);
1146 if (len > sizeof(mcs_set))
1147 len = sizeof(mcs_set);
1148 memcpy(mcs_set,
1149 nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]),
1150 len);
1151 }
1152
1153 for (i = 0; i < 3; i++) {
1154 __u8 phy_cap_support[] = { BIT(1) | BIT(2), BIT(3), BIT(4) };
1155 char *bw[] = { "<= 80", "160", "80+80" };
1156 int j;
1157
1158 if ((phy_cap[0] & (phy_cap_support[i] << 8)) == 0)
1159 continue;
1160
1161 for (j = 0; j < 2; j++) {
1162 int k;
1163 printf("\t\t\tHE %s MCS and NSS set %s MHz\n", j ? "TX" : "RX", bw[i]);
1164 for (k = 0; k < 8; k++) {
1165 __u16 mcs = mcs_set[(i * 2) + j];
1166 mcs >>= k * 2;
1167 mcs &= 0x3;
1168 printf("\t\t\t\t\t %d streams: ", k + 1);
1169 if (mcs == 3)
1170 printf("not supported\n");
1171 else
1172 printf("MCS 0-%d\n", 7 + (mcs * 2));
1173 }
1174
1175 }
1176 }
1177
1178 len = 0;
1179 if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]) {
1180 len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]);
1181 if (len > sizeof(ppet))
1182 len = sizeof(ppet);
1183 memcpy(ppet,
1184 nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]),
1185 len);
1186 }
1187
1188 if (len && (phy_cap[3] & BIT(15))) {
1189 size_t i;
1190
1191 printf("\t\t\tPPE Threshold ");
1192 for (i = 0; i < len; i++)
1193 if (ppet[i])
1194 printf("0x%02x ", ppet[i]);
1195 printf("\n");
1196 }
1197}
1198
492354de
JD
1199void iw_hexdump(const char *prefix, const __u8 *buf, size_t size)
1200{
0ee571d5 1201 size_t i;
492354de
JD
1202
1203 printf("%s: ", prefix);
1204 for (i = 0; i < size; i++) {
1205 if (i && i % 16 == 0)
1206 printf("\n%s: ", prefix);
1207 printf("%02x ", buf[i]);
1208 }
1209 printf("\n\n");
1210}
c1b2b633
SE
1211
1212int get_cf1(const struct chanmode *chanmode, unsigned long freq)
1213{
1214 unsigned int cf1 = freq, j;
1215 unsigned int vht80[] = { 5180, 5260, 5500, 5580, 5660, 5745 };
1216
1217 switch (chanmode->width) {
1218 case NL80211_CHAN_WIDTH_80:
1219 /* setup center_freq1 */
1220 for (j = 0; j < ARRAY_SIZE(vht80); j++) {
1221 if (freq >= vht80[j] && freq < vht80[j] + 80)
1222 break;
1223 }
1224
1225 if (j == ARRAY_SIZE(vht80))
1226 break;
1227
1228 cf1 = vht80[j] + 30;
1229 break;
1230 default:
1231 cf1 = freq + chanmode->freq1_diff;
1232 break;
1233 }
1234
1235 return cf1;
1236}
3c0117c1
JB
1237
1238int parse_random_mac_addr(struct nl_msg *msg, char *addrs)
1239{
1240 char *a_addr, *a_mask, *sep;
1241 unsigned char addr[ETH_ALEN], mask[ETH_ALEN];
1242
1243 if (!*addrs) {
1244 /* randomise all but the multicast bit */
1245 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN,
1246 "\x00\x00\x00\x00\x00\x00");
1247 NLA_PUT(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN,
1248 "\x01\x00\x00\x00\x00\x00");
1249 return 0;
1250 }
1251
1252 if (*addrs != '=')
1253 return 1;
1254
1255 addrs++;
1256 sep = strchr(addrs, '/');
1257 a_addr = addrs;
1258
1259 if (!sep)
1260 return 1;
1261
1262 *sep = 0;
1263 a_mask = sep + 1;
1264 if (mac_addr_a2n(addr, a_addr) || mac_addr_a2n(mask, a_mask))
1265 return 1;
1266
1267 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
1268 NLA_PUT(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN, mask);
1269
1270 return 0;
1271 nla_put_failure:
1272 return -ENOBUFS;
1273}