Import upstream version 5.9+git20210813.1.d59e908
Debian Janitor
2 years ago
44 | 44 | endif |
45 | 45 | |
46 | 46 | ifeq ($(NL2FOUND),Y) |
47 | CFLAGS += -DCONFIG_LIBNL20 | |
48 | LIBS += -lnl-genl | |
47 | override CFLAGS += -DCONFIG_LIBNL20 | |
48 | override LIBS += -lnl-genl | |
49 | 49 | NLLIBNAME = libnl-2.0 |
50 | 50 | endif |
51 | 51 | |
52 | 52 | ifeq ($(NL3xFOUND),Y) |
53 | 53 | # libnl 3.2 might be found as 3.2 and 3.0 |
54 | 54 | NL3FOUND = N |
55 | CFLAGS += -DCONFIG_LIBNL30 | |
56 | LIBS += -lnl-genl-3 | |
55 | override CFLAGS += -DCONFIG_LIBNL30 | |
56 | override LIBS += -lnl-genl-3 | |
57 | 57 | NLLIBNAME = libnl-3.0 |
58 | 58 | endif |
59 | 59 | |
60 | 60 | ifeq ($(NL3FOUND),Y) |
61 | CFLAGS += -DCONFIG_LIBNL30 | |
62 | LIBS += -lnl-genl | |
61 | override CFLAGS += -DCONFIG_LIBNL30 | |
62 | override LIBS += -lnl-genl | |
63 | 63 | NLLIBNAME = libnl-3.0 |
64 | 64 | endif |
65 | 65 | |
66 | 66 | # nl-3.1 has a broken libnl-gnl-3.1.pc file |
67 | 67 | # as show by pkg-config --debug --libs --cflags --exact-version=3.1 libnl-genl-3.1;echo $? |
68 | 68 | ifeq ($(NL31FOUND),Y) |
69 | CFLAGS += -DCONFIG_LIBNL30 | |
70 | LIBS += -lnl-genl | |
69 | override CFLAGS += -DCONFIG_LIBNL30 | |
70 | override LIBS += -lnl-genl | |
71 | 71 | NLLIBNAME = libnl-3.1 |
72 | 72 | endif |
73 | 73 | |
75 | 75 | $(error Cannot find development files for any supported version of libnl) |
76 | 76 | endif |
77 | 77 | |
78 | LIBS += $(shell $(PKG_CONFIG) --libs $(NLLIBNAME)) | |
79 | CFLAGS += $(shell $(PKG_CONFIG) --cflags $(NLLIBNAME)) | |
78 | override LIBS += $(shell $(PKG_CONFIG) --libs $(NLLIBNAME)) | |
79 | override CFLAGS += $(shell $(PKG_CONFIG) --cflags $(NLLIBNAME)) | |
80 | 80 | endif # NO_PKG_CONFIG |
81 | 81 | |
82 | 82 | ifeq ($(V),1) |
8 | 8 | |
9 | 9 | 'iw' is currently maintained at http://git.sipsolutions.net/iw.git/, |
10 | 10 | some more documentation is available at |
11 | http://wireless.kernel.org/en/users/Documentation/iw. | |
11 | https://wireless.wiki.kernel.org/en/users/Documentation/iw | |
12 | 12 | |
13 | 13 | Please send all patches to Johannes Berg <johannes@sipsolutions.net> |
14 | 14 | and CC linux-wireless@vger.kernel.org for community review. |
14 | 14 | { |
15 | 15 | char *end; |
16 | 16 | unsigned char bssid[6]; |
17 | bool need_key = false; | |
17 | 18 | int freq; |
18 | 19 | int ret; |
19 | 20 | |
47 | 48 | if (!argc) |
48 | 49 | return 0; |
49 | 50 | |
50 | if (strcmp(*argv, "key") != 0 && strcmp(*argv, "keys") != 0) | |
51 | if (strcmp(*argv, "auth") == 0) { | |
52 | argv++; | |
53 | argc--; | |
54 | ||
55 | if (!argc) | |
56 | return 1; | |
57 | ||
58 | if (strcmp(argv[0], "open") == 0) { | |
59 | NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, | |
60 | NL80211_AUTHTYPE_OPEN_SYSTEM); | |
61 | } else if (strcmp(argv[0], "shared") == 0) { | |
62 | NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, | |
63 | NL80211_AUTHTYPE_SHARED_KEY); | |
64 | need_key = true; | |
65 | } else { | |
66 | return 1; | |
67 | } | |
68 | ||
69 | argv++; | |
70 | argc--; | |
71 | } | |
72 | ||
73 | if (need_key && !argc) | |
74 | return 1; | |
75 | ||
76 | if (argc && strcmp(*argv, "key") != 0 && strcmp(*argv, "keys") != 0) | |
51 | 77 | return 1; |
52 | 78 | |
53 | 79 | argv++; |
159 | 185 | &printargs); |
160 | 186 | return 0; |
161 | 187 | } |
162 | TOPLEVEL(connect, "[-w] <SSID> [<freq in MHz>] [<bssid>] [key 0:abcde d:1:6162636465] [mfp:req/opt/no]", | |
188 | TOPLEVEL(connect, "[-w] <SSID> [<freq in MHz>] [<bssid>] [auth open|shared] [key 0:abcde d:1:6162636465] [mfp:req/opt/no]", | |
163 | 189 | 0, 0, CIB_NETDEV, iw_connect, |
164 | 190 | "Join the network with the given SSID (and frequency, BSSID).\n" |
165 | 191 | "With -w, wait for the connect to finish or fail."); |
2 | 2 | #include <net/if.h> |
3 | 3 | #include <errno.h> |
4 | 4 | #include <inttypes.h> |
5 | #include <time.h> | |
5 | 6 | #include "iw.h" |
6 | 7 | |
7 | 8 | static int no_seq_check(struct nl_msg *msg, void *arg) |
904 | 905 | int rem_nst; |
905 | 906 | __u16 status; |
906 | 907 | |
907 | if (args->time || args->reltime) { | |
908 | if (args->time || args->reltime || args->ctime) { | |
908 | 909 | unsigned long long usecs, previous; |
909 | 910 | |
910 | 911 | previous = 1000000ULL * args->ts.tv_sec + args->ts.tv_usec; |
911 | 912 | gettimeofday(&args->ts, NULL); |
912 | 913 | usecs = 1000000ULL * args->ts.tv_sec + args->ts.tv_usec; |
914 | ||
913 | 915 | if (args->reltime) { |
914 | 916 | if (!args->have_ts) { |
915 | 917 | usecs = 0; |
917 | 919 | } else |
918 | 920 | usecs -= previous; |
919 | 921 | } |
920 | printf("%llu.%06llu: ", usecs/1000000, usecs % 1000000); | |
922 | ||
923 | if (args->ctime) { | |
924 | struct tm *tm = localtime(&args->ts.tv_sec); | |
925 | char buf[255]; | |
926 | ||
927 | memset(buf, 0, 255); | |
928 | strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm); | |
929 | printf("[%s.%06lu]: ", buf, args->ts.tv_usec); | |
930 | } else { | |
931 | printf("%llu.%06llu: ", usecs/1000000, usecs % 1000000); | |
932 | } | |
921 | 933 | } |
922 | 934 | |
923 | 935 | nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), |
1170 | 1182 | (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]), |
1171 | 1183 | tb[NL80211_ATTR_ACK] ? "acked" : "no ack"); |
1172 | 1184 | break; |
1185 | case NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS: | |
1186 | printf("ctrl. port TX status (cookie %llx): %s\n", | |
1187 | (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]), | |
1188 | tb[NL80211_ATTR_ACK] ? "acked" : "no ack"); | |
1189 | break; | |
1173 | 1190 | case NL80211_CMD_PMKSA_CANDIDATE: |
1174 | 1191 | printf("PMKSA candidate found\n"); |
1175 | 1192 | break; |
1401 | 1418 | enum id_input id) |
1402 | 1419 | { |
1403 | 1420 | struct print_event_args args; |
1421 | int num_time_formats = 0; | |
1404 | 1422 | int ret; |
1405 | 1423 | |
1406 | 1424 | memset(&args, 0, sizeof(args)); |
1411 | 1429 | while (argc > 0) { |
1412 | 1430 | if (strcmp(argv[0], "-f") == 0) |
1413 | 1431 | args.frame = true; |
1414 | else if (strcmp(argv[0], "-t") == 0) | |
1432 | else if (strcmp(argv[0], "-t") == 0) { | |
1433 | num_time_formats++; | |
1415 | 1434 | args.time = true; |
1416 | else if (strcmp(argv[0], "-r") == 0) | |
1435 | } else if (strcmp(argv[0], "-T") == 0) { | |
1436 | num_time_formats++; | |
1437 | args.ctime = true; | |
1438 | } else if (strcmp(argv[0], "-r") == 0) { | |
1439 | num_time_formats++; | |
1417 | 1440 | args.reltime = true; |
1418 | else | |
1441 | } else | |
1419 | 1442 | return 1; |
1420 | 1443 | argc--; |
1421 | 1444 | argv++; |
1422 | 1445 | } |
1423 | 1446 | |
1424 | if (args.time && args.reltime) | |
1447 | if (num_time_formats > 1) | |
1425 | 1448 | return 1; |
1426 | 1449 | |
1427 | 1450 | if (argc) |
1436 | 1459 | TOPLEVEL(event, "[-t|-r] [-f]", 0, 0, CIB_NONE, print_events, |
1437 | 1460 | "Monitor events from the kernel.\n" |
1438 | 1461 | "-t - print timestamp\n" |
1462 | "-T - print absolute, human-readable timestamp\n" | |
1439 | 1463 | "-r - print relative timestamp\n" |
1440 | 1464 | "-f - print full frame for auth/assoc etc."); |
0 | .TH IW 8 "7 June 2012" "iw" "Linux" | |
0 | .TH IW 8 "22 November 2020" "iw" "Linux" | |
1 | 1 | .SH NAME |
2 | 2 | iw \- show / manipulate wireless devices and their configuration |
3 | 3 | .SH SYNOPSIS |
62 | 62 | will print the help for all matching commands. |
63 | 63 | |
64 | 64 | .SH SEE ALSO |
65 | .P | |
65 | 66 | .BR ip (8), |
66 | 67 | .BR crda (8), |
67 | 68 | .BR regdbdump (8), |
68 | .BR regulatory.bin (5) | |
69 | ||
70 | .BR http://wireless.kernel.org/en/users/Documentation/iw | |
69 | .BR regulatory.bin (5). | |
70 | . | |
71 | .P | |
72 | .UR https://wireless.wiki.kernel.org/en/users/Documentation/iw | |
73 | Documentation at kernel wiki | |
74 | .UE . |
286 | 286 | int *ret = arg; |
287 | 287 | int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh); |
288 | 288 | |
289 | *ret = err->error; | |
289 | if (err->error > 0) { | |
290 | /* | |
291 | * This is illegal, per netlink(7), but not impossible (think | |
292 | * "vendor commands"). Callers really expect negative error | |
293 | * codes, so make that happen. | |
294 | */ | |
295 | fprintf(stderr, | |
296 | "ERROR: received positive netlink error code %d\n", | |
297 | err->error); | |
298 | *ret = -EPROTO; | |
299 | } else { | |
300 | *ret = err->error; | |
301 | } | |
290 | 302 | |
291 | 303 | if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) |
292 | 304 | return NL_STOP; |
180 | 180 | struct print_event_args { |
181 | 181 | struct timeval ts; /* internal */ |
182 | 182 | bool have_ts; /* must be set false */ |
183 | bool frame, time, reltime; | |
183 | bool frame, time, reltime, ctime; | |
184 | 184 | }; |
185 | 185 | |
186 | 186 | __u32 listen_events(struct nl80211_state *state, |
212 | 212 | void print_ampdu_spacing(__u8 spacing); |
213 | 213 | void print_ht_capability(__u16 cap); |
214 | 214 | void print_vht_info(__u32 capa, const __u8 *mcs); |
215 | void print_he_capability(const uint8_t *ie, int len); | |
215 | 216 | void print_he_info(struct nlattr *nl_iftype); |
216 | 217 | |
217 | 218 | char *channel_width_name(enum nl80211_chan_width width); |
248 | 249 | |
249 | 250 | #define SCHED_SCAN_OPTIONS "[interval <in_msecs> | scan_plans [<interval_secs:iterations>*] <interval_secs>] " \ |
250 | 251 | "[delay <in_secs>] [freqs <freq>+] [matches [ssid <ssid>]+]] [active [ssid <ssid>]+|passive] " \ |
251 | "[randomise[=<addr>/<mask>]]" | |
252 | "[randomise[=<addr>/<mask>]] [coloc] [flush]" | |
252 | 253 | int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv); |
253 | 254 | |
254 | 255 | DECLARE_SECTION(switch); |
281 | 281 | const char *file; |
282 | 282 | int err; |
283 | 283 | |
284 | if (argc < 1) | |
285 | return HANDLER_RET_USAGE; | |
286 | ||
284 | 287 | file = argv[0]; |
285 | 288 | argc--; |
286 | 289 | argv++; |
10 | 10 | #include "iw.h" |
11 | 11 | |
12 | 12 | SECTION(mesh); |
13 | SECTION(mesh_param); | |
13 | 14 | |
14 | 15 | |
15 | 16 | typedef struct _any_t { |
400 | 401 | |
401 | 402 | for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) { |
402 | 403 | mdescr = &_mesh_param_descrs[i]; |
403 | printf("%s = ", mdescr->name); | |
404 | mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]); | |
405 | printf("\n"); | |
404 | if (mesh_params[mdescr->mesh_param_num]) { | |
405 | printf("%s = ", mdescr->name); | |
406 | mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]); | |
407 | printf("\n"); | |
408 | } | |
406 | 409 | } |
407 | 410 | return NL_SKIP; |
408 | 411 | } |
409 | 412 | |
410 | 413 | /* print out the mesh parameter */ |
411 | mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]); | |
412 | printf("\n"); | |
414 | if (mesh_params[mdescr->mesh_param_num]) { | |
415 | mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]); | |
416 | printf("\n"); | |
417 | } | |
413 | 418 | return NL_SKIP; |
414 | 419 | } |
415 | 420 | |
442 | 447 | NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, get_interface_meshparam, |
443 | 448 | "Retrieve mesh parameter (run command without any to see available ones)."); |
444 | 449 | |
450 | static int dump_interface_meshparam(struct nl80211_state *state, | |
451 | struct nl_msg *msg, | |
452 | int argc, char **argv, | |
453 | enum id_input id) | |
454 | { | |
455 | register_handler(print_mesh_param_handler, NULL); | |
456 | return 0; | |
457 | } | |
458 | ||
459 | COMMAND(mesh_param, dump, "", | |
460 | NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, dump_interface_meshparam, | |
461 | "List all supported mesh parameters"); | |
462 | ||
445 | 463 | static int join_mesh(struct nl80211_state *state, |
446 | 464 | struct nl_msg *msg, int argc, char **argv, |
447 | 465 | enum id_input id) |
53 | 53 | size_t match_len; |
54 | 54 | int ret; |
55 | 55 | |
56 | if (argc < 2) | |
57 | return HANDLER_RET_USAGE; | |
58 | ||
56 | 59 | ret = sscanf(argv[0], "%x", &type); |
57 | 60 | if (ret != 1) { |
58 | 61 | printf("invalid frame type: %s\n", argv[0]); |
95 | 98 | char **mgmt_argv; |
96 | 99 | unsigned int count = 0; |
97 | 100 | int err = 0; |
98 | int i; | |
99 | 101 | |
100 | 102 | mgmt_argv = calloc(mgmt_argc, sizeof(char*)); |
101 | 103 | if (!mgmt_argv) |
105 | 107 | mgmt_argv[1] = "mgmt"; |
106 | 108 | mgmt_argv[2] = "reg"; |
107 | 109 | |
108 | for (i = 3; i < argc; i += 3) { | |
109 | if (strcmp(argv[i], "count") == 0) { | |
110 | count = 1 + atoi(argv[i + 1]); | |
111 | if (count < 1) | |
112 | count = 1; | |
113 | break; | |
114 | } | |
110 | if (argc < 6) { | |
111 | err = HANDLER_RET_USAGE; | |
112 | goto out; | |
113 | } | |
115 | 114 | |
116 | if (strcmp(argv[i], "frame") != 0) { | |
117 | err = 1; | |
115 | argc -= 3; | |
116 | argv += 3; | |
117 | while (argc >= 3) { | |
118 | if (strcmp(argv[0], "frame") != 0) { | |
119 | err = HANDLER_RET_USAGE; | |
118 | 120 | goto out; |
119 | 121 | } |
120 | 122 | |
121 | mgmt_argv[3] = argv[i + 1]; | |
122 | mgmt_argv[4] = argv[i + 2]; | |
123 | mgmt_argv[3] = argv[1]; | |
124 | mgmt_argv[4] = argv[2]; | |
125 | ||
126 | argc -= 3; | |
127 | argv += 3; | |
123 | 128 | |
124 | 129 | err = handle_cmd(state, II_NETDEV, mgmt_argc, mgmt_argv); |
125 | 130 | if (err) |
126 | 131 | goto out; |
132 | } | |
133 | ||
134 | if (argc == 2 && strcmp(argv[0], "count") == 0) { | |
135 | count = 1 + atoi(argv[1]); | |
136 | if (count < 1) | |
137 | count = 1; | |
138 | ||
139 | argc -= 2; | |
140 | argv += 2; | |
141 | } else if (argc) { | |
142 | err = HANDLER_RET_USAGE; | |
143 | goto out; | |
127 | 144 | } |
128 | 145 | |
129 | 146 | mgmt_cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); |
654 | 654 | * When a security association was established on an 802.1X network using |
655 | 655 | * fast transition, this event should be followed by an |
656 | 656 | * %NL80211_CMD_PORT_AUTHORIZED event. |
657 | * Following a %NL80211_CMD_ROAM event userspace can issue | |
658 | * %NL80211_CMD_GET_SCAN in order to obtain the scan information for the | |
659 | * new BSS the card/driver roamed to. | |
657 | 660 | * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify |
658 | 661 | * userspace that a connection was dropped by the AP or due to other |
659 | 662 | * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and |
756 | 759 | * of any other interfaces, and other interfaces will again take |
757 | 760 | * precedence when they are used. |
758 | 761 | * |
759 | * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface. | |
762 | * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface | |
763 | * (no longer supported). | |
760 | 764 | * |
761 | 765 | * @NL80211_CMD_SET_MULTICAST_TO_UNICAST: Configure if this AP should perform |
762 | 766 | * multicast to unicast conversion. When enabled, all multicast packets |
1176 | 1180 | * includes the contents of the frame. %NL80211_ATTR_ACK flag is included |
1177 | 1181 | * if the recipient acknowledged the frame. |
1178 | 1182 | * |
1183 | * @NL80211_CMD_SET_SAR_SPECS: SAR power limitation configuration is | |
1184 | * passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to | |
1185 | * specify the wiphy index to be applied to. | |
1186 | * | |
1179 | 1187 | * @NL80211_CMD_MAX: highest used command number |
1180 | 1188 | * @__NL80211_CMD_AFTER_LAST: internal use |
1181 | 1189 | */ |
1405 | 1413 | NL80211_CMD_UNPROT_BEACON, |
1406 | 1414 | |
1407 | 1415 | NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS, |
1416 | ||
1417 | NL80211_CMD_SET_SAR_SPECS, | |
1408 | 1418 | |
1409 | 1419 | /* add new commands above here */ |
1410 | 1420 | |
1749 | 1759 | * specify just a single bitrate, which is to be used for the beacon. |
1750 | 1760 | * The driver must also specify support for this with the extended |
1751 | 1761 | * features NL80211_EXT_FEATURE_BEACON_RATE_LEGACY, |
1752 | * NL80211_EXT_FEATURE_BEACON_RATE_HT and | |
1753 | * NL80211_EXT_FEATURE_BEACON_RATE_VHT. | |
1762 | * NL80211_EXT_FEATURE_BEACON_RATE_HT, | |
1763 | * NL80211_EXT_FEATURE_BEACON_RATE_VHT and | |
1764 | * NL80211_EXT_FEATURE_BEACON_RATE_HE. | |
1754 | 1765 | * |
1755 | 1766 | * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain |
1756 | 1767 | * at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME. |
1954 | 1965 | * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire |
1955 | 1966 | * probe-response frame. The DA field in the 802.11 header is zero-ed out, |
1956 | 1967 | * to be filled by the FW. |
1957 | * @NL80211_ATTR_DISABLE_HT: Force HT capable interfaces to disable | |
1958 | * this feature. Currently, only supported in mac80211 drivers. | |
1968 | * @NL80211_ATTR_DISABLE_HT: Force HT capable interfaces to disable | |
1969 | * this feature during association. This is a flag attribute. | |
1970 | * Currently only supported in mac80211 drivers. | |
1971 | * @NL80211_ATTR_DISABLE_VHT: Force VHT capable interfaces to disable | |
1972 | * this feature during association. This is a flag attribute. | |
1973 | * Currently only supported in mac80211 drivers. | |
1974 | * @NL80211_ATTR_DISABLE_HE: Force HE capable interfaces to disable | |
1975 | * this feature during association. This is a flag attribute. | |
1976 | * Currently only supported in mac80211 drivers. | |
1959 | 1977 | * @NL80211_ATTR_HT_CAPABILITY_MASK: Specify which bits of the |
1960 | 1978 | * ATTR_HT_CAPABILITY to which attention should be paid. |
1961 | 1979 | * Currently, only mac80211 NICs support this feature. |
2076 | 2094 | * until the channel switch event. |
2077 | 2095 | * @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission |
2078 | 2096 | * must be blocked on the current channel (before the channel switch |
2079 | * operation). | |
2097 | * operation). Also included in the channel switch started event if quiet | |
2098 | * was requested by the AP. | |
2080 | 2099 | * @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information |
2081 | 2100 | * for the time while performing a channel switch. |
2082 | 2101 | * @NL80211_ATTR_CNTDWN_OFFS_BEACON: An array of offsets (u16) to the channel |
2526 | 2545 | * override mask. Used with NL80211_ATTR_S1G_CAPABILITY in |
2527 | 2546 | * NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT. |
2528 | 2547 | * |
2548 | * @NL80211_ATTR_SAE_PWE: Indicates the mechanism(s) allowed for SAE PWE | |
2549 | * derivation in WPA3-Personal networks which are using SAE authentication. | |
2550 | * This is a u8 attribute that encapsulates one of the values from | |
2551 | * &enum nl80211_sae_pwe_mechanism. | |
2552 | * | |
2553 | * @NL80211_ATTR_SAR_SPEC: SAR power limitation specification when | |
2554 | * used with %NL80211_CMD_SET_SAR_SPECS. The message contains fields | |
2555 | * of %nl80211_sar_attrs which specifies the sar type and related | |
2556 | * sar specs. Sar specs contains array of %nl80211_sar_specs_attrs. | |
2557 | * | |
2558 | * @NL80211_ATTR_RECONNECT_REQUESTED: flag attribute, used with deauth and | |
2559 | * disassoc events to indicate that an immediate reconnect to the AP | |
2560 | * is desired. | |
2561 | * | |
2529 | 2562 | * @NUM_NL80211_ATTR: total number of nl80211_attrs available |
2530 | 2563 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
2531 | 2564 | * @__NL80211_ATTR_AFTER_LAST: internal use |
3014 | 3047 | |
3015 | 3048 | NL80211_ATTR_S1G_CAPABILITY, |
3016 | 3049 | NL80211_ATTR_S1G_CAPABILITY_MASK, |
3050 | ||
3051 | NL80211_ATTR_SAE_PWE, | |
3052 | ||
3053 | NL80211_ATTR_RECONNECT_REQUESTED, | |
3054 | ||
3055 | NL80211_ATTR_SAR_SPEC, | |
3056 | ||
3057 | NL80211_ATTR_DISABLE_HE, | |
3017 | 3058 | |
3018 | 3059 | /* add attributes here, update the policy in nl80211.c */ |
3019 | 3060 | |
5895 | 5936 | * @NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP: Driver/device supports |
5896 | 5937 | * unsolicited broadcast probe response transmission |
5897 | 5938 | * |
5939 | * @NL80211_EXT_FEATURE_BEACON_RATE_HE: Driver supports beacon rate | |
5940 | * configuration (AP/mesh) with HE rates. | |
5941 | * | |
5898 | 5942 | * @NUM_NL80211_EXT_FEATURES: number of extended features. |
5899 | 5943 | * @MAX_NL80211_EXT_FEATURES: highest extended feature index. |
5900 | 5944 | */ |
5955 | 5999 | NL80211_EXT_FEATURE_SAE_OFFLOAD_AP, |
5956 | 6000 | NL80211_EXT_FEATURE_FILS_DISCOVERY, |
5957 | 6001 | NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP, |
6002 | NL80211_EXT_FEATURE_BEACON_RATE_HE, | |
5958 | 6003 | |
5959 | 6004 | /* add new features before the definition below */ |
5960 | 6005 | NUM_NL80211_EXT_FEATURES, |
6252 | 6297 | * @NL80211_TDLS_PEER_HT: TDLS peer is HT capable. |
6253 | 6298 | * @NL80211_TDLS_PEER_VHT: TDLS peer is VHT capable. |
6254 | 6299 | * @NL80211_TDLS_PEER_WMM: TDLS peer is WMM capable. |
6300 | * @NL80211_TDLS_PEER_HE: TDLS peer is HE capable. | |
6255 | 6301 | */ |
6256 | 6302 | enum nl80211_tdls_peer_capability { |
6257 | 6303 | NL80211_TDLS_PEER_HT = 1<<0, |
6258 | 6304 | NL80211_TDLS_PEER_VHT = 1<<1, |
6259 | 6305 | NL80211_TDLS_PEER_WMM = 1<<2, |
6306 | NL80211_TDLS_PEER_HE = 1<<3, | |
6260 | 6307 | }; |
6261 | 6308 | |
6262 | 6309 | /** |
7123 | 7170 | NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX = |
7124 | 7171 | __NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST - 1 |
7125 | 7172 | }; |
7173 | ||
7174 | /** | |
7175 | * enum nl80211_sae_pwe_mechanism - The mechanism(s) allowed for SAE PWE | |
7176 | * derivation. Applicable only when WPA3-Personal SAE authentication is | |
7177 | * used. | |
7178 | * | |
7179 | * @NL80211_SAE_PWE_UNSPECIFIED: not specified, used internally to indicate that | |
7180 | * attribute is not present from userspace. | |
7181 | * @NL80211_SAE_PWE_HUNT_AND_PECK: hunting-and-pecking loop only | |
7182 | * @NL80211_SAE_PWE_HASH_TO_ELEMENT: hash-to-element only | |
7183 | * @NL80211_SAE_PWE_BOTH: both hunting-and-pecking loop and hash-to-element | |
7184 | * can be used. | |
7185 | */ | |
7186 | enum nl80211_sae_pwe_mechanism { | |
7187 | NL80211_SAE_PWE_UNSPECIFIED, | |
7188 | NL80211_SAE_PWE_HUNT_AND_PECK, | |
7189 | NL80211_SAE_PWE_HASH_TO_ELEMENT, | |
7190 | NL80211_SAE_PWE_BOTH, | |
7191 | }; | |
7192 | ||
7193 | /** | |
7194 | * enum nl80211_sar_type - type of SAR specs | |
7195 | * | |
7196 | * @NL80211_SAR_TYPE_POWER: power limitation specified in 0.25dBm unit | |
7197 | * | |
7198 | */ | |
7199 | enum nl80211_sar_type { | |
7200 | NL80211_SAR_TYPE_POWER, | |
7201 | ||
7202 | /* add new type here */ | |
7203 | ||
7204 | /* Keep last */ | |
7205 | NUM_NL80211_SAR_TYPE, | |
7206 | }; | |
7207 | ||
7208 | /** | |
7209 | * enum nl80211_sar_attrs - Attributes for SAR spec | |
7210 | * | |
7211 | * @NL80211_SAR_ATTR_TYPE: the SAR type as defined in &enum nl80211_sar_type. | |
7212 | * | |
7213 | * @NL80211_SAR_ATTR_SPECS: Nested array of SAR power | |
7214 | * limit specifications. Each specification contains a set | |
7215 | * of %nl80211_sar_specs_attrs. | |
7216 | * | |
7217 | * For SET operation, it contains array of %NL80211_SAR_ATTR_SPECS_POWER | |
7218 | * and %NL80211_SAR_ATTR_SPECS_RANGE_INDEX. | |
7219 | * | |
7220 | * For sar_capa dump, it contains array of | |
7221 | * %NL80211_SAR_ATTR_SPECS_START_FREQ | |
7222 | * and %NL80211_SAR_ATTR_SPECS_END_FREQ. | |
7223 | * | |
7224 | * @__NL80211_SAR_ATTR_LAST: Internal | |
7225 | * @NL80211_SAR_ATTR_MAX: highest sar attribute | |
7226 | * | |
7227 | * These attributes are used with %NL80211_CMD_SET_SAR_SPEC | |
7228 | */ | |
7229 | enum nl80211_sar_attrs { | |
7230 | __NL80211_SAR_ATTR_INVALID, | |
7231 | ||
7232 | NL80211_SAR_ATTR_TYPE, | |
7233 | NL80211_SAR_ATTR_SPECS, | |
7234 | ||
7235 | __NL80211_SAR_ATTR_LAST, | |
7236 | NL80211_SAR_ATTR_MAX = __NL80211_SAR_ATTR_LAST - 1, | |
7237 | }; | |
7238 | ||
7239 | /** | |
7240 | * enum nl80211_sar_specs_attrs - Attributes for SAR power limit specs | |
7241 | * | |
7242 | * @NL80211_SAR_ATTR_SPECS_POWER: Required (s32)value to specify the actual | |
7243 | * power limit value in units of 0.25 dBm if type is | |
7244 | * NL80211_SAR_TYPE_POWER. (i.e., a value of 44 represents 11 dBm). | |
7245 | * 0 means userspace doesn't have SAR limitation on this associated range. | |
7246 | * | |
7247 | * @NL80211_SAR_ATTR_SPECS_RANGE_INDEX: Required (u32) value to specify the | |
7248 | * index of exported freq range table and the associated power limitation | |
7249 | * is applied to this range. | |
7250 | * | |
7251 | * Userspace isn't required to set all the ranges advertised by WLAN driver, | |
7252 | * and userspace can skip some certain ranges. These skipped ranges don't | |
7253 | * have SAR limitations, and they are same as setting the | |
7254 | * %NL80211_SAR_ATTR_SPECS_POWER to any unreasonable high value because any | |
7255 | * value higher than regulatory allowed value just means SAR power | |
7256 | * limitation is removed, but it's required to set at least one range. | |
7257 | * It's not allowed to set duplicated range in one SET operation. | |
7258 | * | |
7259 | * Every SET operation overwrites previous SET operation. | |
7260 | * | |
7261 | * @NL80211_SAR_ATTR_SPECS_START_FREQ: Required (u32) value to specify the start | |
7262 | * frequency of this range edge when registering SAR capability to wiphy. | |
7263 | * It's not a channel center frequency. The unit is kHz. | |
7264 | * | |
7265 | * @NL80211_SAR_ATTR_SPECS_END_FREQ: Required (u32) value to specify the end | |
7266 | * frequency of this range edge when registering SAR capability to wiphy. | |
7267 | * It's not a channel center frequency. The unit is kHz. | |
7268 | * | |
7269 | * @__NL80211_SAR_ATTR_SPECS_LAST: Internal | |
7270 | * @NL80211_SAR_ATTR_SPECS_MAX: highest sar specs attribute | |
7271 | */ | |
7272 | enum nl80211_sar_specs_attrs { | |
7273 | __NL80211_SAR_ATTR_SPECS_INVALID, | |
7274 | ||
7275 | NL80211_SAR_ATTR_SPECS_POWER, | |
7276 | NL80211_SAR_ATTR_SPECS_RANGE_INDEX, | |
7277 | NL80211_SAR_ATTR_SPECS_START_FREQ, | |
7278 | NL80211_SAR_ATTR_SPECS_END_FREQ, | |
7279 | ||
7280 | __NL80211_SAR_ATTR_SPECS_LAST, | |
7281 | NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1, | |
7282 | }; | |
7283 | ||
7126 | 7284 | #endif /* __LINUX_NL80211_H */ |
198 | 198 | } |
199 | 199 | |
200 | 200 | COMMAND(set, freq, |
201 | "<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n" | |
201 | "<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]\n" | |
202 | 202 | "<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]", |
203 | 203 | NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq, |
204 | 204 | "Set frequency/channel the hardware is using, including HT\n" |
205 | 205 | "configuration."); |
206 | 206 | COMMAND(set, freq, |
207 | "<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n" | |
207 | "<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]\n" | |
208 | 208 | "<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]", |
209 | 209 | NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL); |
210 | 210 | |
221 | 221 | |
222 | 222 | return put_chandef(msg, &chandef); |
223 | 223 | } |
224 | COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]", | |
224 | COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]", | |
225 | 225 | NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL); |
226 | COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]", | |
226 | COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]", | |
227 | 227 | NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL); |
228 | 228 | |
229 | 229 |
74 | 74 | return 0; |
75 | 75 | } |
76 | 76 | |
77 | COMMAND(get, power_save, "<param>", | |
77 | COMMAND(get, power_save, "", | |
78 | 78 | NL80211_CMD_GET_POWER_SAVE, 0, CIB_NETDEV, get_power_save, |
79 | 79 | "Retrieve power save state."); |
201 | 201 | err = parse_random_mac_addr(msg, v[0] + 9); |
202 | 202 | if (err) |
203 | 203 | goto nla_put_failure; |
204 | } else if (!strncmp(v[0], "coloc", 5)) { | |
205 | flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ; | |
206 | } else if (!strncmp(v[0], "flush", 5)) { | |
207 | flags |= NL80211_SCAN_FLAG_FLUSH; | |
204 | 208 | } else { |
205 | 209 | /* this element is not for us, so |
206 | 210 | * return to continue parsing. |
419 | 423 | break; |
420 | 424 | } else if (strcmp(argv[i], "ap-force") == 0) { |
421 | 425 | flags |= NL80211_SCAN_FLAG_AP; |
426 | break; | |
427 | } else if (strcmp(argv[i], "coloc") == 0) { | |
428 | flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ; | |
422 | 429 | break; |
423 | 430 | } else if (strcmp(argv[i], "duration-mandatory") == 0) { |
424 | 431 | duration_mandatory = true; |
507 | 514 | |
508 | 515 | if (have_freqs) |
509 | 516 | nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs); |
517 | else | |
518 | flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ; | |
510 | 519 | if (flags) |
511 | 520 | NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, flags); |
512 | 521 | if (duration) |
2262 | 2271 | printf("\n"); |
2263 | 2272 | } |
2264 | 2273 | |
2274 | static void print_he_capa(const uint8_t type, uint8_t len, const uint8_t *data, | |
2275 | const struct print_ies_data *ie_buffer) | |
2276 | { | |
2277 | printf("\n"); | |
2278 | print_he_capability(data, len); | |
2279 | } | |
2280 | ||
2281 | static const struct ie_print ext_printers[] = { | |
2282 | [35] = { "HE capabilities", print_he_capa, 21, 54, BIT(PRINT_SCAN), }, | |
2283 | }; | |
2284 | ||
2285 | static void print_extension(unsigned char len, unsigned char *ie, | |
2286 | bool unknown, enum print_ie_type ptype) | |
2287 | { | |
2288 | unsigned char tag; | |
2289 | ||
2290 | if (len < 1) { | |
2291 | printf("\tExtension IE: <empty>\n"); | |
2292 | return; | |
2293 | } | |
2294 | ||
2295 | tag = ie[0]; | |
2296 | if (tag < ARRAY_SIZE(ext_printers) && ext_printers[tag].name && | |
2297 | ext_printers[tag].flags & BIT(ptype)) { | |
2298 | print_ie(&ext_printers[tag], tag, len - 1, ie + 1, NULL); | |
2299 | return; | |
2300 | } | |
2301 | ||
2302 | if (unknown) { | |
2303 | int i; | |
2304 | ||
2305 | printf("\tUnknown Extension ID (%d):", ie[0]); | |
2306 | for (i = 1; i < len; i++) | |
2307 | printf(" %.2x", ie[i]); | |
2308 | printf("\n"); | |
2309 | } | |
2310 | } | |
2311 | ||
2265 | 2312 | void print_ies(unsigned char *ie, int ielen, bool unknown, |
2266 | 2313 | enum print_ie_type ptype) |
2267 | 2314 | { |
2280 | 2327 | ie[0], ie[1], ie + 2, &ie_buffer); |
2281 | 2328 | } else if (ie[0] == 221 /* vendor */) { |
2282 | 2329 | print_vendor(ie[1], ie + 2, unknown, ptype); |
2330 | } else if (ie[0] == 255 /* extension */) { | |
2331 | print_extension(ie[1], ie + 2, unknown, ptype); | |
2283 | 2332 | } else if (unknown) { |
2284 | 2333 | int i; |
2285 | 2334 | |
2599 | 2648 | NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump, |
2600 | 2649 | "Dump the current scan results. If -u is specified, print unknown\n" |
2601 | 2650 | "data in scan results."); |
2602 | COMMAND(scan, trigger, "[freq <freq>*] [duration <dur>] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force,duration-mandatory] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", | |
2651 | COMMAND(scan, trigger, "[freq <freq>*] [duration <dur>] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force,duration-mandatory,coloc] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", | |
2603 | 2652 | NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan, |
2604 | 2653 | "Trigger a scan on the given frequencies with probing for the given\n" |
2605 | 2654 | "SSIDs (or wildcard if not given) unless passive scanning is requested.\n" |
328 | 328 | [NL80211_STA_INFO_ACK_SIGNAL] = {.type = NLA_U8 }, |
329 | 329 | [NL80211_STA_INFO_ACK_SIGNAL_AVG] = { .type = NLA_U8 }, |
330 | 330 | [NL80211_STA_INFO_AIRTIME_LINK_METRIC] = { .type = NLA_U32 }, |
331 | [NL80211_STA_INFO_CONNECTED_TO_AS] = { .type = NLA_FLAG }, | |
332 | [NL80211_STA_INFO_CONNECTED_TO_GATE] = { .type = NLA_FLAG }, | |
331 | [NL80211_STA_INFO_CONNECTED_TO_AS] = { .type = NLA_U8 }, | |
332 | [NL80211_STA_INFO_CONNECTED_TO_GATE] = { .type = NLA_U8 }, | |
333 | 333 | }; |
334 | 334 | char *chain; |
335 | 335 | struct timeval now; |
336 | 336 | unsigned long long now_ms; |
337 | 337 | |
338 | 338 | gettimeofday(&now, NULL); |
339 | now_ms = now.tv_sec * 1000; | |
339 | now_ms = now.tv_sec * 1000ULL; | |
340 | 340 | now_ms += (now.tv_usec / 1000); |
341 | 341 | |
342 | 342 | nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), |
600 | 600 | unsigned long long assoc_at_ms; |
601 | 601 | |
602 | 602 | clock_gettime(CLOCK_BOOTTIME, &now_ts); |
603 | boot_ns = now_ts.tv_sec * 1000000000; | |
603 | boot_ns = now_ts.tv_sec * 1000000000ULL; | |
604 | 604 | boot_ns += now_ts.tv_nsec; |
605 | 605 | |
606 | 606 | bt = (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_ASSOC_AT_BOOTTIME]); |
575 | 575 | * user by giving "NOHT" instead. |
576 | 576 | * |
577 | 577 | * The working specifier if chan is set are: |
578 | * <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz] | |
578 | * <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz] | |
579 | 579 | * |
580 | 580 | * And if frequency is set: |
581 | * <freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz] | |
581 | * <freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz] | |
582 | 582 | * <control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]] |
583 | 583 | * |
584 | 584 | * If the mode/channel width is not given the NOHT is assumed. |
618 | 618 | .width = NL80211_CHAN_WIDTH_80, |
619 | 619 | .freq1_diff = 0, |
620 | 620 | .chantype = -1 }, |
621 | { .name = "160MHz", | |
622 | .width = NL80211_CHAN_WIDTH_160, | |
623 | .freq1_diff = 0, | |
624 | .chantype = -1 }, | |
621 | 625 | }; |
622 | 626 | const struct chanmode *chanmode_selected = NULL; |
623 | 627 | unsigned int freq; |
984 | 988 | printf("\t\tVHT TX highest supported: %d Mbps\n", tmp & 0x1fff); |
985 | 989 | } |
986 | 990 | |
987 | void print_he_info(struct nlattr *nl_iftype) | |
988 | { | |
989 | struct nlattr *tb[NL80211_BAND_IFTYPE_ATTR_MAX + 1]; | |
990 | struct nlattr *tb_flags[NL80211_IFTYPE_MAX + 1]; | |
991 | char *iftypes[NUM_NL80211_IFTYPES] = { | |
992 | "Unspec", "Adhoc", "Station", "AP", "AP/VLAN", "WDS", "Monitor", | |
993 | "Mesh", "P2P/Client", "P2P/Go", "P2P/Device", "OCB", "NAN", | |
994 | }; | |
995 | __u16 mac_cap[3] = { 0 }; | |
996 | __u16 phy_cap[6] = { 0 }; | |
997 | __u16 mcs_set[6] = { 0 }; | |
998 | __u8 ppet[25] = { 0 }; | |
999 | size_t len; | |
991 | static void __print_he_capa(const __u16 *mac_cap, | |
992 | const __u16 *phy_cap, | |
993 | const __u16 *mcs_set, size_t mcs_len, | |
994 | const __u8 *ppet, int ppet_len, | |
995 | bool indent) | |
996 | { | |
997 | size_t mcs_used; | |
1000 | 998 | int i; |
999 | const char *pre = indent ? "\t" : ""; | |
1001 | 1000 | |
1002 | 1001 | #define PRINT_HE_CAP(_var, _idx, _bit, _str) \ |
1003 | 1002 | do { \ |
1004 | 1003 | if (_var[_idx] & BIT(_bit)) \ |
1005 | printf("\t\t\t\t" _str "\n"); \ | |
1004 | printf("%s\t\t\t" _str "\n", pre); \ | |
1006 | 1005 | } while (0) |
1007 | 1006 | |
1008 | 1007 | #define PRINT_HE_CAP_MASK(_var, _idx, _shift, _mask, _str) \ |
1009 | 1008 | do { \ |
1010 | 1009 | if ((_var[_idx] >> _shift) & _mask) \ |
1011 | printf("\t\t\t\t" _str ": %d\n", (_var[_idx] >> _shift) & _mask); \ | |
1010 | printf("%s\t\t\t" _str ": %d\n", pre, (_var[_idx] >> _shift) & _mask); \ | |
1012 | 1011 | } while (0) |
1013 | 1012 | |
1014 | 1013 | #define PRINT_HE_MAC_CAP(...) PRINT_HE_CAP(mac_cap, __VA_ARGS__) |
1017 | 1016 | #define PRINT_HE_PHY_CAP0(_idx, _bit, ...) PRINT_HE_CAP(phy_cap, _idx, _bit + 8, __VA_ARGS__) |
1018 | 1017 | #define PRINT_HE_PHY_CAP_MASK(...) PRINT_HE_CAP_MASK(phy_cap, __VA_ARGS__) |
1019 | 1018 | |
1020 | nla_parse(tb, NL80211_BAND_IFTYPE_ATTR_MAX, | |
1021 | nla_data(nl_iftype), nla_len(nl_iftype), NULL); | |
1022 | ||
1023 | if (!tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES]) | |
1024 | return; | |
1025 | ||
1026 | if (nla_parse_nested(tb_flags, NL80211_IFTYPE_MAX, | |
1027 | tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES], NULL)) | |
1028 | return; | |
1029 | ||
1030 | printf("\t\tHE Iftypes:"); | |
1031 | for (i = 0; i < NUM_NL80211_IFTYPES; i++) | |
1032 | if (nla_get_flag(tb_flags[i]) && iftypes[i]) | |
1033 | printf(" %s", iftypes[i]); | |
1034 | printf("\n"); | |
1035 | ||
1036 | if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]) { | |
1037 | len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]); | |
1038 | if (len > sizeof(mac_cap)) | |
1039 | len = sizeof(mac_cap); | |
1040 | memcpy(mac_cap, | |
1041 | nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]), | |
1042 | len); | |
1043 | } | |
1044 | printf("\t\t\tHE MAC Capabilities (0x"); | |
1019 | printf("%s\t\tHE MAC Capabilities (0x", pre); | |
1045 | 1020 | for (i = 0; i < 3; i++) |
1046 | 1021 | printf("%04x", mac_cap[i]); |
1047 | 1022 | printf("):\n"); |
1081 | 1056 | PRINT_HE_MAC_CAP(2, 11, "UL 2x996-Tone RU"); |
1082 | 1057 | PRINT_HE_MAC_CAP(2, 12, "OM Control UL MU Data Disable RX"); |
1083 | 1058 | |
1084 | if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]) { | |
1085 | len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]); | |
1086 | ||
1087 | if (len > sizeof(phy_cap) - 1) | |
1088 | len = sizeof(phy_cap) - 1; | |
1089 | memcpy(&((__u8 *)phy_cap)[1], | |
1090 | nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]), | |
1091 | len); | |
1092 | } | |
1093 | printf("\t\t\tHE PHY Capabilities: (0x"); | |
1059 | printf("%s\t\tHE PHY Capabilities: (0x", pre); | |
1094 | 1060 | for (i = 0; i < 11; i++) |
1095 | 1061 | printf("%02x", ((__u8 *)phy_cap)[i + 1]); |
1096 | 1062 | printf("):\n"); |
1160 | 1126 | PRINT_HE_PHY_CAP(5, 4, "RX Full BW SU Using HE MU PPDU with Compression SIGB"); |
1161 | 1127 | PRINT_HE_PHY_CAP(5, 5, "RX Full BW SU Using HE MU PPDU with Non-Compression SIGB"); |
1162 | 1128 | |
1129 | mcs_used = 0; | |
1130 | for (i = 0; i < 3; i++) { | |
1131 | __u8 phy_cap_support[] = { BIT(1) | BIT(2), BIT(3), BIT(4) }; | |
1132 | char *bw[] = { "<= 80", "160", "80+80" }; | |
1133 | int j; | |
1134 | ||
1135 | if ((phy_cap[0] & (phy_cap_support[i] << 8)) == 0) | |
1136 | continue; | |
1137 | ||
1138 | /* Supports more, but overflow? Abort. */ | |
1139 | if ((i * 2 + 2) * sizeof(mcs_set[0]) >= mcs_len) | |
1140 | return; | |
1141 | ||
1142 | for (j = 0; j < 2; j++) { | |
1143 | int k; | |
1144 | printf("%s\t\tHE %s MCS and NSS set %s MHz\n", pre, j ? "TX" : "RX", bw[i]); | |
1145 | for (k = 0; k < 8; k++) { | |
1146 | __u16 mcs = mcs_set[(i * 2) + j]; | |
1147 | mcs >>= k * 2; | |
1148 | mcs &= 0x3; | |
1149 | printf("%s\t\t\t%d streams: ", pre, k + 1); | |
1150 | if (mcs == 3) | |
1151 | printf("not supported\n"); | |
1152 | else | |
1153 | printf("MCS 0-%d\n", 7 + (mcs * 2)); | |
1154 | } | |
1155 | ||
1156 | } | |
1157 | mcs_used += 2 * sizeof(mcs_set[0]); | |
1158 | } | |
1159 | ||
1160 | /* Caller didn't provide ppet; infer it, if there's trailing space. */ | |
1161 | if (!ppet) { | |
1162 | ppet = (const void *)((const __u8 *)mcs_set + mcs_used); | |
1163 | if (mcs_used < mcs_len) | |
1164 | ppet_len = mcs_len - mcs_used; | |
1165 | else | |
1166 | ppet_len = 0; | |
1167 | } | |
1168 | ||
1169 | if (ppet_len && (phy_cap[3] & BIT(15))) { | |
1170 | printf("%s\t\tPPE Threshold ", pre); | |
1171 | for (i = 0; i < ppet_len; i++) | |
1172 | if (ppet[i]) | |
1173 | printf("0x%02x ", ppet[i]); | |
1174 | printf("\n"); | |
1175 | } | |
1176 | } | |
1177 | ||
1178 | void print_he_info(struct nlattr *nl_iftype) | |
1179 | { | |
1180 | struct nlattr *tb[NL80211_BAND_IFTYPE_ATTR_MAX + 1]; | |
1181 | struct nlattr *tb_flags[NL80211_IFTYPE_MAX + 1]; | |
1182 | char *iftypes[NUM_NL80211_IFTYPES] = { | |
1183 | "Unspec", "Adhoc", "Station", "AP", "AP/VLAN", "WDS", "Monitor", | |
1184 | "Mesh", "P2P/Client", "P2P/Go", "P2P/Device", "OCB", "NAN", | |
1185 | }; | |
1186 | __u16 mac_cap[3] = { 0 }; | |
1187 | __u16 phy_cap[6] = { 0 }; | |
1188 | __u16 mcs_set[6] = { 0 }; | |
1189 | __u8 ppet[25] = { 0 }; | |
1190 | size_t len; | |
1191 | int i; | |
1192 | int mcs_len = 0, ppet_len = 0; | |
1193 | ||
1194 | nla_parse(tb, NL80211_BAND_IFTYPE_ATTR_MAX, | |
1195 | nla_data(nl_iftype), nla_len(nl_iftype), NULL); | |
1196 | ||
1197 | if (!tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES]) | |
1198 | return; | |
1199 | ||
1200 | if (nla_parse_nested(tb_flags, NL80211_IFTYPE_MAX, | |
1201 | tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES], NULL)) | |
1202 | return; | |
1203 | ||
1204 | printf("\t\tHE Iftypes:"); | |
1205 | for (i = 0; i < NUM_NL80211_IFTYPES; i++) | |
1206 | if (nla_get_flag(tb_flags[i]) && iftypes[i]) | |
1207 | printf(" %s", iftypes[i]); | |
1208 | printf("\n"); | |
1209 | ||
1210 | if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]) { | |
1211 | len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]); | |
1212 | if (len > sizeof(mac_cap)) | |
1213 | len = sizeof(mac_cap); | |
1214 | memcpy(mac_cap, | |
1215 | nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]), | |
1216 | len); | |
1217 | } | |
1218 | ||
1219 | if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]) { | |
1220 | len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]); | |
1221 | ||
1222 | if (len > sizeof(phy_cap) - 1) | |
1223 | len = sizeof(phy_cap) - 1; | |
1224 | memcpy(&((__u8 *)phy_cap)[1], | |
1225 | nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]), | |
1226 | len); | |
1227 | } | |
1228 | ||
1163 | 1229 | if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]) { |
1164 | 1230 | len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]); |
1165 | 1231 | if (len > sizeof(mcs_set)) |
1167 | 1233 | memcpy(mcs_set, |
1168 | 1234 | nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]), |
1169 | 1235 | len); |
1170 | } | |
1171 | ||
1172 | for (i = 0; i < 3; i++) { | |
1173 | __u8 phy_cap_support[] = { BIT(1) | BIT(2), BIT(3), BIT(4) }; | |
1174 | char *bw[] = { "<= 80", "160", "80+80" }; | |
1175 | int j; | |
1176 | ||
1177 | if ((phy_cap[0] & (phy_cap_support[i] << 8)) == 0) | |
1178 | continue; | |
1179 | ||
1180 | for (j = 0; j < 2; j++) { | |
1181 | int k; | |
1182 | printf("\t\t\tHE %s MCS and NSS set %s MHz\n", j ? "TX" : "RX", bw[i]); | |
1183 | for (k = 0; k < 8; k++) { | |
1184 | __u16 mcs = mcs_set[(i * 2) + j]; | |
1185 | mcs >>= k * 2; | |
1186 | mcs &= 0x3; | |
1187 | printf("\t\t\t\t\t %d streams: ", k + 1); | |
1188 | if (mcs == 3) | |
1189 | printf("not supported\n"); | |
1190 | else | |
1191 | printf("MCS 0-%d\n", 7 + (mcs * 2)); | |
1192 | } | |
1193 | ||
1194 | } | |
1195 | } | |
1196 | ||
1197 | len = 0; | |
1236 | mcs_len = len; | |
1237 | } | |
1238 | ||
1198 | 1239 | if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]) { |
1199 | 1240 | len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]); |
1200 | 1241 | if (len > sizeof(ppet)) |
1202 | 1243 | memcpy(ppet, |
1203 | 1244 | nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]), |
1204 | 1245 | len); |
1205 | } | |
1206 | ||
1207 | if (len && (phy_cap[3] & BIT(15))) { | |
1208 | size_t i; | |
1209 | ||
1210 | printf("\t\t\tPPE Threshold "); | |
1211 | for (i = 0; i < len; i++) | |
1212 | if (ppet[i]) | |
1213 | printf("0x%02x ", ppet[i]); | |
1214 | printf("\n"); | |
1215 | } | |
1246 | ppet_len = len; | |
1247 | } | |
1248 | ||
1249 | __print_he_capa(mac_cap, phy_cap, mcs_set, mcs_len, ppet, ppet_len, | |
1250 | true); | |
1251 | } | |
1252 | ||
1253 | void print_he_capability(const uint8_t *ie, int len) | |
1254 | { | |
1255 | const void *mac_cap, *phy_cap, *mcs_set; | |
1256 | int mcs_len; | |
1257 | int i = 0; | |
1258 | ||
1259 | mac_cap = &ie[i]; | |
1260 | i += 6; | |
1261 | ||
1262 | phy_cap = &ie[i]; | |
1263 | i += 11; | |
1264 | ||
1265 | mcs_set = &ie[i]; | |
1266 | mcs_len = len - i; | |
1267 | ||
1268 | __print_he_capa(mac_cap, phy_cap - 1, mcs_set, mcs_len, NULL, 0, false); | |
1216 | 1269 | } |
1217 | 1270 | |
1218 | 1271 | void iw_hexdump(const char *prefix, const __u8 *buf, size_t size) |
1231 | 1284 | int get_cf1(const struct chanmode *chanmode, unsigned long freq) |
1232 | 1285 | { |
1233 | 1286 | unsigned int cf1 = freq, j; |
1234 | unsigned int vht80[] = { 5180, 5260, 5500, 5580, 5660, 5745 }; | |
1287 | unsigned int bw80[] = { 5180, 5260, 5500, 5580, 5660, 5745, | |
1288 | 5955, 6035, 6115, 6195, 6275, 6355, | |
1289 | 6435, 6515, 6595, 6675, 6755, 6835, | |
1290 | 6195, 6995 }; | |
1291 | unsigned int vht160[] = { 5180, 5500 }; | |
1235 | 1292 | |
1236 | 1293 | switch (chanmode->width) { |
1237 | 1294 | case NL80211_CHAN_WIDTH_80: |
1238 | 1295 | /* setup center_freq1 */ |
1239 | for (j = 0; j < ARRAY_SIZE(vht80); j++) { | |
1240 | if (freq >= vht80[j] && freq < vht80[j] + 80) | |
1296 | for (j = 0; j < ARRAY_SIZE(bw80); j++) { | |
1297 | if (freq >= bw80[j] && freq < bw80[j] + 80) | |
1241 | 1298 | break; |
1242 | 1299 | } |
1243 | 1300 | |
1244 | if (j == ARRAY_SIZE(vht80)) | |
1301 | if (j == ARRAY_SIZE(bw80)) | |
1245 | 1302 | break; |
1246 | 1303 | |
1247 | cf1 = vht80[j] + 30; | |
1304 | cf1 = bw80[j] + 30; | |
1305 | break; | |
1306 | case NL80211_CHAN_WIDTH_160: | |
1307 | /* setup center_freq1 */ | |
1308 | for (j = 0; j < ARRAY_SIZE(vht160); j++) { | |
1309 | if (freq >= vht160[j] && freq < vht160[j] + 160) | |
1310 | break; | |
1311 | } | |
1312 | ||
1313 | if (j == ARRAY_SIZE(vht160)) | |
1314 | break; | |
1315 | ||
1316 | cf1 = vht160[j] + 70; | |
1248 | 1317 | break; |
1249 | 1318 | default: |
1250 | 1319 | cf1 = freq + chanmode->freq1_diff; |