diff options
author | Xin Li <delphij@google.com> | 2022-08-15 22:02:38 -0700 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2022-08-15 22:02:38 -0700 |
commit | 5120c04b23a9737a87280ce080604dc56536c72a (patch) | |
tree | 950dc2a5fb5f86f84e4e2c51bfcbca7bfceb13b9 | |
parent | 116da4ddf395ff517253298b410254793b7c9a4b (diff) | |
parent | 999e129ee24a3c15e633b8489382faba831e87fe (diff) | |
download | iw-5120c04b23a9737a87280ce080604dc56536c72a.tar.gz |
DO NOT MERGE - Merge Android 13main-16k
Bug: 242648940
Merged-In: I972a9b84667c8527209c8983f454d8511acc004e
Change-Id: I4e3e68ff71bbcb77dfccf34f76139778fba5b664
-rw-r--r-- | Android.bp | 8 | ||||
-rw-r--r-- | Makefile | 44 | ||||
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | ap.c | 163 | ||||
-rw-r--r-- | bitrate.c | 250 | ||||
-rw-r--r-- | bloom.c | 80 | ||||
-rw-r--r-- | coalesce.c | 12 | ||||
-rw-r--r-- | connect.c | 64 | ||||
-rw-r--r-- | cqm.c | 4 | ||||
-rw-r--r-- | event.c | 829 | ||||
-rw-r--r-- | ftm.c | 157 | ||||
-rw-r--r-- | hwsim.c | 15 | ||||
-rw-r--r-- | ibss.c | 87 | ||||
-rw-r--r-- | ieee80211.h | 17 | ||||
-rw-r--r-- | info.c | 236 | ||||
-rw-r--r-- | interface.c | 448 | ||||
-rw-r--r-- | iw.8 | 12 | ||||
-rw-r--r-- | iw.c | 127 | ||||
-rw-r--r-- | iw.h | 172 | ||||
-rw-r--r-- | link.c | 18 | ||||
-rw-r--r-- | measurements.c | 348 | ||||
-rw-r--r-- | mesh.c | 152 | ||||
-rw-r--r-- | mgmt.c | 171 | ||||
-rw-r--r-- | mpath.c | 58 | ||||
-rw-r--r-- | mpp.c | 7 | ||||
-rw-r--r-- | nan.c | 506 | ||||
-rw-r--r-- | nl80211.h | 3199 | ||||
-rw-r--r-- | ocb.c | 54 | ||||
-rw-r--r-- | offch.c | 5 | ||||
-rw-r--r-- | p2p.c | 8 | ||||
-rw-r--r-- | phy.c | 567 | ||||
-rw-r--r-- | ps.c | 19 | ||||
-rw-r--r-- | reg.c | 44 | ||||
-rw-r--r-- | roc.c | 3 | ||||
-rw-r--r-- | sar.c | 71 | ||||
-rw-r--r-- | scan.c | 845 | ||||
-rw-r--r-- | sha256.c | 205 | ||||
-rw-r--r-- | sha256.h | 61 | ||||
-rw-r--r-- | station.c | 493 | ||||
-rw-r--r-- | survey.c | 17 | ||||
-rw-r--r-- | util.c | 1055 | ||||
-rw-r--r-- | vendor.c | 76 | ||||
-rwxr-xr-x | version.sh | 44 | ||||
-rw-r--r-- | wowlan.c | 31 |
44 files changed, 9828 insertions, 956 deletions
@@ -76,6 +76,14 @@ cc_defaults { "p2p.c", "vendor.c", "sections.c", + "ap.c", + "bloom.c", + "ftm.c", + "measurements.c", + "mgmt.c", + "nan.c", + "sar.c", + "sha256.c", ":iw_version", ], @@ -9,19 +9,19 @@ MKDIR ?= mkdir -p INSTALL ?= install CC ?= "gcc" -CFLAGS ?= -O2 -g -CFLAGS += -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration +cc-option = $(shell set -e ; $(CC) $(1) -c -x c /dev/null -o /dev/null >/dev/null 2>&1 && echo '$(1)') -OBJS = iw.o genl.o event.o info.o phy.o \ - interface.o ibss.o station.o survey.o util.o ocb.o \ - mesh.o mpath.o mpp.o scan.o reg.o version.o \ - reason.o status.o connect.o link.o offch.o ps.o cqm.o \ - bitrate.o wowlan.o coalesce.o roc.o p2p.o vendor.o -OBJS += sections.o +CFLAGS_EVAL := $(call cc-option,-Wstringop-overflow=4) -OBJS-$(HWSIM) += hwsim.o +CFLAGS ?= -O2 -g +CFLAGS += -Wall -Wextra -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common +CFLAGS += -Werror-implicit-function-declaration -Wsign-compare -Wno-unused-parameter +CFLAGS += -Wdeclaration-after-statement +CFLAGS += $(CFLAGS_EVAL) -OBJS += $(OBJS-y) $(OBJS-Y) +_OBJS := $(sort $(patsubst %.c,%.o,$(wildcard *.c))) +VERSION_OBJS := $(filter-out version.o, $(_OBJS)) +OBJS := $(VERSION_OBJS) version.o ALL = iw @@ -45,30 +45,30 @@ NLLIBNAME = libnl-1 endif ifeq ($(NL2FOUND),Y) -CFLAGS += -DCONFIG_LIBNL20 -LIBS += -lnl-genl +override CFLAGS += -DCONFIG_LIBNL20 +override LIBS += -lnl-genl NLLIBNAME = libnl-2.0 endif ifeq ($(NL3xFOUND),Y) # libnl 3.2 might be found as 3.2 and 3.0 NL3FOUND = N -CFLAGS += -DCONFIG_LIBNL30 -LIBS += -lnl-genl-3 +override CFLAGS += -DCONFIG_LIBNL30 +override LIBS += -lnl-genl-3 NLLIBNAME = libnl-3.0 endif ifeq ($(NL3FOUND),Y) -CFLAGS += -DCONFIG_LIBNL30 -LIBS += -lnl-genl +override CFLAGS += -DCONFIG_LIBNL30 +override LIBS += -lnl-genl NLLIBNAME = libnl-3.0 endif # nl-3.1 has a broken libnl-gnl-3.1.pc file # as show by pkg-config --debug --libs --cflags --exact-version=3.1 libnl-genl-3.1;echo $? ifeq ($(NL31FOUND),Y) -CFLAGS += -DCONFIG_LIBNL30 -LIBS += -lnl-genl +override CFLAGS += -DCONFIG_LIBNL30 +override LIBS += -lnl-genl NLLIBNAME = libnl-3.1 endif @@ -76,8 +76,8 @@ ifeq ($(NLLIBNAME),) $(error Cannot find development files for any supported version of libnl) endif -LIBS += $(shell $(PKG_CONFIG) --libs $(NLLIBNAME)) -CFLAGS += $(shell $(PKG_CONFIG) --cflags $(NLLIBNAME)) +override LIBS += $(shell $(PKG_CONFIG) --libs $(NLLIBNAME)) +override CFLAGS += $(shell $(PKG_CONFIG) --cflags $(NLLIBNAME)) endif # NO_PKG_CONFIG ifeq ($(V),1) @@ -90,8 +90,6 @@ endif all: $(ALL) -VERSION_OBJS := $(filter-out version.o, $(OBJS)) - version.c: version.sh $(patsubst %.o,%.c,$(VERSION_OBJS)) nl80211.h iw.h Makefile \ $(wildcard .git/index .git/refs/tags) @$(NQ) ' GEN ' $@ @@ -99,7 +97,7 @@ version.c: version.sh $(patsubst %.o,%.c,$(VERSION_OBJS)) nl80211.h iw.h Makefil %.o: %.c iw.h nl80211.h @$(NQ) ' CC ' $@ - $(Q)$(CC) $(CFLAGS) -c -o $@ $< + $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< ifeq ($(IW_ANDROID_BUILD),) iw: $(OBJS) @@ -9,7 +9,7 @@ to find libnl. 'iw' is currently maintained at http://git.sipsolutions.net/iw.git/, some more documentation is available at -http://wireless.kernel.org/en/users/Documentation/iw. +https://wireless.wiki.kernel.org/en/users/Documentation/iw Please send all patches to Johannes Berg <johannes@sipsolutions.net> and CC linux-wireless@vger.kernel.org for community review. @@ -0,0 +1,163 @@ +#include <errno.h> +#include <netlink/genl/genl.h> +#include <netlink/genl/family.h> +#include <netlink/genl/ctrl.h> +#include <netlink/msg.h> +#include <netlink/attr.h> +#include "nl80211.h" +#include "iw.h" + +SECTION(ap); + +static int handle_start_ap(struct nl80211_state *state, + struct nl_msg *msg, int argc, char **argv, + enum id_input id) +{ + struct chandef chandef; + int res, parsed; + char *end; + int val, len; + char buf[2304]; + + if (argc < 6) + return 1; + + /* SSID */ + NLA_PUT(msg, NL80211_ATTR_SSID, strlen(argv[0]), argv[0]); + argv++; + argc--; + + /* chandef */ + res = parse_freqchan(&chandef, false, argc, argv, &parsed); + if (res) + return res; + argc -= parsed; + argv += parsed; + res = put_chandef(msg, &chandef); + if (res) + return res; + + /* beacon interval */ + val = strtoul(argv[0], &end, 10); + if (*end != '\0') + return -EINVAL; + + NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, val); + argv++; + argc--; + + /* dtim */ + val = strtoul(argv[0], &end, 10); + if (*end != '\0') + return -EINVAL; + + NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, val); + argv++; + argc--; + + if (strcmp(argv[0], "hidden-ssid") == 0) { + argc--; + argv++; + NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, + NL80211_HIDDEN_SSID_ZERO_LEN); + } else if (strcmp(argv[0], "zeroed-ssid") == 0) { + argc--; + argv++; + NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID, + NL80211_HIDDEN_SSID_ZERO_CONTENTS); + } + + /* beacon head must be provided */ + if (strcmp(argv[0], "head") != 0) + return 1; + argv++; + argc--; + + len = strlen(argv[0]); + if (!len || (len % 2)) + return -EINVAL; + + if (!hex2bin(&argv[0][0], buf)) + return -EINVAL; + + NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, (len / 2), &buf); + argv++; + argc--; + + if (!argc) + return 0; + + /* tail is optional */ + if (strcmp(argv[0], "tail") == 0) { + argv++; + argc--; + + if (!argc) + return -EINVAL; + + len = strlen(argv[0]); + if (!len || (len % 2)) + return -EINVAL; + + if (!hex2bin(&argv[0][0], buf)) + return -EINVAL; + + NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, (len / 2), &buf); + argv++; + argc--; + } + + if (!argc) + return 0; + + /* inactivity time (optional) */ + if (strcmp(argv[0], "inactivity-time") == 0) { + argv++; + argc--; + + if (!argc) + return -EINVAL; + len = strlen(argv[0]); + if (!len) + return -EINVAL; + + val = strtoul(argv[0], &end, 10); + if (*end != '\0') + return -EINVAL; + + NLA_PUT_U16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT, val); + argv++; + argc--; + } + + if (!argc) { + return 0; + } + + if (strcmp(*argv, "key") != 0 && strcmp(*argv, "keys") != 0) + return 1; + + argv++; + argc--; + + return parse_keys(msg, &argv, &argc); + nla_put_failure: + return -ENOSPC; +} +COMMAND(ap, start, "", + NL80211_CMD_NEW_BEACON, 0, CIB_NETDEV, handle_start_ap, + "<SSID> <control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]" + " <beacon interval in TU> <DTIM period> [hidden-ssid|zeroed-ssid] head" + " <beacon head in hexadecimal> [tail <beacon tail in hexadecimal>]" + " [inactivity-time <inactivity time in seconds>] [key0:abcde d:1:6162636465]\n"); + +static int handle_stop_ap(struct nl80211_state *state, + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + return 0; +} +COMMAND(ap, stop, "", + NL80211_CMD_DEL_BEACON, 0, CIB_NETDEV, handle_stop_ap, + "Stop AP functionality\n"); @@ -4,13 +4,22 @@ #include "iw.h" -static int parse_vht_chunk(const char *arg, __u8 *nss, __u16 *mcs) +static int parse_rate_chunk(const char *arg, __u8 *nss, __u16 *mcs, unsigned int mode) { - int count, i; - unsigned int inss, mcs_start, mcs_end, tab[10]; + unsigned int count, i; + unsigned int inss, mcs_start, mcs_end, tab[12]; + unsigned int max_mcs = 0, max_nss = 0; *nss = 0; *mcs = 0; + if (mode == NL80211_TXRATE_HE) { + max_mcs = 11; + max_nss = NL80211_HE_NSS_MAX; + } else { + max_mcs = 9; + max_nss = NL80211_VHT_NSS_MAX; + } + if (strchr(arg, '-')) { /* Format: NSS:MCS_START-MCS_END */ count = sscanf(arg, "%u:%u-%u", &inss, &mcs_start, &mcs_end); @@ -18,13 +27,13 @@ static int parse_vht_chunk(const char *arg, __u8 *nss, __u16 *mcs) if (count != 3) return 0; - if (inss < 1 || inss > NL80211_VHT_NSS_MAX) + if (inss < 1 || inss > max_nss) return 0; if (mcs_start > mcs_end) return 0; - if (mcs_start > 9 || mcs_end > 9) + if (mcs_start > max_mcs || mcs_end > max_mcs) return 0; *nss = inss; @@ -33,19 +42,26 @@ static int parse_vht_chunk(const char *arg, __u8 *nss, __u16 *mcs) } else { /* Format: NSS:MCSx,MCSy,... */ - count = sscanf(arg, "%u:%u,%u,%u,%u,%u,%u,%u,%u,%u,%u", &inss, - &tab[0], &tab[1], &tab[2], &tab[3], &tab[4], &tab[5], - &tab[6], &tab[7], &tab[8], &tab[9]); + if (mode == NL80211_TXRATE_HE) { + count = sscanf(arg, "%u:%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u", + &inss, &tab[0], &tab[1], &tab[2], &tab[3], + &tab[4], &tab[5], &tab[6], &tab[7], &tab[8], + &tab[9], &tab[10], &tab[11]); + } else { + count = sscanf(arg, "%u:%u,%u,%u,%u,%u,%u,%u,%u,%u,%u", &inss, + &tab[0], &tab[1], &tab[2], &tab[3], &tab[4], + &tab[5], &tab[6], &tab[7], &tab[8], &tab[9]); + } if (count < 2) return 0; - if (inss < 1 || inss > NL80211_VHT_NSS_MAX) + if (inss < 1 || inss > max_nss) return 0; *nss = inss; for (i = 0; i < count - 1; i++) { - if (tab[i] > 9) + if (tab[i] > max_mcs) return 0; *mcs |= 1 << tab[i]; } @@ -54,6 +70,16 @@ static int parse_vht_chunk(const char *arg, __u8 *nss, __u16 *mcs) return 1; } +static int parse_vht_chunk(const char *arg, __u8 *nss, __u16 *mcs) +{ + return parse_rate_chunk(arg, nss, mcs, NL80211_TXRATE_VHT); +} + +static int parse_he_chunk(const char *arg, __u8 *nss, __u16 *mcs) +{ + return parse_rate_chunk(arg, nss, mcs, NL80211_TXRATE_HE); +} + static int setup_vht(struct nl80211_txrate_vht *txrate_vht, int argc, char **argv) { @@ -64,7 +90,7 @@ static int setup_vht(struct nl80211_txrate_vht *txrate_vht, memset(txrate_vht, 0, sizeof(*txrate_vht)); for (i = 0; i < argc; i++) { - if(!parse_vht_chunk(argv[i], &nss, &mcs)) + if (!parse_vht_chunk(argv[i], &nss, &mcs)) return 0; nss--; @@ -74,16 +100,53 @@ static int setup_vht(struct nl80211_txrate_vht *txrate_vht, return 1; } +static int setup_he(struct nl80211_txrate_he *txrate_he, + int argc, char **argv) +{ + __u8 nss; + __u16 mcs; + int i; + + memset(txrate_he, 0, sizeof(*txrate_he)); + + for (i = 0; i < argc; i++) { + if (!parse_he_chunk(argv[i], &nss, &mcs)) + return 0; + + nss--; + txrate_he->mcs[nss] |= mcs; + } + + return 1; +} + +#define HE_GI_STR_MAX 16 +#define HE_GI_08_STR "0.8" +#define HE_GI_16_STR "1.6" +#define HE_GI_32_STR "3.2" +static int parse_he_gi(char *he_gi) +{ + if (he_gi == NULL) + return 0; + + if (!strncmp(he_gi, HE_GI_08_STR, sizeof(HE_GI_08_STR))) + return NL80211_RATE_INFO_HE_GI_0_8; + if (!strncmp(he_gi, HE_GI_16_STR, sizeof(HE_GI_16_STR))) + return NL80211_RATE_INFO_HE_GI_1_6; + if (!strncmp(he_gi, HE_GI_32_STR, sizeof(HE_GI_32_STR))) + return NL80211_RATE_INFO_HE_GI_3_2; + + return -1; +} + #define VHT_ARGC_MAX 100 -static int handle_bitrates(struct nl80211_state *state, - struct nl_cb *cb, - struct nl_msg *msg, - int argc, char **argv, - enum id_input id) +int set_bitrates(struct nl_msg *msg, + int argc, char **argv, + enum nl80211_attrs attr) { struct nlattr *nl_rates, *nl_band; - int i; + int i, ret = 0; bool have_legacy_24 = false, have_legacy_5 = false; uint8_t legacy_24[32], legacy_5[32]; int n_legacy_24 = 0, n_legacy_5 = 0; @@ -91,24 +154,40 @@ static int handle_bitrates(struct nl80211_state *state, int *n_legacy = NULL; bool have_ht_mcs_24 = false, have_ht_mcs_5 = false; bool have_vht_mcs_24 = false, have_vht_mcs_5 = false; + bool have_he_mcs_24 = false, have_he_mcs_5 = false; + bool have_he_mcs_6 = false; uint8_t ht_mcs_24[77], ht_mcs_5[77]; int n_ht_mcs_24 = 0, n_ht_mcs_5 = 0; struct nl80211_txrate_vht txrate_vht_24 = {}; struct nl80211_txrate_vht txrate_vht_5 = {}; + struct nl80211_txrate_he txrate_he_24 = {}; + struct nl80211_txrate_he txrate_he_5 = {}; + struct nl80211_txrate_he txrate_he_6 = {}; uint8_t *mcs = NULL; int *n_mcs = NULL; char *vht_argv_5[VHT_ARGC_MAX] = {}; char *vht_argv_24[VHT_ARGC_MAX] = {}; - char **vht_argv = NULL; + char *he_argv_5[VHT_ARGC_MAX] = {}; char *he_argv_24[VHT_ARGC_MAX] = {}; + char *he_argv_6[VHT_ARGC_MAX] = {}; + char **vht_argv = NULL, **he_argv = NULL; int vht_argc_5 = 0; int vht_argc_24 = 0; - int *vht_argc = NULL; + int he_argc_5 = 0; int he_argc_24 = 0; + int he_argc_6 = 0; + int *vht_argc = NULL, *he_argc = NULL; int sgi_24 = 0, sgi_5 = 0, lgi_24 = 0, lgi_5 = 0; + int has_he_gi_24 = 0, has_he_gi_5 = 0, has_he_ltf_24 = 0, has_he_ltf_5 = 0; + int has_he_gi_6 = 0, has_he_ltf_6 = 0; + int he_gi = 0, he_ltf = 0; + char *he_gi_argv = NULL; enum { S_NONE, S_LEGACY, S_HT, S_VHT, + S_HE, S_GI, + S_HE_GI, + S_HE_LTF, } parser_state = S_NONE; for (i = 0; i < argc; i++) { @@ -159,6 +238,27 @@ static int handle_bitrates(struct nl80211_state *state, vht_argv = vht_argv_5; vht_argc = &vht_argc_5; have_vht_mcs_5 = true; + } else if (strcmp(argv[i], "he-mcs-2.4") == 0) { + if (have_he_mcs_24) + return 1; + parser_state = S_HE; + he_argv = he_argv_24; + he_argc = &he_argc_24; + have_he_mcs_24 = true; + } else if (strcmp(argv[i], "he-mcs-5") == 0) { + if (have_he_mcs_5) + return 1; + parser_state = S_HE; + he_argv = he_argv_5; + he_argc = &he_argc_5; + have_he_mcs_5 = true; + } else if (strcmp(argv[i], "he-mcs-6") == 0) { + if (have_he_mcs_6) + return 1; + parser_state = S_HE; + he_argv = he_argv_6; + he_argc = &he_argc_6; + have_he_mcs_6 = true; } else if (strcmp(argv[i], "sgi-2.4") == 0) { sgi_24 = 1; parser_state = S_GI; @@ -171,6 +271,24 @@ static int handle_bitrates(struct nl80211_state *state, } else if (strcmp(argv[i], "lgi-5") == 0) { lgi_5 = 1; parser_state = S_GI; + } else if (strcmp(argv[i], "he-gi-2.4") == 0) { + has_he_gi_24 = 1; + parser_state = S_HE_GI; + } else if (strcmp(argv[i], "he-gi-5") == 0) { + has_he_gi_5 = 1; + parser_state = S_HE_GI; + } else if (strcmp(argv[i], "he-gi-6") == 0) { + has_he_gi_6 = 1; + parser_state = S_HE_GI; + } else if (strcmp(argv[i], "he-ltf-2.4") == 0) { + has_he_ltf_24 = 1; + parser_state = S_HE_LTF; + } else if (strcmp(argv[i], "he-ltf-5") == 0) { + has_he_ltf_5 = 1; + parser_state = S_HE_LTF; + } else if (strcmp(argv[i], "he-ltf-6") == 0) { + has_he_ltf_6 = 1; + parser_state = S_HE_LTF; } else switch (parser_state) { case S_LEGACY: tmpd = strtod(argv[i], &end); @@ -193,19 +311,53 @@ static int handle_bitrates(struct nl80211_state *state, return 1; vht_argv[(*vht_argc)++] = argv[i]; break; + case S_HE: + if (*he_argc >= VHT_ARGC_MAX) + return 1; + he_argv[(*he_argc)++] = argv[i]; + break; case S_GI: break; + case S_HE_GI: + he_gi_argv = argv[i]; + break; + case S_HE_LTF: + he_ltf = strtol(argv[i], &end, 0); + if (*end != '\0') + return 1; + if (he_ltf < 0 || he_ltf > 4) + return 1; + he_ltf = he_ltf >> 1; + break; default: + if (attr != NL80211_ATTR_TX_RATES) + goto next; return 1; } } +next: + if (attr != NL80211_ATTR_TX_RATES) + ret = i; + if (have_vht_mcs_24) - if(!setup_vht(&txrate_vht_24, vht_argc_24, vht_argv_24)) + if (!setup_vht(&txrate_vht_24, vht_argc_24, vht_argv_24)) return -EINVAL; if (have_vht_mcs_5) - if(!setup_vht(&txrate_vht_5, vht_argc_5, vht_argv_5)) + if (!setup_vht(&txrate_vht_5, vht_argc_5, vht_argv_5)) + return -EINVAL; + + if (have_he_mcs_24) + if (!setup_he(&txrate_he_24, he_argc_24, he_argv_24)) + return -EINVAL; + + if (have_he_mcs_5) + if (!setup_he(&txrate_he_5, he_argc_5, he_argv_5)) + return -EINVAL; + + if (have_he_mcs_6) + if (!setup_he(&txrate_he_6, he_argc_6, he_argv_6)) return -EINVAL; if (sgi_5 && lgi_5) @@ -214,11 +366,18 @@ static int handle_bitrates(struct nl80211_state *state, if (sgi_24 && lgi_24) return 1; - nl_rates = nla_nest_start(msg, NL80211_ATTR_TX_RATES); + if (he_gi_argv) { + he_gi = parse_he_gi(he_gi_argv); + if (he_gi < 0) + return 1; + } + + nl_rates = nla_nest_start(msg, attr); if (!nl_rates) goto nla_put_failure; - if (have_legacy_24 || have_ht_mcs_24 || have_vht_mcs_24 || sgi_24 || lgi_24) { + if (have_legacy_24 || have_ht_mcs_24 || have_vht_mcs_24 || have_he_mcs_24 || + sgi_24 || lgi_24 || has_he_gi_24 || has_he_ltf_24) { nl_band = nla_nest_start(msg, NL80211_BAND_2GHZ); if (!nl_band) goto nla_put_failure; @@ -228,14 +387,22 @@ static int handle_bitrates(struct nl80211_state *state, nla_put(msg, NL80211_TXRATE_HT, n_ht_mcs_24, ht_mcs_24); if (have_vht_mcs_24) nla_put(msg, NL80211_TXRATE_VHT, sizeof(txrate_vht_24), &txrate_vht_24); + if (have_he_mcs_24) + nla_put(msg, NL80211_TXRATE_HE, sizeof(txrate_he_24), + &txrate_he_24); if (sgi_24) nla_put_u8(msg, NL80211_TXRATE_GI, NL80211_TXRATE_FORCE_SGI); if (lgi_24) nla_put_u8(msg, NL80211_TXRATE_GI, NL80211_TXRATE_FORCE_LGI); + if (has_he_gi_24) + nla_put_u8(msg, NL80211_TXRATE_HE_GI, he_gi); + if (has_he_ltf_24) + nla_put_u8(msg, NL80211_TXRATE_HE_LTF, he_ltf); nla_nest_end(msg, nl_band); } - if (have_legacy_5 || have_ht_mcs_5 || have_vht_mcs_5 || sgi_5 || lgi_5) { + if (have_legacy_5 || have_ht_mcs_5 || have_vht_mcs_5 || have_he_mcs_5 || + sgi_5 || lgi_5 || has_he_gi_5 || has_he_ltf_5) { nl_band = nla_nest_start(msg, NL80211_BAND_5GHZ); if (!nl_band) goto nla_put_failure; @@ -245,24 +412,53 @@ static int handle_bitrates(struct nl80211_state *state, nla_put(msg, NL80211_TXRATE_HT, n_ht_mcs_5, ht_mcs_5); if (have_vht_mcs_5) nla_put(msg, NL80211_TXRATE_VHT, sizeof(txrate_vht_5), &txrate_vht_5); + if (have_he_mcs_5) + nla_put(msg, NL80211_TXRATE_HE, sizeof(txrate_he_5), + &txrate_he_5); if (sgi_5) nla_put_u8(msg, NL80211_TXRATE_GI, NL80211_TXRATE_FORCE_SGI); if (lgi_5) nla_put_u8(msg, NL80211_TXRATE_GI, NL80211_TXRATE_FORCE_LGI); + if (has_he_gi_5) + nla_put_u8(msg, NL80211_TXRATE_HE_GI, he_gi); + if (has_he_ltf_5) + nla_put_u8(msg, NL80211_TXRATE_HE_LTF, he_ltf); + nla_nest_end(msg, nl_band); + } + + if (have_he_mcs_6 || has_he_gi_6 || has_he_ltf_6) { + nl_band = nla_nest_start(msg, NL80211_BAND_6GHZ); + if (!nl_band) + goto nla_put_failure; + if (have_he_mcs_6) + nla_put(msg, NL80211_TXRATE_HE, sizeof(txrate_he_6), + &txrate_he_6); + if (has_he_gi_6) + nla_put_u8(msg, NL80211_TXRATE_HE_GI, he_gi); + if (has_he_ltf_6) + nla_put_u8(msg, NL80211_TXRATE_HE_LTF, he_ltf); nla_nest_end(msg, nl_band); } nla_nest_end(msg, nl_rates); - return 0; + return ret; nla_put_failure: return -ENOBUFS; } +static int handle_bitrates(struct nl80211_state *state, + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + return set_bitrates(msg, argc, argv, NL80211_ATTR_TX_RATES); +} + #define DESCR_LEGACY "[legacy-<2.4|5> <legacy rate in Mbps>*]" -#define DESCR DESCR_LEGACY " [ht-mcs-<2.4|5> <MCS index>*] [vht-mcs-<2.4|5> <NSS:MCSx,MCSy... | NSS:MCSx-MCSy>*] [sgi-2.4|lgi-2.4] [sgi-5|lgi-5]" +#define DESCR DESCR_LEGACY " [ht-mcs-<2.4|5> <MCS index>*] [vht-mcs-<2.4|5> [he-mcs-<2.4|5|6> <NSS:MCSx,MCSy... | NSS:MCSx-MCSy>*] [sgi-2.4|lgi-2.4] [sgi-5|lgi-5]" -COMMAND(set, bitrates, "[legacy-<2.4|5> <legacy rate in Mbps>*] [ht-mcs-<2.4|5> <MCS index>*] [vht-mcs-<2.4|5> <NSS:MCSx,MCSy... | NSS:MCSx-MCSy>*] [sgi-2.4|lgi-2.4] [sgi-5|lgi-5]", +COMMAND(set, bitrates, "[legacy-<2.4|5> <legacy rate in Mbps>*] [ht-mcs-<2.4|5> <MCS index>*] [vht-mcs-<2.4|5> [he-mcs-<2.4|5|6> <NSS:MCSx,MCSy... | NSS:MCSx-MCSy>*] [sgi-2.4|lgi-2.4] [sgi-5|lgi-5] [he-gi-<2.4|5|6> <0.8|1.6|3.2>] [he-ltf-<2.4|5|6> <1|2|4>]", NL80211_CMD_SET_TX_BITRATE_MASK, 0, CIB_NETDEV, handle_bitrates, "Sets up the specified rate masks.\n" "Not passing any arguments would clear the existing mask (if any)."); @@ -0,0 +1,80 @@ +#include <inttypes.h> +#include "iw.h" + +static uint32_t crc32_tab[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +static uint32_t crc32(uint32_t crc, const void *buf, size_t size) +{ + const uint8_t *p; + + p = buf; + while (size--) + crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8); + + return crc; +} + +static uint16_t h(uint8_t j, const uint8_t *buf, size_t len, uint16_t m) +{ + uint32_t crc = crc32(~0, &j, 1); + + return (crc32(crc, buf, len) & 0xffff) % m; +} + +static void set_bit(uint8_t *bf, uint16_t m) +{ + bf[m / 8] |= 1 << (m & 7); +} + +void nan_bf(uint8_t idx, uint8_t *bf, uint16_t bf_len, const uint8_t *buf, + size_t len) +{ + uint8_t i; + + for (i = 0; i < 4; ++i) + set_bit(bf, h(i + idx * 4, buf, len, 8 * bf_len)); +} @@ -1,4 +1,3 @@ -#include <net/if.h> #include <errno.h> #include <string.h> #include <stdio.h> @@ -9,14 +8,12 @@ #include <netlink/msg.h> #include <netlink/attr.h> -#include <arpa/inet.h> - #include "nl80211.h" #include "iw.h" SECTION(coalesce); -static int handle_coalesce_enable(struct nl80211_state *state, struct nl_cb *cb, +static int handle_coalesce_enable(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -185,7 +182,7 @@ COMMAND(coalesce, enable, "<config-file>", "match '43:34:00:12' after 18 bytes of offset in Rx packet.\n"); static int -handle_coalesce_disable(struct nl80211_state *state, struct nl_cb *cb, +handle_coalesce_disable(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -274,12 +271,11 @@ static int print_coalesce_handler(struct nl_msg *msg, void *arg) return NL_SKIP; } -static int handle_coalesce_show(struct nl80211_state *state, struct nl_cb *cb, +static int handle_coalesce_show(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, - print_coalesce_handler, NULL); + register_handler(print_coalesce_handler, NULL); return 0; } @@ -9,13 +9,15 @@ #include "nl80211.h" #include "iw.h" -static int iw_conn(struct nl80211_state *state, struct nl_cb *cb, +static int iw_conn(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { char *end; unsigned char bssid[6]; + bool need_key = false; int freq; + int ret; if (argc < 1) return 1; @@ -47,19 +49,60 @@ static int iw_conn(struct nl80211_state *state, struct nl_cb *cb, if (!argc) return 0; - if (strcmp(*argv, "key") != 0 && strcmp(*argv, "keys") != 0) + if (strcmp(*argv, "auth") == 0) { + argv++; + argc--; + + if (!argc) + return 1; + + if (strcmp(argv[0], "open") == 0) { + NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, + NL80211_AUTHTYPE_OPEN_SYSTEM); + } else if (strcmp(argv[0], "shared") == 0) { + NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, + NL80211_AUTHTYPE_SHARED_KEY); + need_key = true; + } else { + return 1; + } + + argv++; + argc--; + } + + if (need_key && !argc) + return 1; + + if (argc && strcmp(*argv, "key") != 0 && strcmp(*argv, "keys") != 0) return 1; argv++; argc--; - return parse_keys(msg, argv, argc); + ret = parse_keys(msg, &argv, &argc); + if (ret) + return ret; + + if (!argc) + return 0; + + if (!strcmp(*argv, "mfp:req")) + NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED); + else if (!strcmp(*argv, "mfp:opt")) + NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_OPTIONAL); + else if (!strcmp(*argv, "mfp:no")) + NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_NO); + else + return -EINVAL; + + return 0; + nla_put_failure: return -ENOSPC; } static int disconnect(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -70,7 +113,7 @@ TOPLEVEL(disconnect, NULL, NL80211_CMD_DISCONNECT, 0, CIB_NETDEV, disconnect, "Disconnect from the current network."); -static int iw_connect(struct nl80211_state *state, struct nl_cb *cb, +static int iw_connect(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -137,16 +180,19 @@ static int iw_connect(struct nl80211_state *state, struct nl_cb *cb, * Alas, the kernel doesn't do that (yet). */ - __do_listen_events(state, ARRAY_SIZE(cmds), cmds, &printargs); + __do_listen_events(state, + ARRAY_SIZE(cmds), cmds, + ARRAY_SIZE(cmds), cmds, + &printargs); return 0; } -TOPLEVEL(connect, "[-w] <SSID> [<freq in MHz>] [<bssid>] [key 0:abcde d:1:6162636465]", +TOPLEVEL(connect, "[-w] <SSID> [<freq in MHz>] [<bssid>] [auth open|shared] [key 0:abcde d:1:6162636465] [mfp:req/opt/no]", 0, 0, CIB_NETDEV, iw_connect, "Join the network with the given SSID (and frequency, BSSID).\n" "With -w, wait for the connect to finish or fail."); HIDDEN(connect, establish, "", NL80211_CMD_CONNECT, 0, CIB_NETDEV, iw_conn); -static int iw_auth(struct nl80211_state *state, struct nl_cb *cb, +static int iw_auth(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -208,7 +254,7 @@ static int iw_auth(struct nl80211_state *state, struct nl_cb *cb, argv++; argc--; - return parse_keys(msg, argv, argc); + return parse_keys(msg, &argv, &argc); nla_put_failure: return -ENOSPC; } @@ -9,7 +9,7 @@ #include "nl80211.h" #include "iw.h" -static int iw_cqm_rssi(struct nl80211_state *state, struct nl_cb *cb, +static int iw_cqm_rssi(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -34,6 +34,8 @@ static int iw_cqm_rssi(struct nl80211_state *state, struct nl_cb *cb, /* connection quality monitor attributes */ cqm = nlmsg_alloc(); + if (!cqm) + return -ENOMEM; NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, thold); NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hyst); @@ -2,6 +2,8 @@ #include <stdbool.h> #include <net/if.h> #include <errno.h> +#include <inttypes.h> +#include <time.h> #include "iw.h" static int no_seq_check(struct nl_msg *msg, void *arg) @@ -45,12 +47,14 @@ static void print_frame(struct print_event_args *args, struct nlattr *attr) { uint8_t *frame; size_t len; - int i; + unsigned int i; char macbuf[6*3]; uint16_t tmp; - if (!attr) + if (!attr) { printf(" [no frame]"); + return; + } frame = nla_data(attr); len = nla_len(attr); @@ -119,17 +123,20 @@ static void parse_cqm_event(struct nlattr **attrs) if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]) { enum nl80211_cqm_rssi_threshold_event rssi_event; + int32_t rssi_level = -1; bool found_one = false; rssi_event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]); + if (cqm[NL80211_ATTR_CQM_RSSI_LEVEL]) + rssi_level = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_LEVEL]); switch (rssi_event) { case NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: - printf("RSSI went above threshold\n"); + printf("RSSI (%i dBm) went above threshold\n", rssi_level); found_one = true; break; case NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW: - printf("RSSI went below threshold\n"); + printf("RSSI (%i dBm) went below threshold\n", rssi_level); found_one = true; break; case NL80211_CQM_RSSI_BEACON_LOSS_EVENT: @@ -242,9 +249,8 @@ static void parse_wowlan_wake_event(struct nlattr **attrs) nla_for_each_nested(match, tb[NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS], rem_nst) { - nla_parse(tb_match, NUM_NL80211_ATTR, nla_data(match), - nla_len(match), - NULL); + nla_parse_nested(tb_match, NL80211_ATTR_MAX, match, + NULL); printf("\t\tSSID: \""); print_ssid_escaped(nla_len(tb_match[NL80211_ATTR_SSID]), nla_data(tb_match[NL80211_ATTR_SSID])); @@ -291,6 +297,617 @@ static void parse_wowlan_wake_event(struct nlattr **attrs) printf("\t* TCP connection ran out of tokens\n"); } +extern struct vendor_event *__start_vendor_event[]; +extern struct vendor_event *__stop_vendor_event; + +// Dummy to force the section to exist +VENDOR_EVENT(0xffffffff, 0xffffffff, NULL); + +static void parse_vendor_event(struct nlattr **attrs, bool dump) +{ + __u32 vendor_id, subcmd; + unsigned int i; + + if (!attrs[NL80211_ATTR_VENDOR_ID] || + !attrs[NL80211_ATTR_VENDOR_SUBCMD]) + return; + + vendor_id = nla_get_u32(attrs[NL80211_ATTR_VENDOR_ID]); + subcmd = nla_get_u32(attrs[NL80211_ATTR_VENDOR_SUBCMD]); + + printf("vendor event %.6x:%d", vendor_id, subcmd); + + for (i = 0; i < &__stop_vendor_event - __start_vendor_event; i++) { + struct vendor_event *ev = __start_vendor_event[i]; + + if (!ev) + continue; + + if (ev->vendor_id != vendor_id) + continue; + if (ev->subcmd != subcmd) + continue; + if (!ev->callback) + continue; + + ev->callback(vendor_id, subcmd, attrs[NL80211_ATTR_VENDOR_DATA]); + goto out; + } + + if (dump && attrs[NL80211_ATTR_VENDOR_DATA]) + iw_hexdump("vendor event", + nla_data(attrs[NL80211_ATTR_VENDOR_DATA]), + nla_len(attrs[NL80211_ATTR_VENDOR_DATA])); +out: + printf("\n"); +} + +static void parse_nan_term(struct nlattr **attrs) +{ + struct nlattr *func[NL80211_NAN_FUNC_ATTR_MAX + 1]; + + static struct nla_policy + nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = { + [NL80211_NAN_FUNC_TYPE] = { .type = NLA_U8 }, + [NL80211_NAN_FUNC_SERVICE_ID] = { }, + [NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 }, + [NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG }, + [NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG }, + [NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 }, + [NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 }, + [NL80211_NAN_FUNC_FOLLOW_UP_DEST] = { }, + [NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG }, + [NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 }, + [NL80211_NAN_FUNC_SERVICE_INFO] = { }, + [NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED }, + [NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED }, + [NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED }, + [NL80211_NAN_FUNC_INSTANCE_ID] = { .type = NLA_U8}, + }; + + if (!attrs[NL80211_ATTR_COOKIE]) { + printf("Bad NAN func termination format - cookie is missing\n"); + return; + } + + if (nla_parse_nested(func, NL80211_NAN_FUNC_ATTR_MAX, + attrs[NL80211_ATTR_NAN_FUNC], + nan_func_policy)) { + printf("NAN: failed to parse nan func\n"); + return; + } + + if (!func[NL80211_NAN_FUNC_INSTANCE_ID]) { + printf("Bad NAN func termination format-instance id missing\n"); + return; + } + + if (!func[NL80211_NAN_FUNC_TERM_REASON]) { + printf("Bad NAN func termination format - reason is missing\n"); + return; + } + printf("NAN(cookie=0x%llx): Termination event: id = %d, reason = ", + (long long int)nla_get_u64(attrs[NL80211_ATTR_COOKIE]), + nla_get_u8(func[NL80211_NAN_FUNC_INSTANCE_ID])); + switch (nla_get_u8(func[NL80211_NAN_FUNC_TERM_REASON])) { + case NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST: + printf("user request\n"); + break; + case NL80211_NAN_FUNC_TERM_REASON_TTL_EXPIRED: + printf("expired\n"); + break; + case NL80211_NAN_FUNC_TERM_REASON_ERROR: + printf("error\n"); + break; + default: + printf("unknown\n"); + } +} + +static const char *ftm_fail_reason(unsigned int reason) +{ +#define FTM_FAIL_REASON(x) case NL80211_PMSR_FTM_FAILURE_##x: return #x + switch (reason) { + FTM_FAIL_REASON(UNSPECIFIED); + FTM_FAIL_REASON(NO_RESPONSE); + FTM_FAIL_REASON(REJECTED); + FTM_FAIL_REASON(WRONG_CHANNEL); + FTM_FAIL_REASON(PEER_NOT_CAPABLE); + FTM_FAIL_REASON(INVALID_TIMESTAMP); + FTM_FAIL_REASON(PEER_BUSY); + FTM_FAIL_REASON(BAD_CHANGED_PARAMS); + default: + return "unknown"; + } +} + +static void parse_pmsr_ftm_data(struct nlattr *data) +{ + struct nlattr *ftm[NL80211_PMSR_FTM_RESP_ATTR_MAX + 1]; + + printf(" FTM"); + nla_parse_nested(ftm, NL80211_PMSR_FTM_RESP_ATTR_MAX, data, NULL); + + if (ftm[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON]) { + printf(" failed: %s (%d)", + ftm_fail_reason(nla_get_u32(ftm[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON])), + nla_get_u32(ftm[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON])); + if (ftm[NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME]) + printf(" retry after %us", + nla_get_u32(ftm[NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME])); + printf("\n"); + return; + } + + printf("\n"); + +#define PFTM(tp, attr, sign) \ + do { \ + if (ftm[NL80211_PMSR_FTM_RESP_ATTR_##attr]) \ + printf(" " #attr ": %lld\n", \ + (sign long long)nla_get_##tp( \ + ftm[NL80211_PMSR_FTM_RESP_ATTR_##attr])); \ + } while (0) + + PFTM(u32, BURST_INDEX, unsigned); + PFTM(u32, NUM_FTMR_ATTEMPTS, unsigned); + PFTM(u32, NUM_FTMR_SUCCESSES, unsigned); + PFTM(u8, NUM_BURSTS_EXP, unsigned); + PFTM(u8, BURST_DURATION, unsigned); + PFTM(u8, FTMS_PER_BURST, unsigned); + PFTM(u32, RSSI_AVG, signed); + PFTM(u32, RSSI_SPREAD, unsigned); + PFTM(u64, RTT_AVG, signed); + PFTM(u64, RTT_VARIANCE, unsigned); + PFTM(u64, RTT_SPREAD, unsigned); + PFTM(u64, DIST_AVG, signed); + PFTM(u64, DIST_VARIANCE, unsigned); + PFTM(u64, DIST_SPREAD, unsigned); + + if (ftm[NL80211_PMSR_FTM_RESP_ATTR_TX_RATE]) { + char buf[100]; + + parse_bitrate(ftm[NL80211_PMSR_FTM_RESP_ATTR_TX_RATE], + buf, sizeof(buf)); + printf(" TX bitrate: %s\n", buf); + } + + if (ftm[NL80211_PMSR_FTM_RESP_ATTR_RX_RATE]) { + char buf[100]; + + parse_bitrate(ftm[NL80211_PMSR_FTM_RESP_ATTR_RX_RATE], + buf, sizeof(buf)); + printf(" RX bitrate: %s\n", buf); + } + + if (ftm[NL80211_PMSR_FTM_RESP_ATTR_LCI]) + iw_hexdump(" LCI", + nla_data(ftm[NL80211_PMSR_FTM_RESP_ATTR_LCI]), + nla_len(ftm[NL80211_PMSR_FTM_RESP_ATTR_LCI])); + + if (ftm[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]) + iw_hexdump(" civic location", + nla_data(ftm[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]), + nla_len(ftm[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC])); +} + +static const char *pmsr_status(unsigned int status) +{ +#define PMSR_STATUS(x) case NL80211_PMSR_STATUS_##x: return #x + switch (status) { + PMSR_STATUS(SUCCESS); + PMSR_STATUS(REFUSED); + PMSR_STATUS(TIMEOUT); + PMSR_STATUS(FAILURE); + default: + return "unknown"; + } +#undef PMSR_STATUS +} + +static void parse_pmsr_peer(struct nlattr *peer) +{ + struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1]; + struct nlattr *resp[NL80211_PMSR_RESP_ATTR_MAX + 1]; + struct nlattr *data[NL80211_PMSR_TYPE_MAX + 1]; + char macbuf[6*3]; + int err; + + err = nla_parse_nested(tb, NL80211_PMSR_PEER_ATTR_MAX, peer, NULL); + if (err) { + printf(" Peer: failed to parse!\n"); + return; + } + + if (!tb[NL80211_PMSR_PEER_ATTR_ADDR]) { + printf(" Peer: no MAC address\n"); + return; + } + + mac_addr_n2a(macbuf, nla_data(tb[NL80211_PMSR_PEER_ATTR_ADDR])); + printf(" Peer %s:", macbuf); + + if (!tb[NL80211_PMSR_PEER_ATTR_RESP]) { + printf(" no response!\n"); + return; + } + + err = nla_parse_nested(resp, NL80211_PMSR_RESP_ATTR_MAX, + tb[NL80211_PMSR_PEER_ATTR_RESP], NULL); + if (err) { + printf(" failed to parse response!\n"); + return; + } + + if (resp[NL80211_PMSR_RESP_ATTR_STATUS]) + printf(" status=%d (%s)", + nla_get_u32(resp[NL80211_PMSR_RESP_ATTR_STATUS]), + pmsr_status(nla_get_u32(resp[NL80211_PMSR_RESP_ATTR_STATUS]))); + if (resp[NL80211_PMSR_RESP_ATTR_HOST_TIME]) + printf(" @%llu", + (unsigned long long)nla_get_u64(resp[NL80211_PMSR_RESP_ATTR_HOST_TIME])); + if (resp[NL80211_PMSR_RESP_ATTR_AP_TSF]) + printf(" tsf=%llu", + (unsigned long long)nla_get_u64(resp[NL80211_PMSR_RESP_ATTR_AP_TSF])); + if (resp[NL80211_PMSR_RESP_ATTR_FINAL]) + printf(" (final)"); + + if (!resp[NL80211_PMSR_RESP_ATTR_DATA]) { + printf(" - no data!\n"); + return; + } + + printf("\n"); + + nla_parse_nested(data, NL80211_PMSR_TYPE_MAX, + resp[NL80211_PMSR_RESP_ATTR_DATA], NULL); + + if (data[NL80211_PMSR_TYPE_FTM]) + parse_pmsr_ftm_data(data[NL80211_PMSR_TYPE_FTM]); +} + +static void parse_pmsr_result(struct nlattr **tb, + struct print_event_args *pargs) +{ + struct nlattr *pmsr[NL80211_PMSR_ATTR_MAX + 1]; + struct nlattr *peer; + unsigned long long cookie; + int err, i; + + if (!tb[NL80211_ATTR_COOKIE]) { + printf("Peer measurements: no cookie!\n"); + return; + } + cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); + + if (!tb[NL80211_ATTR_PEER_MEASUREMENTS]) { + printf("Peer measurements: no measurement data!\n"); + return; + } + + err = nla_parse_nested(pmsr, NL80211_PMSR_ATTR_MAX, + tb[NL80211_ATTR_PEER_MEASUREMENTS], NULL); + if (err) { + printf("Peer measurements: failed to parse measurement data!\n"); + return; + } + + if (!pmsr[NL80211_PMSR_ATTR_PEERS]) { + printf("Peer measurements: no peer data!\n"); + return; + } + + printf("Peer measurements (cookie %llu):\n", cookie); + + nla_for_each_nested(peer, pmsr[NL80211_PMSR_ATTR_PEERS], i) + parse_pmsr_peer(peer); +} + +static void parse_nan_match(struct nlattr **attrs) +{ + char macbuf[6*3]; + __u64 cookie; + struct nlattr *match[NL80211_NAN_MATCH_ATTR_MAX + 1]; + struct nlattr *local_func[NL80211_NAN_FUNC_ATTR_MAX + 1]; + struct nlattr *peer_func[NL80211_NAN_FUNC_ATTR_MAX + 1]; + + static struct nla_policy + nan_match_policy[NL80211_NAN_MATCH_ATTR_MAX + 1] = { + [NL80211_NAN_MATCH_FUNC_LOCAL] = { .type = NLA_NESTED }, + [NL80211_NAN_MATCH_FUNC_PEER] = { .type = NLA_NESTED }, + }; + + static struct nla_policy + nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = { + [NL80211_NAN_FUNC_TYPE] = { .type = NLA_U8 }, + [NL80211_NAN_FUNC_SERVICE_ID] = { }, + [NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 }, + [NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG }, + [NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG }, + [NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 }, + [NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 }, + [NL80211_NAN_FUNC_FOLLOW_UP_DEST] = { }, + [NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG }, + [NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 }, + [NL80211_NAN_FUNC_SERVICE_INFO] = { }, + [NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED }, + [NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED }, + [NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED }, + [NL80211_NAN_FUNC_INSTANCE_ID] = { .type = NLA_U8}, + }; + + cookie = nla_get_u64(attrs[NL80211_ATTR_COOKIE]); + mac_addr_n2a(macbuf, nla_data(attrs[NL80211_ATTR_MAC])); + + if (nla_parse_nested(match, NL80211_NAN_MATCH_ATTR_MAX, + attrs[NL80211_ATTR_NAN_MATCH], + nan_match_policy)) { + printf("NAN: failed to parse nan match event\n"); + return; + } + + if (nla_parse_nested(local_func, NL80211_NAN_FUNC_ATTR_MAX, + match[NL80211_NAN_MATCH_FUNC_LOCAL], + nan_func_policy)) { + printf("NAN: failed to parse nan local func\n"); + return; + } + + if (nla_parse_nested(peer_func, NL80211_NAN_FUNC_ATTR_MAX, + match[NL80211_NAN_MATCH_FUNC_PEER], + nan_func_policy)) { + printf("NAN: failed to parse nan local func\n"); + return; + } + + if (nla_get_u8(peer_func[NL80211_NAN_FUNC_TYPE]) == + NL80211_NAN_FUNC_PUBLISH) { + printf( + "NAN(cookie=0x%llx): DiscoveryResult, peer_id=%d, local_id=%d, peer_mac=%s", + cookie, + nla_get_u8(peer_func[NL80211_NAN_FUNC_INSTANCE_ID]), + nla_get_u8(local_func[NL80211_NAN_FUNC_INSTANCE_ID]), + macbuf); + if (peer_func[NL80211_NAN_FUNC_SERVICE_INFO]) + printf(", info=%.*s", + nla_len(peer_func[NL80211_NAN_FUNC_SERVICE_INFO]), + (char *)nla_data(peer_func[NL80211_NAN_FUNC_SERVICE_INFO])); + } else if (nla_get_u8(peer_func[NL80211_NAN_FUNC_TYPE]) == + NL80211_NAN_FUNC_SUBSCRIBE) { + printf( + "NAN(cookie=0x%llx): Replied, peer_id=%d, local_id=%d, peer_mac=%s", + cookie, + nla_get_u8(peer_func[NL80211_NAN_FUNC_INSTANCE_ID]), + nla_get_u8(local_func[NL80211_NAN_FUNC_INSTANCE_ID]), + macbuf); + } else if (nla_get_u8(peer_func[NL80211_NAN_FUNC_TYPE]) == + NL80211_NAN_FUNC_FOLLOW_UP) { + printf( + "NAN(cookie=0x%llx): FollowUpReceive, peer_id=%d, local_id=%d, peer_mac=%s", + cookie, + nla_get_u8(peer_func[NL80211_NAN_FUNC_INSTANCE_ID]), + nla_get_u8(local_func[NL80211_NAN_FUNC_INSTANCE_ID]), + macbuf); + if (peer_func[NL80211_NAN_FUNC_SERVICE_INFO]) + printf(", info=%.*s", + nla_len(peer_func[NL80211_NAN_FUNC_SERVICE_INFO]), + (char *)nla_data(peer_func[NL80211_NAN_FUNC_SERVICE_INFO])); + } else { + printf("NaN: Malformed event"); + } + + printf("\n"); +} + +static void parse_new_peer_candidate(struct nlattr **attrs) +{ + char macbuf[ETH_ALEN * 3]; + int32_t sig_dbm; + + printf("new peer candidate"); + if (attrs[NL80211_ATTR_MAC]) { + mac_addr_n2a(macbuf, nla_data(attrs[NL80211_ATTR_MAC])); + printf(" %s", macbuf); + } + if (attrs[NL80211_ATTR_RX_SIGNAL_DBM]) { + sig_dbm = nla_get_u32(attrs[NL80211_ATTR_RX_SIGNAL_DBM]); + printf(" %d dBm", sig_dbm); + } + + printf("\n"); +} + +static void parse_recv_interface(struct nlattr **attrs, int command) +{ + switch (command) { + case NL80211_CMD_NEW_INTERFACE: + printf("new interface"); + break; + case NL80211_CMD_DEL_INTERFACE: + printf("del interface"); + break; + case NL80211_CMD_SET_INTERFACE: + printf("set interface"); + break; + default: + printf("unknown interface command (%i) received\n", command); + return; + } + + if (attrs[NL80211_ATTR_IFTYPE]) { + printf(" type "); + switch (nla_get_u32(attrs[NL80211_ATTR_IFTYPE])) { + case NL80211_IFTYPE_STATION: + printf("station"); + break; + case NL80211_IFTYPE_AP: + printf("access point"); + break; + case NL80211_IFTYPE_MESH_POINT: + printf("mesh point"); + break; + case NL80211_IFTYPE_ADHOC: + printf("IBSS"); + break; + case NL80211_IFTYPE_MONITOR: + printf("monitor"); + break; + case NL80211_IFTYPE_AP_VLAN: + printf("AP-VLAN"); + break; + case NL80211_IFTYPE_WDS: + printf("WDS"); + break; + case NL80211_IFTYPE_P2P_CLIENT: + printf("P2P-client"); + break; + case NL80211_IFTYPE_P2P_GO: + printf("P2P-GO"); + break; + case NL80211_IFTYPE_P2P_DEVICE: + printf("P2P-Device"); + break; + case NL80211_IFTYPE_OCB: + printf("OCB"); + break; + case NL80211_IFTYPE_NAN: + printf("NAN"); + break; + default: + printf("unknown (%d)", + nla_get_u32(attrs[NL80211_ATTR_IFTYPE])); + break; + } + } + + if (attrs[NL80211_ATTR_MESH_ID]) { + printf(" meshid "); + print_ssid_escaped(nla_len(attrs[NL80211_ATTR_MESH_ID]), + nla_data(attrs[NL80211_ATTR_MESH_ID])); + } + + if (attrs[NL80211_ATTR_4ADDR]) { + printf(" use 4addr %d", nla_get_u8(attrs[NL80211_ATTR_4ADDR])); + } + + printf("\n"); +} + +static void parse_sta_opmode_changed(struct nlattr **attrs) +{ + char macbuf[ETH_ALEN*3]; + + printf("sta opmode changed"); + + if (attrs[NL80211_ATTR_MAC]) { + mac_addr_n2a(macbuf, nla_data(attrs[NL80211_ATTR_MAC])); + printf(" %s", macbuf); + } + + if (attrs[NL80211_ATTR_SMPS_MODE]) + printf(" smps mode %d", nla_get_u8(attrs[NL80211_ATTR_SMPS_MODE])); + + if (attrs[NL80211_ATTR_CHANNEL_WIDTH]) + printf(" chan width %d", nla_get_u8(attrs[NL80211_ATTR_CHANNEL_WIDTH])); + + if (attrs[NL80211_ATTR_NSS]) + printf(" nss %d", nla_get_u8(attrs[NL80211_ATTR_NSS])); + + printf("\n"); +} + +static void parse_ch_switch_notify(struct nlattr **attrs, int command) +{ + switch (command) { + case NL80211_CMD_CH_SWITCH_STARTED_NOTIFY: + printf("channel switch started"); + break; + case NL80211_CMD_CH_SWITCH_NOTIFY: + printf("channel switch"); + break; + default: + printf("unknown channel switch command (%i) received\n", command); + return; + } + + if (attrs[NL80211_ATTR_CH_SWITCH_COUNT]) + printf(" (count=%d)", nla_get_u32(attrs[NL80211_ATTR_CH_SWITCH_COUNT])); + + if (attrs[NL80211_ATTR_WIPHY_FREQ]) + printf(" freq=%d", nla_get_u32(attrs[NL80211_ATTR_WIPHY_FREQ])); + + if (attrs[NL80211_ATTR_CHANNEL_WIDTH]) { + printf(" width="); + switch(nla_get_u32(attrs[NL80211_ATTR_CHANNEL_WIDTH])) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + printf("\"20 MHz\""); + break; + case NL80211_CHAN_WIDTH_40: + printf("\"40 MHz\""); + break; + case NL80211_CHAN_WIDTH_80: + printf("\"80 MHz\""); + break; + case NL80211_CHAN_WIDTH_80P80: + printf("\"80+80 MHz\""); + break; + case NL80211_CHAN_WIDTH_160: + printf("\"160 MHz\""); + break; + case NL80211_CHAN_WIDTH_5: + printf("\"5 MHz\""); + break; + case NL80211_CHAN_WIDTH_10: + printf("\"10 MHz\""); + break; + default: + printf("\"unknown\""); + } + } + + if (attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { + printf(" type="); + switch(nla_get_u32(attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) { + case NL80211_CHAN_NO_HT: + printf("\"No HT\""); + break; + case NL80211_CHAN_HT20: + printf("\"HT20\""); + break; + case NL80211_CHAN_HT40MINUS: + printf("\"HT40-\""); + break; + case NL80211_CHAN_HT40PLUS: + printf("\"HT40+\""); + break; + } + } + + if (attrs[NL80211_ATTR_CENTER_FREQ1]) + printf(" freq1=%d", nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ1])); + + if (attrs[NL80211_ATTR_CENTER_FREQ2]) + printf(" freq2=%d", nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ2])); + + printf("\n"); +} + +static void parse_assoc_comeback(struct nlattr **attrs, int command) +{ + __u32 timeout = 0; + char macbuf[6 * 3] = "<unset>"; + + if (attrs[NL80211_ATTR_MAC]) + mac_addr_n2a(macbuf, nla_data(attrs[NL80211_ATTR_MAC])); + + if (attrs[NL80211_ATTR_TIMEOUT]) + timeout = nla_get_u32(attrs[NL80211_ATTR_TIMEOUT]); + + printf("assoc comeback bssid %s timeout %d\n", + macbuf, timeout); +} + static int print_event(struct nl_msg *msg, void *arg) { struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); @@ -304,12 +921,13 @@ static int print_event(struct nl_msg *msg, void *arg) int rem_nst; __u16 status; - if (args->time || args->reltime) { + if (args->time || args->reltime || args->ctime) { unsigned long long usecs, previous; previous = 1000000ULL * args->ts.tv_sec + args->ts.tv_usec; gettimeofday(&args->ts, NULL); usecs = 1000000ULL * args->ts.tv_sec + args->ts.tv_usec; + if (args->reltime) { if (!args->have_ts) { usecs = 0; @@ -317,15 +935,28 @@ static int print_event(struct nl_msg *msg, void *arg) } else usecs -= previous; } - printf("%llu.%06llu: ", usecs/1000000, usecs % 1000000); + + if (args->ctime) { + struct tm *tm = localtime(&args->ts.tv_sec); + char buf[255]; + + memset(buf, 0, 255); + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm); + printf("[%s.%06lu]: ", buf, args->ts.tv_usec); + } else { + printf("%llu.%06llu: ", usecs/1000000, usecs % 1000000); + } } nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb[NL80211_ATTR_IFINDEX] && tb[NL80211_ATTR_WIPHY]) { - if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname); - printf("%s (phy #%d): ", ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY])); + /* if_indextoname may fails on delete interface/wiphy event */ + if (if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname)) + printf("%s (phy #%d): ", ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY])); + else + printf("phy #%d: ", nla_get_u32(tb[NL80211_ATTR_WIPHY])); } else if (tb[NL80211_ATTR_WDEV] && tb[NL80211_ATTR_WIPHY]) { printf("wdev 0x%llx (phy #%d): ", (unsigned long long)nla_get_u64(tb[NL80211_ATTR_WDEV]), @@ -348,6 +979,7 @@ static int print_event(struct nl_msg *msg, void *arg) break; case NL80211_CMD_NEW_SCAN_RESULTS: printf("scan finished:"); + /* fall through */ case NL80211_CMD_SCAN_ABORTED: if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED) printf("scan aborted:"); @@ -374,8 +1006,12 @@ static int print_event(struct nl_msg *msg, void *arg) case NL80211_CMD_SCHED_SCAN_RESULTS: printf("got scheduled scan results\n"); break; + case NL80211_CMD_WIPHY_REG_CHANGE: case NL80211_CMD_REG_CHANGE: - printf("regulatory domain change: "); + if (gnlh->cmd == NL80211_CMD_WIPHY_REG_CHANGE) + printf("regulatory domain change (phy): "); + else + printf("regulatory domain change: "); reg_type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]); @@ -498,7 +1134,9 @@ static int print_event(struct nl_msg *msg, void *arg) break; case NL80211_CMD_CONNECT: status = 0; - if (!tb[NL80211_ATTR_STATUS_CODE]) + if (tb[NL80211_ATTR_TIMED_OUT]) + printf("timed out"); + else if (!tb[NL80211_ATTR_STATUS_CODE]) printf("unknown connect status"); else if (nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]) == 0) printf("connected"); @@ -544,6 +1182,11 @@ static int print_event(struct nl_msg *msg, void *arg) nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]), (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE])); break; + case NL80211_CMD_FRAME_WAIT_CANCEL: + printf("frame wait cancel on freq %d (cookie %llx)\n", + nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]), + (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE])); + break; case NL80211_CMD_NOTIFY_CQM: parse_cqm_event(tb); break; @@ -555,6 +1198,11 @@ static int print_event(struct nl_msg *msg, void *arg) (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]), tb[NL80211_ATTR_ACK] ? "acked" : "no ack"); break; + case NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS: + printf("ctrl. port TX status (cookie %llx): %s\n", + (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]), + tb[NL80211_ATTR_ACK] ? "acked" : "no ack"); + break; case NL80211_CMD_PMKSA_CANDIDATE: printf("PMKSA candidate found\n"); break; @@ -572,42 +1220,81 @@ static int print_event(struct nl_msg *msg, void *arg) tb[NL80211_ATTR_ACK] ? "acked" : "no ack"); break; case NL80211_CMD_VENDOR: - printf("vendor event %.6x:%d\n", - nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]), - nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD])); - if (args->frame && tb[NL80211_ATTR_VENDOR_DATA]) - iw_hexdump("vendor event", - nla_data(tb[NL80211_ATTR_VENDOR_DATA]), - nla_len(tb[NL80211_ATTR_VENDOR_DATA])); - break; - case NL80211_CMD_RADAR_DETECT: - printf("radar event "); - if (tb[NL80211_ATTR_RADAR_EVENT]) { - switch (nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT])) { - case NL80211_RADAR_DETECTED: - printf("(radar detected)"); - break; - case NL80211_RADAR_CAC_FINISHED: - printf("(cac finished)"); - break; - case NL80211_RADAR_CAC_ABORTED: - printf("(cac aborted)"); - break; - case NL80211_RADAR_NOP_FINISHED: - printf("(nop finished)"); - break; - default: - printf("(unknown)"); - break; - }; - } else { - printf("(unknown)"); + parse_vendor_event(tb, args->frame); + break; + case NL80211_CMD_RADAR_DETECT: { + enum nl80211_radar_event event_type; + uint32_t freq; + + if (!tb[NL80211_ATTR_RADAR_EVENT] || + !tb[NL80211_ATTR_WIPHY_FREQ]) { + printf("BAD radar event\n"); + break; + } + + freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); + event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]); + + switch (event_type) { + case NL80211_RADAR_DETECTED: + printf("%d MHz: radar detected\n", freq); + break; + case NL80211_RADAR_CAC_FINISHED: + printf("%d MHz: CAC finished\n", freq); + break; + case NL80211_RADAR_CAC_ABORTED: + printf("%d MHz: CAC was aborted\n", freq); + break; + case NL80211_RADAR_NOP_FINISHED: + printf("%d MHz: NOP finished\n", freq); + break; + case NL80211_RADAR_PRE_CAC_EXPIRED: + printf("%d MHz: PRE-CAC expired\n", freq); + break; + case NL80211_RADAR_CAC_STARTED: + printf("%d MHz: CAC started\n", freq); + break; + default: + printf("%d MHz: unknown radar event\n", freq); + } } - printf("\n"); break; case NL80211_CMD_DEL_WIPHY: printf("delete wiphy\n"); break; + case NL80211_CMD_PEER_MEASUREMENT_RESULT: + parse_pmsr_result(tb, args); + break; + case NL80211_CMD_PEER_MEASUREMENT_COMPLETE: + printf("peer measurement complete\n"); + break; + case NL80211_CMD_DEL_NAN_FUNCTION: + parse_nan_term(tb); + break; + case NL80211_CMD_NAN_MATCH: + parse_nan_match(tb); + break; + case NL80211_CMD_NEW_PEER_CANDIDATE: + parse_new_peer_candidate(tb); + break; + case NL80211_CMD_NEW_INTERFACE: + case NL80211_CMD_SET_INTERFACE: + case NL80211_CMD_DEL_INTERFACE: + parse_recv_interface(tb, gnlh->cmd); + break; + case NL80211_CMD_STA_OPMODE_CHANGED: + parse_sta_opmode_changed(tb); + break; + case NL80211_CMD_STOP_AP: + printf("stop ap\n"); + break; + case NL80211_CMD_CH_SWITCH_STARTED_NOTIFY: + case NL80211_CMD_CH_SWITCH_NOTIFY: + parse_ch_switch_notify(tb, gnlh->cmd); + break; + case NL80211_CMD_ASSOC_COMEBACK: /* 147 */ + parse_assoc_comeback(tb, gnlh->cmd); + break; default: printf("unknown event %d (%s)\n", gnlh->cmd, command_name(gnlh->cmd)); @@ -619,8 +1306,9 @@ static int print_event(struct nl_msg *msg, void *arg) } struct wait_event { - int n_cmds; + int n_cmds, n_prints; const __u32 *cmds; + const __u32 *prints; __u32 cmd; struct print_event_args *pargs; }; @@ -631,14 +1319,18 @@ static int wait_event(struct nl_msg *msg, void *arg) struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); int i; - for (i = 0; i < wait->n_cmds; i++) { - if (gnlh->cmd == wait->cmds[i]) { - wait->cmd = gnlh->cmd; - if (wait->pargs) + if (wait->pargs) { + for (i = 0; i < wait->n_prints; i++) { + if (gnlh->cmd == wait->prints[i]) print_event(msg, wait->pargs); } } + for (i = 0; i < wait->n_cmds; i++) { + if (gnlh->cmd == wait->cmds[i]) + wait->cmd = gnlh->cmd; + } + return NL_SKIP; } @@ -686,11 +1378,19 @@ int __prepare_listen_events(struct nl80211_state *state) return ret; } + mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "nan"); + if (mcid >= 0) { + ret = nl_socket_add_membership(state->nl_sock, mcid); + if (ret) + return ret; + } + return 0; } __u32 __do_listen_events(struct nl80211_state *state, const int n_waits, const __u32 *waits, + const int n_prints, const __u32 *prints, struct print_event_args *args) { struct nl_cb *cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); @@ -703,14 +1403,17 @@ __u32 __do_listen_events(struct nl80211_state *state, /* no sequence checking for multicast messages */ nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, NULL); if (n_waits && waits) { wait_ev.cmds = waits; wait_ev.n_cmds = n_waits; + wait_ev.prints = prints; + wait_ev.n_prints = n_prints; wait_ev.pargs = args; - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, wait_event, &wait_ev); + register_handler(wait_event, &wait_ev); } else - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_event, args); + register_handler(print_event, args); wait_ev.cmd = 0; @@ -731,16 +1434,16 @@ __u32 listen_events(struct nl80211_state *state, if (ret) return ret; - return __do_listen_events(state, n_waits, waits, NULL); + return __do_listen_events(state, n_waits, waits, 0, NULL, NULL); } static int print_events(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { struct print_event_args args; + int num_time_formats = 0; int ret; memset(&args, 0, sizeof(args)); @@ -751,17 +1454,22 @@ static int print_events(struct nl80211_state *state, while (argc > 0) { if (strcmp(argv[0], "-f") == 0) args.frame = true; - else if (strcmp(argv[0], "-t") == 0) + else if (strcmp(argv[0], "-t") == 0) { + num_time_formats++; args.time = true; - else if (strcmp(argv[0], "-r") == 0) + } else if (strcmp(argv[0], "-T") == 0) { + num_time_formats++; + args.ctime = true; + } else if (strcmp(argv[0], "-r") == 0) { + num_time_formats++; args.reltime = true; - else + } else return 1; argc--; argv++; } - if (args.time && args.reltime) + if (num_time_formats > 1) return 1; if (argc) @@ -771,10 +1479,11 @@ static int print_events(struct nl80211_state *state, if (ret) return ret; - return __do_listen_events(state, 0, NULL, &args); + return __do_listen_events(state, 0, NULL, 0, NULL, &args); } -TOPLEVEL(event, "[-t] [-r] [-f]", 0, 0, CIB_NONE, print_events, +TOPLEVEL(event, "[-t|-T|-r] [-f]", 0, 0, CIB_NONE, print_events, "Monitor events from the kernel.\n" "-t - print timestamp\n" - "-r - print relative timstamp\n" + "-T - print absolute, human-readable timestamp\n" + "-r - print relative timestamp\n" "-f - print full frame for auth/assoc etc."); @@ -0,0 +1,157 @@ +#include <errno.h> + +#include <netlink/genl/genl.h> +#include <netlink/genl/family.h> +#include <netlink/genl/ctrl.h> +#include <netlink/msg.h> +#include <netlink/attr.h> +#include <inttypes.h> + +#include "nl80211.h" +#include "iw.h" + +SECTION(ftm); + +static int handle_ftm_stats(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *info[NL80211_FTM_STATS_MAX + 1]; + static struct nla_policy info_policy[NL80211_FTM_STATS_MAX + 1] = { + [NL80211_FTM_STATS_SUCCESS_NUM] = { .type = NLA_U32 }, + [NL80211_FTM_STATS_PARTIAL_NUM] = { .type = NLA_U32 }, + [NL80211_FTM_STATS_FAILED_NUM] = { .type = NLA_U32 }, + [NL80211_FTM_STATS_ASAP_NUM] = { .type = NLA_U32 }, + [NL80211_FTM_STATS_NON_ASAP_NUM] = { .type = NLA_U32 }, + [NL80211_FTM_STATS_TOTAL_DURATION_MSEC] = { .type = NLA_U64 }, + [NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM] = { .type = NLA_U32 }, + [NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM] + = { .type = NLA_U32 }, + [NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM] + = { .type = NLA_U32 }, + }; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb[NL80211_ATTR_FTM_RESPONDER_STATS]) { + fprintf(stderr, "FTM responder statistics are missing"); + return NL_SKIP; + } + + nla_parse(info, NL80211_REG_RULE_ATTR_MAX, + nla_data(tb[NL80211_ATTR_FTM_RESPONDER_STATS]), + nla_len(tb[NL80211_ATTR_FTM_RESPONDER_STATS]), + info_policy); + + printf("FTM responder stats:\n"); + + if (info[NL80211_FTM_STATS_SUCCESS_NUM]) + printf("\tSuccess num %u\n", + nla_get_u32(info[NL80211_FTM_STATS_SUCCESS_NUM])); + + if (info[NL80211_FTM_STATS_PARTIAL_NUM]) + printf("\tPartial success num %u\n", + nla_get_u32(info[NL80211_FTM_STATS_PARTIAL_NUM])); + + if (info[NL80211_FTM_STATS_FAILED_NUM]) + printf("\tFailed num %u\n", + nla_get_u32(info[NL80211_FTM_STATS_FAILED_NUM])); + + if (info[NL80211_FTM_STATS_ASAP_NUM]) + printf("\tASAP success num %u\n", + nla_get_u32(info[NL80211_FTM_STATS_ASAP_NUM])); + + if (info[NL80211_FTM_STATS_NON_ASAP_NUM]) + printf("\tNon ASAP num %u\n", + nla_get_u32(info[NL80211_FTM_STATS_NON_ASAP_NUM])); + + if (info[NL80211_FTM_STATS_TOTAL_DURATION_MSEC]) + printf("\tTotal duration %" PRIu64 "\n", + nla_get_u64(info[NL80211_FTM_STATS_TOTAL_DURATION_MSEC])); + + if (info[NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM]) + printf("\tUnknown triggers num %u\n", + nla_get_u32(info[NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM])); + + if (info[NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM]) + printf("\tRescheduled requests num %u\n", + nla_get_u32(info[NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM])); + + if (info[NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM]) + printf("\tOut of window num %u\n", + nla_get_u32(info[NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM])); + + return NL_SKIP; +} + +static int handle_ftm_get_stats(struct nl80211_state *state, + struct nl_msg *msg, int argc, char **argv, + enum id_input id) +{ + register_handler(handle_ftm_stats, NULL); + return 0; +} + +COMMAND(ftm, get_stats, "", + NL80211_CMD_GET_FTM_RESPONDER_STATS, 0, CIB_NETDEV, handle_ftm_get_stats, + "Get FTM responder statistics.\n"); + +static int handle_ftm_start_responder(struct nl80211_state *state, + struct nl_msg *msg, int argc, char **argv, + enum id_input id) +{ + int i; + char buf[256]; + bool lci_present = false, civic_present = false; + struct nlattr *ftm = nla_nest_start(msg, NL80211_ATTR_FTM_RESPONDER); + + if (!ftm) + return -ENOBUFS; + + nla_put_flag(msg, NL80211_FTM_RESP_ATTR_ENABLED); + + for (i = 0; i < argc; i++) { + if (strncmp(argv[i], "lci=", 4) == 0) { + size_t lci_len = strlen(argv[i] + 4); + + if (lci_present || !lci_len || lci_len % 2 || + !hex2bin(argv[i] + 4, buf)) { + printf("Illegal LCI buffer!\n"); + return HANDLER_RET_USAGE; + } + + lci_present = true; + NLA_PUT(msg, NL80211_FTM_RESP_ATTR_LCI, + lci_len / 2, buf); + } else if (strncmp(argv[i], "civic=", 6) == 0) { + size_t civic_len = strlen(argv[i] + 6); + + if (civic_present || !civic_len || civic_len % 2 || + !hex2bin(argv[i] + 6, buf)) { + printf("Illegal CIVIC buffer!\n"); + return HANDLER_RET_USAGE; + } + + civic_present = true; + NLA_PUT(msg, NL80211_FTM_RESP_ATTR_CIVICLOC, + civic_len / 2, buf); + } else { + printf("Illegal argument: %s\n", argv[i]); + return HANDLER_RET_USAGE; + } + } + + nla_nest_end(msg, ftm); + + return 0; + +nla_put_failure: + return -ENOMEM; +} + +COMMAND(ftm, start_responder, + "[lci=<lci buffer in hex>] [civic=<civic buffer in hex>]", + NL80211_CMD_SET_BEACON, 0, CIB_NETDEV, + handle_ftm_start_responder, + "Start an FTM responder. Needs a running ap interface\n"); @@ -1,4 +1,3 @@ -#include <net/if.h> #include <errno.h> #include <string.h> @@ -52,7 +51,7 @@ static int print_hwsim_ps_handler(struct nl_msg *msg, void *arg) return NL_SKIP; } -static int handle_hwsim_getps(struct nl80211_state *state, struct nl_cb *cb, +static int handle_hwsim_getps(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -66,15 +65,14 @@ static int handle_hwsim_getps(struct nl80211_state *state, struct nl_cb *cb, nla_nest_end(msg, tmdata); - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, - print_hwsim_ps_handler, NULL); + register_handler(print_hwsim_ps_handler, NULL); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(hwsim, getps, "", NL80211_CMD_TESTMODE, 0, CIB_PHY, handle_hwsim_getps, ""); -static int handle_hwsim_setps(struct nl80211_state *state, struct nl_cb *cb, +static int handle_hwsim_setps(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -98,15 +96,14 @@ static int handle_hwsim_setps(struct nl80211_state *state, struct nl_cb *cb, nla_nest_end(msg, tmdata); - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, - print_hwsim_ps_handler, NULL); + register_handler(print_hwsim_ps_handler, NULL); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(hwsim, setps, "<value>", NL80211_CMD_TESTMODE, 0, CIB_PHY, handle_hwsim_setps, ""); -static int handle_hwsim_stop_queues(struct nl80211_state *state, struct nl_cb *cb, +static int handle_hwsim_stop_queues(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -128,7 +125,7 @@ static int handle_hwsim_stop_queues(struct nl80211_state *state, struct nl_cb *c } COMMAND(hwsim, stopqueues, "", NL80211_CMD_TESTMODE, 0, CIB_PHY, handle_hwsim_stop_queues, ""); -static int handle_hwsim_wake_queues(struct nl80211_state *state, struct nl_cb *cb, +static int handle_hwsim_wake_queues(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -1,67 +1,26 @@ -#ifndef _POSIX_SOURCE -#define _POSIX_SOURCE -#endif #include <errno.h> #include <string.h> #include <strings.h> -#include <netlink/genl/genl.h> -#include <netlink/genl/family.h> -#include <netlink/genl/ctrl.h> -#include <netlink/msg.h> -#include <netlink/attr.h> - #include "nl80211.h" #include "iw.h" SECTION(ibss); static int join_ibss(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { char *end; + struct chandef chandef; unsigned char abssid[6]; unsigned char rates[NL80211_MAX_SUPP_RATES]; int n_rates = 0; char *value = NULL, *sptr = NULL; float rate; int bintval; - int i; - unsigned long freq; - static const struct { - const char *name; - unsigned int width; - int freq1_diff; - int chantype; /* for older kernel */ - } *chanmode_selected = NULL, chanmode[] = { - { .name = "HT20", - .width = NL80211_CHAN_WIDTH_20, - .freq1_diff = 0, - .chantype = NL80211_CHAN_HT20 }, - { .name = "HT40+", - .width = NL80211_CHAN_WIDTH_40, - .freq1_diff = 10, - .chantype = NL80211_CHAN_HT40PLUS }, - { .name = "HT40-", - .width = NL80211_CHAN_WIDTH_40, - .freq1_diff = -10, - .chantype = NL80211_CHAN_HT40MINUS }, - { .name = "NOHT", - .width = NL80211_CHAN_WIDTH_20_NOHT, - .freq1_diff = 0, - .chantype = NL80211_CHAN_NO_HT }, - { .name = "5MHZ", - .width = NL80211_CHAN_WIDTH_5, - .freq1_diff = 0, - .chantype = -1 }, - { .name = "10MHZ", - .width = NL80211_CHAN_WIDTH_10, - .freq1_diff = 0, - .chantype = -1 }, - }; + int parsed, err; if (argc < 2) return 1; @@ -71,37 +30,16 @@ static int join_ibss(struct nl80211_state *state, argv++; argc--; - /* freq */ - freq = strtoul(argv[0], &end, 10); - if (*end != '\0') - return 1; - - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); - argv++; - argc--; - - if (argc) { - for (i = 0; i < ARRAY_SIZE(chanmode); i++) { - if (strcasecmp(chanmode[i].name, argv[0]) == 0) { - chanmode_selected = &chanmode[i]; - break; - } - } - if (chanmode_selected) { - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - chanmode_selected->width); - NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, - freq + chanmode_selected->freq1_diff); - if (chanmode_selected->chantype != -1) - NLA_PUT_U32(msg, - NL80211_ATTR_WIPHY_CHANNEL_TYPE, - chanmode_selected->chantype); + err = parse_freqchan(&chandef, false, argc, argv, &parsed); + if (err) + return err; - argv++; - argc--; - } + argv += parsed; + argc -= parsed; - } + err = put_chandef(msg, &chandef); + if (err) + return err; if (argc && strcmp(argv[0], "fixed-freq") == 0) { NLA_PUT_FLAG(msg, NL80211_ATTR_FREQ_FIXED); @@ -177,13 +115,12 @@ static int join_ibss(struct nl80211_state *state, argv++; argc--; - return parse_keys(msg, argv, argc); + return parse_keys(msg, &argv, &argc); nla_put_failure: return -ENOSPC; } static int leave_ibss(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -194,7 +131,7 @@ COMMAND(ibss, leave, NULL, NL80211_CMD_LEAVE_IBSS, 0, CIB_NETDEV, leave_ibss, "Leave the current IBSS cell."); COMMAND(ibss, join, - "<SSID> <freq in MHz> [HT20|HT40+|HT40-|NOHT|5MHZ|10MHZ] [fixed-freq] [<fixed bssid>] [beacon-interval <TU>]" + "<SSID> <freq in MHz> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz] [fixed-freq] [<fixed bssid>] [beacon-interval <TU>]" " [basic-rates <rate in Mbps,rate2,...>] [mcast-rate <rate in Mbps>] " "[key d:0:abcde]", NL80211_CMD_JOIN_IBSS, 0, CIB_NETDEV, join_ibss, diff --git a/ieee80211.h b/ieee80211.h index 8745608..3713a4d 100644 --- a/ieee80211.h +++ b/ieee80211.h @@ -58,4 +58,21 @@ struct ieee80211_vht_cap { struct ieee80211_vht_mcs_info mcs; } __attribute__ ((packed)); +#define SUITE(oui, id) (((oui) << 8) | (id)) + +/* cipher suite selectors */ +#define WLAN_CIPHER_SUITE_USE_GROUP SUITE(0x000FAC, 0) +#define WLAN_CIPHER_SUITE_WEP40 SUITE(0x000FAC, 1) +#define WLAN_CIPHER_SUITE_TKIP SUITE(0x000FAC, 2) +/* reserved: SUITE(0x000FAC, 3) */ +#define WLAN_CIPHER_SUITE_CCMP SUITE(0x000FAC, 4) +#define WLAN_CIPHER_SUITE_WEP104 SUITE(0x000FAC, 5) +#define WLAN_CIPHER_SUITE_AES_CMAC SUITE(0x000FAC, 6) +#define WLAN_CIPHER_SUITE_GCMP SUITE(0x000FAC, 8) +#define WLAN_CIPHER_SUITE_GCMP_256 SUITE(0x000FAC, 9) +#define WLAN_CIPHER_SUITE_CCMP_256 SUITE(0x000FAC, 10) +#define WLAN_CIPHER_SUITE_BIP_GMAC_128 SUITE(0x000FAC, 11) +#define WLAN_CIPHER_SUITE_BIP_GMAC_256 SUITE(0x000FAC, 12) +#define WLAN_CIPHER_SUITE_BIP_CMAC_256 SUITE(0x000FAC, 13) + #endif /* __IEEE80211 */ @@ -1,6 +1,4 @@ #include <stdbool.h> -#include <errno.h> -#include <net/if.h> #include <netlink/genl/genl.h> #include <netlink/genl/family.h> @@ -33,11 +31,21 @@ static char *cipher_name(__u32 c) case 0x000fac02: return "TKIP (00-0f-ac:2)"; case 0x000fac04: - return "CCMP (00-0f-ac:4)"; + return "CCMP-128 (00-0f-ac:4)"; case 0x000fac06: return "CMAC (00-0f-ac:6)"; case 0x000fac08: - return "GCMP (00-0f-ac:8)"; + return "GCMP-128 (00-0f-ac:8)"; + case 0x000fac09: + return "GCMP-256 (00-0f-ac:9)"; + case 0x000fac0a: + return "CCMP-256 (00-0f-ac:10)"; + case 0x000fac0b: + return "GMAC-128 (00-0f-ac:11)"; + case 0x000fac0c: + return "GMAC-256 (00-0f-ac:12)"; + case 0x000fac0d: + return "CMAC-256 (00-0f-ac:13)"; case 0x00147201: return "WPI-SMS4 (00-14-72:1)"; default: @@ -49,20 +57,6 @@ static char *cipher_name(__u32 c) } } -static char *dfs_state_name(enum nl80211_dfs_state state) -{ - switch (state) { - case NL80211_DFS_USABLE: - return "usable"; - case NL80211_DFS_AVAILABLE: - return "available"; - case NL80211_DFS_UNAVAILABLE: - return "unavailable"; - default: - return "unknown"; - } -} - static int ext_feature_isset(const unsigned char *ext_features, int ext_features_len, enum nl80211_ext_feature_index ftidx) { @@ -75,6 +69,16 @@ static int ext_feature_isset(const unsigned char *ext_features, int ext_features return (ft_byte & BIT(ftidx % 8)) != 0; } +static void _ext_feat_print(const struct nlattr *tb, + enum nl80211_ext_feature_index idx, + const char *feature_name, const char *feature_desc) +{ + if (ext_feature_isset(nla_data(tb), nla_len(tb),idx)) + printf("\t\t* [ %s ]: %s\n", feature_name, feature_desc); +} +#define ext_feat_print(tb, name, desc) \ + _ext_feat_print(tb, NL80211_EXT_FEATURE_##name, #name, desc) + static int print_phy_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; @@ -101,10 +105,9 @@ static int print_phy_handler(struct nl_msg *msg, void *arg) struct nlattr *nl_band; struct nlattr *nl_freq; struct nlattr *nl_rate; - struct nlattr *nl_mode; struct nlattr *nl_cmd; struct nlattr *nl_if, *nl_ftype; - int rem_band, rem_freq, rem_rate, rem_mode, rem_cmd, rem_ftype, rem_if; + int rem_band, rem_freq, rem_rate, rem_cmd, rem_ftype, rem_if; int open; /* * static variables only work here, other applications need to use the @@ -129,6 +132,9 @@ static int print_phy_handler(struct nl_msg *msg, void *arg) if (print_name && tb_msg[NL80211_ATTR_WIPHY_NAME]) printf("Wiphy %s\n", nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME])); + if (print_name && tb_msg[NL80211_ATTR_WIPHY]) + printf("\twiphy index: %u\n", nla_get_u32(tb_msg[NL80211_ATTR_WIPHY])); + /* needed for split dump */ if (tb_msg[NL80211_ATTR_WIPHY_BANDS]) { nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) { @@ -160,7 +166,17 @@ static int print_phy_handler(struct nl_msg *msg, void *arg) tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]) print_vht_info(nla_get_u32(tb_band[NL80211_BAND_ATTR_VHT_CAPA]), nla_data(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET])); - + if (tb_band[NL80211_BAND_ATTR_IFTYPE_DATA]) { + struct nlattr *nl_iftype; + int rem_band; + + nla_for_each_nested(nl_iftype, + tb_band[NL80211_BAND_ATTR_IFTYPE_DATA], + rem_band) { + print_he_info(nl_iftype); + print_eht_info(nl_iftype, last_band); + } + } if (tb_band[NL80211_BAND_ATTR_FREQS]) { if (!band_had_freq) { printf("\t\tFrequencies:\n"); @@ -200,22 +216,6 @@ next: if (open) printf(")"); printf("\n"); - - if (!tb_freq[NL80211_FREQUENCY_ATTR_DISABLED] && tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) { - enum nl80211_dfs_state state = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]); - unsigned long time; - - printf("\t\t\t DFS state: %s", dfs_state_name(state)); - if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]) { - time = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]); - printf(" (for %lu sec)", time/1000); - } - printf("\n"); - if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]) - printf("\t\t\t DFS CAC time: %u ms\n", - nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME])); - } - } } @@ -250,6 +250,15 @@ next: if (tb_msg[NL80211_ATTR_MAX_MATCH_SETS]) printf("\tmax # match sets: %d\n", nla_get_u8(tb_msg[NL80211_ATTR_MAX_MATCH_SETS])); + if (tb_msg[NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS]) + printf("\tmax # scan plans: %d\n", + nla_get_u32(tb_msg[NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS])); + if (tb_msg[NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL]) + printf("\tmax scan plan interval: %d\n", + nla_get_u32(tb_msg[NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL])); + if (tb_msg[NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS]) + printf("\tmax scan plan iterations: %d\n", + nla_get_u32(tb_msg[NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS])); if (tb_msg[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) { unsigned int frag; @@ -315,17 +324,13 @@ next: nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_ANTENNA_TX]), nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_ANTENNA_RX])); - if (tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]) { - printf("\tSupported interface modes:\n"); - nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES], rem_mode) - printf("\t\t * %s\n", iftype_name(nla_type(nl_mode))); - } + if (tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]) + print_iftype_list("\tSupported interface modes", "\t\t", + tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]); - if (tb_msg[NL80211_ATTR_SOFTWARE_IFTYPES]) { - printf("\tsoftware interface modes (can always be added):\n"); - nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SOFTWARE_IFTYPES], rem_mode) - printf("\t\t * %s\n", iftype_name(nla_type(nl_mode))); - } + if (tb_msg[NL80211_ATTR_SOFTWARE_IFTYPES]) + print_iftype_list("\tsoftware interface modes (can always be added)", + "\t\t", tb_msg[NL80211_ATTR_SOFTWARE_IFTYPES]); if (tb_msg[NL80211_ATTR_INTERFACE_COMBINATIONS]) { struct nlattr *nl_combi; @@ -367,8 +372,6 @@ next: } nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS], rem_limit) { - bool ift_comma = false; - err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT, nl_limit, iface_limit_policy); if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES]) { @@ -379,13 +382,8 @@ next: if (comma) printf(", "); comma = true; - printf("#{"); - - nla_for_each_nested(nl_mode, tb_limit[NL80211_IFACE_LIMIT_TYPES], rem_mode) { - printf("%s %s", ift_comma ? "," : "", - iftype_name(nla_type(nl_mode))); - ift_comma = true; - } + printf("#{ "); + print_iftype_line(tb_limit[NL80211_IFACE_LIMIT_TYPES]); printf(" } <= %u", nla_get_u32(tb_limit[NL80211_IFACE_LIMIT_MAX])); } printf(",\n\t\t "); @@ -494,12 +492,13 @@ broken_combination: if (tb_wowlan[NL80211_WOWLAN_TRIG_MAGIC_PKT]) printf("\t\t * wake up on magic packet\n"); if (tb_wowlan[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { + unsigned int len = nla_len(tb_wowlan[NL80211_WOWLAN_TRIG_PKT_PATTERN]); + pat = nla_data(tb_wowlan[NL80211_WOWLAN_TRIG_PKT_PATTERN]); printf("\t\t * wake up on pattern match, up to %u patterns of %u-%u bytes,\n" "\t\t maximum packet offset %u bytes\n", pat->max_patterns, pat->min_pattern_len, pat->max_pattern_len, - (nla_len(tb_wowlan[NL80211_WOWLAN_TRIG_PKT_PATTERN]) < - sizeof(*pat)) ? 0 : pat->max_pkt_offset); + len < sizeof(*pat) ? 0 : pat->max_pkt_offset); } if (tb_wowlan[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED]) printf("\t\t * can do GTK rekeying\n"); @@ -527,8 +526,10 @@ broken_combination: if (tb_msg[NL80211_ATTR_HT_CAPABILITY_MASK]) { struct ieee80211_ht_cap *cm; + unsigned int len = nla_len(tb_msg[NL80211_ATTR_HT_CAPABILITY_MASK]); + printf("\tHT Capability overrides:\n"); - if (nla_len(tb_msg[NL80211_ATTR_HT_CAPABILITY_MASK]) >= sizeof(*cm)) { + if (len >= sizeof(*cm)) { cm = nla_data(tb_msg[NL80211_ATTR_HT_CAPABILITY_MASK]); printf("\t\t * MCS: %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx" " %02hhx %02hhx %02hhx %02hhx\n", @@ -611,19 +612,103 @@ broken_combination: printf("\tDevice supports configuring vdev MAC-addr on create.\n"); if (features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) printf("\tDevice supports TDLS channel switching\n"); + if (features & NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR) + printf("\tDevice supports randomizing MAC-addr in scans.\n"); + if (features & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR) + printf("\tDevice supports randomizing MAC-addr in sched scans.\n"); + if (features & NL80211_FEATURE_ND_RANDOM_MAC_ADDR) + printf("\tDevice supports randomizing MAC-addr in net-detect scans.\n"); } + if (tb_msg[NL80211_ATTR_TDLS_SUPPORT]) + printf("\tDevice supports T-DLS.\n"); + if (tb_msg[NL80211_ATTR_EXT_FEATURES]) { struct nlattr *tb = tb_msg[NL80211_ATTR_EXT_FEATURES]; - if (ext_feature_isset(nla_data(tb), nla_len(tb), - NL80211_EXT_FEATURE_VHT_IBSS)) - printf("\tDevice supports VHT-IBSS.\n"); + printf("\tSupported extended features:\n"); + + ext_feat_print(tb, VHT_IBSS, "VHT-IBSS"); + ext_feat_print(tb, RRM, "RRM"); + ext_feat_print(tb, MU_MIMO_AIR_SNIFFER, "MU-MIMO sniffer"); + ext_feat_print(tb, SCAN_START_TIME, "scan start timestamp"); + ext_feat_print(tb, BSS_PARENT_TSF, + "BSS last beacon/probe TSF"); + ext_feat_print(tb, SET_SCAN_DWELL, "scan dwell setting"); + ext_feat_print(tb, BEACON_RATE_LEGACY, + "legacy beacon rate setting"); + ext_feat_print(tb, BEACON_RATE_HT, "HT beacon rate setting"); + ext_feat_print(tb, BEACON_RATE_VHT, "VHT beacon rate setting"); + ext_feat_print(tb, FILS_STA, + "STA FILS (Fast Initial Link Setup)"); + ext_feat_print(tb, MGMT_TX_RANDOM_TA, + "randomized TA while not associated"); + ext_feat_print(tb, MGMT_TX_RANDOM_TA_CONNECTED, + "randomized TA while associated"); + ext_feat_print(tb, SCHED_SCAN_RELATIVE_RSSI, + "sched_scan for BSS with better RSSI report"); + ext_feat_print(tb, CQM_RSSI_LIST, + "multiple CQM_RSSI_THOLD records"); + ext_feat_print(tb, FILS_SK_OFFLOAD, + "FILS shared key authentication offload"); + ext_feat_print(tb, 4WAY_HANDSHAKE_STA_PSK, + "4-way handshake with PSK in station mode"); + ext_feat_print(tb, 4WAY_HANDSHAKE_STA_1X, + "4-way handshake with 802.1X in station mode"); + ext_feat_print(tb, FILS_MAX_CHANNEL_TIME, + "FILS max channel attribute override with dwell time"); + ext_feat_print(tb, ACCEPT_BCAST_PROBE_RESP, + "accepts broadcast probe response"); + ext_feat_print(tb, OCE_PROBE_REQ_HIGH_TX_RATE, + "probe request TX at high rate (at least 5.5Mbps)"); + ext_feat_print(tb, OCE_PROBE_REQ_DEFERRAL_SUPPRESSION, + "probe request tx deferral and suppression"); + ext_feat_print(tb, MFP_OPTIONAL, + "MFP_OPTIONAL value in ATTR_USE_MFP"); + ext_feat_print(tb, LOW_SPAN_SCAN, "low span scan"); + ext_feat_print(tb, LOW_POWER_SCAN, "low power scan"); + ext_feat_print(tb, HIGH_ACCURACY_SCAN, "high accuracy scan"); + ext_feat_print(tb, DFS_OFFLOAD, "DFS offload"); + ext_feat_print(tb, CONTROL_PORT_OVER_NL80211, + "control port over nl80211"); + ext_feat_print(tb, ACK_SIGNAL_SUPPORT, + "ack signal level support"); + ext_feat_print(tb, TXQS, "FQ-CoDel-enabled intermediate TXQs"); + ext_feat_print(tb, AIRTIME_FAIRNESS, + "airtime fairness scheduling"); + ext_feat_print(tb, AQL, + "Airtime Queue Limits (AQL)"); + ext_feat_print(tb, SCAN_RANDOM_SN, + "use random sequence numbers in scans"); + ext_feat_print(tb, SCAN_MIN_PREQ_CONTENT, + "use probe request with only rate IEs in scans"); + ext_feat_print(tb, CAN_REPLACE_PTK0, + "can safely replace PTK 0 when rekeying"); + ext_feat_print(tb, ENABLE_FTM_RESPONDER, + "enable FTM (Fine Time Measurement) responder"); + ext_feat_print(tb, AP_PMKSA_CACHING, + "PMKSA caching supported in AP mode"); + ext_feat_print(tb, SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD, + "band specific RSSI thresholds for scheduled scan"); + ext_feat_print(tb, EXT_KEY_ID, "Extended Key ID support"); + ext_feat_print(tb, STA_TX_PWR, "TX power control per station"); + ext_feat_print(tb, SAE_OFFLOAD, "SAE offload support"); + ext_feat_print(tb, VLAN_OFFLOAD, "VLAN offload support"); + ext_feat_print(tb, BEACON_PROTECTION, "beacon protection support"); + ext_feat_print(tb, CONTROL_PORT_NO_PREAUTH, "disable pre-auth over nl80211 control port support"); + ext_feat_print(tb, PROTECTED_TWT, "protected Target Wake Time (TWT) support"); + ext_feat_print(tb, DEL_IBSS_STA, "deletion of IBSS station support"); + ext_feat_print(tb, MULTICAST_REGISTRATIONS, "mgmt frame registration for multicast"); + ext_feat_print(tb, BEACON_PROTECTION_CLIENT, "beacon prot. for clients support"); + ext_feat_print(tb, SCAN_FREQ_KHZ, "scan on kHz frequency support"); + ext_feat_print(tb, CONTROL_PORT_OVER_NL80211_TX_STATUS, "tx status for nl80211 control port support"); + ext_feat_print(tb, OPERATING_CHANNEL_VALIDATION, "Operating Channel Validation (OCV) support"); + ext_feat_print(tb, 4WAY_HANDSHAKE_AP_PSK, "AP mode PSK offload support"); + ext_feat_print(tb, BSS_COLOR, "BSS coloring support"); + ext_feat_print(tb, FILS_CRYPTO_OFFLOAD, "FILS crypto offload"); + ext_feat_print(tb, RADAR_BACKGROUND, "Radar background support"); } - if (tb_msg[NL80211_ATTR_TDLS_SUPPORT]) - printf("\tDevice supports T-DLS.\n"); - if (tb_msg[NL80211_ATTR_COALESCE_RULE]) { struct nl80211_coalesce_rule_support *rule; struct nl80211_pattern_support *pat; @@ -632,20 +717,23 @@ broken_combination: rule = nla_data(tb_msg[NL80211_ATTR_COALESCE_RULE]); pat = &rule->pat; printf("\t\t * Maximum %u coalesce rules supported\n" - "\t\t * Each rule contains upto %u patterns of %u-%u bytes,\n" + "\t\t * Each rule contains up to %u patterns of %u-%u bytes,\n" "\t\t maximum packet offset %u bytes\n" "\t\t * Maximum supported coalescing delay %u msecs\n", rule->max_rules, pat->max_patterns, pat->min_pattern_len, pat->max_pattern_len, pat->max_pkt_offset, rule->max_delay); } + if (tb_msg[NL80211_ATTR_MAX_AP_ASSOC_STA]) + printf("\tMaximum associated stations in AP mode: %u\n", + nla_get_u16(tb_msg[NL80211_ATTR_MAX_AP_ASSOC_STA])); + return NL_SKIP; } static bool nl80211_has_split_wiphy = false; static int handle_info(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -653,13 +741,13 @@ static int handle_info(struct nl80211_state *state, char *feat_args[] = { "features", "-q" }; int err; - err = handle_cmd(state, CIB_NONE, 2, feat_args); + err = handle_cmd(state, II_NONE, 2, feat_args); if (!err && nl80211_has_split_wiphy) { nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP); nlmsg_hdr(msg)->nlmsg_flags |= NLM_F_DUMP; } - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_phy_handler, NULL); + register_handler(print_phy_handler, NULL); return 0; } @@ -669,12 +757,11 @@ TOPLEVEL(list, NULL, NL80211_CMD_GET_WIPHY, NLM_F_DUMP, CIB_NONE, handle_info, "List all wireless devices and their capabilities."); TOPLEVEL(phy, NULL, NL80211_CMD_GET_WIPHY, NLM_F_DUMP, CIB_NONE, handle_info, NULL); -static int handle_commands(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, +static int handle_commands(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { int i; - for (i = 1; i < NL80211_CMD_MAX; i++) + for (i = 1; i <= NL80211_CMD_MAX; i++) printf("%d (0x%x): %s\n", i, i, command_name(i)); /* don't send netlink messages */ return 2; @@ -705,12 +792,11 @@ static int print_feature_handler(struct nl_msg *msg, void *arg) return NL_SKIP; } -static int handle_features(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, +static int handle_features(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { unsigned long print = argc == 0 || strcmp(argv[0], "-q"); - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_feature_handler, (void *)print); + register_handler(print_feature_handler, (void *)print); return 0; } diff --git a/interface.c b/interface.c index 80437bd..84990c9 100644 --- a/interface.c +++ b/interface.c @@ -1,4 +1,3 @@ -#include <net/if.h> #include <errno.h> #include <string.h> #include <stdbool.h> @@ -17,7 +16,9 @@ "control: show control frames\n"\ "otherbss: show frames from other BSSes\n"\ "cook: use cooked mode\n"\ - "active: use active mode (ACK incoming unicast packets)" + "active: use active mode (ACK incoming unicast packets)\n"\ + "mumimo-groupid <GROUP_ID>: use MUMIMO according to a group id\n"\ + "mumimo-follow-mac <MAC_ADDRESS>: use MUMIMO according to a MAC address" SECTION(interface); @@ -31,6 +32,55 @@ static char *mntr_flags[NL80211_MNTR_FLAG_MAX + 1] = { "active", }; +static int parse_mumimo_options(int *_argc, char ***_argv, struct nl_msg *msg) +{ + uint8_t mumimo_group[VHT_MUMIMO_GROUP_LEN]; + unsigned char mac_addr[ETH_ALEN]; + char **argv = *_argv; + int argc = *_argc; + int i; + unsigned int val; + + if (strcmp(*argv, "mumimo-groupid") == 0) { + argc--; + argv++; + if (!argc || strlen(*argv) != VHT_MUMIMO_GROUP_LEN*2) { + fprintf(stderr, "Invalid groupID: %s\n", *argv); + return 1; + } + + for (i = 0; i < VHT_MUMIMO_GROUP_LEN; i++) { + if (sscanf((*argv) + i*2, "%2x", &val) != 1) { + fprintf(stderr, "Failed reading groupID\n"); + return 1; + } + mumimo_group[i] = val; + } + + NLA_PUT(msg, + NL80211_ATTR_MU_MIMO_GROUP_DATA, + VHT_MUMIMO_GROUP_LEN, + mumimo_group); + argc--; + argv++; + } else if (strcmp(*argv, "mumimo-follow-mac") == 0) { + argc--; + argv++; + if (!argc || mac_addr_a2n(mac_addr, *argv)) { + fprintf(stderr, "Invalid MAC address\n"); + return 1; + } + NLA_PUT(msg, NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR, + ETH_ALEN, mac_addr); + argc--; + argv++; + } + nla_put_failure: + *_argc = argc; + *_argv = argv; + return 0; +} + static int parse_mntr_flags(int *_argc, char ***_argv, struct nl_msg *msg) { @@ -46,6 +96,15 @@ static int parse_mntr_flags(int *_argc, char ***_argv, while (argc) { int ok = 0; + + /* parse MU-MIMO options */ + err = parse_mumimo_options(&argc, &argv, msg); + if (err) + goto out; + else if (!argc) + break; + + /* parse monitor flags */ for (flag = __NL80211_MNTR_FLAG_INVALID; flag <= NL80211_MNTR_FLAG_MAX; flag++) { if (strcmp(*argv, mntr_flags[flag]) == 0) { @@ -144,6 +203,9 @@ static int get_if_type(int *argc, char ***argv, enum nl80211_iftype *type, } else if (strcmp(tpstr, "__p2pgo") == 0) { *type = NL80211_IFTYPE_P2P_GO; return 0; + } else if (strcmp(tpstr, "__nan") == 0) { + *type = NL80211_IFTYPE_NAN; + return 0; } fprintf(stderr, "invalid interface type %s\n", tpstr); @@ -165,7 +227,6 @@ nla_put_failure: } static int handle_interface_add(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -256,7 +317,6 @@ COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [4addr on|off] [f NL80211_CMD_NEW_INTERFACE, 0, CIB_NETDEV, handle_interface_add, NULL); static int handle_interface_del(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -298,6 +358,12 @@ char *channel_width_name(enum nl80211_chan_width width) return "80+80 MHz"; case NL80211_CHAN_WIDTH_160: return "160 MHz"; + case NL80211_CHAN_WIDTH_5: + return "5 MHz"; + case NL80211_CHAN_WIDTH_10: + return "10 MHz"; + case NL80211_CHAN_WIDTH_320: + return "320 MHz"; default: return "unknown"; } @@ -370,23 +436,40 @@ static int print_iface_handler(struct nl_msg *msg, void *arg) printf("\n"); } + if (tb_msg[NL80211_ATTR_WIPHY_TX_POWER_LEVEL]) { + int32_t txp = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_TX_POWER_LEVEL]); + + printf("%s\ttxpower %d.%.2d dBm\n", + indent, txp / 100, txp % 100); + } + + if (tb_msg[NL80211_ATTR_TXQ_STATS]) { + char buf[150]; + parse_txq_stats(buf, sizeof(buf), tb_msg[NL80211_ATTR_TXQ_STATS], 1, -1, indent); + printf("%s\tmulticast TXQ:%s\n", indent, buf); + } + + if (tb_msg[NL80211_ATTR_4ADDR]) { + uint8_t use_4addr = nla_get_u8(tb_msg[NL80211_ATTR_4ADDR]); + if (use_4addr) + printf("%s\t4addr: on\n", indent); + } + return NL_SKIP; } static int handle_interface_info(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_iface_handler, NULL); + register_handler(print_iface_handler, NULL); return 0; } TOPLEVEL(info, NULL, NL80211_CMD_GET_INTERFACE, 0, CIB_NETDEV, handle_interface_info, "Show information for this interface."); static int handle_interface_set(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -399,6 +482,8 @@ static int handle_interface_set(struct nl80211_state *state, switch (parse_mntr_flags(&argc, &argv, msg)) { case 0: return 0; + case 1: + return 1; case -ENOMEM: fprintf(stderr, "failed to allocate flags\n"); return 2; @@ -417,7 +502,6 @@ COMMAND(set, monitor, "<flag>*", VALID_FLAGS); static int handle_interface_meshid(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -441,20 +525,18 @@ COMMAND(set, meshid, "<meshid>", static unsigned int dev_dump_wiphy; static int handle_dev_dump(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { dev_dump_wiphy = -1; - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_iface_handler, &dev_dump_wiphy); + register_handler(print_iface_handler, &dev_dump_wiphy); return 0; } TOPLEVEL(dev, NULL, NL80211_CMD_GET_INTERFACE, NLM_F_DUMP, CIB_NONE, handle_dev_dump, "List all network interfaces for wireless hardware."); static int handle_interface_type(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -481,7 +563,6 @@ COMMAND(set, type, "<type>", IFACE_TYPES); static int handle_interface_4addr(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -495,7 +576,6 @@ COMMAND(set, 4addr, "<on|off>", "Set interface 4addr (WDS) mode."); static int handle_interface_noack_map(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -523,7 +603,6 @@ COMMAND(set, noack_map, "<map>", static int handle_interface_wds_peer(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -555,7 +634,6 @@ COMMAND(set, peer, "<MAC address>", "Set interface WDS peer."); static int set_mcast_rate(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -563,10 +641,8 @@ static int set_mcast_rate(struct nl80211_state *state, float rate; char *end; - if (argc != 1) { - printf("Invalid parameters!\n"); - return 2; - } + if (argc != 1) + return 1; rate = strtod(argv[0], &end); if (*end != '\0') @@ -582,3 +658,337 @@ nla_put_failure: COMMAND(set, mcast_rate, "<rate in Mbps>", NL80211_CMD_SET_MCAST_RATE, 0, CIB_NETDEV, set_mcast_rate, "Set the multicast bitrate."); + + +static int handle_chanfreq(struct nl80211_state *state, struct nl_msg *msg, + bool chan, int argc, char **argv, + enum id_input id) +{ + struct chandef chandef; + int res; + int parsed; + char *end; + + res = parse_freqchan(&chandef, chan, argc, argv, &parsed); + if (res) + return res; + + argc -= parsed; + argv += parsed; + + while (argc) { + unsigned int beacons = 10; + + if (strcmp(argv[0], "beacons") == 0) { + if (argc < 2) + return 1; + + beacons = strtol(argv[1], &end, 10); + if (*end) + return 1; + + argc -= 2; + argv += 2; + + NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, beacons); + } else if (strcmp(argv[0], "block-tx") == 0) { + argc -= 1; + argv += 1; + + NLA_PUT_FLAG(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX); + } else { + return 1; + } + } + + return put_chandef(msg, &chandef); + + nla_put_failure: + return -ENOBUFS; +} + +static int handle_freq(struct nl80211_state *state, struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + return handle_chanfreq(state, msg, false, argc, argv, id); +} + +static int handle_chan(struct nl80211_state *state, struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + return handle_chanfreq(state, msg, true, argc, argv, id); +} + +SECTION(switch); +COMMAND(switch, freq, + "<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz] [beacons <count>] [block-tx]\n" + "<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]] [beacons <count>] [block-tx]", + NL80211_CMD_CHANNEL_SWITCH, 0, CIB_NETDEV, handle_freq, + "Switch the operating channel by sending a channel switch announcement (CSA)."); +COMMAND(switch, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz] [beacons <count>] [block-tx]", + NL80211_CMD_CHANNEL_SWITCH, 0, CIB_NETDEV, handle_chan, NULL); + + +static int toggle_tid_param(const char *argv0, const char *argv1, + struct nl_msg *msg, uint32_t attr) +{ + uint8_t val; + + if (strcmp(argv1, "on") == 0) { + val = NL80211_TID_CONFIG_ENABLE; + } else if (strcmp(argv1, "off") == 0) { + val = NL80211_TID_CONFIG_DISABLE; + } else { + fprintf(stderr, "Invalid %s parameter: %s\n", argv0, argv1); + return 2; + } + + NLA_PUT_U8(msg, attr, val); + return 0; + + nla_put_failure: + return -ENOBUFS; +} + +static int handle_tid_config(struct nl80211_state *state, + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + struct nlattr *tids_array = NULL; + struct nlattr *tids_entry = NULL; + enum nl80211_tx_rate_setting txrate_type; + unsigned char peer[ETH_ALEN]; + int tids_num = 0; + char *end; + int ret; + enum { + PS_ADDR, + PS_TIDS, + PS_CONF, + } parse_state = PS_ADDR; + unsigned int attr; + + while (argc) { + switch (parse_state) { + case PS_ADDR: + if (strcmp(argv[0], "peer") == 0) { + if (argc < 2) { + fprintf(stderr, "Not enough args for %s\n", argv[0]); + return HANDLER_RET_USAGE; + } + + if (mac_addr_a2n(peer, argv[1])) { + fprintf(stderr, "Invalid MAC address\n"); + return 2; + } + + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer); + + argc -= 2; + argv += 2; + parse_state = PS_TIDS; + + } else if (strcmp(argv[0], "tids") == 0) { + parse_state = PS_TIDS; + } else { + fprintf(stderr, "Peer MAC address expected\n"); + return HANDLER_RET_USAGE; + } + + break; + case PS_TIDS: + if (strcmp(argv[0], "tids") == 0) { + if (argc < 2) { + fprintf(stderr, "not enough args for %s\n", argv[0]); + return HANDLER_RET_USAGE; + } + + if (!tids_array) { + tids_array = nla_nest_start(msg, NL80211_ATTR_TID_CONFIG); + if (!tids_array) + return -ENOBUFS; + } + + if (tids_entry) { + nla_nest_end(msg, tids_entry); + tids_num++; + } + + tids_entry = nla_nest_start(msg, tids_num); + if (!tids_entry) + return -ENOBUFS; + + NLA_PUT_U16(msg, NL80211_TID_CONFIG_ATTR_TIDS, strtol(argv[1], &end, 0)); + if (*end) { + fprintf(stderr, "Invalid TID mask value: %s\n", argv[1]); + return 2; + } + + argc -= 2; + argv += 2; + parse_state = PS_CONF; + } else { + fprintf(stderr, "TID mask expected\n"); + return HANDLER_RET_USAGE; + } + + break; + case PS_CONF: + if (strcmp(argv[0], "tids") == 0) { + parse_state = PS_TIDS; + } else if (strcmp(argv[0], "override") == 0) { + NLA_PUT_FLAG(msg, NL80211_TID_CONFIG_ATTR_OVERRIDE); + + argc -= 1; + argv += 1; + } else if (strcmp(argv[0], "ampdu") == 0) { + if (argc < 2) { + fprintf(stderr, "not enough args for %s\n", argv[0]); + return HANDLER_RET_USAGE; + } + + ret = toggle_tid_param(argv[0], argv[1], msg, + NL80211_TID_CONFIG_ATTR_AMPDU_CTRL); + if (ret) + return ret; + + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "amsdu") == 0) { + if (argc < 2) { + fprintf(stderr, "not enough args for %s\n", argv[0]); + return HANDLER_RET_USAGE; + } + + ret = toggle_tid_param(argv[0], argv[1], msg, + NL80211_TID_CONFIG_ATTR_AMSDU_CTRL); + if (ret) + return ret; + + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "noack") == 0) { + if (argc < 2) { + fprintf(stderr, "not enough args for %s\n", argv[0]); + return HANDLER_RET_USAGE; + } + + ret = toggle_tid_param(argv[0], argv[1], msg, + NL80211_TID_CONFIG_ATTR_NOACK); + if (ret) + return ret; + + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "rtscts") == 0) { + if (argc < 2) { + fprintf(stderr, "not enough args for %s\n", argv[0]); + return HANDLER_RET_USAGE; + } + + ret = toggle_tid_param(argv[0], argv[1], msg, + NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL); + if (ret) + return ret; + + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "sretry") == 0) { + if (argc < 2) { + fprintf(stderr, "not enough args for %s\n", argv[0]); + return HANDLER_RET_USAGE; + } + + NLA_PUT_U8(msg, NL80211_TID_CONFIG_ATTR_RETRY_SHORT, strtol(argv[1], &end, 0)); + if (*end) { + fprintf(stderr, "Invalid short_retry value: %s\n", argv[1]); + return 2; + } + + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "lretry") == 0) { + if (argc < 2) { + fprintf(stderr, "not enough args for %s\n", argv[0]); + return HANDLER_RET_USAGE; + } + + NLA_PUT_U8(msg, NL80211_TID_CONFIG_ATTR_RETRY_LONG, strtol(argv[1], &end, 0)); + if (*end) { + fprintf(stderr, "Invalid long_retry value: %s\n", argv[1]); + return 2; + } + + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "bitrates") == 0) { + if (argc < 2) { + fprintf(stderr, "not enough args for %s\n", argv[0]); + return HANDLER_RET_USAGE; + } + if (!strcmp(argv[1], "auto")) + txrate_type = NL80211_TX_RATE_AUTOMATIC; + else if (!strcmp(argv[1], "fixed")) + txrate_type = NL80211_TX_RATE_FIXED; + else if (!strcmp(argv[1], "limit")) + txrate_type = NL80211_TX_RATE_LIMITED; + else { + printf("Invalid parameter: %s\n", argv[0]); + return 2; + } + NLA_PUT_U8(msg, NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE, txrate_type); + argc -= 2; + argv += 2; + if (txrate_type != NL80211_TX_RATE_AUTOMATIC) { + attr = NL80211_TID_CONFIG_ATTR_TX_RATE; + ret = set_bitrates(msg, argc, argv, + attr); + if (ret < 2) + return 1; + + argc -= ret; + argv += ret; + } + } else { + fprintf(stderr, "Unknown parameter: %s\n", argv[0]); + return HANDLER_RET_USAGE; + } + + break; + default: + fprintf(stderr, "Failed to parse: internal failure\n"); + return HANDLER_RET_USAGE; + } + } + + if (tids_entry) + nla_nest_end(msg, tids_entry); + + if (tids_array) + nla_nest_end(msg, tids_array); + + return 0; + +nla_put_failure: + return -ENOBUFS; +} + +COMMAND(set, tidconf, "[peer <MAC address>] tids <mask> [override] [sretry <num>] [lretry <num>] " + "[ampdu [on|off]] [amsdu [on|off]] [noack [on|off]] [rtscts [on|off]]" + "[bitrates <type [auto|fixed|limit]> [legacy-<2.4|5> <legacy rate in Mbps>*] [ht-mcs-<2.4|5> <MCS index>*]" + " [vht-mcs-<2.4|5> <NSS:MCSx,MCSy... | NSS:MCSx-MCSy>*] [sgi-2.4|lgi-2.4] [sgi-5|lgi-5]]", + NL80211_CMD_SET_TID_CONFIG, 0, CIB_NETDEV, handle_tid_config, + "Setup per-node TID specific configuration for TIDs selected by bitmask.\n" + "If MAC address is not specified, then supplied TID configuration\n" + "applied to all the peers.\n" + "Examples:\n" + " $ iw dev wlan0 set tidconf tids 0x1 ampdu off\n" + " $ iw dev wlan0 set tidconf tids 0x5 ampdu off amsdu off rtscts on\n" + " $ iw dev wlan0 set tidconf tids 0x3 override ampdu on noack on rtscts on\n" + " $ iw dev wlan0 set tidconf peer xx:xx:xx:xx:xx:xx tids 0x1 ampdu off tids 0x3 amsdu off rtscts on\n" + " $ iw dev wlan0 set tidconf peer xx:xx:xx:xx:xx:xx tids 0x2 bitrates auto\n" + " $ iw dev wlan0 set tidconf peer xx:xx:xx:xx:xx:xx tids 0x2 bitrates limit vht-mcs-5 4:9\n" + ); @@ -1,4 +1,4 @@ -.TH IW 8 "7 June 2012" "iw" "Linux" +.TH IW 8 "22 November 2020" "iw" "Linux" .SH NAME iw \- show / manipulate wireless devices and their configuration .SH SYNOPSIS @@ -63,9 +63,13 @@ will print all supported commands, while will print the help for all matching commands. .SH SEE ALSO +.P .BR ip (8), .BR crda (8), .BR regdbdump (8), -.BR regulatory.bin (5) - -.BR http://wireless.kernel.org/en/users/Documentation/iw +.BR regulatory.bin (5). +. +.P +.UR https://wireless.wiki.kernel.org/en/users/Documentation/iw +Documentation at kernel wiki +.UE . @@ -13,6 +13,7 @@ #include <fcntl.h> #include <unistd.h> #include <stdbool.h> +#include <linux/netlink.h> #include <netlink/genl/genl.h> #include <netlink/genl/family.h> @@ -54,14 +55,19 @@ static int nl80211_init(struct nl80211_state *state) return -ENOMEM; } - nl_socket_set_buffer_size(state->nl_sock, 8192, 8192); - if (genl_connect(state->nl_sock)) { fprintf(stderr, "Failed to connect to generic netlink.\n"); err = -ENOLINK; goto out_handle_destroy; } + nl_socket_set_buffer_size(state->nl_sock, 8192, 8192); + + /* try to set NETLINK_EXT_ACK to 1, ignoring errors */ + err = 1; + setsockopt(nl_socket_get_fd(state->nl_sock), SOL_NETLINK, + NETLINK_EXT_ACK, &err, sizeof(err)); + state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211"); if (state->nl80211_id < 0) { fprintf(stderr, "nl80211 not found.\n"); @@ -83,12 +89,12 @@ static void nl80211_cleanup(struct nl80211_state *state) static int cmd_size; -extern struct cmd __start___cmd; -extern struct cmd __stop___cmd; +extern struct cmd *__start___cmd[]; +extern struct cmd *__stop___cmd; -#define for_each_cmd(_cmd) \ - for (_cmd = &__start___cmd; _cmd < &__stop___cmd; \ - _cmd = (const struct cmd *)((char *)_cmd + cmd_size)) +#define for_each_cmd(_cmd, i) \ + for (i = 0; i < &__stop___cmd - __start___cmd; i++) \ + if ((_cmd = __start___cmd[i])) static void __usage_cmd(const struct cmd *cmd, char *indent, bool full) @@ -186,6 +192,7 @@ static void usage(int argc, char **argv) bool full = argc >= 0; const char *sect_filt = NULL; const char *cmd_filt = NULL; + unsigned int i, j; if (argc > 0) sect_filt = argv[0]; @@ -197,7 +204,7 @@ static void usage(int argc, char **argv) usage_options(); printf("\t--version\tshow version (%s)\n", iw_version); printf("Commands:\n"); - for_each_cmd(section) { + for_each_cmd(section, i) { if (section->parent) continue; @@ -207,7 +214,7 @@ static void usage(int argc, char **argv) if (section->handler && !section->hidden) __usage_cmd(section, "\t", full); - for_each_cmd(cmd) { + for_each_cmd(cmd, j) { if (section != cmd->parent) continue; if (!cmd->handler || cmd->hidden) @@ -228,7 +235,6 @@ static void usage(int argc, char **argv) } static int print_help(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -274,8 +280,47 @@ static int phy_lookup(char *name) static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) { + struct nlmsghdr *nlh = (struct nlmsghdr *)err - 1; + int len = nlh->nlmsg_len; + struct nlattr *attrs; + struct nlattr *tb[NLMSGERR_ATTR_MAX + 1]; int *ret = arg; - *ret = err->error; + int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh); + + if (err->error > 0) { + /* + * This is illegal, per netlink(7), but not impossible (think + * "vendor commands"). Callers really expect negative error + * codes, so make that happen. + */ + fprintf(stderr, + "ERROR: received positive netlink error code %d\n", + err->error); + *ret = -EPROTO; + } else { + *ret = err->error; + } + + if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) + return NL_STOP; + + if (!(nlh->nlmsg_flags & NLM_F_CAPPED)) + ack_len += err->msg.nlmsg_len - sizeof(*nlh); + + if (len <= ack_len) + return NL_STOP; + + attrs = (void *)((unsigned char *)nlh + ack_len); + len -= ack_len; + + nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, len, NULL); + if (tb[NLMSGERR_ATTR_MSG]) { + len = strnlen((char *)nla_data(tb[NLMSGERR_ATTR_MSG]), + nla_len(tb[NLMSGERR_ATTR_MSG])); + fprintf(stderr, "kernel reports: %*s\n", len, + (char *)nla_data(tb[NLMSGERR_ATTR_MSG])); + } + return NL_STOP; } @@ -293,6 +338,23 @@ static int ack_handler(struct nl_msg *msg, void *arg) return NL_STOP; } +static int (*registered_handler)(struct nl_msg *, void *); +static void *registered_handler_data; + +void register_handler(int (*handler)(struct nl_msg *, void *), void *data) +{ + registered_handler = handler; + registered_handler_data = data; +} + +int valid_handler(struct nl_msg *msg, void *arg) +{ + if (registered_handler) + return registered_handler(msg, registered_handler_data); + + return NL_OK; +} + static int __handle_cmd(struct nl80211_state *state, enum id_input idby, int argc, char **argv, const struct cmd **cmdout) { @@ -301,7 +363,7 @@ static int __handle_cmd(struct nl80211_state *state, enum id_input idby, struct nl_cb *s_cb; struct nl_msg *msg; signed long long devidx = 0; - int err, o_argc; + int err, o_argc, i; const char *command, *section; char *tmp, **o_argv; enum command_identify_by command_idby = CIB_NONE; @@ -353,7 +415,7 @@ static int __handle_cmd(struct nl80211_state *state, enum id_input idby, argc--; argv++; - for_each_cmd(sectcmd) { + for_each_cmd(sectcmd, i) { if (sectcmd->parent) continue; /* ok ... bit of a hack for the dupe 'info' section */ @@ -371,7 +433,7 @@ static int __handle_cmd(struct nl80211_state *state, enum id_input idby, if (argc > 0) { command = *argv; - for_each_cmd(cmd) { + for_each_cmd(cmd, i) { if (!cmd->handler) continue; if (cmd->parent != sectcmd) @@ -424,7 +486,7 @@ static int __handle_cmd(struct nl80211_state *state, enum id_input idby, if (!cmd->cmd) { argc = o_argc; argv = o_argv; - return cmd->handler(state, NULL, NULL, argc, argv, idby); + return cmd->handler(state, NULL, argc, argv, idby); } msg = nlmsg_alloc(); @@ -438,7 +500,7 @@ static int __handle_cmd(struct nl80211_state *state, enum id_input idby, if (!cb || !s_cb) { fprintf(stderr, "failed to allocate netlink callbacks\n"); err = 2; - goto out_free_msg; + goto out; } genlmsg_put(msg, 0, 0, state->nl80211_id, 0, @@ -458,7 +520,7 @@ static int __handle_cmd(struct nl80211_state *state, enum id_input idby, break; } - err = cmd->handler(state, cb, msg, argc, argv, idby); + err = cmd->handler(state, msg, argc, argv, idby); if (err) goto out; @@ -473,12 +535,13 @@ static int __handle_cmd(struct nl80211_state *state, enum id_input idby, nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, NULL); while (err > 0) nl_recvmsgs(state->nl_sock, cb); out: nl_cb_put(cb); - out_free_msg: + nl_cb_put(s_cb); nlmsg_free(msg); return err; nla_put_failure: @@ -492,6 +555,25 @@ int handle_cmd(struct nl80211_state *state, enum id_input idby, return __handle_cmd(state, idby, argc, argv, NULL); } +/* + * Unfortunately, I don't know how densely the linker packs the struct cmd. + * For example, if you have a 72-byte struct cmd, the linker will pad each + * out to 96 bytes before putting them together in the section. There must + * be some algorithm, but I haven't found it yet. + * + * We used to calculate this by taking the (abs value of) the difference + * between __section_get and __section_set, but if LTO is enabled then this + * stops working because the entries of the "__cmd" section get rearranged + * freely by the compiler/linker. + * + * Fix this by using yet another "__sizer" section that only contains these + * two entries - then the (abs value of) the difference between them will + * be how they get packed and that can be used to iterate the __cmd section + * as well. + */ +static struct cmd sizer1 __attribute__((section("__sizer"))) = {}; +static struct cmd sizer2 __attribute__((section("__sizer"))) = {}; + int main(int argc, char **argv) { struct nl80211_state nlstate; @@ -499,7 +581,7 @@ int main(int argc, char **argv) const struct cmd *cmd = NULL; /* calculate command size including padding */ - cmd_size = abs((long)&__section_set - (long)&__section_get); + cmd_size = labs((long)&sizer2 - (long)&sizer1); /* strip off self */ argc--; argv0 = *argv++; @@ -544,8 +626,9 @@ int main(int argc, char **argv) err = __handle_cmd(&nlstate, II_WDEV, argc, argv, &cmd); } else { int idx; - enum id_input idby = II_NONE; + enum id_input idby; detect: + idby = II_NONE; if ((idx = if_nametoindex(argv[0])) != 0) idby = II_NETDEV; else if ((idx = phy_lookup(argv[0])) >= 0) @@ -553,11 +636,13 @@ int main(int argc, char **argv) err = __handle_cmd(&nlstate, idby, argc, argv, &cmd); } - if (err == 1) { + if (err == HANDLER_RET_USAGE) { if (cmd) usage_cmd(cmd); else usage(0, NULL); + } else if (err == HANDLER_RET_DONE) { + err = 0; } else if (err < 0) fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err); @@ -11,7 +11,36 @@ #include "nl80211.h" #include "ieee80211.h" +#ifndef NL_CAPABILITY_VERSION_3_5_0 +#define nla_nest_start(msg, attrtype) \ + nla_nest_start(msg, NLA_F_NESTED | (attrtype)) +#endif + +/* support for extack if compilation headers are too old */ +#ifndef NETLINK_EXT_ACK +#define NETLINK_EXT_ACK 11 +enum nlmsgerr_attrs { + NLMSGERR_ATTR_UNUSED, + NLMSGERR_ATTR_MSG, + NLMSGERR_ATTR_OFFS, + NLMSGERR_ATTR_COOKIE, + + __NLMSGERR_ATTR_MAX, + NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1 +}; +#endif +#ifndef NLM_F_CAPPED +#define NLM_F_CAPPED 0x100 +#endif +#ifndef NLM_F_ACK_TLVS +#define NLM_F_ACK_TLVS 0x200 +#endif +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 +#endif + #define ETH_ALEN 6 +#define VHT_MUMIMO_GROUP_LEN 24 /* libnl 1.x compatibility code */ #if !defined(CONFIG_LIBNL20) && !defined(CONFIG_LIBNL30) @@ -38,6 +67,9 @@ enum id_input { II_WDEV, }; +#define HANDLER_RET_USAGE 1 +#define HANDLER_RET_DONE 3 + struct cmd { const char *name; const char *args; @@ -48,11 +80,10 @@ struct cmd { const enum command_identify_by idby; /* * The handler should return a negative error code, - * zero on success, 1 if the arguments were wrong - * and the usage message should and 2 otherwise. + * zero on success, 1 if the arguments were wrong. + * Return 2 iff you provide the error message yourself. */ int (*handler)(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id); @@ -60,13 +91,27 @@ struct cmd { const struct cmd *parent; }; +struct chanmode { + const char *name; + unsigned int width; + int freq1_diff; + int chantype; /* for older kernel */ +}; + +struct chandef { + enum nl80211_chan_width width; + + unsigned int control_freq; + unsigned int center_freq1; + unsigned int center_freq2; +}; + #define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(ar[0])) #define DIV_ROUND_UP(x, y) (((x) + (y - 1)) / (y)) #define __COMMAND(_section, _symname, _name, _args, _nlcmd, _flags, _hidden, _idby, _handler, _help, _sel)\ static struct cmd \ - __cmd ## _ ## _symname ## _ ## _handler ## _ ## _nlcmd ## _ ## _idby ## _ ## _hidden\ - __attribute__((used)) __attribute__((section("__cmd"))) = { \ + __cmd ## _ ## _symname ## _ ## _handler ## _ ## _nlcmd ## _ ## _idby ## _ ## _hidden = {\ .name = (_name), \ .args = (_args), \ .cmd = (_nlcmd), \ @@ -77,7 +122,10 @@ struct cmd { .help = (_help), \ .parent = _section, \ .selector = (_sel), \ - } + }; \ + static struct cmd *__cmd ## _ ## _symname ## _ ## _handler ## _ ## _nlcmd ## _ ## _idby ## _ ## _hidden ## _p \ + __attribute__((used,section("__cmd"))) = \ + &__cmd ## _ ## _symname ## _ ## _handler ## _ ## _nlcmd ## _ ## _idby ## _ ## _hidden #define __ACMD(_section, _symname, _name, _args, _nlcmd, _flags, _hidden, _idby, _handler, _help, _sel, _alias)\ __COMMAND(_section, _symname, _name, _args, _nlcmd, _flags, _hidden, _idby, _handler, _help, _sel);\ static const struct cmd *_alias = &__cmd ## _ ## _symname ## _ ## _handler ## _ ## _nlcmd ## _ ## _idby ## _ ## _hidden @@ -89,9 +137,7 @@ struct cmd { __COMMAND(&(__section ## _ ## section), name, #name, args, cmd, flags, 1, idby, handler, NULL, NULL) #define TOPLEVEL(_name, _args, _nlcmd, _flags, _idby, _handler, _help) \ - struct cmd \ - __section ## _ ## _name \ - __attribute__((used)) __attribute__((section("__cmd"))) = { \ + struct cmd __section ## _ ## _name = { \ .name = (#_name), \ .args = (_args), \ .cmd = (_nlcmd), \ @@ -99,17 +145,37 @@ struct cmd { .idby = (_idby), \ .handler = (_handler), \ .help = (_help), \ - } + }; \ + static struct cmd *__section ## _ ## _name ## _p \ + __attribute__((used,section("__cmd"))) = &__section ## _ ## _name + #define SECTION(_name) \ - struct cmd __section ## _ ## _name \ - __attribute__((used)) __attribute__((section("__cmd"))) = { \ + struct cmd __section ## _ ## _name = { \ .name = (#_name), \ .hidden = 1, \ - } + }; \ + static struct cmd *__section ## _ ## _name ## _p \ + __attribute__((used,section("__cmd"))) = &__section ## _ ## _name #define DECLARE_SECTION(_name) \ extern struct cmd __section ## _ ## _name; +struct vendor_event { + unsigned int vendor_id, subcmd; + void (*callback)(unsigned int vendor_id, unsigned int subcmd, + struct nlattr *data); +}; + +#define VENDOR_EVENT(_id, _subcmd, _callback) \ + static const struct vendor_event \ + vendor_event_ ## _id ## _ ## _subcmd = { \ + .vendor_id = _id, \ + .subcmd = _subcmd, \ + .callback = _callback, \ + }, * const vendor_event_ ## _id ## _ ## _subcmd ## _p \ + __attribute__((used,section("vendor_event"))) = \ + &vendor_event_ ## _id ## _ ## _subcmd + extern const char iw_version[]; extern int iw_debug; @@ -120,7 +186,7 @@ int handle_cmd(struct nl80211_state *state, enum id_input idby, struct print_event_args { struct timeval ts; /* internal */ bool have_ts; /* must be set false */ - bool frame, time, reltime; + bool frame, time, reltime, ctime; }; __u32 listen_events(struct nl80211_state *state, @@ -128,25 +194,38 @@ __u32 listen_events(struct nl80211_state *state, int __prepare_listen_events(struct nl80211_state *state); __u32 __do_listen_events(struct nl80211_state *state, const int n_waits, const __u32 *waits, + const int n_prints, const __u32 *prints, struct print_event_args *args); +int valid_handler(struct nl_msg *msg, void *arg); +void register_handler(int (*handler)(struct nl_msg *, void *), void *data); int mac_addr_a2n(unsigned char *mac_addr, char *arg); -void mac_addr_n2a(char *mac_addr, unsigned char *arg); +void mac_addr_n2a(char *mac_addr, const unsigned char *arg); int parse_hex_mask(char *hexmask, unsigned char **result, size_t *result_len, unsigned char **mask); unsigned char *parse_hex(char *hex, size_t *outlen); -int parse_keys(struct nl_msg *msg, char **argv, int argc); +int parse_keys(struct nl_msg *msg, char **argv[], int *argc); +int parse_freqchan(struct chandef *chandef, bool chan, int argc, char **argv, int *parsed); +enum nl80211_chan_width str_to_bw(const char *str); +int parse_txq_stats(char *buf, int buflen, struct nlattr *tid_stats_attr, int header, + int tid, const char *indent); +int put_chandef(struct nl_msg *msg, struct chandef *chandef); void print_ht_mcs(const __u8 *mcs); void print_ampdu_length(__u8 exponent); void print_ampdu_spacing(__u8 spacing); void print_ht_capability(__u16 cap); void print_vht_info(__u32 capa, const __u8 *mcs); +void print_he_capability(const uint8_t *ie, int len); +void print_he_info(struct nlattr *nl_iftype); +void print_eht_info(struct nlattr *nl_iftype, int band); char *channel_width_name(enum nl80211_chan_width width); const char *iftype_name(enum nl80211_iftype iftype); +void print_iftype_list(const char *name, const char *pfx, struct nlattr *attr); +void print_iftype_line(struct nlattr *attr); const char *command_name(enum nl80211_commands cmd); int ieee80211_channel_to_frequency(int chan, enum nl80211_band band); int ieee80211_frequency_to_channel(int freq); @@ -173,11 +252,66 @@ void print_ies(unsigned char *ie, int ielen, bool unknown, void parse_bitrate(struct nlattr *bitrate_attr, char *buf, int buflen); void iw_hexdump(const char *prefix, const __u8 *data, size_t len); -#define SCHED_SCAN_OPTIONS "interval <in_msecs> [delay <in_secs>] " \ - "[freqs <freq>+] [matches [ssid <ssid>]+]] [active [ssid <ssid>]+|passive] [randomise[=<addr>/<mask>]]" +int get_cf1(const struct chanmode *chanmode, unsigned long freq); + +int parse_random_mac_addr(struct nl_msg *msg, char *addrs); + +#define SCHED_SCAN_OPTIONS "[interval <in_msecs> | scan_plans [<interval_secs:iterations>*] <interval_secs>] " \ + "[delay <in_secs>] [freqs <freq>+] [matches [ssid <ssid>]+]] [active [ssid <ssid>]+|passive] " \ + "[randomise[=<addr>/<mask>]] [coloc] [flush]" int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv); -DECLARE_SECTION(set); +void nan_bf(uint8_t idx, uint8_t *bf, uint16_t bf_len, const uint8_t *buf, + size_t len); + +char *hex2bin(const char *hex, char *buf); + +int set_bitrates(struct nl_msg *msg, int argc, char **argv, + enum nl80211_attrs attr); + + +/* sections */ +DECLARE_SECTION(ap); +DECLARE_SECTION(auth); +DECLARE_SECTION(cac); +DECLARE_SECTION(channels); +DECLARE_SECTION(coalesce); +DECLARE_SECTION(commands); +DECLARE_SECTION(connect); +DECLARE_SECTION(cqm); +DECLARE_SECTION(del); +DECLARE_SECTION(dev); +DECLARE_SECTION(disconnect); +DECLARE_SECTION(event); +DECLARE_SECTION(features); +DECLARE_SECTION(ftm); DECLARE_SECTION(get); +DECLARE_SECTION(help); +DECLARE_SECTION(hwsim); +DECLARE_SECTION(ibss); +DECLARE_SECTION(info); +DECLARE_SECTION(interface); +DECLARE_SECTION(link); +DECLARE_SECTION(list); +DECLARE_SECTION(measurement); +DECLARE_SECTION(mesh); +DECLARE_SECTION(mesh_param); +DECLARE_SECTION(mgmt); +DECLARE_SECTION(mpath); +DECLARE_SECTION(mpp); +DECLARE_SECTION(nan); +DECLARE_SECTION(ocb); +DECLARE_SECTION(offchannel); +DECLARE_SECTION(p2p); +DECLARE_SECTION(phy); +DECLARE_SECTION(reg); +DECLARE_SECTION(roc); +DECLARE_SECTION(scan); +DECLARE_SECTION(set); +DECLARE_SECTION(station); +DECLARE_SECTION(survey); +DECLARE_SECTION(switch); +DECLARE_SECTION(vendor); +DECLARE_SECTION(wowlan); #endif /* __IW_H */ @@ -1,7 +1,6 @@ #include <net/if.h> #include <errno.h> #include <string.h> -#include <ctype.h> #include <stdbool.h> #include <netlink/genl/genl.h> @@ -98,7 +97,6 @@ static int link_bss_handler(struct nl_msg *msg, void *arg) } static int handle_scan_for_link(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -106,7 +104,7 @@ static int handle_scan_for_link(struct nl80211_state *state, if (argc > 0) return 1; - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, link_bss_handler, &lr); + register_handler(link_bss_handler, &lr); return 0; } @@ -123,6 +121,7 @@ static int print_link_sta(struct nl_msg *msg, void *arg) [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, + [NL80211_STA_INFO_RX_BITRATE] = { .type = NLA_NESTED }, [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED }, [NL80211_STA_INFO_LLID] = { .type = NLA_U16 }, [NL80211_STA_INFO_PLID] = { .type = NLA_U16 }, @@ -162,6 +161,12 @@ static int print_link_sta(struct nl_msg *msg, void *arg) printf("\tsignal: %d dBm\n", (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL])); + if (sinfo[NL80211_STA_INFO_RX_BITRATE]) { + char buf[100]; + + parse_bitrate(sinfo[NL80211_STA_INFO_RX_BITRATE], buf, sizeof(buf)); + printf("\trx bitrate: %s\n", buf); + } if (sinfo[NL80211_STA_INFO_TX_BITRATE]) { char buf[100]; @@ -199,7 +204,6 @@ static int print_link_sta(struct nl_msg *msg, void *arg) } static int handle_link_sta(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -222,14 +226,14 @@ static int handle_link_sta(struct nl80211_state *state, NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_link_sta, NULL); + register_handler(print_link_sta, NULL); return 0; nla_put_failure: return -ENOBUFS; } -static int handle_link(struct nl80211_state *state, struct nl_cb *cb, +static int handle_link(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -269,7 +273,7 @@ static int handle_link(struct nl80211_state *state, struct nl_cb *cb, } TOPLEVEL(link, NULL, 0, 0, CIB_NETDEV, handle_link, "Print information about the current link, if any."); -HIDDEN(link, get_sta, "", NL80211_CMD_GET_STATION, 0, +HIDDEN(link, get_sta, "<mac-addr>", NL80211_CMD_GET_STATION, 0, CIB_NETDEV, handle_link_sta); HIDDEN(link, get_bss, NULL, NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_for_link); diff --git a/measurements.c b/measurements.c new file mode 100644 index 0000000..89cbbfe --- /dev/null +++ b/measurements.c @@ -0,0 +1,348 @@ +#include <errno.h> + +#include "nl80211.h" +#include "iw.h" +#include <unistd.h> + +SECTION(measurement); + +static int put_preamble(struct nl_msg *msg, char *s) +{ + static const struct { + const char *name; + unsigned int val; + } preamble_map[] = { + { .name = "legacy", .val = NL80211_PREAMBLE_LEGACY, }, + { .name = "ht", .val = NL80211_PREAMBLE_HT, }, + { .name = "vht", .val = NL80211_PREAMBLE_VHT, }, + { .name = "dmg", .val = NL80211_PREAMBLE_DMG, }, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(preamble_map); i++) { + if (strcasecmp(preamble_map[i].name, s) == 0) { + NLA_PUT_U32(msg, NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE, + preamble_map[i].val); + return 0; + } + } + +nla_put_failure: + return -1; +} + +static int parse_ftm_target(struct nl_msg *msg, char *str, int peer_index) +{ + unsigned char addr[ETH_ALEN]; + int res, consumed; + char *bw = NULL, *pos, *tmp, *save_ptr, *delims = " \t\n"; + struct nlattr *peer, *req, *reqdata, *ftm, *chan; + bool report_ap_tsf = false, preamble = false; + unsigned int freq = 0, cf1 = 0, cf2 = 0; + + res = sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx%n", + &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5], + &consumed); + + if (res != ETH_ALEN) { + printf("Invalid MAC address\n"); + return HANDLER_RET_USAGE; + } + + peer = nla_nest_start(msg, peer_index); + + NLA_PUT(msg, NL80211_PMSR_PEER_ATTR_ADDR, ETH_ALEN, addr); + + req = nla_nest_start(msg, NL80211_PMSR_PEER_ATTR_REQ); + if (!req) + goto nla_put_failure; + reqdata = nla_nest_start(msg, NL80211_PMSR_REQ_ATTR_DATA); + if (!reqdata) + goto nla_put_failure; + ftm = nla_nest_start(msg, NL80211_PMSR_TYPE_FTM); + if (!ftm) + goto nla_put_failure; + + str += consumed; + pos = strtok_r(str, delims, &save_ptr); + + while (pos) { + if (strncmp(pos, "cf=", 3) == 0) { + freq = strtol(pos + 3, &tmp, 0); + if (*tmp) { + printf("Invalid cf value!\n"); + return HANDLER_RET_USAGE; + } + } else if (strncmp(pos, "bw=", 3) == 0) { + bw = pos + 3; + } else if (strncmp(pos, "cf1=", 4) == 0) { + cf1 = strtol(pos + 4, &tmp, 0); + if (*tmp) { + printf("Invalid cf1 value!\n"); + return HANDLER_RET_USAGE; + } + } else if (strncmp(pos, "cf2=", 4) == 0) { + cf2 = strtol(pos + 4, &tmp, 0); + if (*tmp) { + printf("Invalid cf2 value!\n"); + return HANDLER_RET_USAGE; + } + } else if (strncmp(pos, "bursts_exp=", 11) == 0) { + NLA_PUT_U8(msg, + NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP, + strtol(pos + 11, &tmp, 0)); + if (*tmp) { + printf("Invalid bursts_exp value!\n"); + return HANDLER_RET_USAGE; + } + } else if (strncmp(pos, "burst_period=", 13) == 0) { + NLA_PUT_U16(msg, NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD, + strtol(pos + 13, &tmp, 0)); + if (*tmp) { + printf("Invalid burst_period value!\n"); + return HANDLER_RET_USAGE; + } + } else if (strncmp(pos, "retries=", 8) == 0) { + NLA_PUT_U8(msg, + NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES, + strtol(pos + 8, &tmp, 0)); + if (*tmp) { + printf("Invalid retries value!\n"); + return HANDLER_RET_USAGE; + } + } else if (strncmp(pos, "burst_duration=", 15) == 0) { + NLA_PUT_U8(msg, + NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION, + strtol(pos + 15, &tmp, 0)); + if (*tmp) { + printf("Invalid burst_duration value!\n"); + return HANDLER_RET_USAGE; + } + } else if (strncmp(pos, "ftms_per_burst=", 15) == 0) { + NLA_PUT_U8(msg, + NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST, + strtol(pos + 15, &tmp, 0)); + if (*tmp) { + printf("Invalid ftms_per_burst value!\n"); + return HANDLER_RET_USAGE; + } + } else if (strcmp(pos, "asap") == 0) { + NLA_PUT_FLAG(msg, NL80211_PMSR_FTM_REQ_ATTR_ASAP); + } else if (strcmp(pos, "ap-tsf") == 0) { + report_ap_tsf = true; + } else if (strcmp(pos, "civic") == 0) { + NLA_PUT_FLAG(msg, NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC); + } else if (strcmp(pos, "lci") == 0) { + NLA_PUT_FLAG(msg, NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI); + } else if (strncmp(pos, "preamble=", 9) == 0) { + if (put_preamble(msg, pos + 9)) { + printf("Invalid preamble %s\n", pos + 9); + return HANDLER_RET_USAGE; + } + preamble = true; + } else if (strncmp(pos, "tb", 2) == 0) { + NLA_PUT_FLAG(msg, + NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED); + NLA_PUT_U32(msg, NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE, + NL80211_PREAMBLE_HE); + preamble = true; + } else if (strncmp(pos, "non_tb", 6) == 0) { + NLA_PUT_FLAG(msg, + NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED); + NLA_PUT_U32(msg, NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE, + NL80211_PREAMBLE_HE); + preamble = true; + } else if (strncmp(pos, "lmr_feedback", 12) == 0) { + NLA_PUT_FLAG(msg, + NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK); + } else if (strncmp(pos, "bss_color=", 10) == 0) { + NLA_PUT_U8(msg, + NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR, + strtol(pos + 10, &tmp, 0)); + if (*tmp) { + printf("Invalid bss_color value!\n"); + return HANDLER_RET_USAGE; + } + } else { + printf("Unknown parameter %s\n", pos); + return HANDLER_RET_USAGE; + } + + pos = strtok_r(NULL, delims, &save_ptr); + } + + if (!preamble) { + int preamble = -1; + + switch (str_to_bw(bw)) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_5: + case NL80211_CHAN_WIDTH_10: + preamble = NL80211_PREAMBLE_LEGACY; + break; + case NL80211_CHAN_WIDTH_20: + case NL80211_CHAN_WIDTH_40: + preamble = NL80211_PREAMBLE_HT; + break; + case NL80211_CHAN_WIDTH_80: + case NL80211_CHAN_WIDTH_80P80: + case NL80211_CHAN_WIDTH_160: + preamble = NL80211_PREAMBLE_VHT; + break; + default: + return HANDLER_RET_USAGE; + } + + NLA_PUT_U32(msg, NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE, preamble); + } + + nla_nest_end(msg, ftm); + if (report_ap_tsf) + NLA_PUT_FLAG(msg, NL80211_PMSR_REQ_ATTR_GET_AP_TSF); + nla_nest_end(msg, reqdata); + nla_nest_end(msg, req); + + /* set the channel */ + chan = nla_nest_start(msg, NL80211_PMSR_PEER_ATTR_CHAN); + if (!chan) + goto nla_put_failure; + if (freq) + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); + if (cf1) + NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, cf1); + if (cf2) + NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, cf2); + if (bw) + NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, + str_to_bw(bw)); + nla_nest_end(msg, chan); + + nla_nest_end(msg, peer); + return 0; +nla_put_failure: + return -ENOBUFS; +} + +static int parse_ftm_config(struct nl_msg *msg, const char *file) +{ + FILE *input; + char line[256]; + int line_num; + + input = fopen(file, "r"); + if (!input) { + int err = errno; + + printf("Failed to open file: %s\n", strerror(err)); + return -err; + } + + for (line_num = 1; fgets(line, sizeof(line), input); line_num++) { + if (line[0] == '#') + continue; + + if (parse_ftm_target(msg, line, line_num)) { + printf("Invalid FTM configuration at line %d!\n", + line_num); + return HANDLER_RET_USAGE; + } + } + + return 0; +} + +static int handle_ftm_req(struct nl80211_state *state, struct nl_msg *msg, + int argc, char **argv, enum id_input id) +{ + int err, i; + static char **req_argv; + static const __u32 wait[] = { + NL80211_CMD_PEER_MEASUREMENT_COMPLETE, + }; + static const __u32 print[] = { + NL80211_CMD_PEER_MEASUREMENT_RESULT, + NL80211_CMD_PEER_MEASUREMENT_COMPLETE, + }; + struct print_event_args printargs = { }; + + req_argv = calloc(argc + 1, sizeof(req_argv[0])); + req_argv[0] = argv[0]; + req_argv[1] = "measurement"; + req_argv[2] = "ftm_request_send"; + for (i = 3; i < argc; i++) + req_argv[i] = argv[i]; + + err = handle_cmd(state, id, argc, req_argv); + + free(req_argv); + + if (err) + return err; + + __do_listen_events(state, + ARRAY_SIZE(wait), wait, + ARRAY_SIZE(print), print, + &printargs); + return 0; +} + +static int handle_ftm_req_send(struct nl80211_state *state, struct nl_msg *msg, + int argc, char **argv, enum id_input id) +{ + struct nlattr *pmsr, *peers; + const char *file; + int err; + + if (argc < 1) + return HANDLER_RET_USAGE; + + file = argv[0]; + argc--; + argv++; + while (argc) { + if (strncmp(argv[0], "randomise", 9) == 0 || + strncmp(argv[0], "randomize", 9) == 0) { + err = parse_random_mac_addr(msg, argv[0] + 9); + if (err) + return err; + } else if (strncmp(argv[0], "timeout=", 8) == 0) { + char *end; + + NLA_PUT_U32(msg, NL80211_ATTR_TIMEOUT, + strtoul(argv[0] + 8, &end, 0)); + if (*end) + return HANDLER_RET_USAGE; + } else { + return HANDLER_RET_USAGE; + } + + argc--; + argv++; + } + + pmsr = nla_nest_start(msg, NL80211_ATTR_PEER_MEASUREMENTS); + if (!pmsr) + goto nla_put_failure; + peers = nla_nest_start(msg, NL80211_PMSR_ATTR_PEERS); + if (!peers) + goto nla_put_failure; + + err = parse_ftm_config(msg, file); + if (err) + return err; + + nla_nest_end(msg, peers); + nla_nest_end(msg, pmsr); + + return 0; + +nla_put_failure: + return -ENOBUFS; +} +COMMAND(measurement, ftm_request, "<config-file> [timeout=<seconds>] [randomise[=<addr>/<mask>]]", 0, 0, + CIB_NETDEV, handle_ftm_req, + "Send an FTM request to the targets supplied in the config file.\n" + "Each line in the file represents a target, with the following format:\n" + "<addr> bw=<[20|40|80|80+80|160]> cf=<center_freq> [cf1=<center_freq1>] [cf2=<center_freq2>] [ftms_per_burst=<samples per burst>] [ap-tsf] [asap] [bursts_exp=<num of bursts exponent>] [burst_period=<burst period>] [retries=<num of retries>] [burst_duration=<burst duration>] [preamble=<legacy,ht,vht,dmg>] [lci] [civic] [tb] [non_tb]"); +HIDDEN(measurement, ftm_request_send, "", NL80211_CMD_PEER_MEASUREMENT_START, + 0, CIB_NETDEV, handle_ftm_req_send); @@ -1,4 +1,3 @@ -#include <net/if.h> #include <errno.h> #include <string.h> @@ -12,6 +11,7 @@ #include "iw.h" SECTION(mesh); +SECTION(mesh_param); typedef struct _any_t { @@ -194,7 +194,7 @@ static void _print_s32_in_dBm(struct nlattr *a) /* The current mesh parameters */ -const static struct mesh_param_descr _mesh_param_descrs[] = +static const struct mesh_param_descr _mesh_param_descrs[] = { {"mesh_retry_timeout", NL80211_MESHCONF_RETRY_TIMEOUT, @@ -265,11 +265,17 @@ const static struct mesh_param_descr _mesh_param_descrs[] = _my_nla_put_u16, _parse_u16, _print_u16_in_TUs}, {"mesh_plink_timeout", NL80211_MESHCONF_PLINK_TIMEOUT, _my_nla_put_u32, _parse_u32, _print_u32_in_seconds}, + {"mesh_connected_to_gate", NL80211_MESHCONF_CONNECTED_TO_GATE, + _my_nla_put_u8, _parse_u8_as_bool, _print_u8}, + {"mesh_nolearn", NL80211_MESHCONF_NOLEARN, + _my_nla_put_u8, _parse_u8_as_bool, _print_u8}, + {"mesh_connected_to_as", NL80211_MESHCONF_CONNECTED_TO_AS, + _my_nla_put_u8, _parse_u8_as_bool, _print_u8}, }; static void print_all_mesh_param_descr(void) { - int i; + unsigned int i; printf("Possible mesh parameters are:\n"); @@ -279,7 +285,7 @@ static void print_all_mesh_param_descr(void) static const struct mesh_param_descr *find_mesh_param(const char *name) { - int i; + unsigned int i; /* Find out what mesh parameter we want to change. */ for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) { @@ -287,13 +293,11 @@ static const struct mesh_param_descr *find_mesh_param(const char *name) return _mesh_param_descrs + i; } - print_all_mesh_param_descr(); return NULL; } /* Setter */ static int set_interface_meshparam(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -301,14 +305,16 @@ static int set_interface_meshparam(struct nl80211_state *state, const struct mesh_param_descr *mdescr; struct nlattr *container; uint32_t ret; - int err; + int err = 2; container = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS); if (!container) return -ENOBUFS; - if (!argc) + if (!argc) { + print_all_mesh_param_descr(); return 1; + } while (argc) { const char *name; @@ -336,8 +342,11 @@ static int set_interface_meshparam(struct nl80211_state *state, } mdescr = find_mesh_param(name); - if (!mdescr) + if (!mdescr) { + printf("Could not find the parameter %s.\n", name); + print_all_mesh_param_descr(); return 2; + } /* Parse the new value */ ret = mdescr->parse_fn(value, &any); @@ -389,42 +398,50 @@ static int print_mesh_param_handler(struct nl_msg *msg, void *arg) return -EINVAL; if (!mdescr) { - int i; + unsigned int i; + /* print out all the supported mesh parameters */ for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) { mdescr = &_mesh_param_descrs[i]; - printf("%s = ", mdescr->name); - mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]); - printf("\n"); + if (mesh_params[mdescr->mesh_param_num]) { + printf("%s = ", mdescr->name); + mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]); + printf("\n"); + } } return NL_SKIP; } - /* print out the mesh parameter */ - mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]); - printf("\n"); + /* print out the requested mesh parameter */ + if (mesh_params[mdescr->mesh_param_num]) { + mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]); + printf("\n"); + } return NL_SKIP; } static int get_interface_meshparam(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { const struct mesh_param_descr *mdescr = NULL; - if (argc > 1) + if (argc == 0) { + print_all_mesh_param_descr(); return 1; - - if (argc == 1) { + } else if (argc == 1) { mdescr = find_mesh_param(argv[0]); - if (!mdescr) + if (!mdescr) { + printf("Could not find the parameter %s.\n", argv[0]); + print_all_mesh_param_descr(); return 2; + } + } else { + return 1; } - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, - print_mesh_param_handler, (void *)mdescr); + register_handler(print_mesh_param_handler, (void *)mdescr); return 0; } @@ -432,39 +449,28 @@ COMMAND(get, mesh_param, "[<param>]", NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, get_interface_meshparam, "Retrieve mesh parameter (run command without any to see available ones)."); -static int join_mesh(struct nl80211_state *state, struct nl_cb *cb, +static int dump_interface_meshparam(struct nl80211_state *state, + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + register_handler(print_mesh_param_handler, NULL); + return 0; +} + +COMMAND(mesh_param, dump, "", + NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, dump_interface_meshparam, + "List all supported mesh parameters"); + +static int join_mesh(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { struct nlattr *container; float rate; unsigned char rates[NL80211_MAX_SUPP_RATES]; - int bintval, dtim_period, i, n_rates = 0; + int bintval, dtim_period, n_rates = 0; char *end, *value = NULL, *sptr = NULL; - unsigned long freq = 0; - static const struct { - const char *name; - unsigned int width; - int freq1_diff; - int chantype; /* for older kernel */ - } *chanmode_selected = NULL, chanmode[] = { - { .name = "HT20", - .width = NL80211_CHAN_WIDTH_20, - .freq1_diff = 0, - .chantype = NL80211_CHAN_HT20 }, - { .name = "HT40+", - .width = NL80211_CHAN_WIDTH_40, - .freq1_diff = 10, - .chantype = NL80211_CHAN_HT40PLUS }, - { .name = "HT40-", - .width = NL80211_CHAN_WIDTH_40, - .freq1_diff = -10, - .chantype = NL80211_CHAN_HT40MINUS }, - { .name = "NOHT", - .width = NL80211_CHAN_WIDTH_20_NOHT, - .freq1_diff = 0, - .chantype = NL80211_CHAN_NO_HT }, - }; if (argc < 1) return 1; @@ -475,40 +481,20 @@ static int join_mesh(struct nl80211_state *state, struct nl_cb *cb, /* freq */ if (argc > 1 && strcmp(argv[0], "freq") == 0) { - argv++; - argc--; + struct chandef chandef; + int err, parsed; - freq = strtoul(argv[0], &end, 10); - if (*end != '\0') - return 1; - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); - - argv++; - argc--; - } - - /* channel type */ - if (argc) { - for (i = 0; i < ARRAY_SIZE(chanmode); i++) { - if (strcasecmp(chanmode[i].name, argv[0]) == 0) { - chanmode_selected = &chanmode[i]; - break; - } - } + err = parse_freqchan(&chandef, false, argc - 1, argv + 1, + &parsed); + if (err) + return err; - if (chanmode_selected) { - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - chanmode_selected->width); - NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, - freq + chanmode_selected->freq1_diff); - if (chanmode_selected->chantype != -1) - NLA_PUT_U32(msg, - NL80211_ATTR_WIPHY_CHANNEL_TYPE, - chanmode_selected->chantype); + argv += parsed + 1; + argc -= parsed + 1; - argv++; - argc--; - } + err = put_chandef(msg, &chandef); + if (err) + return err; } /* basic rates */ @@ -598,11 +584,11 @@ static int join_mesh(struct nl80211_state *state, struct nl_cb *cb, if (!argc) return 0; - return set_interface_meshparam(state, cb, msg, argc, argv, id); + return set_interface_meshparam(state, msg, argc, argv, id); nla_put_failure: return -ENOBUFS; } -COMMAND(mesh, join, "<mesh ID> [[freq <freq in MHz> <HT20|HT40+|HT40-|NOHT>]" +COMMAND(mesh, join, "<mesh ID> [[freq <freq in MHz> <NOHT|HT20|HT40+|HT40-|80MHz>]" " [basic-rates <rate in Mbps,rate2,...>]], [mcast-rate <rate in Mbps>]" " [beacon-interval <time in TUs>] [dtim-period <value>]" " [vendor_sync on|off] [<param>=<value>]*", @@ -611,7 +597,7 @@ COMMAND(mesh, join, "<mesh ID> [[freq <freq in MHz> <HT20|HT40+|HT40-|NOHT>]" "mcast-rate and mesh parameters. Basic-rates are applied only if\n" "frequency is provided."); -static int leave_mesh(struct nl80211_state *state, struct nl_cb *cb, +static int leave_mesh(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -0,0 +1,171 @@ +#include <string.h> +#include <errno.h> + +#include <netlink/genl/genl.h> +#include <netlink/genl/family.h> +#include <netlink/genl/ctrl.h> +#include <netlink/msg.h> +#include <netlink/attr.h> + +#include "nl80211.h" +#include "iw.h" + +SECTION(mgmt); + +static int seq_handler(struct nl_msg *msg, void *arg) +{ + return NL_OK; +} + +static int dump_mgmt_frame(struct nl_msg *msg, void *arg) +{ + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; + + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) { + uint32_t freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]); + printf("freq %u MHz\n", freq); + } + + if (tb_msg[NL80211_ATTR_RX_SIGNAL_DBM]) { + /* nl80211_send_mgmt sends signed dBm value as u32 */ + int dbm = nla_get_u32(tb_msg[NL80211_ATTR_RX_SIGNAL_DBM]); + printf("rssi %d dBm\n", dbm); + } + + if (tb_msg[NL80211_ATTR_FRAME]) { + int len = nla_len(tb_msg[NL80211_ATTR_FRAME]); + uint8_t *data = nla_data(tb_msg[NL80211_ATTR_FRAME]); + iw_hexdump("mgmt", data, len); + } + + return 0; +} + +static int register_mgmt_frame(struct nl80211_state *state, + struct nl_msg *msg, int argc, char **argv, + enum id_input id) +{ + unsigned int type; + unsigned char *match; + size_t match_len; + int ret; + + if (argc < 2) + return HANDLER_RET_USAGE; + + ret = sscanf(argv[0], "%x", &type); + if (ret != 1) { + printf("invalid frame type: %s\n", argv[0]); + return 2; + } + + match = parse_hex(argv[1], &match_len); + if (!match) { + printf("invalid frame pattern: %s\n", argv[1]); + return 2; + } + + NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type); + NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match); + + free(match); + return 0; + +nla_put_failure: + free(match); + return -ENOBUFS; +} + +static int handle_mgmt_reg(struct nl80211_state *state, + struct nl_msg *msg, int argc, + char **argv, enum id_input id) +{ + return register_mgmt_frame(state, msg, argc, argv, id); +} + +HIDDEN(mgmt, reg, "", NL80211_CMD_REGISTER_FRAME, 0, CIB_NETDEV, handle_mgmt_reg); + +static int handle_mgmt_dump(struct nl80211_state *state, + struct nl_msg *msg, int argc, + char **argv, enum id_input id) +{ + struct nl_cb *mgmt_cb; + char *ndev = argv[0]; + int mgmt_argc = 5; + char **mgmt_argv; + unsigned int count = 0; + int err = 0; + + mgmt_argv = calloc(mgmt_argc, sizeof(char*)); + if (!mgmt_argv) + return -ENOMEM; + + mgmt_argv[0] = ndev; + mgmt_argv[1] = "mgmt"; + mgmt_argv[2] = "reg"; + + if (argc < 6) { + err = HANDLER_RET_USAGE; + goto out; + } + + argc -= 3; + argv += 3; + while (argc >= 3) { + if (strcmp(argv[0], "frame") != 0) { + err = HANDLER_RET_USAGE; + goto out; + } + + mgmt_argv[3] = argv[1]; + mgmt_argv[4] = argv[2]; + + argc -= 3; + argv += 3; + + err = handle_cmd(state, II_NETDEV, mgmt_argc, mgmt_argv); + if (err) + goto out; + } + + if (argc == 2 && strcmp(argv[0], "count") == 0) { + count = 1 + atoi(argv[1]); + if (count < 1) + count = 1; + + argc -= 2; + argv += 2; + } else if (argc) { + err = HANDLER_RET_USAGE; + goto out; + } + + mgmt_cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); + if (!mgmt_cb) { + err = 1; + goto out; + } + + /* need to turn off sequence number checking */ + nl_cb_set(mgmt_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, seq_handler, NULL); + nl_cb_set(mgmt_cb, NL_CB_VALID, NL_CB_CUSTOM, dump_mgmt_frame, NULL); + + while (--count) + nl_recvmsgs(state->nl_sock, mgmt_cb); + + nl_cb_put(mgmt_cb); +out: + free(mgmt_argv); + return err; +} + +COMMAND(mgmt, dump, "frame <type as hex ab> <pattern as hex ab:cd:..> [frame <type> <pattern>]* [count <frames>]", + 0, 0, CIB_NETDEV, handle_mgmt_dump, + "Register for receiving certain mgmt frames and print them.\n" + "Frames are selected by their type and pattern containing\n" + "the first several bytes of the frame that should match.\n\n" + "Example: iw dev wlan0 mgmt dump frame 40 00 frame 40 01:02 count 10\n"); @@ -38,6 +38,8 @@ static int print_mpath_handler(struct nl_msg *msg, void *arg) [NL80211_MPATH_INFO_DISCOVERY_TIMEOUT] = { .type = NLA_U32 }, [NL80211_MPATH_INFO_DISCOVERY_RETRIES] = { .type = NLA_U8 }, [NL80211_MPATH_INFO_FLAGS] = { .type = NLA_U8 }, + [NL80211_MPATH_INFO_HOP_COUNT] = { .type = NLA_U8 }, + [NL80211_MPATH_INFO_PATH_CHANGE] = { .type = NLA_U32 }, }; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), @@ -85,13 +87,57 @@ static int print_mpath_handler(struct nl_msg *msg, void *arg) if (pinfo[NL80211_MPATH_INFO_FLAGS]) printf("\t0x%x", nla_get_u8(pinfo[NL80211_MPATH_INFO_FLAGS])); + if (pinfo[NL80211_MPATH_INFO_HOP_COUNT]) + printf("\t%u", + nla_get_u8(pinfo[NL80211_MPATH_INFO_HOP_COUNT])); + if (pinfo[NL80211_MPATH_INFO_PATH_CHANGE]) + printf("\t%u", + nla_get_u32(pinfo[NL80211_MPATH_INFO_PATH_CHANGE])); printf("\n"); return NL_SKIP; } +static int handle_mpath_probe(struct nl80211_state *state, + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + unsigned char dst[ETH_ALEN]; + unsigned char *frame; + size_t frame_len; + + if (argc < 3) + return 1; + + if (mac_addr_a2n(dst, argv[0])) { + fprintf(stderr, "invalid mac address\n"); + return 2; + } + + if (strcmp("frame", argv[1]) != 0) + return 1; + + frame = parse_hex(argv[2], &frame_len); + if (!frame) { + fprintf(stderr, "invalid frame pattern: %p\n", frame); + return 2; + } + + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); + NLA_PUT(msg, NL80211_ATTR_FRAME, frame_len, frame); + + return 0; + nla_put_failure: + return -ENOBUFS; +} +COMMAND(mpath, probe, "<destination MAC address> frame <frame>", + NL80211_CMD_PROBE_MESH_LINK, 0, CIB_NETDEV, handle_mpath_probe, + "Inject ethernet frame to given peer overriding the next hop\n" + "lookup from mpath table.\n." + "Example: iw dev wlan0 mpath probe xx:xx:xx:xx:xx:xx frame 01:xx:xx:00\n"); + static int handle_mpath_get(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -113,7 +159,7 @@ static int handle_mpath_get(struct nl80211_state *state, NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_mpath_handler, NULL); + register_handler(print_mpath_handler, NULL); return 0; nla_put_failure: @@ -127,7 +173,6 @@ COMMAND(mpath, del, "<MAC address>", "Remove the mesh path to the given node."); static int handle_mpath_set(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -163,7 +208,7 @@ static int handle_mpath_set(struct nl80211_state *state, NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_mpath_handler, NULL); + register_handler(print_mpath_handler, NULL); return 0; nla_put_failure: return -ENOBUFS; @@ -176,14 +221,13 @@ COMMAND(mpath, set, "<destination MAC address> next_hop <next hop MAC address>", "Set an existing mesh path's next hop."); static int handle_mpath_dump(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { printf("DEST ADDR NEXT HOP IFACE\tSN\tMETRIC\tQLEN\t" - "EXPTIME\t\tDTIM\tDRET\tFLAGS\n"); - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_mpath_handler, NULL); + "EXPTIME\tDTIM\tDRET\tFLAGS\tHOP_COUNT\tPATH_CHANGE\n"); + register_handler(print_mpath_handler, NULL); return 0; } COMMAND(mpath, dump, NULL, @@ -1,6 +1,5 @@ #include <net/if.h> #include <errno.h> -#include <string.h> #include <netlink/genl/genl.h> #include <netlink/genl/family.h> @@ -37,7 +36,6 @@ static int print_mpp_handler(struct nl_msg *msg, void *arg) } static int handle_mpp_get(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -59,7 +57,7 @@ static int handle_mpp_get(struct nl80211_state *state, NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_mpp_handler, NULL); + register_handler(print_mpp_handler, NULL); return 0; nla_put_failure: @@ -70,13 +68,12 @@ COMMAND(mpp, get, "<MAC address>", "Get information on mesh proxy path to the given node."); static int handle_mpp_dump(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { printf("DEST ADDR PROXY NODE IFACE\n"); - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_mpp_handler, NULL); + register_handler(print_mpp_handler, NULL); return 0; } COMMAND(mpp, dump, NULL, @@ -0,0 +1,506 @@ +#include <net/if.h> +#include <errno.h> +#include <string.h> + +#include <netlink/genl/genl.h> +#include <netlink/genl/family.h> +#include <netlink/genl/ctrl.h> +#include <netlink/msg.h> +#include <netlink/attr.h> + +#include <ctype.h> +#include <inttypes.h> +#include "nl80211.h" +#include "iw.h" +#include "sha256.h" + +SECTION(nan); + +static int parse_bands(int argc, char **argv) +{ + int i = 0, bands = 0; + + for (i = 0; i < argc; i++) { + if (!strcasecmp("2ghz", argv[i])) + bands |= BIT(NL80211_BAND_2GHZ); + else if (!strcasecmp("5ghz", argv[i])) + bands |= BIT(NL80211_BAND_5GHZ); + else + return -EINVAL; + } + + return bands; +} + +static int handle_nan_start(struct nl80211_state *state, + struct nl_msg *msg, int argc, char **argv, + enum id_input id) +{ + int bands = 0; + + if (argc < 2) + return -EINVAL; + + if (strcmp(argv[0], "pref") == 0) { + argv++; + argc--; + NLA_PUT_U8(msg, NL80211_ATTR_NAN_MASTER_PREF, atoi(argv[0])); + argv++; + argc--; + } else { + /* Master preference is mandatory */ + return -EINVAL; + } + + if (argc > 1 && !strcmp(argv[0], "bands")) { + argv++; + argc--; + + bands = parse_bands(argc, argv); + if (bands < 0) + return bands; + + NLA_PUT_U32(msg, NL80211_ATTR_BANDS, bands); + } else if (argc != 0) + return -EINVAL; + + return 0; +nla_put_failure: + return -ENOBUFS; +} +COMMAND(nan, start, "pref <pref> [bands [2GHz] [5GHz]]", + NL80211_CMD_START_NAN, 0, CIB_WDEV, handle_nan_start, ""); + +static int handle_nan_stop(struct nl80211_state *state, + struct nl_msg *msg, int argc, char **argv, + enum id_input id) +{ + return 0; +} +COMMAND(nan, stop, "", NL80211_CMD_STOP_NAN, 0, CIB_WDEV, handle_nan_stop, ""); + +static int handle_nan_config(struct nl80211_state *state, + struct nl_msg *msg, int argc, char **argv, + enum id_input id) +{ + int bands = 0; + + if (argc < 2) + return -EINVAL; + + if (strcmp(argv[0], "pref") == 0) { + argv++; + argc--; + NLA_PUT_U8(msg, NL80211_ATTR_NAN_MASTER_PREF, atoi(argv[0])); + argv++; + argc--; + } + + if (argc > 1 && !strcmp(argv[0], "bands")) { + argv++; + argc--; + + bands = parse_bands(argc, argv); + if (bands < 0) + return bands; + + NLA_PUT_U32(msg, NL80211_ATTR_BANDS, bands); + argv++; + argc--; + } else if (argc != 0) + return -EINVAL; + + return 0; +nla_put_failure: + return -ENOBUFS; +} +COMMAND(nan, config, "[pref <pref>] [bands [2GHz] [5GHz]]", + NL80211_CMD_CHANGE_NAN_CONFIG, 0, CIB_WDEV, handle_nan_config, ""); + +static int handle_nan_rm_func(struct nl80211_state *state, + struct nl_msg *msg, int argc, char **argv, + enum id_input id) +{ + if (argc != 2) + return -EINVAL; + + if (strcmp(argv[0], "cookie") == 0) { + argv++; + argc--; + NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, atoi(argv[0])); + argv++; + argc--; + } + + if (argc != 0) + return -EINVAL; + + return 0; +nla_put_failure: + return -ENOBUFS; +} +COMMAND(nan, rm_func, "cookie <cookie>", NL80211_CMD_DEL_NAN_FUNCTION, 0, + CIB_WDEV, handle_nan_rm_func, ""); + +static int compute_service_id(const unsigned char *serv_name, + unsigned int len, unsigned char *res) +{ + size_t size = len; + unsigned char md_value[32]; + int retcode = sha256(serv_name, size, md_value); + + if (retcode) + return retcode; + memcpy(res, md_value, 6); + + return 0; +} + +static int print_instance_id_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct nlattr *func[NL80211_NAN_FUNC_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb[NL80211_ATTR_COOKIE]) { + fprintf(stderr, "cookie is missing!\n"); + return NL_SKIP; + } + + nla_parse_nested(func, NL80211_NAN_FUNC_ATTR_MAX, + tb[NL80211_ATTR_NAN_FUNC], + NULL); + if (!func[NL80211_NAN_FUNC_INSTANCE_ID]) { + fprintf(stderr, "instance id is missing!\n"); + return NL_SKIP; + } + + printf("instance_id: %d, cookie: %" PRIu64 "\n", + nla_get_u8(func[NL80211_NAN_FUNC_INSTANCE_ID]), + nla_get_u64(tb[NL80211_ATTR_COOKIE])); + + return NL_SKIP; +} + +static int parse_srf(char **argv, int argc, struct nl_msg *func_attrs) +{ + struct nl_msg *srf_attrs; + int old_argc = argc; + unsigned char mac_addr[ETH_ALEN]; + char *cur_mac, *sptr = NULL; + + srf_attrs = nlmsg_alloc(); + if (strcmp(argv[0], "include") == 0) + NLA_PUT_FLAG(srf_attrs, NL80211_NAN_SRF_INCLUDE); + else if (strcmp(argv[0], "exclude") != 0) + return -EINVAL; + + argc--; + argv++; + if (strcmp(argv[0], "bf") == 0) { + unsigned char *srf; + size_t srf_len; + __u8 bf_idx; + int err; + + argc--; + argv++; + + if (argc < 3) + return -EINVAL; + + bf_idx = atoi(argv[0]); + NLA_PUT_U8(srf_attrs, NL80211_NAN_SRF_BF_IDX, bf_idx); + + argc--; + argv++; + srf_len = atoi(argv[0]); + if (srf_len == 0 || srf_len > NL80211_NAN_FUNC_SRF_MAX_LEN) + return -EINVAL; + + argc--; + argv++; + srf = malloc(srf_len); + if (!srf) + return -ENOBUFS; + + memset(srf, 0, srf_len); + cur_mac = strtok_r(argv[0], ";", &sptr); + while (cur_mac) { + if (mac_addr_a2n(mac_addr, cur_mac)) { + printf("mac format error %s\n", cur_mac); + free(srf); + return -EINVAL; + } + + nan_bf(bf_idx, srf, srf_len, mac_addr, ETH_ALEN); + cur_mac = strtok_r(NULL, ";", &sptr); + } + + err = nla_put(srf_attrs, NL80211_NAN_SRF_BF, srf_len, srf); + free(srf); + if (err) + goto nla_put_failure; + argv++; + argc--; + } else if (strcmp(argv[0], "list") == 0) { + struct nlattr *nl_macs = nla_nest_start(srf_attrs, + NL80211_NAN_SRF_MAC_ADDRS); + int i = 0; + + argc--; + argv++; + cur_mac = strtok_r(argv[0], ";", &sptr); + while (cur_mac) { + if (mac_addr_a2n(mac_addr, cur_mac)) + return -EINVAL; + + nla_put(srf_attrs, ++i, ETH_ALEN, mac_addr); + cur_mac = strtok_r(NULL, ";", &sptr); + } + + nla_nest_end(srf_attrs, nl_macs); + argv++; + argc--; + } else { + return -EINVAL; + } + + nla_put_nested(func_attrs, NL80211_NAN_FUNC_SRF, srf_attrs); + return old_argc - argc; +nla_put_failure: + return -ENOBUFS; +} + +static void parse_match_filter(char *filter, struct nl_msg *func_attrs, int tx) +{ + struct nlattr *nl_filt; + char *cur_filt, *sptr = NULL; + int i = 0; + + if (tx) + nl_filt = nla_nest_start(func_attrs, + NL80211_NAN_FUNC_TX_MATCH_FILTER); + else + nl_filt = nla_nest_start(func_attrs, + NL80211_NAN_FUNC_RX_MATCH_FILTER); + + cur_filt = strtok_r(filter, ":", &sptr); + while (cur_filt) { + if (strcmp(cur_filt, "*") != 0) + nla_put(func_attrs, ++i, strlen(cur_filt), cur_filt); + else + nla_put(func_attrs, ++i, 0, NULL); + + cur_filt = strtok_r(NULL, ":", &sptr); + } + + nla_nest_end(func_attrs, nl_filt); +} + +static int handle_nan_add_func(struct nl80211_state *state, + struct nl_msg *msg, int argc, char **argv, + enum id_input id) +{ + struct nl_msg *func_attrs = NULL; + int err = 0; + __u8 type; + + func_attrs = nlmsg_alloc(); + if (!func_attrs) { + err = -ENOBUFS; + goto out; + } + + if (argc > 1 && strcmp(argv[0], "type") == 0) { + argv++; + argc--; + if (strcmp(argv[0], "publish") == 0) + type = NL80211_NAN_FUNC_PUBLISH; + else if (strcmp(argv[0], "subscribe") == 0) + type = NL80211_NAN_FUNC_SUBSCRIBE; + else if (strcmp(argv[0], "followup") == 0) + type = NL80211_NAN_FUNC_FOLLOW_UP; + else + return -EINVAL; + argv++; + argc--; + + NLA_PUT_U8(func_attrs, NL80211_NAN_FUNC_TYPE, type); + } else { + return -EINVAL; + } + + if (type == NL80211_NAN_FUNC_SUBSCRIBE) { + if (argc > 1 && strcmp(argv[0], "active") == 0) { + argv++; + argc--; + NLA_PUT_FLAG(func_attrs, + NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE); + } + } + + if (type == NL80211_NAN_FUNC_PUBLISH) { + __u8 publish_type = 0; + + if (argc > 1 && strcmp(argv[0], "solicited") == 0) { + argv++; + argc--; + publish_type |= NL80211_NAN_SOLICITED_PUBLISH; + } + + if (argc > 1 && strcmp(argv[0], "unsolicited") == 0) { + argv++; + argc--; + publish_type |= NL80211_NAN_UNSOLICITED_PUBLISH; + } + + NLA_PUT_U8(func_attrs, NL80211_NAN_FUNC_PUBLISH_TYPE, + publish_type); + + /* only allow for solicited publish */ + if (argc > 1 && strcmp(argv[0], "bcast") == 0) { + argv++; + argc--; + if (!(publish_type & NL80211_NAN_SOLICITED_PUBLISH)) + return -EINVAL; + + NLA_PUT_FLAG(func_attrs, + NL80211_NAN_FUNC_PUBLISH_BCAST); + } + } + + if (argc > 1 && strcmp(argv[0], "close_range") == 0) { + argv++; + argc--; + NLA_PUT_FLAG(func_attrs, NL80211_NAN_FUNC_CLOSE_RANGE); + } + + if (argc > 1 && strcmp(argv[0], "name") == 0) { + unsigned char serv_id_c[6] = {0}; + __u64 service_id; + + argv++; + argc--; + compute_service_id((const unsigned char *)argv[0], + strlen(argv[0]), serv_id_c); + service_id = (__u64)serv_id_c[0] << 0 | + (__u64)serv_id_c[1] << 8 | + (__u64)serv_id_c[2] << 16 | + (__u64)serv_id_c[3] << 24 | + (__u64)serv_id_c[4] << 32 | + (__u64)serv_id_c[5] << 40; + + NLA_PUT(func_attrs, NL80211_NAN_FUNC_SERVICE_ID, 6, + &service_id); + argv++; + argc--; + } else { + return -EINVAL; + } + + if (argc > 1 && strcmp(argv[0], "info") == 0) { + argv++; + argc--; + NLA_PUT(func_attrs, NL80211_NAN_FUNC_SERVICE_INFO, + strlen(argv[0]), argv[0]); + argv++; + argc--; + } + + if (type == NL80211_NAN_FUNC_FOLLOW_UP) { + if (argc > 1 && strcmp(argv[0], "flw_up_id") == 0) { + argv++; + argc--; + NLA_PUT_U8(func_attrs, NL80211_NAN_FUNC_FOLLOW_UP_ID, + atoi(argv[0])); + argv++; + argc--; + } + + if (argc > 1 && strcmp(argv[0], "flw_up_req_id") == 0) { + argv++; + argc--; + NLA_PUT_U8(func_attrs, + NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID, + atoi(argv[0])); + argv++; + argc--; + } + + if (argc > 1 && strcmp(argv[0], "flw_up_dest") == 0) { + unsigned char addr[6]; + + argv++; + argc--; + if (mac_addr_a2n(addr, argv[0])) + goto nla_put_failure; + nla_put(func_attrs, NL80211_NAN_FUNC_FOLLOW_UP_DEST, + ETH_ALEN, addr); + argv++; + argc--; + } + } + + if (type != NL80211_NAN_FUNC_FOLLOW_UP && + argc > 1 && strcmp(argv[0], "ttl") == 0) { + argv++; + argc--; + NLA_PUT_U32(func_attrs, NL80211_NAN_FUNC_TTL, atoi(argv[0])); + argv++; + argc--; + } + + if (type != NL80211_NAN_FUNC_FOLLOW_UP && + argc >= 4 && strcmp(argv[0], "srf") == 0) { + int res; + + argv++; + argc--; + res = parse_srf(argv, argc, func_attrs); + if (res < 0) + return -EINVAL; + + argc -= res; + argv += res; + } + + if (type != NL80211_NAN_FUNC_FOLLOW_UP && + argc > 1 && strcmp(argv[0], "rx_filter") == 0) { + argv++; + argc--; + parse_match_filter(argv[0], func_attrs, 0); + + argv++; + argc--; + } + + if (type != NL80211_NAN_FUNC_FOLLOW_UP && + argc > 1 && strcmp(argv[0], "tx_filter") == 0) { + argv++; + argc--; + parse_match_filter(argv[0], func_attrs, 1); + + argv++; + argc--; + } + + if (argc != 0) + return -EINVAL; + + nla_put_nested(msg, NL80211_ATTR_NAN_FUNC, func_attrs); + register_handler(print_instance_id_handler, NULL); + + return err; +nla_put_failure: + return -ENOBUFS; +out: + return err; +} +COMMAND(nan, add_func, + "type <publish|subscribe|followup> [active] [solicited] [unsolicited] [bcast] [close_range] name <name> [info <info>] [flw_up_id <id> flw_up_req_id <id> flw_up_dest <mac>] [ttl <ttl>] [srf <include|exclude> <bf|list> [bf_idx] [bf_len] <mac1;mac2...>] [rx_filter <str1:str2...>] [tx_filter <str1:str2...>]", + NL80211_CMD_ADD_NAN_FUNCTION, 0, CIB_WDEV, + handle_nan_add_func, ""); @@ -10,6 +10,8 @@ * Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez@atheros.com> * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com> * Copyright 2008 Colin McCabe <colin@cozybit.com> + * Copyright 2015-2017 Intel Deutschland GmbH + * Copyright (C) 2018-2022 Intel Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -47,8 +49,14 @@ #define NL80211_MULTICAST_GROUP_REG "regulatory" #define NL80211_MULTICAST_GROUP_MLME "mlme" #define NL80211_MULTICAST_GROUP_VENDOR "vendor" +#define NL80211_MULTICAST_GROUP_NAN "nan" #define NL80211_MULTICAST_GROUP_TESTMODE "testmode" +#define NL80211_EDMG_BW_CONFIG_MIN 4 +#define NL80211_EDMG_BW_CONFIG_MAX 15 +#define NL80211_EDMG_CHANNELS_MIN 1 +#define NL80211_EDMG_CHANNELS_MAX 0x3c /* 0b00111100 */ + /** * DOC: Station handling * @@ -171,6 +179,151 @@ */ /** + * DOC: WPA/WPA2 EAPOL handshake offload + * + * By setting @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK flag drivers + * can indicate they support offloading EAPOL handshakes for WPA/WPA2 + * preshared key authentication in station mode. In %NL80211_CMD_CONNECT + * the preshared key should be specified using %NL80211_ATTR_PMK. Drivers + * supporting this offload may reject the %NL80211_CMD_CONNECT when no + * preshared key material is provided, for example when that driver does + * not support setting the temporal keys through %NL80211_CMD_NEW_KEY. + * + * Similarly @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X flag can be + * set by drivers indicating offload support of the PTK/GTK EAPOL + * handshakes during 802.1X authentication in station mode. In order to + * use the offload the %NL80211_CMD_CONNECT should have + * %NL80211_ATTR_WANT_1X_4WAY_HS attribute flag. Drivers supporting this + * offload may reject the %NL80211_CMD_CONNECT when the attribute flag is + * not present. + * + * By setting @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK flag drivers + * can indicate they support offloading EAPOL handshakes for WPA/WPA2 + * preshared key authentication in AP mode. In %NL80211_CMD_START_AP + * the preshared key should be specified using %NL80211_ATTR_PMK. Drivers + * supporting this offload may reject the %NL80211_CMD_START_AP when no + * preshared key material is provided, for example when that driver does + * not support setting the temporal keys through %NL80211_CMD_NEW_KEY. + * + * For 802.1X the PMK or PMK-R0 are set by providing %NL80211_ATTR_PMK + * using %NL80211_CMD_SET_PMK. For offloaded FT support also + * %NL80211_ATTR_PMKR0_NAME must be provided. + */ + +/** + * DOC: FILS shared key authentication offload + * + * FILS shared key authentication offload can be advertized by drivers by + * setting @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD flag. The drivers that support + * FILS shared key authentication offload should be able to construct the + * authentication and association frames for FILS shared key authentication and + * eventually do a key derivation as per IEEE 802.11ai. The below additional + * parameters should be given to driver in %NL80211_CMD_CONNECT and/or in + * %NL80211_CMD_UPDATE_CONNECT_PARAMS. + * %NL80211_ATTR_FILS_ERP_USERNAME - used to construct keyname_nai + * %NL80211_ATTR_FILS_ERP_REALM - used to construct keyname_nai + * %NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used to construct erp message + * %NL80211_ATTR_FILS_ERP_RRK - used to generate the rIK and rMSK + * rIK should be used to generate an authentication tag on the ERP message and + * rMSK should be used to derive a PMKSA. + * rIK, rMSK should be generated and keyname_nai, sequence number should be used + * as specified in IETF RFC 6696. + * + * When FILS shared key authentication is completed, driver needs to provide the + * below additional parameters to userspace, which can be either after setting + * up a connection or after roaming. + * %NL80211_ATTR_FILS_KEK - used for key renewal + * %NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used in further EAP-RP exchanges + * %NL80211_ATTR_PMKID - used to identify the PMKSA used/generated + * %Nl80211_ATTR_PMK - used to update PMKSA cache in userspace + * The PMKSA can be maintained in userspace persistently so that it can be used + * later after reboots or wifi turn off/on also. + * + * %NL80211_ATTR_FILS_CACHE_ID is the cache identifier advertized by a FILS + * capable AP supporting PMK caching. It specifies the scope within which the + * PMKSAs are cached in an ESS. %NL80211_CMD_SET_PMKSA and + * %NL80211_CMD_DEL_PMKSA are enhanced to allow support for PMKSA caching based + * on FILS cache identifier. Additionally %NL80211_ATTR_PMK is used with + * %NL80211_SET_PMKSA to specify the PMK corresponding to a PMKSA for driver to + * use in a FILS shared key connection with PMKSA caching. + */ + +/** + * DOC: SAE authentication offload + * + * By setting @NL80211_EXT_FEATURE_SAE_OFFLOAD flag drivers can indicate they + * support offloading SAE authentication for WPA3-Personal networks in station + * mode. Similarly @NL80211_EXT_FEATURE_SAE_OFFLOAD_AP flag can be set by + * drivers indicating the offload support in AP mode. + * + * The password for SAE should be specified using %NL80211_ATTR_SAE_PASSWORD in + * %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP for station and AP mode + * respectively. + */ + +/** + * DOC: VLAN offload support for setting group keys and binding STAs to VLANs + * + * By setting @NL80211_EXT_FEATURE_VLAN_OFFLOAD flag drivers can indicate they + * support offloading VLAN functionality in a manner where the driver exposes a + * single netdev that uses VLAN tagged frames and separate VLAN-specific netdevs + * can then be added using RTM_NEWLINK/IFLA_VLAN_ID similarly to the Ethernet + * case. Frames received from stations that are not assigned to any VLAN are + * delivered on the main netdev and frames to such stations can be sent through + * that main netdev. + * + * %NL80211_CMD_NEW_KEY (for group keys), %NL80211_CMD_NEW_STATION, and + * %NL80211_CMD_SET_STATION will optionally specify vlan_id using + * %NL80211_ATTR_VLAN_ID. + */ + +/** + * DOC: TID configuration + * + * TID config support can be checked in the %NL80211_ATTR_TID_CONFIG + * attribute given in wiphy capabilities. + * + * The necessary configuration parameters are mentioned in + * &enum nl80211_tid_config_attr and it will be passed to the + * %NL80211_CMD_SET_TID_CONFIG command in %NL80211_ATTR_TID_CONFIG. + * + * If the configuration needs to be applied for specific peer then the MAC + * address of the peer needs to be passed in %NL80211_ATTR_MAC, otherwise the + * configuration will be applied for all the connected peers in the vif except + * any peers that have peer specific configuration for the TID by default; if + * the %NL80211_TID_CONFIG_ATTR_OVERRIDE flag is set, peer specific values + * will be overwritten. + * + * All this configuration is valid only for STA's current connection + * i.e. the configuration will be reset to default when the STA connects back + * after disconnection/roaming, and this configuration will be cleared when + * the interface goes down. + */ + +/** + * DOC: FILS shared key crypto offload + * + * This feature is applicable to drivers running in AP mode. + * + * FILS shared key crypto offload can be advertised by drivers by setting + * @NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD flag. The drivers that support + * FILS shared key crypto offload should be able to encrypt and decrypt + * association frames for FILS shared key authentication as per IEEE 802.11ai. + * With this capability, for FILS key derivation, drivers depend on userspace. + * + * After FILS key derivation, userspace shares the FILS AAD details with the + * driver and the driver stores the same to use in decryption of association + * request and in encryption of association response. The below parameters + * should be given to the driver in %NL80211_CMD_SET_FILS_AAD. + * %NL80211_ATTR_MAC - STA MAC address, used for storing FILS AAD per STA + * %NL80211_ATTR_FILS_KEK - Used for encryption or decryption + * %NL80211_ATTR_FILS_NONCES - Used for encryption or decryption + * (STA Nonce 16 bytes followed by AP Nonce 16 bytes) + * + * Once the association is done, the driver cleans the FILS AAD data. + */ + +/** * enum nl80211_commands - supported nl80211 commands * * @NL80211_CMD_UNSPEC: unspecified command to catch errors @@ -179,13 +332,14 @@ * to get a list of all present wiphys. * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME, - * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ (and the - * attributes determining the channel width; this is used for setting - * monitor mode channel), %NL80211_ATTR_WIPHY_RETRY_SHORT, - * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD, - * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD. - * However, for setting the channel, see %NL80211_CMD_SET_CHANNEL - * instead, the support here is for backward compatibility only. + * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, + * %NL80211_ATTR_WIPHY_FREQ_OFFSET (and the attributes determining the + * channel width; this is used for setting monitor mode channel), + * %NL80211_ATTR_WIPHY_RETRY_SHORT, %NL80211_ATTR_WIPHY_RETRY_LONG, + * %NL80211_ATTR_WIPHY_FRAG_THRESHOLD, and/or + * %NL80211_ATTR_WIPHY_RTS_THRESHOLD. However, for setting the channel, + * see %NL80211_CMD_SET_CHANNEL instead, the support here is for backward + * compatibility only. * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request * or rename notification. Has attributes %NL80211_ATTR_WIPHY and * %NL80211_ATTR_WIPHY_NAME. @@ -206,7 +360,10 @@ * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from * userspace to request deletion of a virtual interface, then requires - * attribute %NL80211_ATTR_IFINDEX. + * attribute %NL80211_ATTR_IFINDEX. If multiple BSSID advertisements are + * enabled using %NL80211_ATTR_MBSSID_CONFIG, %NL80211_ATTR_MBSSID_ELEMS, + * and if this command is used for the transmitting interface, then all + * the non-transmitting interfaces are deleted as well. * * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. @@ -234,7 +391,8 @@ * %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_INACTIVITY_TIMEOUT, * %NL80211_ATTR_ACL_POLICY and %NL80211_ATTR_MAC_ADDRS. * The channel to use can be set on the interface or be given using the - * %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width. + * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_FREQ_OFFSET, and the + * attributes determining channel width. * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP @@ -244,7 +402,7 @@ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the - * the interface identified by %NL80211_ATTR_IFINDEX. + * interface identified by %NL80211_ATTR_IFINDEX. * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC * or, if no MAC address given, all stations, on the interface identified * by %NL80211_ATTR_IFINDEX. %NL80211_ATTR_MGMT_SUBTYPE and @@ -264,7 +422,7 @@ * @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by * %NL80211_ATTR_MAC. * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the - * the interface identified by %NL80211_ATTR_IFINDEX. + * interface identified by %NL80211_ATTR_IFINDEX. * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC * or, if no MAC address given, all mesh paths, on the interface identified * by %NL80211_ATTR_IFINDEX. @@ -321,14 +479,24 @@ * @NL80211_CMD_GET_SCAN: get scan results * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters * %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the - * probe requests at CCK rate or not. + * probe requests at CCK rate or not. %NL80211_ATTR_BSSID can be used to + * specify a BSSID to scan for; if not included, the wildcard BSSID will + * be used. * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to * NL80211_CMD_GET_SCAN and on the "scan" multicast group) * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, * partial scan results may be available * * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan at certain - * intervals, as specified by %NL80211_ATTR_SCHED_SCAN_INTERVAL. + * intervals and certain number of cycles, as specified by + * %NL80211_ATTR_SCHED_SCAN_PLANS. If %NL80211_ATTR_SCHED_SCAN_PLANS is + * not specified and only %NL80211_ATTR_SCHED_SCAN_INTERVAL is specified, + * scheduled scan will run in an infinite loop with the specified interval. + * These attributes are mutually exculsive, + * i.e. NL80211_ATTR_SCHED_SCAN_INTERVAL must not be passed if + * NL80211_ATTR_SCHED_SCAN_PLANS is defined. + * If for some reason scheduled scan is aborted by the driver, all scan + * plans are canceled (including scan plans that did not start yet). * Like with normal scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS) * are passed, they are used in the probe requests. For * broadcast, a broadcast SSID must be passed (ie. an empty @@ -339,7 +507,9 @@ * are used. Extra IEs can also be passed from the userspace by * using the %NL80211_ATTR_IE attribute. The first cycle of the * scheduled scan can be delayed by %NL80211_ATTR_SCHED_SCAN_DELAY - * is supplied. + * is supplied. If the device supports multiple concurrent scheduled + * scans, it will allow such when the caller provides the flag attribute + * %NL80211_ATTR_SCHED_SCAN_MULTI to indicate user-space support for it. * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT if * scheduled scan is not running. The caller may assume that as soon * as the call returns, it is safe to start a new scheduled scan again. @@ -358,10 +528,18 @@ * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to * NL80211_CMD_GET_SURVEY and on the "scan" multicast group) * - * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry, using %NL80211_ATTR_MAC - * (for the BSSID) and %NL80211_ATTR_PMKID. + * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry using %NL80211_ATTR_MAC + * (for the BSSID), %NL80211_ATTR_PMKID, and optionally %NL80211_ATTR_PMK + * (PMK is used for PTKSA derivation in case of FILS shared key offload) or + * using %NL80211_ATTR_SSID, %NL80211_ATTR_FILS_CACHE_ID, + * %NL80211_ATTR_PMKID, and %NL80211_ATTR_PMK in case of FILS + * authentication where %NL80211_ATTR_FILS_CACHE_ID is the identifier + * advertized by a FILS capable AP identifying the scope of PMKSA in an + * ESS. * @NL80211_CMD_DEL_PMKSA: Delete a PMKSA cache entry, using %NL80211_ATTR_MAC - * (for the BSSID) and %NL80211_ATTR_PMKID. + * (for the BSSID) and %NL80211_ATTR_PMKID or using %NL80211_ATTR_SSID, + * %NL80211_ATTR_FILS_CACHE_ID, and %NL80211_ATTR_PMKID in case of FILS + * authentication. * @NL80211_CMD_FLUSH_PMKSA: Flush all PMKSA cache entries. * * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain @@ -399,11 +577,12 @@ * interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and * BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify * the SSID (mainly for association, but is included in authentication - * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used - * to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE - * is used to specify the authentication type. %NL80211_ATTR_IE is used to - * define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs) - * to be added to the frame. + * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ + + * %NL80211_ATTR_WIPHY_FREQ_OFFSET is used to specify the frequence of the + * channel in MHz. %NL80211_ATTR_AUTH_TYPE is used to specify the + * authentication type. %NL80211_ATTR_IE is used to define IEs + * (VendorSpecificInfo, but also including RSN IE and FT IEs) to be added + * to the frame. * When used as an event, this reports reception of an Authentication * frame in station and IBSS modes when the local MLME processed the * frame, i.e., it was for the local STA and was received in correct @@ -418,7 +597,11 @@ * @NL80211_CMD_ASSOCIATE: association request and notification; like * NL80211_CMD_AUTHENTICATE but for Association and Reassociation * (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request, - * MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives). + * MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives). The + * %NL80211_ATTR_PREV_BSSID attribute is used to specify whether the + * request is for the initial association to an ESS (that attribute not + * included) or for reassociation within the ESS (that attribute is + * included). * @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like * NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to * MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication @@ -454,10 +637,12 @@ * requests to connect to a specified network but without separating * auth and assoc steps. For this, you need to specify the SSID in a * %NL80211_ATTR_SSID attribute, and can optionally specify the association - * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP, - * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, + * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, + * %NL80211_ATTR_USE_MFP, %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, + * %NL80211_ATTR_WIPHY_FREQ_OFFSET, %NL80211_ATTR_CONTROL_PORT, * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, - * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, + * %NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and * %NL80211_ATTR_WIPHY_FREQ_HINT. * If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are * restrictions on BSS selection, i.e., they effectively prevent roaming @@ -468,6 +653,17 @@ * set of BSSID,frequency parameters is used (i.e., either the enforcing * %NL80211_ATTR_MAC,%NL80211_ATTR_WIPHY_FREQ or the less strict * %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT). + * Driver shall not modify the IEs specified through %NL80211_ATTR_IE if + * %NL80211_ATTR_MAC is included. However, if %NL80211_ATTR_MAC_HINT is + * included, these IEs through %NL80211_ATTR_IE are specified by the user + * space based on the best possible BSS selected. Thus, if the driver ends + * up selecting a different BSS, it can modify these IEs accordingly (e.g. + * userspace asks the driver to perform PMKSA caching with BSS1 and the + * driver ends up selecting BSS2 with different PMKSA cache entry; RSNIE + * has to get updated with the apt PMKID). + * %NL80211_ATTR_PREV_BSSID can be used to request a reassociation within + * the ESS in case the device is already associated and an association with + * a different BSS is desired. * Background scan period can optionally be * specified in %NL80211_ATTR_BG_SCAN_PERIOD, * if not specified default background scan configuration @@ -475,9 +671,19 @@ * This attribute is ignored if driver does not support roam scan. * It is also sent as an event, with the BSSID and response IEs when the * connection is established or failed to be established. This can be - * determined by the STATUS_CODE attribute. - * @NL80211_CMD_ROAM: request that the card roam (currently not implemented), - * sent as an event when the card/driver roamed by itself. + * determined by the %NL80211_ATTR_STATUS_CODE attribute (0 = success, + * non-zero = failure). If %NL80211_ATTR_TIMED_OUT is included in the + * event, the connection attempt failed due to not being able to initiate + * authentication/association or not receiving a response from the AP. + * Non-zero %NL80211_ATTR_STATUS_CODE value is indicated in that case as + * well to remain backwards compatible. + * @NL80211_CMD_ROAM: Notification indicating the card/driver roamed by itself. + * When a security association was established on an 802.1X network using + * fast transition, this event should be followed by an + * %NL80211_CMD_PORT_AUTHORIZED event. + * Following a %NL80211_CMD_ROAM event userspace can issue + * %NL80211_CMD_GET_SCAN in order to obtain the scan information for the + * new BSS the card/driver roamed to. * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify * userspace that a connection was dropped by the AP or due to other * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and @@ -523,6 +729,10 @@ * four bytes for vendor frames including the OUI. The registration * cannot be dropped, but is removed automatically when the netlink * socket is closed. Multiple registrations can be made. + * The %NL80211_ATTR_RECEIVE_MULTICAST flag attribute can be given if + * %NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS is available, in which + * case the registration can also be modified to include/exclude the + * flag, rather than requiring unregistration to change it. * @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for * backward compatibility * @NL80211_CMD_FRAME: Management frame TX request and RX notification. This @@ -545,7 +755,9 @@ * is used during CSA period. * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this * command may be used with the corresponding cookie to cancel the wait - * time if it is known that it is no longer necessary. + * time if it is known that it is no longer necessary. This command is + * also sent as an event whenever the driver has completed the off-channel + * wait time. * @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility. * @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame * transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies @@ -574,7 +786,22 @@ * of any other interfaces, and other interfaces will again take * precedence when they are used. * - * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface. + * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface + * (no longer supported). + * + * @NL80211_CMD_SET_MULTICAST_TO_UNICAST: Configure if this AP should perform + * multicast to unicast conversion. When enabled, all multicast packets + * with ethertype ARP, IPv4 or IPv6 (possibly within an 802.1Q header) + * will be sent out to each station once with the destination (multicast) + * MAC address replaced by the station's MAC address. Note that this may + * break certain expectations of the receiver, e.g. the ability to drop + * unicast IP packets encapsulated in multicast L2 frames, or the ability + * to not send destination unreachable messages in such cases. + * This can only be toggled per BSS. Configure this on an interface of + * type %NL80211_IFTYPE_AP. It applies to all its VLAN interfaces + * (%NL80211_IFTYPE_AP_VLAN), except for those in 4addr (WDS) mode. + * If %NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED is not present with this + * command, the feature is disabled. * * @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial * mesh config parameters may be given. @@ -606,7 +833,7 @@ * various triggers. These triggers can be configured through this * command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For * more background information, see - * http://wireless.kernel.org/en/users/Documentation/WoWLAN. + * https://wireless.wiki.kernel.org/en/users/Documentation/WoWLAN. * The @NL80211_CMD_SET_WOWLAN command can also be used as a notification * from the driver reporting the wakeup reason. In this case, the * @NL80211_ATTR_WOWLAN_TRIGGERS attribute will contain the reason @@ -746,7 +973,7 @@ * @NL80211_CMD_SET_COALESCE: Configure coalesce rules or clear existing rules. * * @NL80211_CMD_CHANNEL_SWITCH: Perform a channel switch by announcing the - * the new channel information (Channel Switch Announcement - CSA) + * new channel information (Channel Switch Announcement - CSA) * in the beacon for some time (as defined in the * %NL80211_ATTR_CH_SWITCH_COUNT parameter) and then change to the * new channel. Userspace provides the new channel information (using @@ -811,6 +1038,205 @@ * as an event to indicate changes for devices with wiphy-specific regdom * management. * + * @NL80211_CMD_ABORT_SCAN: Stop an ongoing scan. Returns -ENOENT if a scan is + * not running. The driver indicates the status of the scan through + * cfg80211_scan_done(). + * + * @NL80211_CMD_START_NAN: Start NAN operation, identified by its + * %NL80211_ATTR_WDEV interface. This interface must have been + * previously created with %NL80211_CMD_NEW_INTERFACE. After it + * has been started, the NAN interface will create or join a + * cluster. This command must have a valid + * %NL80211_ATTR_NAN_MASTER_PREF attribute and optional + * %NL80211_ATTR_BANDS attributes. If %NL80211_ATTR_BANDS is + * omitted or set to 0, it means don't-care and the device will + * decide what to use. After this command NAN functions can be + * added. + * @NL80211_CMD_STOP_NAN: Stop the NAN operation, identified by + * its %NL80211_ATTR_WDEV interface. + * @NL80211_CMD_ADD_NAN_FUNCTION: Add a NAN function. The function is defined + * with %NL80211_ATTR_NAN_FUNC nested attribute. When called, this + * operation returns the strictly positive and unique instance id + * (%NL80211_ATTR_NAN_FUNC_INST_ID) and a cookie (%NL80211_ATTR_COOKIE) + * of the function upon success. + * Since instance ID's can be re-used, this cookie is the right + * way to identify the function. This will avoid races when a termination + * event is handled by the user space after it has already added a new + * function that got the same instance id from the kernel as the one + * which just terminated. + * This cookie may be used in NAN events even before the command + * returns, so userspace shouldn't process NAN events until it processes + * the response to this command. + * Look at %NL80211_ATTR_SOCKET_OWNER as well. + * @NL80211_CMD_DEL_NAN_FUNCTION: Delete a NAN function by cookie. + * This command is also used as a notification sent when a NAN function is + * terminated. This will contain a %NL80211_ATTR_NAN_FUNC_INST_ID + * and %NL80211_ATTR_COOKIE attributes. + * @NL80211_CMD_CHANGE_NAN_CONFIG: Change current NAN + * configuration. NAN must be operational (%NL80211_CMD_START_NAN + * was executed). It must contain at least one of the following + * attributes: %NL80211_ATTR_NAN_MASTER_PREF, + * %NL80211_ATTR_BANDS. If %NL80211_ATTR_BANDS is omitted, the + * current configuration is not changed. If it is present but + * set to zero, the configuration is changed to don't-care + * (i.e. the device can decide what to do). + * @NL80211_CMD_NAN_FUNC_MATCH: Notification sent when a match is reported. + * This will contain a %NL80211_ATTR_NAN_MATCH nested attribute and + * %NL80211_ATTR_COOKIE. + * + * @NL80211_CMD_UPDATE_CONNECT_PARAMS: Update one or more connect parameters + * for subsequent roaming cases if the driver or firmware uses internal + * BSS selection. This command can be issued only while connected and it + * does not result in a change for the current association. Currently, + * only the %NL80211_ATTR_IE data is used and updated with this command. + * + * @NL80211_CMD_SET_PMK: For offloaded 4-Way handshake, set the PMK or PMK-R0 + * for the given authenticator address (specified with %NL80211_ATTR_MAC). + * When %NL80211_ATTR_PMKR0_NAME is set, %NL80211_ATTR_PMK specifies the + * PMK-R0, otherwise it specifies the PMK. + * @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously + * configured PMK for the authenticator address identified by + * %NL80211_ATTR_MAC. + * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates an 802.1X FT roam was + * completed successfully. Drivers that support 4 way handshake offload + * should send this event after indicating 802.1X FT assocation with + * %NL80211_CMD_ROAM. If the 4 way handshake failed %NL80211_CMD_DISCONNECT + * should be indicated instead. + * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request + * and RX notification. This command is used both as a request to transmit + * a control port frame and as a notification that a control port frame + * has been received. %NL80211_ATTR_FRAME is used to specify the + * frame contents. The frame is the raw EAPoL data, without ethernet or + * 802.11 headers. + * When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added + * indicating the protocol type of the received frame; whether the frame + * was received unencrypted and the MAC address of the peer respectively. + * + * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded. + * + * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host + * drivers that do not define separate commands for authentication and + * association, but rely on user space for the authentication to happen. + * This interface acts both as the event request (driver to user space) + * to trigger the authentication and command response (userspace to + * driver) to indicate the authentication status. + * + * User space uses the %NL80211_CMD_CONNECT command to the host driver to + * trigger a connection. The host driver selects a BSS and further uses + * this interface to offload only the authentication part to the user + * space. Authentication frames are passed between the driver and user + * space through the %NL80211_CMD_FRAME interface. Host driver proceeds + * further with the association after getting successful authentication + * status. User space indicates the authentication status through + * %NL80211_ATTR_STATUS_CODE attribute in %NL80211_CMD_EXTERNAL_AUTH + * command interface. + * + * Host driver reports this status on an authentication failure to the + * user space through the connect result as the user space would have + * initiated the connection through the connect request. + * + * @NL80211_CMD_STA_OPMODE_CHANGED: An event that notify station's + * ht opmode or vht opmode changes using any of %NL80211_ATTR_SMPS_MODE, + * %NL80211_ATTR_CHANNEL_WIDTH,%NL80211_ATTR_NSS attributes with its + * address(specified in %NL80211_ATTR_MAC). + * + * @NL80211_CMD_GET_FTM_RESPONDER_STATS: Retrieve FTM responder statistics, in + * the %NL80211_ATTR_FTM_RESPONDER_STATS attribute. + * + * @NL80211_CMD_PEER_MEASUREMENT_START: start a (set of) peer measurement(s) + * with the given parameters, which are encapsulated in the nested + * %NL80211_ATTR_PEER_MEASUREMENTS attribute. Optionally, MAC address + * randomization may be enabled and configured by specifying the + * %NL80211_ATTR_MAC and %NL80211_ATTR_MAC_MASK attributes. + * If a timeout is requested, use the %NL80211_ATTR_TIMEOUT attribute. + * A u64 cookie for further %NL80211_ATTR_COOKIE use is returned in + * the netlink extended ack message. + * + * To cancel a measurement, close the socket that requested it. + * + * Measurement results are reported to the socket that requested the + * measurement using @NL80211_CMD_PEER_MEASUREMENT_RESULT when they + * become available, so applications must ensure a large enough socket + * buffer size. + * + * Depending on driver support it may or may not be possible to start + * multiple concurrent measurements. + * @NL80211_CMD_PEER_MEASUREMENT_RESULT: This command number is used for the + * result notification from the driver to the requesting socket. + * @NL80211_CMD_PEER_MEASUREMENT_COMPLETE: Notification only, indicating that + * the measurement completed, using the measurement cookie + * (%NL80211_ATTR_COOKIE). + * + * @NL80211_CMD_NOTIFY_RADAR: Notify the kernel that a radar signal was + * detected and reported by a neighboring device on the channel + * indicated by %NL80211_ATTR_WIPHY_FREQ and other attributes + * determining the width and type. + * + * @NL80211_CMD_UPDATE_OWE_INFO: This interface allows the host driver to + * offload OWE processing to user space. This intends to support + * OWE AKM by the host drivers that implement SME but rely + * on the user space for the cryptographic/DH IE processing in AP mode. + * + * @NL80211_CMD_PROBE_MESH_LINK: The requirement for mesh link metric + * refreshing, is that from one mesh point we be able to send some data + * frames to other mesh points which are not currently selected as a + * primary traffic path, but which are only 1 hop away. The absence of + * the primary path to the chosen node makes it necessary to apply some + * form of marking on a chosen packet stream so that the packets can be + * properly steered to the selected node for testing, and not by the + * regular mesh path lookup. Further, the packets must be of type data + * so that the rate control (often embedded in firmware) is used for + * rate selection. + * + * Here attribute %NL80211_ATTR_MAC is used to specify connected mesh + * peer MAC address and %NL80211_ATTR_FRAME is used to specify the frame + * content. The frame is ethernet data. + * + * @NL80211_CMD_SET_TID_CONFIG: Data frame TID specific configuration + * is passed using %NL80211_ATTR_TID_CONFIG attribute. + * + * @NL80211_CMD_UNPROT_BEACON: Unprotected or incorrectly protected Beacon + * frame. This event is used to indicate that a received Beacon frame was + * dropped because it did not include a valid MME MIC while beacon + * protection was enabled (BIGTK configured in station mode). + * + * @NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS: Report TX status of a control + * port frame transmitted with %NL80211_CMD_CONTROL_PORT_FRAME. + * %NL80211_ATTR_COOKIE identifies the TX command and %NL80211_ATTR_FRAME + * includes the contents of the frame. %NL80211_ATTR_ACK flag is included + * if the recipient acknowledged the frame. + * + * @NL80211_CMD_SET_SAR_SPECS: SAR power limitation configuration is + * passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to + * specify the wiphy index to be applied to. + * + * @NL80211_CMD_OBSS_COLOR_COLLISION: This notification is sent out whenever + * mac80211/drv detects a bss color collision. + * + * @NL80211_CMD_COLOR_CHANGE_REQUEST: This command is used to indicate that + * userspace wants to change the BSS color. + * + * @NL80211_CMD_COLOR_CHANGE_STARTED: Notify userland, that a color change has + * started + * + * @NL80211_CMD_COLOR_CHANGE_ABORTED: Notify userland, that the color change has + * been aborted + * + * @NL80211_CMD_COLOR_CHANGE_COMPLETED: Notify userland that the color change + * has completed + * + * @NL80211_CMD_SET_FILS_AAD: Set FILS AAD data to the driver using - + * &NL80211_ATTR_MAC - for STA MAC address + * &NL80211_ATTR_FILS_KEK - for KEK + * &NL80211_ATTR_FILS_NONCES - for FILS Nonces + * (STA Nonce 16 bytes followed by AP Nonce 16 bytes) + * + * @NL80211_CMD_ASSOC_COMEBACK: notification about an association + * temporal rejection with comeback. The event includes %NL80211_ATTR_MAC + * to describe the BSSID address of the AP and %NL80211_ATTR_TIMEOUT to + * specify the timeout value. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -997,6 +1423,64 @@ enum nl80211_commands { NL80211_CMD_WIPHY_REG_CHANGE, + NL80211_CMD_ABORT_SCAN, + + NL80211_CMD_START_NAN, + NL80211_CMD_STOP_NAN, + NL80211_CMD_ADD_NAN_FUNCTION, + NL80211_CMD_DEL_NAN_FUNCTION, + NL80211_CMD_CHANGE_NAN_CONFIG, + NL80211_CMD_NAN_MATCH, + + NL80211_CMD_SET_MULTICAST_TO_UNICAST, + + NL80211_CMD_UPDATE_CONNECT_PARAMS, + + NL80211_CMD_SET_PMK, + NL80211_CMD_DEL_PMK, + + NL80211_CMD_PORT_AUTHORIZED, + + NL80211_CMD_RELOAD_REGDB, + + NL80211_CMD_EXTERNAL_AUTH, + + NL80211_CMD_STA_OPMODE_CHANGED, + + NL80211_CMD_CONTROL_PORT_FRAME, + + NL80211_CMD_GET_FTM_RESPONDER_STATS, + + NL80211_CMD_PEER_MEASUREMENT_START, + NL80211_CMD_PEER_MEASUREMENT_RESULT, + NL80211_CMD_PEER_MEASUREMENT_COMPLETE, + + NL80211_CMD_NOTIFY_RADAR, + + NL80211_CMD_UPDATE_OWE_INFO, + + NL80211_CMD_PROBE_MESH_LINK, + + NL80211_CMD_SET_TID_CONFIG, + + NL80211_CMD_UNPROT_BEACON, + + NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS, + + NL80211_CMD_SET_SAR_SPECS, + + NL80211_CMD_OBSS_COLOR_COLLISION, + + NL80211_CMD_COLOR_CHANGE_REQUEST, + + NL80211_CMD_COLOR_CHANGE_STARTED, + NL80211_CMD_COLOR_CHANGE_ABORTED, + NL80211_CMD_COLOR_CHANGE_COMPLETED, + + NL80211_CMD_SET_FILS_AAD, + + NL80211_CMD_ASSOC_COMEBACK, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -1042,7 +1526,8 @@ enum nl80211_commands { * of &enum nl80211_chan_width, describing the channel width. See the * documentation of the enum for more information. * @NL80211_ATTR_CENTER_FREQ1: Center frequency of the first part of the - * channel, used for anything but 20 MHz bandwidth + * channel, used for anything but 20 MHz bandwidth. In S1G this is the + * operating channel center frequency. * @NL80211_ATTR_CENTER_FREQ2: Center frequency of the second part of the * channel, used only for 80+80 MHz bandwidth * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ @@ -1107,7 +1592,7 @@ enum nl80211_commands { * rates as defined by IEEE 802.11 7.3.2.2 but without the length * restriction (at most %NL80211_MAX_SUPP_RATES). * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station - * to, or the AP interface the station was originally added to to. + * to, or the AP interface the station was originally added to. * @NL80211_ATTR_STA_INFO: information about a station, part of station info * given for %NL80211_CMD_GET_STATION, nested attribute containing * info as possible, see &enum nl80211_sta_info. @@ -1219,8 +1704,12 @@ enum nl80211_commands { * * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is * used for the association (&enum nl80211_mfp, represented as a u32); - * this attribute can be used - * with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests + * this attribute can be used with %NL80211_CMD_ASSOCIATE and + * %NL80211_CMD_CONNECT requests. %NL80211_MFP_OPTIONAL is not allowed for + * %NL80211_CMD_ASSOCIATE since user space SME is expected and hence, it + * must have decided whether to use management frame protection or not. + * Setting %NL80211_MFP_OPTIONAL with a %NL80211_CMD_CONNECT request will + * let the driver (or the firmware) decide whether to use MFP or not. * * @NL80211_ATTR_STA_FLAGS2: Attribute containing a * &struct nl80211_sta_flag_update. @@ -1240,6 +1729,16 @@ enum nl80211_commands { * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom * ethertype frames used for key negotiation must not be encrypted. + * @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control + * port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE) + * will be sent directly to the network interface or sent via the NL80211 + * socket. If this attribute is missing, then legacy behavior of sending + * control port frames directly to the network interface is used. If the + * flag is included, then control port frames are sent over NL80211 instead + * using %CMD_CONTROL_PORT_FRAME. If control port routing over NL80211 is + * to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER + * flag. When used with %NL80211_ATTR_CONTROL_PORT_NO_PREAUTH, pre-auth + * frames are not forwared over the control port. * * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. * We recommend using nested, driver-specific attributes within this. @@ -1264,14 +1763,23 @@ enum nl80211_commands { * (a u32 with flags from &enum nl80211_wpa_versions). * @NL80211_ATTR_AKM_SUITES: Used with CONNECT, ASSOCIATE, and NEW_BEACON to * indicate which key management algorithm(s) to use (an array of u32). + * This attribute is also sent in response to @NL80211_CMD_GET_WIPHY, + * indicating the supported AKM suites, intended for specific drivers which + * implement SME and have constraints on which AKMs are supported and also + * the cases where an AKM support is offloaded to the driver/firmware. + * If there is no such notification from the driver, user space should + * assume the driver supports all the AKM suites. * * @NL80211_ATTR_REQ_IE: (Re)association request information elements as * sent out by the card, for ROAM and successful CONNECT events. * @NL80211_ATTR_RESP_IE: (Re)association response information elements as * sent by peer, for ROAM and successful CONNECT events. * - * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE - * commands to specify using a reassociate frame + * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used in ASSOCIATE and CONNECT + * commands to specify a request to reassociate within an ESS, i.e., to use + * Reassociate Request frame (with the value of this attribute in the + * Current AP address field) instead of Association Request frame which is + * used for the initial association to an ESS. * * @NL80211_ATTR_KEY: key information in a nested attribute with * %NL80211_KEY_* sub-attributes @@ -1311,7 +1819,14 @@ enum nl80211_commands { * enum nl80211_band value is used as the index (nla_type() of the nested * data. If a band is not included, it will be configured to allow all * rates based on negotiated supported rates information. This attribute - * is used with %NL80211_CMD_SET_TX_BITRATE_MASK. + * is used with %NL80211_CMD_SET_TX_BITRATE_MASK and with starting AP, + * and joining mesh networks (not IBSS yet). In the later case, it must + * specify just a single bitrate, which is to be used for the beacon. + * The driver must also specify support for this with the extended + * features NL80211_EXT_FEATURE_BEACON_RATE_LEGACY, + * NL80211_EXT_FEATURE_BEACON_RATE_HT, + * NL80211_EXT_FEATURE_BEACON_RATE_VHT and + * NL80211_EXT_FEATURE_BEACON_RATE_HE. * * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain * at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME. @@ -1431,7 +1946,7 @@ enum nl80211_commands { * the values passed in @NL80211_ATTR_SCAN_SSIDS (eg. if an SSID * is included in the probe request, but the match attributes * will never let it go through), -EINVAL may be returned. - * If ommited, no filtering is done. + * If omitted, no filtering is done. * * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported * interface combinations. In each nested item, it contains attributes @@ -1515,8 +2030,15 @@ enum nl80211_commands { * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire * probe-response frame. The DA field in the 802.11 header is zero-ed out, * to be filled by the FW. - * @NL80211_ATTR_DISABLE_HT: Force HT capable interfaces to disable - * this feature. Currently, only supported in mac80211 drivers. + * @NL80211_ATTR_DISABLE_HT: Force HT capable interfaces to disable + * this feature during association. This is a flag attribute. + * Currently only supported in mac80211 drivers. + * @NL80211_ATTR_DISABLE_VHT: Force VHT capable interfaces to disable + * this feature during association. This is a flag attribute. + * Currently only supported in mac80211 drivers. + * @NL80211_ATTR_DISABLE_HE: Force HE capable interfaces to disable + * this feature during association. This is a flag attribute. + * Currently only supported in mac80211 drivers. * @NL80211_ATTR_HT_CAPABILITY_MASK: Specify which bits of the * ATTR_HT_CAPABILITY to which attention should be paid. * Currently, only mac80211 NICs support this feature. @@ -1536,7 +2058,7 @@ enum nl80211_commands { * * @NL80211_ATTR_INACTIVITY_TIMEOUT: timeout value in seconds, this can be * used by the drivers which has MLME in firmware and does not have support - * to report per station tx/rx activity to free up the staion entry from + * to report per station tx/rx activity to free up the station entry from * the list. This needs to be used when the driver advertises the * capability to timeout the stations. * @@ -1557,8 +2079,16 @@ enum nl80211_commands { * the connection request from a station. nl80211_connect_failed_reason * enum has different reasons of connection failure. * - * @NL80211_ATTR_SAE_DATA: SAE elements in Authentication frames. This starts - * with the Authentication transaction sequence number field. + * @NL80211_ATTR_AUTH_DATA: Fields and elements in Authentication frames. + * This contains the authentication frame body (non-IE and IE data), + * excluding the Authentication algorithm number, i.e., starting at the + * Authentication transaction sequence number field. It is used with + * authentication algorithms that need special fields to be added into + * the frames (SAE and FILS). Currently, only the SAE cases use the + * initial two fields (Authentication transaction sequence number and + * Status code). However, those fields are included in the attribute data + * for all authentication algorithms to keep the attribute definition + * consistent. * * @NL80211_ATTR_VHT_CAPABILITY: VHT Capability information element (from * association request when used with NL80211_CMD_NEW_STATION) @@ -1629,13 +2159,14 @@ enum nl80211_commands { * until the channel switch event. * @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission * must be blocked on the current channel (before the channel switch - * operation). + * operation). Also included in the channel switch started event if quiet + * was requested by the AP. * @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information * for the time while performing a channel switch. - * @NL80211_ATTR_CSA_C_OFF_BEACON: An array of offsets (u16) to the channel - * switch counters in the beacons tail (%NL80211_ATTR_BEACON_TAIL). - * @NL80211_ATTR_CSA_C_OFF_PRESP: An array of offsets (u16) to the channel - * switch counters in the probe response (%NL80211_ATTR_PROBE_RESP). + * @NL80211_ATTR_CNTDWN_OFFS_BEACON: An array of offsets (u16) to the channel + * switch or color change counters in the beacons tail (%NL80211_ATTR_BEACON_TAIL). + * @NL80211_ATTR_CNTDWN_OFFS_PRESP: An array of offsets (u16) to the channel + * switch or color change counters in the probe response (%NL80211_ATTR_PROBE_RESP). * * @NL80211_ATTR_RXMGMT_FLAGS: flags for nl80211_send_mgmt(), u32. * As specified in the &enum nl80211_rxmgmt_flags. @@ -1643,7 +2174,7 @@ enum nl80211_commands { * @NL80211_ATTR_STA_SUPPORTED_CHANNELS: array of supported channels. * * @NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES: array of supported - * supported operating classes. + * operating classes. * * @NL80211_ATTR_HANDLE_DFS: A flag indicating whether user space * controls DFS operation in IBSS mode. If the flag is included in @@ -1659,7 +2190,9 @@ enum nl80211_commands { * * @NL80211_ATTR_OPMODE_NOTIF: Operating mode field from Operating Mode * Notification Element based on association request when used with - * %NL80211_CMD_NEW_STATION; u8 attribute. + * %NL80211_CMD_NEW_STATION or %NL80211_CMD_SET_STATION (only when + * %NL80211_FEATURE_FULL_AP_CLIENT_STATE is supported, or with TDLS); + * u8 attribute. * * @NL80211_ATTR_VENDOR_ID: The vendor ID, either a 24-bit OUI or, if * %NL80211_VENDOR_ID_IS_LINUX is set, a special Linux ID (not used yet) @@ -1701,6 +2234,19 @@ enum nl80211_commands { * regulatory indoor configuration would be owned by the netlink socket * that configured the indoor setting, and the indoor operation would be * cleared when the socket is closed. + * If set during NAN interface creation, the interface will be destroyed + * if the socket is closed just like any other interface. Moreover, NAN + * notifications will be sent in unicast to that socket. Without this + * attribute, the notifications will be sent to the %NL80211_MCGRP_NAN + * multicast group. + * If set during %NL80211_CMD_ASSOCIATE or %NL80211_CMD_CONNECT the + * station will deauthenticate when the socket is closed. + * If set during %NL80211_CMD_JOIN_IBSS the IBSS will be automatically + * torn down when the socket is closed. + * If set during %NL80211_CMD_JOIN_MESH the mesh setup will be + * automatically torn down when the socket is closed. + * If set during %NL80211_CMD_START_AP the AP will be automatically + * disabled when the socket is closed. * * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is * the TDLS link initiator. @@ -1712,6 +2258,8 @@ enum nl80211_commands { * underlying device supports these minimal RRM features: * %NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES, * %NL80211_FEATURE_QUIET, + * Or, if global RRM is supported, see: + * %NL80211_EXT_FEATURE_RRM * If this flag is used, driver must add the Power Capabilities IE to the * association request. In addition, it must also set the RRM capability * flag in the association request's Capability Info field. @@ -1755,12 +2303,366 @@ enum nl80211_commands { * over all channels. * * @NL80211_ATTR_SCHED_SCAN_DELAY: delay before the first cycle of a - * scheduled scan (or a WoWLAN net-detect scan) is started, u32 - * in seconds. + * scheduled scan is started. Or the delay before a WoWLAN + * net-detect scan is started, counting from the moment the + * system is suspended. This value is a u32, in seconds. * @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device * is operating in an indoor environment. * + * @NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS: maximum number of scan plans for + * scheduled scan supported by the device (u32), a wiphy attribute. + * @NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL: maximum interval (in seconds) for + * a scan plan (u32), a wiphy attribute. + * @NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS: maximum number of iterations in + * a scan plan (u32), a wiphy attribute. + * @NL80211_ATTR_SCHED_SCAN_PLANS: a list of scan plans for scheduled scan. + * Each scan plan defines the number of scan iterations and the interval + * between scans. The last scan plan will always run infinitely, + * thus it must not specify the number of iterations, only the interval + * between scans. The scan plans are executed sequentially. + * Each scan plan is a nested attribute of &enum nl80211_sched_scan_plan. + * @NL80211_ATTR_PBSS: flag attribute. If set it means operate + * in a PBSS. Specified in %NL80211_CMD_CONNECT to request + * connecting to a PCP, and in %NL80211_CMD_START_AP to start + * a PCP instead of AP. Relevant for DMG networks only. + * @NL80211_ATTR_BSS_SELECT: nested attribute for driver supporting the + * BSS selection feature. When used with %NL80211_CMD_GET_WIPHY it contains + * attributes according &enum nl80211_bss_select_attr to indicate what + * BSS selection behaviours are supported. When used with %NL80211_CMD_CONNECT + * it contains the behaviour-specific attribute containing the parameters for + * BSS selection to be done by driver and/or firmware. + * + * @NL80211_ATTR_STA_SUPPORT_P2P_PS: whether P2P PS mechanism supported + * or not. u8, one of the values of &enum nl80211_sta_p2p_ps_status + * + * @NL80211_ATTR_PAD: attribute used for padding for 64-bit alignment + * + * @NL80211_ATTR_IFTYPE_EXT_CAPA: Nested attribute of the following attributes: + * %NL80211_ATTR_IFTYPE, %NL80211_ATTR_EXT_CAPA, + * %NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities per + * interface type. + * + * @NL80211_ATTR_MU_MIMO_GROUP_DATA: array of 24 bytes that defines a MU-MIMO + * groupID for monitor mode. + * The first 8 bytes are a mask that defines the membership in each + * group (there are 64 groups, group 0 and 63 are reserved), + * each bit represents a group and set to 1 for being a member in + * that group and 0 for not being a member. + * The remaining 16 bytes define the position in each group: 2 bits for + * each group. + * (smaller group numbers represented on most significant bits and bigger + * group numbers on least significant bits.) + * This attribute is used only if all interfaces are in monitor mode. + * Set this attribute in order to monitor packets using the given MU-MIMO + * groupID data. + * to turn off that feature set all the bits of the groupID to zero. + * @NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR: mac address for the sniffer to follow + * when using MU-MIMO air sniffer. + * to turn that feature off set an invalid mac address + * (e.g. FF:FF:FF:FF:FF:FF) + * + * @NL80211_ATTR_SCAN_START_TIME_TSF: The time at which the scan was actually + * started (u64). The time is the TSF of the BSS the interface that + * requested the scan is connected to (if available, otherwise this + * attribute must not be included). + * @NL80211_ATTR_SCAN_START_TIME_TSF_BSSID: The BSS according to which + * %NL80211_ATTR_SCAN_START_TIME_TSF is set. + * @NL80211_ATTR_MEASUREMENT_DURATION: measurement duration in TUs (u16). If + * %NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY is not set, this is the + * maximum measurement duration allowed. This attribute is used with + * measurement requests. It can also be used with %NL80211_CMD_TRIGGER_SCAN + * if the scan is used for beacon report radio measurement. + * @NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY: flag attribute that indicates + * that the duration specified with %NL80211_ATTR_MEASUREMENT_DURATION is + * mandatory. If this flag is not set, the duration is the maximum duration + * and the actual measurement duration may be shorter. + * + * @NL80211_ATTR_MESH_PEER_AID: Association ID for the mesh peer (u16). This is + * used to pull the stored data for mesh peer in power save state. + * + * @NL80211_ATTR_NAN_MASTER_PREF: the master preference to be used by + * %NL80211_CMD_START_NAN and optionally with + * %NL80211_CMD_CHANGE_NAN_CONFIG. Its type is u8 and it can't be 0. + * Also, values 1 and 255 are reserved for certification purposes and + * should not be used during a normal device operation. + * @NL80211_ATTR_BANDS: operating bands configuration. This is a u32 + * bitmask of BIT(NL80211_BAND_*) as described in %enum + * nl80211_band. For instance, for NL80211_BAND_2GHZ, bit 0 + * would be set. This attribute is used with + * %NL80211_CMD_START_NAN and %NL80211_CMD_CHANGE_NAN_CONFIG, and + * it is optional. If no bands are set, it means don't-care and + * the device will decide what to use. + * @NL80211_ATTR_NAN_FUNC: a function that can be added to NAN. See + * &enum nl80211_nan_func_attributes for description of this nested + * attribute. + * @NL80211_ATTR_NAN_MATCH: used to report a match. This is a nested attribute. + * See &enum nl80211_nan_match_attributes. + * @NL80211_ATTR_FILS_KEK: KEK for FILS (Re)Association Request/Response frame + * protection. + * @NL80211_ATTR_FILS_NONCES: Nonces (part of AAD) for FILS (Re)Association + * Request/Response frame protection. This attribute contains the 16 octet + * STA Nonce followed by 16 octets of AP Nonce. + * + * @NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED: Indicates whether or not multicast + * packets should be send out as unicast to all stations (flag attribute). + * + * @NL80211_ATTR_BSSID: The BSSID of the AP. Note that %NL80211_ATTR_MAC is also + * used in various commands/events for specifying the BSSID. + * + * @NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI: Relative RSSI threshold by which + * other BSSs has to be better or slightly worse than the current + * connected BSS so that they get reported to user space. + * This will give an opportunity to userspace to consider connecting to + * other matching BSSs which have better or slightly worse RSSI than + * the current connected BSS by using an offloaded operation to avoid + * unnecessary wakeups. + * + * @NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST: When present the RSSI level for BSSs in + * the specified band is to be adjusted before doing + * %NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI based comparison to figure out + * better BSSs. The attribute value is a packed structure + * value as specified by &struct nl80211_bss_select_rssi_adjust. + * + * @NL80211_ATTR_TIMEOUT_REASON: The reason for which an operation timed out. + * u32 attribute with an &enum nl80211_timeout_reason value. This is used, + * e.g., with %NL80211_CMD_CONNECT event. + * + * @NL80211_ATTR_FILS_ERP_USERNAME: EAP Re-authentication Protocol (ERP) + * username part of NAI used to refer keys rRK and rIK. This is used with + * %NL80211_CMD_CONNECT. + * + * @NL80211_ATTR_FILS_ERP_REALM: EAP Re-authentication Protocol (ERP) realm part + * of NAI specifying the domain name of the ER server. This is used with + * %NL80211_CMD_CONNECT. + * + * @NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM: Unsigned 16-bit ERP next sequence number + * to use in ERP messages. This is used in generating the FILS wrapped data + * for FILS authentication and is used with %NL80211_CMD_CONNECT. + * + * @NL80211_ATTR_FILS_ERP_RRK: ERP re-authentication Root Key (rRK) for the + * NAI specified by %NL80211_ATTR_FILS_ERP_USERNAME and + * %NL80211_ATTR_FILS_ERP_REALM. This is used for generating rIK and rMSK + * from successful FILS authentication and is used with + * %NL80211_CMD_CONNECT. + * + * @NL80211_ATTR_FILS_CACHE_ID: A 2-octet identifier advertized by a FILS AP + * identifying the scope of PMKSAs. This is used with + * @NL80211_CMD_SET_PMKSA and @NL80211_CMD_DEL_PMKSA. + * + * @NL80211_ATTR_PMK: attribute for passing PMK key material. Used with + * %NL80211_CMD_SET_PMKSA for the PMKSA identified by %NL80211_ATTR_PMKID. + * For %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP it is used to provide + * PSK for offloading 4-way handshake for WPA/WPA2-PSK networks. For 802.1X + * authentication it is used with %NL80211_CMD_SET_PMK. For offloaded FT + * support this attribute specifies the PMK-R0 if NL80211_ATTR_PMKR0_NAME + * is included as well. + * + * @NL80211_ATTR_SCHED_SCAN_MULTI: flag attribute which user-space shall use to + * indicate that it supports multiple active scheduled scan requests. + * @NL80211_ATTR_SCHED_SCAN_MAX_REQS: indicates maximum number of scheduled + * scan request that may be active for the device (u32). + * + * @NL80211_ATTR_WANT_1X_4WAY_HS: flag attribute which user-space can include + * in %NL80211_CMD_CONNECT to indicate that for 802.1X authentication it + * wants to use the supported offload of the 4-way handshake. + * @NL80211_ATTR_PMKR0_NAME: PMK-R0 Name for offloaded FT. + * @NL80211_ATTR_PORT_AUTHORIZED: (reserved) + * + * @NL80211_ATTR_EXTERNAL_AUTH_ACTION: Identify the requested external + * authentication operation (u32 attribute with an + * &enum nl80211_external_auth_action value). This is used with the + * %NL80211_CMD_EXTERNAL_AUTH request event. + * @NL80211_ATTR_EXTERNAL_AUTH_SUPPORT: Flag attribute indicating that the user + * space supports external authentication. This attribute shall be used + * with %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP request. The driver + * may offload authentication processing to user space if this capability + * is indicated in the respective requests from the user space. (This flag + * attribute deprecated for %NL80211_CMD_START_AP, use + * %NL80211_ATTR_AP_SETTINGS_FLAGS) + * + * @NL80211_ATTR_NSS: Station's New/updated RX_NSS value notified using this + * u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED. + * + * @NL80211_ATTR_TXQ_STATS: TXQ statistics (nested attribute, see &enum + * nl80211_txq_stats) + * @NL80211_ATTR_TXQ_LIMIT: Total packet limit for the TXQ queues for this phy. + * The smaller of this and the memory limit is enforced. + * @NL80211_ATTR_TXQ_MEMORY_LIMIT: Total memory limit (in bytes) for the + * TXQ queues for this phy. The smaller of this and the packet limit is + * enforced. + * @NL80211_ATTR_TXQ_QUANTUM: TXQ scheduler quantum (bytes). Number of bytes + * a flow is assigned on each round of the DRR scheduler. + * @NL80211_ATTR_HE_CAPABILITY: HE Capability information element (from + * association request when used with NL80211_CMD_NEW_STATION). Can be set + * only if %NL80211_STA_FLAG_WME is set. + * + * @NL80211_ATTR_FTM_RESPONDER: nested attribute which user-space can include + * in %NL80211_CMD_START_AP or %NL80211_CMD_SET_BEACON for fine timing + * measurement (FTM) responder functionality and containing parameters as + * possible, see &enum nl80211_ftm_responder_attr + * + * @NL80211_ATTR_FTM_RESPONDER_STATS: Nested attribute with FTM responder + * statistics, see &enum nl80211_ftm_responder_stats. + * + * @NL80211_ATTR_TIMEOUT: Timeout for the given operation in milliseconds (u32), + * if the attribute is not given no timeout is requested. Note that 0 is an + * invalid value. + * + * @NL80211_ATTR_PEER_MEASUREMENTS: peer measurements request (and result) + * data, uses nested attributes specified in + * &enum nl80211_peer_measurement_attrs. + * This is also used for capability advertisement in the wiphy information, + * with the appropriate sub-attributes. + * + * @NL80211_ATTR_AIRTIME_WEIGHT: Station's weight when scheduled by the airtime + * scheduler. + * + * @NL80211_ATTR_STA_TX_POWER_SETTING: Transmit power setting type (u8) for + * station associated with the AP. See &enum nl80211_tx_power_setting for + * possible values. + * @NL80211_ATTR_STA_TX_POWER: Transmit power level (s16) in dBm units. This + * allows to set Tx power for a station. If this attribute is not included, + * the default per-interface tx power setting will be overriding. Driver + * should be picking up the lowest tx power, either tx power per-interface + * or per-station. + * + * @NL80211_ATTR_SAE_PASSWORD: attribute for passing SAE password material. It + * is used with %NL80211_CMD_CONNECT to provide password for offloading + * SAE authentication for WPA3-Personal networks. + * + * @NL80211_ATTR_TWT_RESPONDER: Enable target wait time responder support. + * + * @NL80211_ATTR_HE_OBSS_PD: nested attribute for OBSS Packet Detection + * functionality. + * + * @NL80211_ATTR_WIPHY_EDMG_CHANNELS: bitmap that indicates the 2.16 GHz + * channel(s) that are allowed to be used for EDMG transmissions. + * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251. (u8 attribute) + * @NL80211_ATTR_WIPHY_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes + * the allowed channel bandwidth configurations. (u8 attribute) + * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13. + * + * @NL80211_ATTR_VLAN_ID: VLAN ID (1..4094) for the station and VLAN group key + * (u16). + * + * @NL80211_ATTR_HE_BSS_COLOR: nested attribute for BSS Color Settings. + * + * @NL80211_ATTR_IFTYPE_AKM_SUITES: nested array attribute, with each entry + * using attributes from &enum nl80211_iftype_akm_attributes. This + * attribute is sent in a response to %NL80211_CMD_GET_WIPHY indicating + * supported AKM suites capability per interface. AKMs advertised in + * %NL80211_ATTR_AKM_SUITES are default capabilities if AKM suites not + * advertised for a specific interface type. + * + * @NL80211_ATTR_TID_CONFIG: TID specific configuration in a + * nested attribute with &enum nl80211_tid_config_attr sub-attributes; + * on output (in wiphy attributes) it contains only the feature sub- + * attributes. + * + * @NL80211_ATTR_CONTROL_PORT_NO_PREAUTH: disable preauth frame rx on control + * port in order to forward/receive them as ordinary data frames. + * + * @NL80211_ATTR_PMK_LIFETIME: Maximum lifetime for PMKSA in seconds (u32, + * dot11RSNAConfigPMKReauthThreshold; 0 is not a valid value). + * An optional parameter configured through %NL80211_CMD_SET_PMKSA. + * Drivers that trigger roaming need to know the lifetime of the + * configured PMKSA for triggering the full vs. PMKSA caching based + * authentication. This timeout helps authentication methods like SAE, + * where PMK gets updated only by going through a full (new SAE) + * authentication instead of getting updated during an association for EAP + * authentication. No new full authentication within the PMK expiry shall + * result in a disassociation at the end of the lifetime. + * + * @NL80211_ATTR_PMK_REAUTH_THRESHOLD: Reauthentication threshold time, in + * terms of percentage of %NL80211_ATTR_PMK_LIFETIME + * (u8, dot11RSNAConfigPMKReauthThreshold, 1..100). This is an optional + * parameter configured through %NL80211_CMD_SET_PMKSA. Requests the + * driver to trigger a full authentication roam (without PMKSA caching) + * after the reauthentication threshold time, but before the PMK lifetime + * has expired. + * + * Authentication methods like SAE need to be able to generate a new PMKSA + * entry without having to force a disconnection after the PMK timeout. If + * no roaming occurs between the reauth threshold and PMK expiration, + * disassociation is still forced. + * @NL80211_ATTR_RECEIVE_MULTICAST: multicast flag for the + * %NL80211_CMD_REGISTER_FRAME command, see the description there. + * @NL80211_ATTR_WIPHY_FREQ_OFFSET: offset of the associated + * %NL80211_ATTR_WIPHY_FREQ in positive KHz. Only valid when supplied with + * an %NL80211_ATTR_WIPHY_FREQ_OFFSET. + * @NL80211_ATTR_CENTER_FREQ1_OFFSET: Center frequency offset in KHz for the + * first channel segment specified in %NL80211_ATTR_CENTER_FREQ1. + * @NL80211_ATTR_SCAN_FREQ_KHZ: nested attribute with KHz frequencies + * + * @NL80211_ATTR_HE_6GHZ_CAPABILITY: HE 6 GHz Band Capability element (from + * association request when used with NL80211_CMD_NEW_STATION). + * + * @NL80211_ATTR_FILS_DISCOVERY: Optional parameter to configure FILS + * discovery. It is a nested attribute, see + * &enum nl80211_fils_discovery_attributes. + * + * @NL80211_ATTR_UNSOL_BCAST_PROBE_RESP: Optional parameter to configure + * unsolicited broadcast probe response. It is a nested attribute, see + * &enum nl80211_unsol_bcast_probe_resp_attributes. + * + * @NL80211_ATTR_S1G_CAPABILITY: S1G Capability information element (from + * association request when used with NL80211_CMD_NEW_STATION) + * @NL80211_ATTR_S1G_CAPABILITY_MASK: S1G Capability Information element + * override mask. Used with NL80211_ATTR_S1G_CAPABILITY in + * NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT. + * + * @NL80211_ATTR_SAE_PWE: Indicates the mechanism(s) allowed for SAE PWE + * derivation in WPA3-Personal networks which are using SAE authentication. + * This is a u8 attribute that encapsulates one of the values from + * &enum nl80211_sae_pwe_mechanism. + * + * @NL80211_ATTR_SAR_SPEC: SAR power limitation specification when + * used with %NL80211_CMD_SET_SAR_SPECS. The message contains fields + * of %nl80211_sar_attrs which specifies the sar type and related + * sar specs. Sar specs contains array of %nl80211_sar_specs_attrs. + * + * @NL80211_ATTR_RECONNECT_REQUESTED: flag attribute, used with deauth and + * disassoc events to indicate that an immediate reconnect to the AP + * is desired. + * + * @NL80211_ATTR_OBSS_COLOR_BITMAP: bitmap of the u64 BSS colors for the + * %NL80211_CMD_OBSS_COLOR_COLLISION event. + * + * @NL80211_ATTR_COLOR_CHANGE_COUNT: u8 attribute specifying the number of TBTT's + * until the color switch event. + * @NL80211_ATTR_COLOR_CHANGE_COLOR: u8 attribute specifying the color that we are + * switching to + * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE + * information for the time while performing a color switch. + * + * @NL80211_ATTR_MBSSID_CONFIG: Nested attribute for multiple BSSID + * advertisements (MBSSID) parameters in AP mode. + * Kernel uses this attribute to indicate the driver's support for MBSSID + * and enhanced multi-BSSID advertisements (EMA AP) to the userspace. + * Userspace should use this attribute to configure per interface MBSSID + * parameters. + * See &enum nl80211_mbssid_config_attributes for details. + * + * @NL80211_ATTR_MBSSID_ELEMS: Nested parameter to pass multiple BSSID elements. + * Mandatory parameter for the transmitting interface to enable MBSSID. + * Optional for the non-transmitting interfaces. + * + * @NL80211_ATTR_RADAR_BACKGROUND: Configure dedicated offchannel chain + * available for radar/CAC detection on some hw. This chain can't be used + * to transmit or receive frames and it is bounded to a running wdev. + * Background radar/CAC detection allows to avoid the CAC downtime + * switching on a different channel during CAC detection on the selected + * radar channel. + * + * @NL80211_ATTR_AP_SETTINGS_FLAGS: u32 attribute contains ap settings flags, + * enumerated in &enum nl80211_ap_settings_flags. This attribute shall be + * used with %NL80211_CMD_START_AP request. + * + * @NL80211_ATTR_EHT_CAPABILITY: EHT Capability information element (from + * association request when used with NL80211_CMD_NEW_STATION). Can be set + * only if %NL80211_STA_FLAG_WME is set. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -2019,7 +2921,7 @@ enum nl80211_attrs { NL80211_ATTR_CONN_FAILED_REASON, - NL80211_ATTR_SAE_DATA, + NL80211_ATTR_AUTH_DATA, NL80211_ATTR_VHT_CAPABILITY, @@ -2067,8 +2969,8 @@ enum nl80211_attrs { NL80211_ATTR_CH_SWITCH_COUNT, NL80211_ATTR_CH_SWITCH_BLOCK_TX, NL80211_ATTR_CSA_IES, - NL80211_ATTR_CSA_C_OFF_BEACON, - NL80211_ATTR_CSA_C_OFF_PRESP, + NL80211_ATTR_CNTDWN_OFFS_BEACON, + NL80211_ATTR_CNTDWN_OFFS_PRESP, NL80211_ATTR_RXMGMT_FLAGS, @@ -2130,6 +3032,149 @@ enum nl80211_attrs { NL80211_ATTR_REG_INDOOR, + NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS, + NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL, + NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS, + NL80211_ATTR_SCHED_SCAN_PLANS, + + NL80211_ATTR_PBSS, + + NL80211_ATTR_BSS_SELECT, + + NL80211_ATTR_STA_SUPPORT_P2P_PS, + + NL80211_ATTR_PAD, + + NL80211_ATTR_IFTYPE_EXT_CAPA, + + NL80211_ATTR_MU_MIMO_GROUP_DATA, + NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR, + + NL80211_ATTR_SCAN_START_TIME_TSF, + NL80211_ATTR_SCAN_START_TIME_TSF_BSSID, + NL80211_ATTR_MEASUREMENT_DURATION, + NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY, + + NL80211_ATTR_MESH_PEER_AID, + + NL80211_ATTR_NAN_MASTER_PREF, + NL80211_ATTR_BANDS, + NL80211_ATTR_NAN_FUNC, + NL80211_ATTR_NAN_MATCH, + + NL80211_ATTR_FILS_KEK, + NL80211_ATTR_FILS_NONCES, + + NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED, + + NL80211_ATTR_BSSID, + + NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI, + NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST, + + NL80211_ATTR_TIMEOUT_REASON, + + NL80211_ATTR_FILS_ERP_USERNAME, + NL80211_ATTR_FILS_ERP_REALM, + NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM, + NL80211_ATTR_FILS_ERP_RRK, + NL80211_ATTR_FILS_CACHE_ID, + + NL80211_ATTR_PMK, + + NL80211_ATTR_SCHED_SCAN_MULTI, + NL80211_ATTR_SCHED_SCAN_MAX_REQS, + + NL80211_ATTR_WANT_1X_4WAY_HS, + NL80211_ATTR_PMKR0_NAME, + NL80211_ATTR_PORT_AUTHORIZED, + + NL80211_ATTR_EXTERNAL_AUTH_ACTION, + NL80211_ATTR_EXTERNAL_AUTH_SUPPORT, + + NL80211_ATTR_NSS, + NL80211_ATTR_ACK_SIGNAL, + + NL80211_ATTR_CONTROL_PORT_OVER_NL80211, + + NL80211_ATTR_TXQ_STATS, + NL80211_ATTR_TXQ_LIMIT, + NL80211_ATTR_TXQ_MEMORY_LIMIT, + NL80211_ATTR_TXQ_QUANTUM, + + NL80211_ATTR_HE_CAPABILITY, + + NL80211_ATTR_FTM_RESPONDER, + + NL80211_ATTR_FTM_RESPONDER_STATS, + + NL80211_ATTR_TIMEOUT, + + NL80211_ATTR_PEER_MEASUREMENTS, + + NL80211_ATTR_AIRTIME_WEIGHT, + NL80211_ATTR_STA_TX_POWER_SETTING, + NL80211_ATTR_STA_TX_POWER, + + NL80211_ATTR_SAE_PASSWORD, + + NL80211_ATTR_TWT_RESPONDER, + + NL80211_ATTR_HE_OBSS_PD, + + NL80211_ATTR_WIPHY_EDMG_CHANNELS, + NL80211_ATTR_WIPHY_EDMG_BW_CONFIG, + + NL80211_ATTR_VLAN_ID, + + NL80211_ATTR_HE_BSS_COLOR, + + NL80211_ATTR_IFTYPE_AKM_SUITES, + + NL80211_ATTR_TID_CONFIG, + + NL80211_ATTR_CONTROL_PORT_NO_PREAUTH, + + NL80211_ATTR_PMK_LIFETIME, + NL80211_ATTR_PMK_REAUTH_THRESHOLD, + + NL80211_ATTR_RECEIVE_MULTICAST, + NL80211_ATTR_WIPHY_FREQ_OFFSET, + NL80211_ATTR_CENTER_FREQ1_OFFSET, + NL80211_ATTR_SCAN_FREQ_KHZ, + + NL80211_ATTR_HE_6GHZ_CAPABILITY, + + NL80211_ATTR_FILS_DISCOVERY, + + NL80211_ATTR_UNSOL_BCAST_PROBE_RESP, + + NL80211_ATTR_S1G_CAPABILITY, + NL80211_ATTR_S1G_CAPABILITY_MASK, + + NL80211_ATTR_SAE_PWE, + + NL80211_ATTR_RECONNECT_REQUESTED, + + NL80211_ATTR_SAR_SPEC, + + NL80211_ATTR_DISABLE_HE, + + NL80211_ATTR_OBSS_COLOR_BITMAP, + + NL80211_ATTR_COLOR_CHANGE_COUNT, + NL80211_ATTR_COLOR_CHANGE_COLOR, + NL80211_ATTR_COLOR_CHANGE_ELEMS, + + NL80211_ATTR_MBSSID_CONFIG, + NL80211_ATTR_MBSSID_ELEMS, + + NL80211_ATTR_RADAR_BACKGROUND, + + NL80211_ATTR_AP_SETTINGS_FLAGS, + + NL80211_ATTR_EHT_CAPABILITY, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2141,6 +3186,9 @@ enum nl80211_attrs { #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION #define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG #define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER +#define NL80211_ATTR_SAE_DATA NL80211_ATTR_AUTH_DATA +#define NL80211_ATTR_CSA_C_OFF_BEACON NL80211_ATTR_CNTDWN_OFFS_BEACON +#define NL80211_ATTR_CSA_C_OFF_PRESP NL80211_ATTR_CNTDWN_OFFS_PRESP /* * Allow user space programs to use #ifdef on new attributes by defining them @@ -2168,17 +3216,22 @@ enum nl80211_attrs { #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS #define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS +#define NL80211_WIPHY_NAME_MAXLEN 64 + #define NL80211_MAX_SUPP_RATES 32 #define NL80211_MAX_SUPP_HT_RATES 77 -#define NL80211_MAX_SUPP_REG_RULES 64 +#define NL80211_MAX_SUPP_REG_RULES 128 #define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0 #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 #define NL80211_HT_CAPABILITY_LEN 26 #define NL80211_VHT_CAPABILITY_LEN 12 - +#define NL80211_HE_MIN_CAPABILITY_LEN 16 +#define NL80211_HE_MAX_CAPABILITY_LEN 54 #define NL80211_MAX_NR_CIPHER_SUITES 5 #define NL80211_MAX_NR_AKM_SUITES 2 +#define NL80211_EHT_MIN_CAPABILITY_LEN 13 +#define NL80211_EHT_MAX_CAPABILITY_LEN 51 #define NL80211_MIN_REMAIN_ON_CHANNEL_TIME 10 @@ -2206,8 +3259,9 @@ enum nl80211_attrs { * and therefore can't be created in the normal ways, use the * %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE * commands to create and destroy one - * @NL80211_IF_TYPE_OCB: Outside Context of a BSS + * @NL80211_IFTYPE_OCB: Outside Context of a BSS * This mode corresponds to the MIB variable dot11OCBActivated=true + * @NL80211_IFTYPE_NAN: NAN device interface type (not a netdev) * @NL80211_IFTYPE_MAX: highest interface type number currently defined * @NUM_NL80211_IFTYPES: number of defined interface types * @@ -2228,6 +3282,7 @@ enum nl80211_iftype { NL80211_IFTYPE_P2P_GO, NL80211_IFTYPE_P2P_DEVICE, NL80211_IFTYPE_OCB, + NL80211_IFTYPE_NAN, /* keep last */ NUM_NL80211_IFTYPES, @@ -2273,6 +3328,20 @@ enum nl80211_sta_flags { NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 }; +/** + * enum nl80211_sta_p2p_ps_status - station support of P2P PS + * + * @NL80211_P2P_PS_UNSUPPORTED: station doesn't support P2P PS mechanism + * @@NL80211_P2P_PS_SUPPORTED: station supports P2P PS mechanism + * @NUM_NL80211_P2P_PS_STATUS: number of values + */ +enum nl80211_sta_p2p_ps_status { + NL80211_P2P_PS_UNSUPPORTED = 0, + NL80211_P2P_PS_SUPPORTED, + + NUM_NL80211_P2P_PS_STATUS, +}; + #define NL80211_STA_FLAG_MAX_OLD_API NL80211_STA_FLAG_TDLS_PEER /** @@ -2288,6 +3357,100 @@ struct nl80211_sta_flag_update { } __attribute__((packed)); /** + * enum nl80211_he_gi - HE guard interval + * @NL80211_RATE_INFO_HE_GI_0_8: 0.8 usec + * @NL80211_RATE_INFO_HE_GI_1_6: 1.6 usec + * @NL80211_RATE_INFO_HE_GI_3_2: 3.2 usec + */ +enum nl80211_he_gi { + NL80211_RATE_INFO_HE_GI_0_8, + NL80211_RATE_INFO_HE_GI_1_6, + NL80211_RATE_INFO_HE_GI_3_2, +}; + +/** + * enum nl80211_he_ltf - HE long training field + * @NL80211_RATE_INFO_HE_1xLTF: 3.2 usec + * @NL80211_RATE_INFO_HE_2xLTF: 6.4 usec + * @NL80211_RATE_INFO_HE_4xLTF: 12.8 usec + */ +enum nl80211_he_ltf { + NL80211_RATE_INFO_HE_1XLTF, + NL80211_RATE_INFO_HE_2XLTF, + NL80211_RATE_INFO_HE_4XLTF, +}; + +/** + * enum nl80211_he_ru_alloc - HE RU allocation values + * @NL80211_RATE_INFO_HE_RU_ALLOC_26: 26-tone RU allocation + * @NL80211_RATE_INFO_HE_RU_ALLOC_52: 52-tone RU allocation + * @NL80211_RATE_INFO_HE_RU_ALLOC_106: 106-tone RU allocation + * @NL80211_RATE_INFO_HE_RU_ALLOC_242: 242-tone RU allocation + * @NL80211_RATE_INFO_HE_RU_ALLOC_484: 484-tone RU allocation + * @NL80211_RATE_INFO_HE_RU_ALLOC_996: 996-tone RU allocation + * @NL80211_RATE_INFO_HE_RU_ALLOC_2x996: 2x996-tone RU allocation + */ +enum nl80211_he_ru_alloc { + NL80211_RATE_INFO_HE_RU_ALLOC_26, + NL80211_RATE_INFO_HE_RU_ALLOC_52, + NL80211_RATE_INFO_HE_RU_ALLOC_106, + NL80211_RATE_INFO_HE_RU_ALLOC_242, + NL80211_RATE_INFO_HE_RU_ALLOC_484, + NL80211_RATE_INFO_HE_RU_ALLOC_996, + NL80211_RATE_INFO_HE_RU_ALLOC_2x996, +}; + +/** + * enum nl80211_eht_gi - EHT guard interval + * @NL80211_RATE_INFO_EHT_GI_0_8: 0.8 usec + * @NL80211_RATE_INFO_EHT_GI_1_6: 1.6 usec + * @NL80211_RATE_INFO_EHT_GI_3_2: 3.2 usec + */ +enum nl80211_eht_gi { + NL80211_RATE_INFO_EHT_GI_0_8, + NL80211_RATE_INFO_EHT_GI_1_6, + NL80211_RATE_INFO_EHT_GI_3_2, +}; + +/** + * enum nl80211_eht_ru_alloc - EHT RU allocation values + * @NL80211_RATE_INFO_EHT_RU_ALLOC_26: 26-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_52: 52-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_52P26: 52+26-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_106: 106-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_106P26: 106+26 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_242: 242-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_484: 484-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_484P242: 484+242 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_996: 996-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_996P484: 996+484 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242: 996+484+242 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_2x996: 2x996-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484: 2x996+484 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_3x996: 3x996-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484: 3x996+484 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_4x996: 4x996-tone RU allocation + */ +enum nl80211_eht_ru_alloc { + NL80211_RATE_INFO_EHT_RU_ALLOC_26, + NL80211_RATE_INFO_EHT_RU_ALLOC_52, + NL80211_RATE_INFO_EHT_RU_ALLOC_52P26, + NL80211_RATE_INFO_EHT_RU_ALLOC_106, + NL80211_RATE_INFO_EHT_RU_ALLOC_106P26, + NL80211_RATE_INFO_EHT_RU_ALLOC_242, + NL80211_RATE_INFO_EHT_RU_ALLOC_484, + NL80211_RATE_INFO_EHT_RU_ALLOC_484P242, + NL80211_RATE_INFO_EHT_RU_ALLOC_996, + NL80211_RATE_INFO_EHT_RU_ALLOC_996P484, + NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242, + NL80211_RATE_INFO_EHT_RU_ALLOC_2x996, + NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484, + NL80211_RATE_INFO_EHT_RU_ALLOC_3x996, + NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484, + NL80211_RATE_INFO_EHT_RU_ALLOC_4x996, +}; + +/** * enum nl80211_rate_info - bitrate information * * These attribute types are used with %NL80211_STA_INFO_TXRATE @@ -2319,6 +3482,20 @@ struct nl80211_sta_flag_update { * @NL80211_RATE_INFO_5_MHZ_WIDTH: 5 MHz width - note that this is * a legacy rate and will be reported as the actual bitrate, i.e. * a quarter of the base (20 MHz) rate + * @NL80211_RATE_INFO_HE_MCS: HE MCS index (u8, 0-11) + * @NL80211_RATE_INFO_HE_NSS: HE NSS value (u8, 1-8) + * @NL80211_RATE_INFO_HE_GI: HE guard interval identifier + * (u8, see &enum nl80211_he_gi) + * @NL80211_RATE_INFO_HE_DCM: HE DCM value (u8, 0/1) + * @NL80211_RATE_INFO_RU_ALLOC: HE RU allocation, if not present then + * non-OFDMA was used (u8, see &enum nl80211_he_ru_alloc) + * @NL80211_RATE_INFO_320_MHZ_WIDTH: 320 MHz bitrate + * @NL80211_RATE_INFO_EHT_MCS: EHT MCS index (u8, 0-15) + * @NL80211_RATE_INFO_EHT_NSS: EHT NSS value (u8, 1-8) + * @NL80211_RATE_INFO_EHT_GI: EHT guard interval identifier + * (u8, see &enum nl80211_eht_gi) + * @NL80211_RATE_INFO_EHT_RU_ALLOC: EHT RU allocation, if not present then + * non-OFDMA was used (u8, see &enum nl80211_eht_ru_alloc) * @__NL80211_RATE_INFO_AFTER_LAST: internal use */ enum nl80211_rate_info { @@ -2335,6 +3512,16 @@ enum nl80211_rate_info { NL80211_RATE_INFO_160_MHZ_WIDTH, NL80211_RATE_INFO_10_MHZ_WIDTH, NL80211_RATE_INFO_5_MHZ_WIDTH, + NL80211_RATE_INFO_HE_MCS, + NL80211_RATE_INFO_HE_NSS, + NL80211_RATE_INFO_HE_GI, + NL80211_RATE_INFO_HE_DCM, + NL80211_RATE_INFO_HE_RU_ALLOC, + NL80211_RATE_INFO_320_MHZ_WIDTH, + NL80211_RATE_INFO_EHT_MCS, + NL80211_RATE_INFO_EHT_NSS, + NL80211_RATE_INFO_EHT_GI, + NL80211_RATE_INFO_EHT_RU_ALLOC, /* keep last */ __NL80211_RATE_INFO_AFTER_LAST, @@ -2430,6 +3617,27 @@ enum nl80211_sta_bss_param { * TID+1 and the special TID 16 (i.e. value 17) is used for non-QoS frames; * each one of those is again nested with &enum nl80211_tid_stats * attributes carrying the actual values. + * @NL80211_STA_INFO_RX_DURATION: aggregate PPDU duration for all frames + * received from the station (u64, usec) + * @NL80211_STA_INFO_PAD: attribute used for padding for 64-bit alignment + * @NL80211_STA_INFO_ACK_SIGNAL: signal strength of the last ACK frame(u8, dBm) + * @NL80211_STA_INFO_ACK_SIGNAL_AVG: avg signal strength of ACK frames (s8, dBm) + * @NL80211_STA_INFO_RX_MPDUS: total number of received packets (MPDUs) + * (u32, from this station) + * @NL80211_STA_INFO_FCS_ERROR_COUNT: total number of packets (MPDUs) received + * with an FCS error (u32, from this station). This count may not include + * some packets with an FCS error due to TA corruption. Hence this counter + * might not be fully accurate. + * @NL80211_STA_INFO_CONNECTED_TO_GATE: set to true if STA has a path to a + * mesh gate (u8, 0 or 1) + * @NL80211_STA_INFO_TX_DURATION: aggregate PPDU duration for all frames + * sent to the station (u64, usec) + * @NL80211_STA_INFO_AIRTIME_WEIGHT: current airtime weight for station (u16) + * @NL80211_STA_INFO_AIRTIME_LINK_METRIC: airtime link metric for mesh station + * @NL80211_STA_INFO_ASSOC_AT_BOOTTIME: Timestamp (CLOCK_BOOTTIME, nanoseconds) + * of STA's association + * @NL80211_STA_INFO_CONNECTED_TO_AS: set to true if STA has a path to a + * authentication server (u8, 0 or 1) * @__NL80211_STA_INFO_AFTER_LAST: internal * @NL80211_STA_INFO_MAX: highest possible station info attribute */ @@ -2466,12 +3674,28 @@ enum nl80211_sta_info { NL80211_STA_INFO_BEACON_RX, NL80211_STA_INFO_BEACON_SIGNAL_AVG, NL80211_STA_INFO_TID_STATS, + NL80211_STA_INFO_RX_DURATION, + NL80211_STA_INFO_PAD, + NL80211_STA_INFO_ACK_SIGNAL, + NL80211_STA_INFO_ACK_SIGNAL_AVG, + NL80211_STA_INFO_RX_MPDUS, + NL80211_STA_INFO_FCS_ERROR_COUNT, + NL80211_STA_INFO_CONNECTED_TO_GATE, + NL80211_STA_INFO_TX_DURATION, + NL80211_STA_INFO_AIRTIME_WEIGHT, + NL80211_STA_INFO_AIRTIME_LINK_METRIC, + NL80211_STA_INFO_ASSOC_AT_BOOTTIME, + NL80211_STA_INFO_CONNECTED_TO_AS, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1 }; +/* we renamed this - stay compatible */ +#define NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG NL80211_STA_INFO_ACK_SIGNAL_AVG + + /** * enum nl80211_tid_stats - per TID statistics attributes * @__NL80211_TID_STATS_INVALID: attribute number 0 is reserved @@ -2482,6 +3706,8 @@ enum nl80211_sta_info { * transmitted MSDUs (not counting the first attempt; u64) * @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted * MSDUs (u64) + * @NL80211_TID_STATS_PAD: attribute used for padding for 64-bit alignment + * @NL80211_TID_STATS_TXQ_STATS: TXQ stats (nested attribute) * @NUM_NL80211_TID_STATS: number of attributes here * @NL80211_TID_STATS_MAX: highest numbered attribute here */ @@ -2491,6 +3717,8 @@ enum nl80211_tid_stats { NL80211_TID_STATS_TX_MSDU, NL80211_TID_STATS_TX_MSDU_RETRIES, NL80211_TID_STATS_TX_MSDU_FAILED, + NL80211_TID_STATS_PAD, + NL80211_TID_STATS_TXQ_STATS, /* keep last */ NUM_NL80211_TID_STATS, @@ -2498,6 +3726,44 @@ enum nl80211_tid_stats { }; /** + * enum nl80211_txq_stats - per TXQ statistics attributes + * @__NL80211_TXQ_STATS_INVALID: attribute number 0 is reserved + * @NUM_NL80211_TXQ_STATS: number of attributes here + * @NL80211_TXQ_STATS_BACKLOG_BYTES: number of bytes currently backlogged + * @NL80211_TXQ_STATS_BACKLOG_PACKETS: number of packets currently + * backlogged + * @NL80211_TXQ_STATS_FLOWS: total number of new flows seen + * @NL80211_TXQ_STATS_DROPS: total number of packet drops + * @NL80211_TXQ_STATS_ECN_MARKS: total number of packet ECN marks + * @NL80211_TXQ_STATS_OVERLIMIT: number of drops due to queue space overflow + * @NL80211_TXQ_STATS_OVERMEMORY: number of drops due to memory limit overflow + * (only for per-phy stats) + * @NL80211_TXQ_STATS_COLLISIONS: number of hash collisions + * @NL80211_TXQ_STATS_TX_BYTES: total number of bytes dequeued from TXQ + * @NL80211_TXQ_STATS_TX_PACKETS: total number of packets dequeued from TXQ + * @NL80211_TXQ_STATS_MAX_FLOWS: number of flow buckets for PHY + * @NL80211_TXQ_STATS_MAX: highest numbered attribute here + */ +enum nl80211_txq_stats { + __NL80211_TXQ_STATS_INVALID, + NL80211_TXQ_STATS_BACKLOG_BYTES, + NL80211_TXQ_STATS_BACKLOG_PACKETS, + NL80211_TXQ_STATS_FLOWS, + NL80211_TXQ_STATS_DROPS, + NL80211_TXQ_STATS_ECN_MARKS, + NL80211_TXQ_STATS_OVERLIMIT, + NL80211_TXQ_STATS_OVERMEMORY, + NL80211_TXQ_STATS_COLLISIONS, + NL80211_TXQ_STATS_TX_BYTES, + NL80211_TXQ_STATS_TX_PACKETS, + NL80211_TXQ_STATS_MAX_FLOWS, + + /* keep last */ + NUM_NL80211_TXQ_STATS, + NL80211_TXQ_STATS_MAX = NUM_NL80211_TXQ_STATS - 1 +}; + +/** * enum nl80211_mpath_flags - nl80211 mesh path flags * * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active @@ -2529,8 +3795,10 @@ enum nl80211_mpath_flags { * &enum nl80211_mpath_flags; * @NL80211_MPATH_INFO_DISCOVERY_TIMEOUT: total path discovery timeout, in msec * @NL80211_MPATH_INFO_DISCOVERY_RETRIES: mesh path discovery retries + * @NL80211_MPATH_INFO_HOP_COUNT: hop count to destination + * @NL80211_MPATH_INFO_PATH_CHANGE: total number of path changes to destination * @NL80211_MPATH_INFO_MAX: highest mesh path information attribute number - * currently defind + * currently defined * @__NL80211_MPATH_INFO_AFTER_LAST: internal use */ enum nl80211_mpath_info { @@ -2542,6 +3810,8 @@ enum nl80211_mpath_info { NL80211_MPATH_INFO_FLAGS, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, NL80211_MPATH_INFO_DISCOVERY_RETRIES, + NL80211_MPATH_INFO_HOP_COUNT, + NL80211_MPATH_INFO_PATH_CHANGE, /* keep last */ __NL80211_MPATH_INFO_AFTER_LAST, @@ -2549,6 +3819,55 @@ enum nl80211_mpath_info { }; /** + * enum nl80211_band_iftype_attr - Interface type data attributes + * + * @__NL80211_BAND_IFTYPE_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_BAND_IFTYPE_ATTR_IFTYPES: nested attribute containing a flag attribute + * for each interface type that supports the band data + * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC: HE MAC capabilities as in HE + * capabilities IE + * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY: HE PHY capabilities as in HE + * capabilities IE + * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET: HE supported NSS/MCS as in HE + * capabilities IE + * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE: HE PPE thresholds information as + * defined in HE capabilities IE + * @NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA: HE 6GHz band capabilities (__le16), + * given for all 6 GHz band channels + * @NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS: vendor element capabilities that are + * advertised on this band/for this iftype (binary) + * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC: EHT MAC capabilities as in EHT + * capabilities element + * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY: EHT PHY capabilities as in EHT + * capabilities element + * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET: EHT supported NSS/MCS as in EHT + * capabilities element + * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE: EHT PPE thresholds information as + * defined in EHT capabilities element + * @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use + * @NL80211_BAND_IFTYPE_ATTR_MAX: highest band attribute currently defined + */ +enum nl80211_band_iftype_attr { + __NL80211_BAND_IFTYPE_ATTR_INVALID, + + NL80211_BAND_IFTYPE_ATTR_IFTYPES, + NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC, + NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY, + NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET, + NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE, + NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA, + NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS, + NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC, + NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY, + NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET, + NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE, + + /* keep last */ + __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST, + NL80211_BAND_IFTYPE_ATTR_MAX = __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST - 1 +}; + +/** * enum nl80211_band_attr - band attributes * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band, @@ -2563,6 +3882,14 @@ enum nl80211_mpath_info { * @NL80211_BAND_ATTR_VHT_MCS_SET: 32-byte attribute containing the MCS set as * defined in 802.11ac * @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE + * @NL80211_BAND_ATTR_IFTYPE_DATA: nested array attribute, with each entry using + * attributes from &enum nl80211_band_iftype_attr + * @NL80211_BAND_ATTR_EDMG_CHANNELS: bitmap that indicates the 2.16 GHz + * channel(s) that are allowed to be used for EDMG transmissions. + * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251. + * @NL80211_BAND_ATTR_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes + * the allowed channel bandwidth configurations. + * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13. * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined * @__NL80211_BAND_ATTR_AFTER_LAST: internal use */ @@ -2578,6 +3905,10 @@ enum nl80211_band_attr { NL80211_BAND_ATTR_VHT_MCS_SET, NL80211_BAND_ATTR_VHT_CAPA, + NL80211_BAND_ATTR_IFTYPE_DATA, + + NL80211_BAND_ATTR_EDMG_CHANNELS, + NL80211_BAND_ATTR_EDMG_BW_CONFIG, /* keep last */ __NL80211_BAND_ATTR_AFTER_LAST, @@ -2587,6 +3918,29 @@ enum nl80211_band_attr { #define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA /** + * enum nl80211_wmm_rule - regulatory wmm rule + * + * @__NL80211_WMMR_INVALID: attribute number 0 is reserved + * @NL80211_WMMR_CW_MIN: Minimum contention window slot. + * @NL80211_WMMR_CW_MAX: Maximum contention window slot. + * @NL80211_WMMR_AIFSN: Arbitration Inter Frame Space. + * @NL80211_WMMR_TXOP: Maximum allowed tx operation time. + * @nl80211_WMMR_MAX: highest possible wmm rule. + * @__NL80211_WMMR_LAST: Internal use. + */ +enum nl80211_wmm_rule { + __NL80211_WMMR_INVALID, + NL80211_WMMR_CW_MIN, + NL80211_WMMR_CW_MAX, + NL80211_WMMR_AIFSN, + NL80211_WMMR_TXOP, + + /* keep last */ + __NL80211_WMMR_LAST, + NL80211_WMMR_MAX = __NL80211_WMMR_LAST - 1 +}; + +/** * enum nl80211_frequency_attr - frequency attributes * @__NL80211_FREQUENCY_ATTR_INVALID: attribute number 0 is reserved * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz @@ -2620,20 +3974,41 @@ enum nl80211_band_attr { * an indoor surroundings, i.e., it is connected to AC power (and not * through portable DC inverters) or is under the control of a master * that is acting as an AP and is connected to AC power. - * @NL80211_FREQUENCY_ATTR_GO_CONCURRENT: GO operation is allowed on this + * @NL80211_FREQUENCY_ATTR_IR_CONCURRENT: IR operation is allowed on this * channel if it's connected concurrently to a BSS on the same channel on * the 2 GHz band or to a channel in the same UNII band (on the 5 GHz - * band), and IEEE80211_CHAN_RADAR is not set. Instantiating a GO on a - * channel that has the GO_CONCURRENT attribute set can be done when there - * is a clear assessment that the device is operating under the guidance of - * an authorized master, i.e., setting up a GO while the device is also - * connected to an AP with DFS and radar detection on the UNII band (it is - * up to user-space, i.e., wpa_supplicant to perform the required - * verifications) + * band), and IEEE80211_CHAN_RADAR is not set. Instantiating a GO or TDLS + * off-channel on a channel that has the IR_CONCURRENT attribute set can be + * done when there is a clear assessment that the device is operating under + * the guidance of an authorized master, i.e., setting up a GO or TDLS + * off-channel while the device is also connected to an AP with DFS and + * radar detection on the UNII band (it is up to user-space, i.e., + * wpa_supplicant to perform the required verifications). Using this + * attribute for IR is disallowed for master interfaces (IBSS, AP). * @NL80211_FREQUENCY_ATTR_NO_20MHZ: 20 MHz operation is not allowed * on this channel in current regulatory domain. * @NL80211_FREQUENCY_ATTR_NO_10MHZ: 10 MHz operation is not allowed * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_WMM: this channel has wmm limitations. + * This is a nested attribute that contains the wmm limitation per AC. + * (see &enum nl80211_wmm_rule) + * @NL80211_FREQUENCY_ATTR_NO_HE: HE operation is not allowed on this channel + * in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_OFFSET: frequency offset in KHz + * @NL80211_FREQUENCY_ATTR_1MHZ: 1 MHz operation is allowed + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_2MHZ: 2 MHz operation is allowed + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_4MHZ: 4 MHz operation is allowed + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_8MHZ: 8 MHz operation is allowed + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_16MHZ: 16 MHz operation is allowed + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_NO_320MHZ: any 320 MHz channel using this channel + * as the primary or any of the secondary channels isn't possible + * @NL80211_FREQUENCY_ATTR_NO_EHT: EHT operation is not allowed on this channel + * in current regulatory domain. * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number * currently defined * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use @@ -2641,7 +4016,7 @@ enum nl80211_band_attr { * See https://apps.fcc.gov/eas/comments/GetPublishedDocument.html?id=327&tn=528122 * for more information on the FCC description of the relaxations allowed * by NL80211_FREQUENCY_ATTR_INDOOR_ONLY and - * NL80211_FREQUENCY_ATTR_GO_CONCURRENT. + * NL80211_FREQUENCY_ATTR_IR_CONCURRENT. */ enum nl80211_frequency_attr { __NL80211_FREQUENCY_ATTR_INVALID, @@ -2659,9 +4034,19 @@ enum nl80211_frequency_attr { NL80211_FREQUENCY_ATTR_NO_160MHZ, NL80211_FREQUENCY_ATTR_DFS_CAC_TIME, NL80211_FREQUENCY_ATTR_INDOOR_ONLY, - NL80211_FREQUENCY_ATTR_GO_CONCURRENT, + NL80211_FREQUENCY_ATTR_IR_CONCURRENT, NL80211_FREQUENCY_ATTR_NO_20MHZ, NL80211_FREQUENCY_ATTR_NO_10MHZ, + NL80211_FREQUENCY_ATTR_WMM, + NL80211_FREQUENCY_ATTR_NO_HE, + NL80211_FREQUENCY_ATTR_OFFSET, + NL80211_FREQUENCY_ATTR_1MHZ, + NL80211_FREQUENCY_ATTR_2MHZ, + NL80211_FREQUENCY_ATTR_4MHZ, + NL80211_FREQUENCY_ATTR_8MHZ, + NL80211_FREQUENCY_ATTR_16MHZ, + NL80211_FREQUENCY_ATTR_NO_320MHZ, + NL80211_FREQUENCY_ATTR_NO_EHT, /* keep last */ __NL80211_FREQUENCY_ATTR_AFTER_LAST, @@ -2672,6 +4057,8 @@ enum nl80211_frequency_attr { #define NL80211_FREQUENCY_ATTR_PASSIVE_SCAN NL80211_FREQUENCY_ATTR_NO_IR #define NL80211_FREQUENCY_ATTR_NO_IBSS NL80211_FREQUENCY_ATTR_NO_IR #define NL80211_FREQUENCY_ATTR_NO_IR NL80211_FREQUENCY_ATTR_NO_IR +#define NL80211_FREQUENCY_ATTR_GO_CONCURRENT \ + NL80211_FREQUENCY_ATTR_IR_CONCURRENT /** * enum nl80211_bitrate_attr - bitrate attributes @@ -2787,6 +4174,7 @@ enum nl80211_reg_rule_attr { * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching, * only report BSS with matching SSID. + * (This cannot be used together with BSSID.) * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a * BSS in scan results. Filtering is turned off if not specified. Note that * if this attribute is in a match set of its own, then it is treated as @@ -2795,6 +4183,23 @@ enum nl80211_reg_rule_attr { * how this API was implemented in the past. Also, due to the same problem, * the only way to create a matchset with only an RSSI filter (with this * attribute) is if there's only a single matchset with the RSSI attribute. + * @NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI: Flag indicating whether + * %NL80211_SCHED_SCAN_MATCH_ATTR_RSSI to be used as absolute RSSI or + * relative to current bss's RSSI. + * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST: When present the RSSI level for + * BSS-es in the specified band is to be adjusted before doing + * RSSI-based BSS selection. The attribute value is a packed structure + * value as specified by &struct nl80211_bss_select_rssi_adjust. + * @NL80211_SCHED_SCAN_MATCH_ATTR_BSSID: BSSID to be used for matching + * (this cannot be used together with SSID). + * @NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI: Nested attribute that carries the + * band specific minimum rssi thresholds for the bands defined in + * enum nl80211_band. The minimum rssi threshold value(s32) specific to a + * band shall be encapsulated in attribute with type value equals to one + * of the NL80211_BAND_* defined in enum nl80211_band. For example, the + * minimum rssi threshold value for 2.4GHZ band shall be encapsulated + * within an attribute of type NL80211_BAND_2GHZ. And one or more of such + * attributes will be nested within this attribute. * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter * attribute number currently defined * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use @@ -2804,6 +4209,10 @@ enum nl80211_sched_scan_match_attr { NL80211_SCHED_SCAN_MATCH_ATTR_SSID, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, + NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI, + NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST, + NL80211_SCHED_SCAN_MATCH_ATTR_BSSID, + NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI, /* keep last */ __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST, @@ -2830,11 +4239,13 @@ enum nl80211_sched_scan_match_attr { * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated * base on contiguous rules and wider channels will be allowed to cross * multiple contiguous/overlapping frequency ranges. - * @NL80211_RRF_GO_CONCURRENT: See &NL80211_FREQUENCY_ATTR_GO_CONCURRENT + * @NL80211_RRF_IR_CONCURRENT: See %NL80211_FREQUENCY_ATTR_IR_CONCURRENT * @NL80211_RRF_NO_HT40MINUS: channels can't be used in HT40- operation * @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed * @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed + * @NL80211_RRF_NO_HE: HE operation not allowed + * @NL80211_RRF_NO_320MHZ: 320MHz operation not allowed */ enum nl80211_reg_rule_flags { NL80211_RRF_NO_OFDM = 1<<0, @@ -2847,11 +4258,13 @@ enum nl80211_reg_rule_flags { NL80211_RRF_NO_IR = 1<<7, __NL80211_RRF_NO_IBSS = 1<<8, NL80211_RRF_AUTO_BW = 1<<11, - NL80211_RRF_GO_CONCURRENT = 1<<12, + NL80211_RRF_IR_CONCURRENT = 1<<12, NL80211_RRF_NO_HT40MINUS = 1<<13, NL80211_RRF_NO_HT40PLUS = 1<<14, NL80211_RRF_NO_80MHZ = 1<<15, NL80211_RRF_NO_160MHZ = 1<<16, + NL80211_RRF_NO_HE = 1<<17, + NL80211_RRF_NO_320MHZ = 1<<18, }; #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR @@ -2859,6 +4272,7 @@ enum nl80211_reg_rule_flags { #define NL80211_RRF_NO_IR NL80211_RRF_NO_IR #define NL80211_RRF_NO_HT40 (NL80211_RRF_NO_HT40MINUS |\ NL80211_RRF_NO_HT40PLUS) +#define NL80211_RRF_GO_CONCURRENT NL80211_RRF_IR_CONCURRENT /* For backport compatibility with older userspace */ #define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS) @@ -2923,8 +4337,12 @@ enum nl80211_user_reg_hint_type { * transmitting data (on channel or globally) * @NL80211_SURVEY_INFO_TIME_SCAN: time the radio spent for scan * (on this channel or globally) + * @NL80211_SURVEY_INFO_PAD: attribute used for padding for 64-bit alignment + * @NL80211_SURVEY_INFO_TIME_BSS_RX: amount of time the radio spent + * receiving frames destined to the local BSS * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number * currently defined + * @NL80211_SURVEY_INFO_FREQUENCY_OFFSET: center frequency offset in KHz * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use */ enum nl80211_survey_info { @@ -2938,6 +4356,9 @@ enum nl80211_survey_info { NL80211_SURVEY_INFO_TIME_RX, NL80211_SURVEY_INFO_TIME_TX, NL80211_SURVEY_INFO_TIME_SCAN, + NL80211_SURVEY_INFO_PAD, + NL80211_SURVEY_INFO_TIME_BSS_RX, + NL80211_SURVEY_INFO_FREQUENCY_OFFSET, /* keep last */ __NL80211_SURVEY_INFO_AFTER_LAST, @@ -3118,6 +4539,21 @@ enum nl80211_mesh_power_mode { * remove it from the STA's list of peers. You may set this to 0 to disable * the removal of the STA. Default is 30 minutes. * + * @NL80211_MESHCONF_CONNECTED_TO_GATE: If set to true then this mesh STA + * will advertise that it is connected to a gate in the mesh formation + * field. If left unset then the mesh formation field will only + * advertise such if there is an active root mesh path. + * + * @NL80211_MESHCONF_NOLEARN: Try to avoid multi-hop path discovery (e.g. + * PREQ/PREP for HWMP) if the destination is a direct neighbor. Note that + * this might not be the optimal decision as a multi-hop route might be + * better. So if using this setting you will likely also want to disable + * dot11MeshForwarding and use another mesh routing protocol on top. + * + * @NL80211_MESHCONF_CONNECTED_TO_AS: If set to true then this mesh STA + * will advertise that it is connected to a authentication server + * in the mesh formation field. + * * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use */ enum nl80211_meshconf_params { @@ -3150,6 +4586,9 @@ enum nl80211_meshconf_params { NL80211_MESHCONF_POWER_MODE, NL80211_MESHCONF_AWAKE_WINDOW, NL80211_MESHCONF_PLINK_TIMEOUT, + NL80211_MESHCONF_CONNECTED_TO_GATE, + NL80211_MESHCONF_NOLEARN, + NL80211_MESHCONF_CONNECTED_TO_AS, /* keep last */ __NL80211_MESHCONF_ATTR_AFTER_LAST, @@ -3280,6 +4719,27 @@ enum nl80211_channel_type { }; /** + * enum nl80211_key_mode - Key mode + * + * @NL80211_KEY_RX_TX: (Default) + * Key can be used for Rx and Tx immediately + * + * The following modes can only be selected for unicast keys and when the + * driver supports @NL80211_EXT_FEATURE_EXT_KEY_ID: + * + * @NL80211_KEY_NO_TX: Only allowed in combination with @NL80211_CMD_NEW_KEY: + * Unicast key can only be used for Rx, Tx not allowed, yet + * @NL80211_KEY_SET_TX: Only allowed in combination with @NL80211_CMD_SET_KEY: + * The unicast key identified by idx and mac is cleared for Tx and becomes + * the preferred Tx key for the station. + */ +enum nl80211_key_mode { + NL80211_KEY_RX_TX, + NL80211_KEY_NO_TX, + NL80211_KEY_SET_TX +}; + +/** * enum nl80211_chan_width - channel width definitions * * These values are used with the %NL80211_ATTR_CHANNEL_WIDTH @@ -3297,6 +4757,13 @@ enum nl80211_channel_type { * attribute must be provided as well * @NL80211_CHAN_WIDTH_5: 5 MHz OFDM channel * @NL80211_CHAN_WIDTH_10: 10 MHz OFDM channel + * @NL80211_CHAN_WIDTH_1: 1 MHz OFDM channel + * @NL80211_CHAN_WIDTH_2: 2 MHz OFDM channel + * @NL80211_CHAN_WIDTH_4: 4 MHz OFDM channel + * @NL80211_CHAN_WIDTH_8: 8 MHz OFDM channel + * @NL80211_CHAN_WIDTH_16: 16 MHz OFDM channel + * @NL80211_CHAN_WIDTH_320: 320 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 + * attribute must be provided as well */ enum nl80211_chan_width { NL80211_CHAN_WIDTH_20_NOHT, @@ -3307,6 +4774,12 @@ enum nl80211_chan_width { NL80211_CHAN_WIDTH_160, NL80211_CHAN_WIDTH_5, NL80211_CHAN_WIDTH_10, + NL80211_CHAN_WIDTH_1, + NL80211_CHAN_WIDTH_2, + NL80211_CHAN_WIDTH_4, + NL80211_CHAN_WIDTH_8, + NL80211_CHAN_WIDTH_16, + NL80211_CHAN_WIDTH_320, }; /** @@ -3317,11 +4790,15 @@ enum nl80211_chan_width { * @NL80211_BSS_CHAN_WIDTH_20: control channel is 20 MHz wide or compatible * @NL80211_BSS_CHAN_WIDTH_10: control channel is 10 MHz wide * @NL80211_BSS_CHAN_WIDTH_5: control channel is 5 MHz wide + * @NL80211_BSS_CHAN_WIDTH_1: control channel is 1 MHz wide + * @NL80211_BSS_CHAN_WIDTH_2: control channel is 2 MHz wide */ enum nl80211_bss_scan_width { NL80211_BSS_CHAN_WIDTH_20, NL80211_BSS_CHAN_WIDTH_10, NL80211_BSS_CHAN_WIDTH_5, + NL80211_BSS_CHAN_WIDTH_1, + NL80211_BSS_CHAN_WIDTH_2, }; /** @@ -3360,6 +4837,20 @@ enum nl80211_bss_scan_width { * (not present if no beacon frame has been received yet) * @NL80211_BSS_PRESP_DATA: the data in @NL80211_BSS_INFORMATION_ELEMENTS and * @NL80211_BSS_TSF is known to be from a probe response (flag attribute) + * @NL80211_BSS_LAST_SEEN_BOOTTIME: CLOCK_BOOTTIME timestamp when this entry + * was last updated by a received frame. The value is expected to be + * accurate to about 10ms. (u64, nanoseconds) + * @NL80211_BSS_PAD: attribute used for padding for 64-bit alignment + * @NL80211_BSS_PARENT_TSF: the time at the start of reception of the first + * octet of the timestamp field of the last beacon/probe received for + * this BSS. The time is the TSF of the BSS specified by + * @NL80211_BSS_PARENT_BSSID. (u64). + * @NL80211_BSS_PARENT_BSSID: the BSS according to which @NL80211_BSS_PARENT_TSF + * is set. + * @NL80211_BSS_CHAIN_SIGNAL: per-chain signal strength of last BSS update. + * Contains a nested array of signal strength attributes (u8, dBm), + * using the nesting index as the antenna number. + * @NL80211_BSS_FREQUENCY_OFFSET: frequency offset in KHz * @__NL80211_BSS_AFTER_LAST: internal * @NL80211_BSS_MAX: highest BSS attribute */ @@ -3379,6 +4870,12 @@ enum nl80211_bss { NL80211_BSS_CHAN_WIDTH, NL80211_BSS_BEACON_TSF, NL80211_BSS_PRESP_DATA, + NL80211_BSS_LAST_SEEN_BOOTTIME, + NL80211_BSS_PAD, + NL80211_BSS_PARENT_TSF, + NL80211_BSS_PARENT_BSSID, + NL80211_BSS_CHAIN_SIGNAL, + NL80211_BSS_FREQUENCY_OFFSET, /* keep last */ __NL80211_BSS_AFTER_LAST, @@ -3411,6 +4908,9 @@ enum nl80211_bss_status { * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r) * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP) * @NL80211_AUTHTYPE_SAE: Simultaneous authentication of equals + * @NL80211_AUTHTYPE_FILS_SK: Fast Initial Link Setup shared key + * @NL80211_AUTHTYPE_FILS_SK_PFS: Fast Initial Link Setup shared key with PFS + * @NL80211_AUTHTYPE_FILS_PK: Fast Initial Link Setup public key * @__NL80211_AUTHTYPE_NUM: internal * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by @@ -3423,6 +4923,9 @@ enum nl80211_auth_type { NL80211_AUTHTYPE_FT, NL80211_AUTHTYPE_NETWORK_EAP, NL80211_AUTHTYPE_SAE, + NL80211_AUTHTYPE_FILS_SK, + NL80211_AUTHTYPE_FILS_SK_PFS, + NL80211_AUTHTYPE_FILS_PK, /* keep last */ __NL80211_AUTHTYPE_NUM, @@ -3449,15 +4952,18 @@ enum nl80211_key_type { * enum nl80211_mfp - Management frame protection state * @NL80211_MFP_NO: Management frame protection not used * @NL80211_MFP_REQUIRED: Management frame protection required + * @NL80211_MFP_OPTIONAL: Management frame protection is optional */ enum nl80211_mfp { NL80211_MFP_NO, NL80211_MFP_REQUIRED, + NL80211_MFP_OPTIONAL, }; enum nl80211_wpa_versions { NL80211_WPA_VERSION_1 = 1 << 0, NL80211_WPA_VERSION_2 = 1 << 1, + NL80211_WPA_VERSION_3 = 1 << 2, }; /** @@ -3496,6 +5002,10 @@ enum nl80211_key_default_types { * @NL80211_KEY_DEFAULT_TYPES: A nested attribute containing flags * attributes, specifying what a key should be set as default as. * See &enum nl80211_key_default_types. + * @NL80211_KEY_MODE: the mode from enum nl80211_key_mode. + * Defaults to @NL80211_KEY_RX_TX. + * @NL80211_KEY_DEFAULT_BEACON: flag indicating default Beacon frame key + * * @__NL80211_KEY_AFTER_LAST: internal * @NL80211_KEY_MAX: highest key attribute */ @@ -3509,6 +5019,8 @@ enum nl80211_key_attributes { NL80211_KEY_DEFAULT_MGMT, NL80211_KEY_TYPE, NL80211_KEY_DEFAULT_TYPES, + NL80211_KEY_MODE, + NL80211_KEY_DEFAULT_BEACON, /* keep last */ __NL80211_KEY_AFTER_LAST, @@ -3527,6 +5039,10 @@ enum nl80211_key_attributes { * @NL80211_TXRATE_VHT: VHT rates allowed for TX rate selection, * see &struct nl80211_txrate_vht * @NL80211_TXRATE_GI: configure GI, see &enum nl80211_txrate_gi + * @NL80211_TXRATE_HE: HE rates allowed for TX rate selection, + * see &struct nl80211_txrate_he + * @NL80211_TXRATE_HE_GI: configure HE GI, 0.8us, 1.6us and 3.2us. + * @NL80211_TXRATE_HE_LTF: configure HE LTF, 1XLTF, 2XLTF and 4XLTF. * @__NL80211_TXRATE_AFTER_LAST: internal * @NL80211_TXRATE_MAX: highest TX rate attribute */ @@ -3536,6 +5052,9 @@ enum nl80211_tx_rate_attributes { NL80211_TXRATE_HT, NL80211_TXRATE_VHT, NL80211_TXRATE_GI, + NL80211_TXRATE_HE, + NL80211_TXRATE_HE_GI, + NL80211_TXRATE_HE_LTF, /* keep last */ __NL80211_TXRATE_AFTER_LAST, @@ -3553,6 +5072,15 @@ struct nl80211_txrate_vht { __u16 mcs[NL80211_VHT_NSS_MAX]; }; +#define NL80211_HE_NSS_MAX 8 +/** + * struct nl80211_txrate_he - HE MCS/NSS txrate bitmap + * @mcs: MCS bitmap table for each NSS (array index 0 for 1 stream, etc.) + */ +struct nl80211_txrate_he { + __u16 mcs[NL80211_HE_NSS_MAX]; +}; + enum nl80211_txrate_gi { NL80211_TXRATE_DEFAULT_GI, NL80211_TXRATE_FORCE_SGI, @@ -3563,12 +5091,22 @@ enum nl80211_txrate_gi { * enum nl80211_band - Frequency band * @NL80211_BAND_2GHZ: 2.4 GHz ISM band * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz) - * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz) + * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 69.12 GHz) + * @NL80211_BAND_6GHZ: around 6 GHz band (5.9 - 7.2 GHz) + * @NL80211_BAND_S1GHZ: around 900MHz, supported by S1G PHYs + * @NL80211_BAND_LC: light communication band (placeholder) + * @NUM_NL80211_BANDS: number of bands, avoid using this in userspace + * since newer kernel versions may support more bands */ enum nl80211_band { NL80211_BAND_2GHZ, NL80211_BAND_5GHZ, NL80211_BAND_60GHZ, + NL80211_BAND_6GHZ, + NL80211_BAND_S1GHZ, + NL80211_BAND_LC, + + NUM_NL80211_BANDS, }; /** @@ -3586,7 +5124,10 @@ enum nl80211_ps_state { * @__NL80211_ATTR_CQM_INVALID: invalid * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies * the threshold for the RSSI level at which an event will be sent. Zero - * to disable. + * to disable. Alternatively, if %NL80211_EXT_FEATURE_CQM_RSSI_LIST is + * set, multiple values can be supplied as a low-to-high sorted array of + * threshold values in dBm. Events will be sent when the RSSI value + * crosses any of the thresholds. * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies * the minimum amount the RSSI level must change after an event before a * new event may be issued (to reduce effects of RSSI oscillation). @@ -3606,6 +5147,8 @@ enum nl80211_ps_state { * %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting. * @NL80211_ATTR_CQM_BEACON_LOSS_EVENT: flag attribute that's set in a beacon * loss event + * @NL80211_ATTR_CQM_RSSI_LEVEL: the RSSI value in dBm that triggered the + * RSSI threshold event. * @__NL80211_ATTR_CQM_AFTER_LAST: internal * @NL80211_ATTR_CQM_MAX: highest key attribute */ @@ -3619,6 +5162,7 @@ enum nl80211_attr_cqm { NL80211_ATTR_CQM_TXE_PKTS, NL80211_ATTR_CQM_TXE_INTVL, NL80211_ATTR_CQM_BEACON_LOSS_EVENT, + NL80211_ATTR_CQM_RSSI_LEVEL, /* keep last */ __NL80211_ATTR_CQM_AFTER_LAST, @@ -3653,6 +5197,92 @@ enum nl80211_tx_power_setting { }; /** + * enum nl80211_tid_config - TID config state + * @NL80211_TID_CONFIG_ENABLE: Enable config for the TID + * @NL80211_TID_CONFIG_DISABLE: Disable config for the TID + */ +enum nl80211_tid_config { + NL80211_TID_CONFIG_ENABLE, + NL80211_TID_CONFIG_DISABLE, +}; + +/* enum nl80211_tx_rate_setting - TX rate configuration type + * @NL80211_TX_RATE_AUTOMATIC: automatically determine TX rate + * @NL80211_TX_RATE_LIMITED: limit the TX rate by the TX rate parameter + * @NL80211_TX_RATE_FIXED: fix TX rate to the TX rate parameter + */ +enum nl80211_tx_rate_setting { + NL80211_TX_RATE_AUTOMATIC, + NL80211_TX_RATE_LIMITED, + NL80211_TX_RATE_FIXED, +}; + +/* enum nl80211_tid_config_attr - TID specific configuration. + * @NL80211_TID_CONFIG_ATTR_PAD: pad attribute for 64-bit values + * @NL80211_TID_CONFIG_ATTR_VIF_SUPP: a bitmap (u64) of attributes supported + * for per-vif configuration; doesn't list the ones that are generic + * (%NL80211_TID_CONFIG_ATTR_TIDS, %NL80211_TID_CONFIG_ATTR_OVERRIDE). + * @NL80211_TID_CONFIG_ATTR_PEER_SUPP: same as the previous per-vif one, but + * per peer instead. + * @NL80211_TID_CONFIG_ATTR_OVERRIDE: flag attribue, if set indicates + * that the new configuration overrides all previous peer + * configurations, otherwise previous peer specific configurations + * should be left untouched. + * @NL80211_TID_CONFIG_ATTR_TIDS: a bitmask value of TIDs (bit 0 to 7) + * Its type is u16. + * @NL80211_TID_CONFIG_ATTR_NOACK: Configure ack policy for the TID. + * specified in %NL80211_TID_CONFIG_ATTR_TID. see %enum nl80211_tid_config. + * Its type is u8. + * @NL80211_TID_CONFIG_ATTR_RETRY_SHORT: Number of retries used with data frame + * transmission, user-space sets this configuration in + * &NL80211_CMD_SET_TID_CONFIG. It is u8 type, min value is 1 and + * the max value is advertised by the driver in this attribute on + * output in wiphy capabilities. + * @NL80211_TID_CONFIG_ATTR_RETRY_LONG: Number of retries used with data frame + * transmission, user-space sets this configuration in + * &NL80211_CMD_SET_TID_CONFIG. Its type is u8, min value is 1 and + * the max value is advertised by the driver in this attribute on + * output in wiphy capabilities. + * @NL80211_TID_CONFIG_ATTR_AMPDU_CTRL: Enable/Disable MPDU aggregation + * for the TIDs specified in %NL80211_TID_CONFIG_ATTR_TIDS. + * Its type is u8, using the values from &nl80211_tid_config. + * @NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL: Enable/Disable RTS_CTS for the TIDs + * specified in %NL80211_TID_CONFIG_ATTR_TIDS. It is u8 type, using + * the values from &nl80211_tid_config. + * @NL80211_TID_CONFIG_ATTR_AMSDU_CTRL: Enable/Disable MSDU aggregation + * for the TIDs specified in %NL80211_TID_CONFIG_ATTR_TIDS. + * Its type is u8, using the values from &nl80211_tid_config. + * @NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE: This attribute will be useful + * to notfiy the driver that what type of txrate should be used + * for the TIDs specified in %NL80211_TID_CONFIG_ATTR_TIDS. using + * the values form &nl80211_tx_rate_setting. + * @NL80211_TID_CONFIG_ATTR_TX_RATE: Data frame TX rate mask should be applied + * with the parameters passed through %NL80211_ATTR_TX_RATES. + * configuration is applied to the data frame for the tid to that connected + * station. + */ +enum nl80211_tid_config_attr { + __NL80211_TID_CONFIG_ATTR_INVALID, + NL80211_TID_CONFIG_ATTR_PAD, + NL80211_TID_CONFIG_ATTR_VIF_SUPP, + NL80211_TID_CONFIG_ATTR_PEER_SUPP, + NL80211_TID_CONFIG_ATTR_OVERRIDE, + NL80211_TID_CONFIG_ATTR_TIDS, + NL80211_TID_CONFIG_ATTR_NOACK, + NL80211_TID_CONFIG_ATTR_RETRY_SHORT, + NL80211_TID_CONFIG_ATTR_RETRY_LONG, + NL80211_TID_CONFIG_ATTR_AMPDU_CTRL, + NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL, + NL80211_TID_CONFIG_ATTR_AMSDU_CTRL, + NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE, + NL80211_TID_CONFIG_ATTR_TX_RATE, + + /* keep last */ + __NL80211_TID_CONFIG_ATTR_AFTER_LAST, + NL80211_TID_CONFIG_ATTR_MAX = __NL80211_TID_CONFIG_ATTR_AFTER_LAST - 1 +}; + +/** * enum nl80211_packet_pattern_attr - packet pattern attribute * @__NL80211_PKTPAT_INVALID: invalid number for nested attribute * @NL80211_PKTPAT_PATTERN: the pattern, values where the mask has @@ -4027,6 +5657,9 @@ enum nl80211_iface_limit_attrs { * of supported channel widths for radar detection. * @NL80211_IFACE_COMB_RADAR_DETECT_REGIONS: u32 attribute containing the bitmap * of supported regulatory regions for radar detection. + * @NL80211_IFACE_COMB_BI_MIN_GCD: u32 attribute specifying the minimum GCD of + * different beacon intervals supported by all the interface combinations + * in this group (if not present, all beacon intervals be identical). * @NUM_NL80211_IFACE_COMB: number of attributes * @MAX_NL80211_IFACE_COMB: highest attribute number * @@ -4034,16 +5667,16 @@ enum nl80211_iface_limit_attrs { * limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2 * => allows an AP and a STA that must match BIs * - * numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8 - * => allows 8 of AP/GO + * numbers = [ #{AP, P2P-GO} <= 8 ], BI min gcd, channels = 1, max = 8, + * => allows 8 of AP/GO that can have BI gcd >= min gcd * * numbers = [ #{STA} <= 2 ], channels = 2, max = 2 - * => allows two STAs on different channels + * => allows two STAs on the same or on different channels * * numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4 * => allows a STA plus three P2P interfaces * - * The list of these four possiblities could completely be contained + * The list of these four possibilities could completely be contained * within the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute to indicate * that any of these groups must match. * @@ -4061,6 +5694,7 @@ enum nl80211_if_combination_attrs { NL80211_IFACE_COMB_NUM_CHANNELS, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS, + NL80211_IFACE_COMB_BI_MIN_GCD, /* keep last */ NUM_NL80211_IFACE_COMB, @@ -4072,7 +5706,7 @@ enum nl80211_if_combination_attrs { * enum nl80211_plink_state - state of a mesh peer link finite state machine * * @NL80211_PLINK_LISTEN: initial state, considered the implicit - * state of non existant mesh peer links + * state of non existent mesh peer links * @NL80211_PLINK_OPN_SNT: mesh plink open frame has been sent to * this mesh peer * @NL80211_PLINK_OPN_RCVD: mesh plink open frame has been received @@ -4082,7 +5716,7 @@ enum nl80211_if_combination_attrs { * @NL80211_PLINK_ESTAB: mesh peer link is established * @NL80211_PLINK_HOLDING: mesh peer link is being closed or cancelled * @NL80211_PLINK_BLOCKED: all frames transmitted from this mesh - * plink are discarded + * plink are discarded, except for authentication frames * @NUM_NL80211_PLINK_STATES: number of peer link states * @MAX_NL80211_PLINK_STATES: highest numerical value of plink states */ @@ -4119,6 +5753,8 @@ enum plink_actions { #define NL80211_KCK_LEN 16 #define NL80211_KEK_LEN 16 +#define NL80211_KCK_EXT_LEN 24 +#define NL80211_KEK_EXT_LEN 32 #define NL80211_REPLAY_CTR_LEN 8 /** @@ -4127,6 +5763,7 @@ enum plink_actions { * @NL80211_REKEY_DATA_KEK: key encryption key (binary) * @NL80211_REKEY_DATA_KCK: key confirmation key (binary) * @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary) + * @NL80211_REKEY_DATA_AKM: AKM data (OUI, suite type) * @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal) * @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal) */ @@ -4135,6 +5772,7 @@ enum nl80211_rekey_data { NL80211_REKEY_DATA_KEK, NL80211_REKEY_DATA_KCK, NL80211_REKEY_DATA_REPLAY_CTR, + NL80211_REKEY_DATA_AKM, /* keep last */ NUM_NL80211_REKEY_DATA, @@ -4215,13 +5853,15 @@ enum nl80211_tdls_operation { NL80211_TDLS_DISABLE_LINK, }; -/* +/** * enum nl80211_ap_sme_features - device-integrated AP features - * Reserved for future use, no bits are defined in - * NL80211_ATTR_DEVICE_AP_SME yet. + * @NL80211_AP_SME_SA_QUERY_OFFLOAD: SA Query procedures offloaded to driver + * when user space indicates support for SA Query procedures offload during + * "start ap" with %NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT. + */ enum nl80211_ap_sme_features { + NL80211_AP_SME_SA_QUERY_OFFLOAD = 1 << 0, }; - */ /** * enum nl80211_feature_flags - device/driver features @@ -4348,18 +5988,257 @@ enum nl80211_feature_flags { NL80211_FEATURE_TDLS_CHANNEL_SWITCH = 1 << 28, NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR = 1 << 29, NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR = 1 << 30, - NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1 << 31, + NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1U << 31, }; /** * enum nl80211_ext_feature_index - bit index of extended features. * @NL80211_EXT_FEATURE_VHT_IBSS: This driver supports IBSS with VHT datarates. + * @NL80211_EXT_FEATURE_RRM: This driver supports RRM. When featured, user can + * request to use RRM (see %NL80211_ATTR_USE_RRM) with + * %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests, which will set + * the ASSOC_REQ_USE_RRM flag in the association request even if + * NL80211_FEATURE_QUIET is not advertized. + * @NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER: This device supports MU-MIMO air + * sniffer which means that it can be configured to hear packets from + * certain groups which can be configured by the + * %NL80211_ATTR_MU_MIMO_GROUP_DATA attribute, + * or can be configured to follow a station by configuring the + * %NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR attribute. + * @NL80211_EXT_FEATURE_SCAN_START_TIME: This driver includes the actual + * time the scan started in scan results event. The time is the TSF of + * the BSS that the interface that requested the scan is connected to + * (if available). + * @NL80211_EXT_FEATURE_BSS_PARENT_TSF: Per BSS, this driver reports the + * time the last beacon/probe was received. The time is the TSF of the + * BSS that the interface that requested the scan is connected to + * (if available). + * @NL80211_EXT_FEATURE_SET_SCAN_DWELL: This driver supports configuration of + * channel dwell time. + * @NL80211_EXT_FEATURE_BEACON_RATE_LEGACY: Driver supports beacon rate + * configuration (AP/mesh), supporting a legacy (non HT/VHT) rate. + * @NL80211_EXT_FEATURE_BEACON_RATE_HT: Driver supports beacon rate + * configuration (AP/mesh) with HT rates. + * @NL80211_EXT_FEATURE_BEACON_RATE_VHT: Driver supports beacon rate + * configuration (AP/mesh) with VHT rates. + * @NL80211_EXT_FEATURE_FILS_STA: This driver supports Fast Initial Link Setup + * with user space SME (NL80211_CMD_AUTHENTICATE) in station mode. + * @NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA: This driver supports randomized TA + * in @NL80211_CMD_FRAME while not associated. + * @NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED: This driver supports + * randomized TA in @NL80211_CMD_FRAME while associated. + * @NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI: The driver supports sched_scan + * for reporting BSSs with better RSSI than the current connected BSS + * (%NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI). + * @NL80211_EXT_FEATURE_CQM_RSSI_LIST: With this driver the + * %NL80211_ATTR_CQM_RSSI_THOLD attribute accepts a list of zero or more + * RSSI threshold values to monitor rather than exactly one threshold. + * @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD: Driver SME supports FILS shared key + * authentication with %NL80211_CMD_CONNECT. + * @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK: Device wants to do 4-way + * handshake with PSK in station mode (PSK is passed as part of the connect + * and associate commands), doing it in the host might not be supported. + * @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X: Device wants to do doing 4-way + * handshake with 802.1X in station mode (will pass EAP frames to the host + * and accept the set_pmk/del_pmk commands), doing it in the host might not + * be supported. + * @NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME: Driver is capable of overriding + * the max channel attribute in the FILS request params IE with the + * actual dwell time. + * @NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP: Driver accepts broadcast probe + * response + * @NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE: Driver supports sending + * the first probe request in each channel at rate of at least 5.5Mbps. + * @NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION: Driver supports + * probe request tx deferral and suppression + * @NL80211_EXT_FEATURE_MFP_OPTIONAL: Driver supports the %NL80211_MFP_OPTIONAL + * value in %NL80211_ATTR_USE_MFP. + * @NL80211_EXT_FEATURE_LOW_SPAN_SCAN: Driver supports low span scan. + * @NL80211_EXT_FEATURE_LOW_POWER_SCAN: Driver supports low power scan. + * @NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN: Driver supports high accuracy scan. + * @NL80211_EXT_FEATURE_DFS_OFFLOAD: HW/driver will offload DFS actions. + * Device or driver will do all DFS-related actions by itself, + * informing user-space about CAC progress, radar detection event, + * channel change triggered by radar detection event. + * No need to start CAC from user-space, no need to react to + * "radar detected" event. + * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211: Driver supports sending and + * receiving control port frames over nl80211 instead of the netdevice. + * @NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT: This driver/device supports + * (average) ACK signal strength reporting. + * @NL80211_EXT_FEATURE_TXQS: Driver supports FQ-CoDel-enabled intermediate + * TXQs. + * @NL80211_EXT_FEATURE_SCAN_RANDOM_SN: Driver/device supports randomizing the + * SN in probe request frames if requested by %NL80211_SCAN_FLAG_RANDOM_SN. + * @NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT: Driver/device can omit all data + * except for supported rates from the probe request content if requested + * by the %NL80211_SCAN_FLAG_MIN_PREQ_CONTENT flag. + * @NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER: Driver supports enabling fine + * timing measurement responder role. + * + * @NL80211_EXT_FEATURE_CAN_REPLACE_PTK0: Driver/device confirm that they are + * able to rekey an in-use key correctly. Userspace must not rekey PTK keys + * if this flag is not set. Ignoring this can leak clear text packets and/or + * freeze the connection. + * @NL80211_EXT_FEATURE_EXT_KEY_ID: Driver supports "Extended Key ID for + * Individually Addressed Frames" from IEEE802.11-2016. + * + * @NL80211_EXT_FEATURE_AIRTIME_FAIRNESS: Driver supports getting airtime + * fairness for transmitted packets and has enabled airtime fairness + * scheduling. + * + * @NL80211_EXT_FEATURE_AP_PMKSA_CACHING: Driver/device supports PMKSA caching + * (set/del PMKSA operations) in AP mode. + * + * @NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD: Driver supports + * filtering of sched scan results using band specific RSSI thresholds. + * + * @NL80211_EXT_FEATURE_STA_TX_PWR: This driver supports controlling tx power + * to a station. + * + * @NL80211_EXT_FEATURE_SAE_OFFLOAD: Device wants to do SAE authentication in + * station mode (SAE password is passed as part of the connect command). + * + * @NL80211_EXT_FEATURE_VLAN_OFFLOAD: The driver supports a single netdev + * with VLAN tagged frames and separate VLAN-specific netdevs added using + * vconfig similarly to the Ethernet case. + * + * @NL80211_EXT_FEATURE_AQL: The driver supports the Airtime Queue Limit (AQL) + * feature, which prevents bufferbloat by using the expected transmission + * time to limit the amount of data buffered in the hardware. + * + * @NL80211_EXT_FEATURE_BEACON_PROTECTION: The driver supports Beacon protection + * and can receive key configuration for BIGTK using key indexes 6 and 7. + * @NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT: The driver supports Beacon + * protection as a client only and cannot transmit protected beacons. + * + * @NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH: The driver can disable the + * forwarding of preauth frames over the control port. They are then + * handled as ordinary data frames. + * + * @NL80211_EXT_FEATURE_PROTECTED_TWT: Driver supports protected TWT frames + * + * @NL80211_EXT_FEATURE_DEL_IBSS_STA: The driver supports removing stations + * in IBSS mode, essentially by dropping their state. + * + * @NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS: management frame registrations + * are possible for multicast frames and those will be reported properly. + * + * @NL80211_EXT_FEATURE_SCAN_FREQ_KHZ: This driver supports receiving and + * reporting scan request with %NL80211_ATTR_SCAN_FREQ_KHZ. In order to + * report %NL80211_ATTR_SCAN_FREQ_KHZ, %NL80211_SCAN_FLAG_FREQ_KHZ must be + * included in the scan request. + * + * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS: The driver + * can report tx status for control port over nl80211 tx operations. + * + * @NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION: Driver supports Operating + * Channel Validation (OCV) when using driver's SME for RSNA handshakes. + * + * @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK: Device wants to do 4-way + * handshake with PSK in AP mode (PSK is passed as part of the start AP + * command). + * + * @NL80211_EXT_FEATURE_SAE_OFFLOAD_AP: Device wants to do SAE authentication + * in AP mode (SAE password is passed as part of the start AP command). + * + * @NL80211_EXT_FEATURE_FILS_DISCOVERY: Driver/device supports FILS discovery + * frames transmission + * + * @NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP: Driver/device supports + * unsolicited broadcast probe response transmission + * + * @NL80211_EXT_FEATURE_BEACON_RATE_HE: Driver supports beacon rate + * configuration (AP/mesh) with HE rates. + * + * @NL80211_EXT_FEATURE_SECURE_LTF: Device supports secure LTF measurement + * exchange protocol. + * + * @NL80211_EXT_FEATURE_SECURE_RTT: Device supports secure RTT measurement + * exchange protocol. + * + * @NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE: Device supports management + * frame protection for all management frames exchanged during the + * negotiation and range measurement procedure. + * + * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision + * detection and change announcemnts. + * + * @NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD: Driver running in AP mode supports + * FILS encryption and decryption for (Re)Association Request and Response + * frames. Userspace has to share FILS AAD details to the driver by using + * @NL80211_CMD_SET_FILS_AAD. + * + * @NL80211_EXT_FEATURE_RADAR_BACKGROUND: Device supports background radar/CAC + * detection. * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. */ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_VHT_IBSS, + NL80211_EXT_FEATURE_RRM, + NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER, + NL80211_EXT_FEATURE_SCAN_START_TIME, + NL80211_EXT_FEATURE_BSS_PARENT_TSF, + NL80211_EXT_FEATURE_SET_SCAN_DWELL, + NL80211_EXT_FEATURE_BEACON_RATE_LEGACY, + NL80211_EXT_FEATURE_BEACON_RATE_HT, + NL80211_EXT_FEATURE_BEACON_RATE_VHT, + NL80211_EXT_FEATURE_FILS_STA, + NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA, + NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED, + NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI, + NL80211_EXT_FEATURE_CQM_RSSI_LIST, + NL80211_EXT_FEATURE_FILS_SK_OFFLOAD, + NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK, + NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X, + NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME, + NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP, + NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE, + NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION, + NL80211_EXT_FEATURE_MFP_OPTIONAL, + NL80211_EXT_FEATURE_LOW_SPAN_SCAN, + NL80211_EXT_FEATURE_LOW_POWER_SCAN, + NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN, + NL80211_EXT_FEATURE_DFS_OFFLOAD, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211, + NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT, + /* we renamed this - stay compatible */ + NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT = NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT, + NL80211_EXT_FEATURE_TXQS, + NL80211_EXT_FEATURE_SCAN_RANDOM_SN, + NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT, + NL80211_EXT_FEATURE_CAN_REPLACE_PTK0, + NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER, + NL80211_EXT_FEATURE_AIRTIME_FAIRNESS, + NL80211_EXT_FEATURE_AP_PMKSA_CACHING, + NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD, + NL80211_EXT_FEATURE_EXT_KEY_ID, + NL80211_EXT_FEATURE_STA_TX_PWR, + NL80211_EXT_FEATURE_SAE_OFFLOAD, + NL80211_EXT_FEATURE_VLAN_OFFLOAD, + NL80211_EXT_FEATURE_AQL, + NL80211_EXT_FEATURE_BEACON_PROTECTION, + NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH, + NL80211_EXT_FEATURE_PROTECTED_TWT, + NL80211_EXT_FEATURE_DEL_IBSS_STA, + NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS, + NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT, + NL80211_EXT_FEATURE_SCAN_FREQ_KHZ, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS, + NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION, + NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK, + NL80211_EXT_FEATURE_SAE_OFFLOAD_AP, + NL80211_EXT_FEATURE_FILS_DISCOVERY, + NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP, + NL80211_EXT_FEATURE_BEACON_RATE_HE, + NL80211_EXT_FEATURE_SECURE_LTF, + NL80211_EXT_FEATURE_SECURE_RTT, + NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, + NL80211_EXT_FEATURE_BSS_COLOR, + NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD, + NL80211_EXT_FEATURE_RADAR_BACKGROUND, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, @@ -4399,12 +6278,31 @@ enum nl80211_connect_failed_reason { }; /** + * enum nl80211_timeout_reason - timeout reasons + * + * @NL80211_TIMEOUT_UNSPECIFIED: Timeout reason unspecified. + * @NL80211_TIMEOUT_SCAN: Scan (AP discovery) timed out. + * @NL80211_TIMEOUT_AUTH: Authentication timed out. + * @NL80211_TIMEOUT_ASSOC: Association timed out. + */ +enum nl80211_timeout_reason { + NL80211_TIMEOUT_UNSPECIFIED, + NL80211_TIMEOUT_SCAN, + NL80211_TIMEOUT_AUTH, + NL80211_TIMEOUT_ASSOC, +}; + +/** * enum nl80211_scan_flags - scan request control flags * * Scan request control flags are used to control the handling * of NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN * requests. * + * NL80211_SCAN_FLAG_LOW_SPAN, NL80211_SCAN_FLAG_LOW_POWER, and + * NL80211_SCAN_FLAG_HIGH_ACCURACY flags are exclusive of each other, i.e., only + * one of them can be used in the request. + * * @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority * @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning * @NL80211_SCAN_FLAG_AP: force a scan even if the interface is configured @@ -4421,12 +6319,59 @@ enum nl80211_connect_failed_reason { * locally administered 1, multicast 0) is assumed. * This flag must not be requested when the feature isn't supported, check * the nl80211 feature flags for the device. + * @NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME: fill the dwell time in the FILS + * request parameters IE in the probe request + * @NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP: accept broadcast probe responses + * @NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE: send probe request frames at + * rate of at least 5.5M. In case non OCE AP is discovered in the channel, + * only the first probe req in the channel will be sent in high rate. + * @NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION: allow probe request + * tx deferral (dot11FILSProbeDelay shall be set to 15ms) + * and suppression (if it has received a broadcast Probe Response frame, + * Beacon frame or FILS Discovery frame from an AP that the STA considers + * a suitable candidate for (re-)association - suitable in terms of + * SSID and/or RSSI. + * @NL80211_SCAN_FLAG_LOW_SPAN: Span corresponds to the total time taken to + * accomplish the scan. Thus, this flag intends the driver to perform the + * scan request with lesser span/duration. It is specific to the driver + * implementations on how this is accomplished. Scan accuracy may get + * impacted with this flag. + * @NL80211_SCAN_FLAG_LOW_POWER: This flag intends the scan attempts to consume + * optimal possible power. Drivers can resort to their specific means to + * optimize the power. Scan accuracy may get impacted with this flag. + * @NL80211_SCAN_FLAG_HIGH_ACCURACY: Accuracy here intends to the extent of scan + * results obtained. Thus HIGH_ACCURACY scan flag aims to get maximum + * possible scan results. This flag hints the driver to use the best + * possible scan configuration to improve the accuracy in scanning. + * Latency and power use may get impacted with this flag. + * @NL80211_SCAN_FLAG_RANDOM_SN: randomize the sequence number in probe + * request frames from this scan to avoid correlation/tracking being + * possible. + * @NL80211_SCAN_FLAG_MIN_PREQ_CONTENT: minimize probe request content to + * only have supported rates and no additional capabilities (unless + * added by userspace explicitly.) + * @NL80211_SCAN_FLAG_FREQ_KHZ: report scan results with + * %NL80211_ATTR_SCAN_FREQ_KHZ. This also means + * %NL80211_ATTR_SCAN_FREQUENCIES will not be included. + * @NL80211_SCAN_FLAG_COLOCATED_6GHZ: scan for colocated APs reported by + * 2.4/5 GHz APs */ enum nl80211_scan_flags { - NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0, - NL80211_SCAN_FLAG_FLUSH = 1<<1, - NL80211_SCAN_FLAG_AP = 1<<2, - NL80211_SCAN_FLAG_RANDOM_ADDR = 1<<3, + NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0, + NL80211_SCAN_FLAG_FLUSH = 1<<1, + NL80211_SCAN_FLAG_AP = 1<<2, + NL80211_SCAN_FLAG_RANDOM_ADDR = 1<<3, + NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME = 1<<4, + NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP = 1<<5, + NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE = 1<<6, + NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION = 1<<7, + NL80211_SCAN_FLAG_LOW_SPAN = 1<<8, + NL80211_SCAN_FLAG_LOW_POWER = 1<<9, + NL80211_SCAN_FLAG_HIGH_ACCURACY = 1<<10, + NL80211_SCAN_FLAG_RANDOM_SN = 1<<11, + NL80211_SCAN_FLAG_MIN_PREQ_CONTENT = 1<<12, + NL80211_SCAN_FLAG_FREQ_KHZ = 1<<13, + NL80211_SCAN_FLAG_COLOCATED_6GHZ = 1<<14, }; /** @@ -4480,12 +6425,20 @@ enum nl80211_smps_mode { * change to the channel status. * @NL80211_RADAR_NOP_FINISHED: The Non-Occupancy Period for this channel is * over, channel becomes usable. + * @NL80211_RADAR_PRE_CAC_EXPIRED: Channel Availability Check done on this + * non-operating channel is expired and no longer valid. New CAC must + * be done on this channel before starting the operation. This is not + * applicable for ETSI dfs domain where pre-CAC is valid for ever. + * @NL80211_RADAR_CAC_STARTED: Channel Availability Check has been started, + * should be generated by HW if NL80211_EXT_FEATURE_DFS_OFFLOAD is enabled. */ enum nl80211_radar_event { NL80211_RADAR_DETECTED, NL80211_RADAR_CAC_FINISHED, NL80211_RADAR_CAC_ABORTED, NL80211_RADAR_NOP_FINISHED, + NL80211_RADAR_PRE_CAC_EXPIRED, + NL80211_RADAR_CAC_STARTED, }; /** @@ -4506,7 +6459,7 @@ enum nl80211_dfs_state { }; /** - * enum enum nl80211_protocol_features - nl80211 protocol features + * enum nl80211_protocol_features - nl80211 protocol features * @NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP: nl80211 supports splitting * wiphy dumps (if requested by the application with the attribute * %NL80211_ATTR_SPLIT_WIPHY_DUMP. Also supported is filtering the @@ -4544,9 +6497,14 @@ enum nl80211_crit_proto_id { * Used by cfg80211_rx_mgmt() * * @NL80211_RXMGMT_FLAG_ANSWERED: frame was answered by device/driver. + * @NL80211_RXMGMT_FLAG_EXTERNAL_AUTH: Host driver intends to offload + * the authentication. Exclusively defined for host drivers that + * advertises the SME functionality but would like the userspace + * to handle certain authentication algorithms (e.g. SAE). */ enum nl80211_rxmgmt_flags { NL80211_RXMGMT_FLAG_ANSWERED = 1 << 0, + NL80211_RXMGMT_FLAG_EXTERNAL_AUTH = 1 << 1, }; /* @@ -4578,11 +6536,1068 @@ struct nl80211_vendor_cmd_info { * @NL80211_TDLS_PEER_HT: TDLS peer is HT capable. * @NL80211_TDLS_PEER_VHT: TDLS peer is VHT capable. * @NL80211_TDLS_PEER_WMM: TDLS peer is WMM capable. + * @NL80211_TDLS_PEER_HE: TDLS peer is HE capable. */ enum nl80211_tdls_peer_capability { NL80211_TDLS_PEER_HT = 1<<0, NL80211_TDLS_PEER_VHT = 1<<1, NL80211_TDLS_PEER_WMM = 1<<2, + NL80211_TDLS_PEER_HE = 1<<3, +}; + +/** + * enum nl80211_sched_scan_plan - scanning plan for scheduled scan + * @__NL80211_SCHED_SCAN_PLAN_INVALID: attribute number 0 is reserved + * @NL80211_SCHED_SCAN_PLAN_INTERVAL: interval between scan iterations. In + * seconds (u32). + * @NL80211_SCHED_SCAN_PLAN_ITERATIONS: number of scan iterations in this + * scan plan (u32). The last scan plan must not specify this attribute + * because it will run infinitely. A value of zero is invalid as it will + * make the scan plan meaningless. + * @NL80211_SCHED_SCAN_PLAN_MAX: highest scheduled scan plan attribute number + * currently defined + * @__NL80211_SCHED_SCAN_PLAN_AFTER_LAST: internal use + */ +enum nl80211_sched_scan_plan { + __NL80211_SCHED_SCAN_PLAN_INVALID, + NL80211_SCHED_SCAN_PLAN_INTERVAL, + NL80211_SCHED_SCAN_PLAN_ITERATIONS, + + /* keep last */ + __NL80211_SCHED_SCAN_PLAN_AFTER_LAST, + NL80211_SCHED_SCAN_PLAN_MAX = + __NL80211_SCHED_SCAN_PLAN_AFTER_LAST - 1 +}; + +/** + * struct nl80211_bss_select_rssi_adjust - RSSI adjustment parameters. + * + * @band: band of BSS that must match for RSSI value adjustment. The value + * of this field is according to &enum nl80211_band. + * @delta: value used to adjust the RSSI value of matching BSS in dB. + */ +struct nl80211_bss_select_rssi_adjust { + __u8 band; + __s8 delta; +} __attribute__((packed)); + +/** + * enum nl80211_bss_select_attr - attributes for bss selection. + * + * @__NL80211_BSS_SELECT_ATTR_INVALID: reserved. + * @NL80211_BSS_SELECT_ATTR_RSSI: Flag indicating only RSSI-based BSS selection + * is requested. + * @NL80211_BSS_SELECT_ATTR_BAND_PREF: attribute indicating BSS + * selection should be done such that the specified band is preferred. + * When there are multiple BSS-es in the preferred band, the driver + * shall use RSSI-based BSS selection as a second step. The value of + * this attribute is according to &enum nl80211_band (u32). + * @NL80211_BSS_SELECT_ATTR_RSSI_ADJUST: When present the RSSI level for + * BSS-es in the specified band is to be adjusted before doing + * RSSI-based BSS selection. The attribute value is a packed structure + * value as specified by &struct nl80211_bss_select_rssi_adjust. + * @NL80211_BSS_SELECT_ATTR_MAX: highest bss select attribute number. + * @__NL80211_BSS_SELECT_ATTR_AFTER_LAST: internal use. + * + * One and only one of these attributes are found within %NL80211_ATTR_BSS_SELECT + * for %NL80211_CMD_CONNECT. It specifies the required BSS selection behaviour + * which the driver shall use. + */ +enum nl80211_bss_select_attr { + __NL80211_BSS_SELECT_ATTR_INVALID, + NL80211_BSS_SELECT_ATTR_RSSI, + NL80211_BSS_SELECT_ATTR_BAND_PREF, + NL80211_BSS_SELECT_ATTR_RSSI_ADJUST, + + /* keep last */ + __NL80211_BSS_SELECT_ATTR_AFTER_LAST, + NL80211_BSS_SELECT_ATTR_MAX = __NL80211_BSS_SELECT_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_nan_function_type - NAN function type + * + * Defines the function type of a NAN function + * + * @NL80211_NAN_FUNC_PUBLISH: function is publish + * @NL80211_NAN_FUNC_SUBSCRIBE: function is subscribe + * @NL80211_NAN_FUNC_FOLLOW_UP: function is follow-up + */ +enum nl80211_nan_function_type { + NL80211_NAN_FUNC_PUBLISH, + NL80211_NAN_FUNC_SUBSCRIBE, + NL80211_NAN_FUNC_FOLLOW_UP, + + /* keep last */ + __NL80211_NAN_FUNC_TYPE_AFTER_LAST, + NL80211_NAN_FUNC_MAX_TYPE = __NL80211_NAN_FUNC_TYPE_AFTER_LAST - 1, +}; + +/** + * enum nl80211_nan_publish_type - NAN publish tx type + * + * Defines how to send publish Service Discovery Frames + * + * @NL80211_NAN_SOLICITED_PUBLISH: publish function is solicited + * @NL80211_NAN_UNSOLICITED_PUBLISH: publish function is unsolicited + */ +enum nl80211_nan_publish_type { + NL80211_NAN_SOLICITED_PUBLISH = 1 << 0, + NL80211_NAN_UNSOLICITED_PUBLISH = 1 << 1, +}; + +/** + * enum nl80211_nan_func_term_reason - NAN functions termination reason + * + * Defines termination reasons of a NAN function + * + * @NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST: requested by user + * @NL80211_NAN_FUNC_TERM_REASON_TTL_EXPIRED: timeout + * @NL80211_NAN_FUNC_TERM_REASON_ERROR: errored + */ +enum nl80211_nan_func_term_reason { + NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST, + NL80211_NAN_FUNC_TERM_REASON_TTL_EXPIRED, + NL80211_NAN_FUNC_TERM_REASON_ERROR, +}; + +#define NL80211_NAN_FUNC_SERVICE_ID_LEN 6 +#define NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN 0xff +#define NL80211_NAN_FUNC_SRF_MAX_LEN 0xff + +/** + * enum nl80211_nan_func_attributes - NAN function attributes + * @__NL80211_NAN_FUNC_INVALID: invalid + * @NL80211_NAN_FUNC_TYPE: &enum nl80211_nan_function_type (u8). + * @NL80211_NAN_FUNC_SERVICE_ID: 6 bytes of the service ID hash as + * specified in NAN spec. This is a binary attribute. + * @NL80211_NAN_FUNC_PUBLISH_TYPE: relevant if the function's type is + * publish. Defines the transmission type for the publish Service Discovery + * Frame, see &enum nl80211_nan_publish_type. Its type is u8. + * @NL80211_NAN_FUNC_PUBLISH_BCAST: relevant if the function is a solicited + * publish. Should the solicited publish Service Discovery Frame be sent to + * the NAN Broadcast address. This is a flag. + * @NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE: relevant if the function's type is + * subscribe. Is the subscribe active. This is a flag. + * @NL80211_NAN_FUNC_FOLLOW_UP_ID: relevant if the function's type is follow up. + * The instance ID for the follow up Service Discovery Frame. This is u8. + * @NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID: relevant if the function's type + * is follow up. This is a u8. + * The requestor instance ID for the follow up Service Discovery Frame. + * @NL80211_NAN_FUNC_FOLLOW_UP_DEST: the MAC address of the recipient of the + * follow up Service Discovery Frame. This is a binary attribute. + * @NL80211_NAN_FUNC_CLOSE_RANGE: is this function limited for devices in a + * close range. The range itself (RSSI) is defined by the device. + * This is a flag. + * @NL80211_NAN_FUNC_TTL: strictly positive number of DWs this function should + * stay active. If not present infinite TTL is assumed. This is a u32. + * @NL80211_NAN_FUNC_SERVICE_INFO: array of bytes describing the service + * specific info. This is a binary attribute. + * @NL80211_NAN_FUNC_SRF: Service Receive Filter. This is a nested attribute. + * See &enum nl80211_nan_srf_attributes. + * @NL80211_NAN_FUNC_RX_MATCH_FILTER: Receive Matching filter. This is a nested + * attribute. It is a list of binary values. + * @NL80211_NAN_FUNC_TX_MATCH_FILTER: Transmit Matching filter. This is a + * nested attribute. It is a list of binary values. + * @NL80211_NAN_FUNC_INSTANCE_ID: The instance ID of the function. + * Its type is u8 and it cannot be 0. + * @NL80211_NAN_FUNC_TERM_REASON: NAN function termination reason. + * See &enum nl80211_nan_func_term_reason. + * + * @NUM_NL80211_NAN_FUNC_ATTR: internal + * @NL80211_NAN_FUNC_ATTR_MAX: highest NAN function attribute + */ +enum nl80211_nan_func_attributes { + __NL80211_NAN_FUNC_INVALID, + NL80211_NAN_FUNC_TYPE, + NL80211_NAN_FUNC_SERVICE_ID, + NL80211_NAN_FUNC_PUBLISH_TYPE, + NL80211_NAN_FUNC_PUBLISH_BCAST, + NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE, + NL80211_NAN_FUNC_FOLLOW_UP_ID, + NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID, + NL80211_NAN_FUNC_FOLLOW_UP_DEST, + NL80211_NAN_FUNC_CLOSE_RANGE, + NL80211_NAN_FUNC_TTL, + NL80211_NAN_FUNC_SERVICE_INFO, + NL80211_NAN_FUNC_SRF, + NL80211_NAN_FUNC_RX_MATCH_FILTER, + NL80211_NAN_FUNC_TX_MATCH_FILTER, + NL80211_NAN_FUNC_INSTANCE_ID, + NL80211_NAN_FUNC_TERM_REASON, + + /* keep last */ + NUM_NL80211_NAN_FUNC_ATTR, + NL80211_NAN_FUNC_ATTR_MAX = NUM_NL80211_NAN_FUNC_ATTR - 1 +}; + +/** + * enum nl80211_nan_srf_attributes - NAN Service Response filter attributes + * @__NL80211_NAN_SRF_INVALID: invalid + * @NL80211_NAN_SRF_INCLUDE: present if the include bit of the SRF set. + * This is a flag. + * @NL80211_NAN_SRF_BF: Bloom Filter. Present if and only if + * %NL80211_NAN_SRF_MAC_ADDRS isn't present. This attribute is binary. + * @NL80211_NAN_SRF_BF_IDX: index of the Bloom Filter. Mandatory if + * %NL80211_NAN_SRF_BF is present. This is a u8. + * @NL80211_NAN_SRF_MAC_ADDRS: list of MAC addresses for the SRF. Present if + * and only if %NL80211_NAN_SRF_BF isn't present. This is a nested + * attribute. Each nested attribute is a MAC address. + * @NUM_NL80211_NAN_SRF_ATTR: internal + * @NL80211_NAN_SRF_ATTR_MAX: highest NAN SRF attribute + */ +enum nl80211_nan_srf_attributes { + __NL80211_NAN_SRF_INVALID, + NL80211_NAN_SRF_INCLUDE, + NL80211_NAN_SRF_BF, + NL80211_NAN_SRF_BF_IDX, + NL80211_NAN_SRF_MAC_ADDRS, + + /* keep last */ + NUM_NL80211_NAN_SRF_ATTR, + NL80211_NAN_SRF_ATTR_MAX = NUM_NL80211_NAN_SRF_ATTR - 1, +}; + +/** + * enum nl80211_nan_match_attributes - NAN match attributes + * @__NL80211_NAN_MATCH_INVALID: invalid + * @NL80211_NAN_MATCH_FUNC_LOCAL: the local function that had the + * match. This is a nested attribute. + * See &enum nl80211_nan_func_attributes. + * @NL80211_NAN_MATCH_FUNC_PEER: the peer function + * that caused the match. This is a nested attribute. + * See &enum nl80211_nan_func_attributes. + * + * @NUM_NL80211_NAN_MATCH_ATTR: internal + * @NL80211_NAN_MATCH_ATTR_MAX: highest NAN match attribute + */ +enum nl80211_nan_match_attributes { + __NL80211_NAN_MATCH_INVALID, + NL80211_NAN_MATCH_FUNC_LOCAL, + NL80211_NAN_MATCH_FUNC_PEER, + + /* keep last */ + NUM_NL80211_NAN_MATCH_ATTR, + NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_MATCH_ATTR - 1 +}; + +/** + * nl80211_external_auth_action - Action to perform with external + * authentication request. Used by NL80211_ATTR_EXTERNAL_AUTH_ACTION. + * @NL80211_EXTERNAL_AUTH_START: Start the authentication. + * @NL80211_EXTERNAL_AUTH_ABORT: Abort the ongoing authentication. + */ +enum nl80211_external_auth_action { + NL80211_EXTERNAL_AUTH_START, + NL80211_EXTERNAL_AUTH_ABORT, +}; + +/** + * enum nl80211_ftm_responder_attributes - fine timing measurement + * responder attributes + * @__NL80211_FTM_RESP_ATTR_INVALID: Invalid + * @NL80211_FTM_RESP_ATTR_ENABLED: FTM responder is enabled + * @NL80211_FTM_RESP_ATTR_LCI: The content of Measurement Report Element + * (9.4.2.22 in 802.11-2016) with type 8 - LCI (9.4.2.22.10), + * i.e. starting with the measurement token + * @NL80211_FTM_RESP_ATTR_CIVIC: The content of Measurement Report Element + * (9.4.2.22 in 802.11-2016) with type 11 - Civic (Section 9.4.2.22.13), + * i.e. starting with the measurement token + * @__NL80211_FTM_RESP_ATTR_LAST: Internal + * @NL80211_FTM_RESP_ATTR_MAX: highest FTM responder attribute. + */ +enum nl80211_ftm_responder_attributes { + __NL80211_FTM_RESP_ATTR_INVALID, + + NL80211_FTM_RESP_ATTR_ENABLED, + NL80211_FTM_RESP_ATTR_LCI, + NL80211_FTM_RESP_ATTR_CIVICLOC, + + /* keep last */ + __NL80211_FTM_RESP_ATTR_LAST, + NL80211_FTM_RESP_ATTR_MAX = __NL80211_FTM_RESP_ATTR_LAST - 1, +}; + +/* + * enum nl80211_ftm_responder_stats - FTM responder statistics + * + * These attribute types are used with %NL80211_ATTR_FTM_RESPONDER_STATS + * when getting FTM responder statistics. + * + * @__NL80211_FTM_STATS_INVALID: attribute number 0 is reserved + * @NL80211_FTM_STATS_SUCCESS_NUM: number of FTM sessions in which all frames + * were ssfully answered (u32) + * @NL80211_FTM_STATS_PARTIAL_NUM: number of FTM sessions in which part of the + * frames were successfully answered (u32) + * @NL80211_FTM_STATS_FAILED_NUM: number of failed FTM sessions (u32) + * @NL80211_FTM_STATS_ASAP_NUM: number of ASAP sessions (u32) + * @NL80211_FTM_STATS_NON_ASAP_NUM: number of non-ASAP sessions (u32) + * @NL80211_FTM_STATS_TOTAL_DURATION_MSEC: total sessions durations - gives an + * indication of how much time the responder was busy (u64, msec) + * @NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM: number of unknown FTM triggers - + * triggers from initiators that didn't finish successfully the negotiation + * phase with the responder (u32) + * @NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM: number of FTM reschedule requests + * - initiator asks for a new scheduling although it already has scheduled + * FTM slot (u32) + * @NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM: number of FTM triggers out of + * scheduled window (u32) + * @NL80211_FTM_STATS_PAD: used for padding, ignore + * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal + * @NL80211_FTM_STATS_MAX: highest possible FTM responder stats attribute + */ +enum nl80211_ftm_responder_stats { + __NL80211_FTM_STATS_INVALID, + NL80211_FTM_STATS_SUCCESS_NUM, + NL80211_FTM_STATS_PARTIAL_NUM, + NL80211_FTM_STATS_FAILED_NUM, + NL80211_FTM_STATS_ASAP_NUM, + NL80211_FTM_STATS_NON_ASAP_NUM, + NL80211_FTM_STATS_TOTAL_DURATION_MSEC, + NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM, + NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM, + NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM, + NL80211_FTM_STATS_PAD, + + /* keep last */ + __NL80211_FTM_STATS_AFTER_LAST, + NL80211_FTM_STATS_MAX = __NL80211_FTM_STATS_AFTER_LAST - 1 +}; + +/** + * enum nl80211_preamble - frame preamble types + * @NL80211_PREAMBLE_LEGACY: legacy (HR/DSSS, OFDM, ERP PHY) preamble + * @NL80211_PREAMBLE_HT: HT preamble + * @NL80211_PREAMBLE_VHT: VHT preamble + * @NL80211_PREAMBLE_DMG: DMG preamble + * @NL80211_PREAMBLE_HE: HE preamble + */ +enum nl80211_preamble { + NL80211_PREAMBLE_LEGACY, + NL80211_PREAMBLE_HT, + NL80211_PREAMBLE_VHT, + NL80211_PREAMBLE_DMG, + NL80211_PREAMBLE_HE, +}; + +/** + * enum nl80211_peer_measurement_type - peer measurement types + * @NL80211_PMSR_TYPE_INVALID: invalid/unused, needed as we use + * these numbers also for attributes + * + * @NL80211_PMSR_TYPE_FTM: flight time measurement + * + * @NUM_NL80211_PMSR_TYPES: internal + * @NL80211_PMSR_TYPE_MAX: highest type number + */ +enum nl80211_peer_measurement_type { + NL80211_PMSR_TYPE_INVALID, + + NL80211_PMSR_TYPE_FTM, + + NUM_NL80211_PMSR_TYPES, + NL80211_PMSR_TYPE_MAX = NUM_NL80211_PMSR_TYPES - 1 +}; + +/** + * enum nl80211_peer_measurement_status - peer measurement status + * @NL80211_PMSR_STATUS_SUCCESS: measurement completed successfully + * @NL80211_PMSR_STATUS_REFUSED: measurement was locally refused + * @NL80211_PMSR_STATUS_TIMEOUT: measurement timed out + * @NL80211_PMSR_STATUS_FAILURE: measurement failed, a type-dependent + * reason may be available in the response data + */ +enum nl80211_peer_measurement_status { + NL80211_PMSR_STATUS_SUCCESS, + NL80211_PMSR_STATUS_REFUSED, + NL80211_PMSR_STATUS_TIMEOUT, + NL80211_PMSR_STATUS_FAILURE, +}; + +/** + * enum nl80211_peer_measurement_req - peer measurement request attributes + * @__NL80211_PMSR_REQ_ATTR_INVALID: invalid + * + * @NL80211_PMSR_REQ_ATTR_DATA: This is a nested attribute with measurement + * type-specific request data inside. The attributes used are from the + * enums named nl80211_peer_measurement_<type>_req. + * @NL80211_PMSR_REQ_ATTR_GET_AP_TSF: include AP TSF timestamp, if supported + * (flag attribute) + * + * @NUM_NL80211_PMSR_REQ_ATTRS: internal + * @NL80211_PMSR_REQ_ATTR_MAX: highest attribute number + */ +enum nl80211_peer_measurement_req { + __NL80211_PMSR_REQ_ATTR_INVALID, + + NL80211_PMSR_REQ_ATTR_DATA, + NL80211_PMSR_REQ_ATTR_GET_AP_TSF, + + /* keep last */ + NUM_NL80211_PMSR_REQ_ATTRS, + NL80211_PMSR_REQ_ATTR_MAX = NUM_NL80211_PMSR_REQ_ATTRS - 1 +}; + +/** + * enum nl80211_peer_measurement_resp - peer measurement response attributes + * @__NL80211_PMSR_RESP_ATTR_INVALID: invalid + * + * @NL80211_PMSR_RESP_ATTR_DATA: This is a nested attribute with measurement + * type-specific results inside. The attributes used are from the enums + * named nl80211_peer_measurement_<type>_resp. + * @NL80211_PMSR_RESP_ATTR_STATUS: u32 value with the measurement status + * (using values from &enum nl80211_peer_measurement_status.) + * @NL80211_PMSR_RESP_ATTR_HOST_TIME: host time (%CLOCK_BOOTTIME) when the + * result was measured; this value is not expected to be accurate to + * more than 20ms. (u64, nanoseconds) + * @NL80211_PMSR_RESP_ATTR_AP_TSF: TSF of the AP that the interface + * doing the measurement is connected to when the result was measured. + * This shall be accurately reported if supported and requested + * (u64, usec) + * @NL80211_PMSR_RESP_ATTR_FINAL: If results are sent to the host partially + * (*e.g. with FTM per-burst data) this flag will be cleared on all but + * the last result; if all results are combined it's set on the single + * result. + * @NL80211_PMSR_RESP_ATTR_PAD: padding for 64-bit attributes, ignore + * + * @NUM_NL80211_PMSR_RESP_ATTRS: internal + * @NL80211_PMSR_RESP_ATTR_MAX: highest attribute number + */ +enum nl80211_peer_measurement_resp { + __NL80211_PMSR_RESP_ATTR_INVALID, + + NL80211_PMSR_RESP_ATTR_DATA, + NL80211_PMSR_RESP_ATTR_STATUS, + NL80211_PMSR_RESP_ATTR_HOST_TIME, + NL80211_PMSR_RESP_ATTR_AP_TSF, + NL80211_PMSR_RESP_ATTR_FINAL, + NL80211_PMSR_RESP_ATTR_PAD, + + /* keep last */ + NUM_NL80211_PMSR_RESP_ATTRS, + NL80211_PMSR_RESP_ATTR_MAX = NUM_NL80211_PMSR_RESP_ATTRS - 1 +}; + +/** + * enum nl80211_peer_measurement_peer_attrs - peer attributes for measurement + * @__NL80211_PMSR_PEER_ATTR_INVALID: invalid + * + * @NL80211_PMSR_PEER_ATTR_ADDR: peer's MAC address + * @NL80211_PMSR_PEER_ATTR_CHAN: channel definition, nested, using top-level + * attributes like %NL80211_ATTR_WIPHY_FREQ etc. + * @NL80211_PMSR_PEER_ATTR_REQ: This is a nested attribute indexed by + * measurement type, with attributes from the + * &enum nl80211_peer_measurement_req inside. + * @NL80211_PMSR_PEER_ATTR_RESP: This is a nested attribute indexed by + * measurement type, with attributes from the + * &enum nl80211_peer_measurement_resp inside. + * + * @NUM_NL80211_PMSR_PEER_ATTRS: internal + * @NL80211_PMSR_PEER_ATTR_MAX: highest attribute number + */ +enum nl80211_peer_measurement_peer_attrs { + __NL80211_PMSR_PEER_ATTR_INVALID, + + NL80211_PMSR_PEER_ATTR_ADDR, + NL80211_PMSR_PEER_ATTR_CHAN, + NL80211_PMSR_PEER_ATTR_REQ, + NL80211_PMSR_PEER_ATTR_RESP, + + /* keep last */ + NUM_NL80211_PMSR_PEER_ATTRS, + NL80211_PMSR_PEER_ATTR_MAX = NUM_NL80211_PMSR_PEER_ATTRS - 1, +}; + +/** + * enum nl80211_peer_measurement_attrs - peer measurement attributes + * @__NL80211_PMSR_ATTR_INVALID: invalid + * + * @NL80211_PMSR_ATTR_MAX_PEERS: u32 attribute used for capability + * advertisement only, indicates the maximum number of peers + * measurements can be done with in a single request + * @NL80211_PMSR_ATTR_REPORT_AP_TSF: flag attribute in capability + * indicating that the connected AP's TSF can be reported in + * measurement results + * @NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR: flag attribute in capability + * indicating that MAC address randomization is supported. + * @NL80211_PMSR_ATTR_TYPE_CAPA: capabilities reported by the device, + * this contains a nesting indexed by measurement type, and + * type-specific capabilities inside, which are from the enums + * named nl80211_peer_measurement_<type>_capa. + * @NL80211_PMSR_ATTR_PEERS: nested attribute, the nesting index is + * meaningless, just a list of peers to measure with, with the + * sub-attributes taken from + * &enum nl80211_peer_measurement_peer_attrs. + * + * @NUM_NL80211_PMSR_ATTR: internal + * @NL80211_PMSR_ATTR_MAX: highest attribute number + */ +enum nl80211_peer_measurement_attrs { + __NL80211_PMSR_ATTR_INVALID, + + NL80211_PMSR_ATTR_MAX_PEERS, + NL80211_PMSR_ATTR_REPORT_AP_TSF, + NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR, + NL80211_PMSR_ATTR_TYPE_CAPA, + NL80211_PMSR_ATTR_PEERS, + + /* keep last */ + NUM_NL80211_PMSR_ATTR, + NL80211_PMSR_ATTR_MAX = NUM_NL80211_PMSR_ATTR - 1 +}; + +/** + * enum nl80211_peer_measurement_ftm_capa - FTM capabilities + * @__NL80211_PMSR_FTM_CAPA_ATTR_INVALID: invalid + * + * @NL80211_PMSR_FTM_CAPA_ATTR_ASAP: flag attribute indicating ASAP mode + * is supported + * @NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP: flag attribute indicating non-ASAP + * mode is supported + * @NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI: flag attribute indicating if LCI + * data can be requested during the measurement + * @NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC: flag attribute indicating if civic + * location data can be requested during the measurement + * @NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES: u32 bitmap attribute of bits + * from &enum nl80211_preamble. + * @NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS: bitmap of values from + * &enum nl80211_chan_width indicating the supported channel + * bandwidths for FTM. Note that a higher channel bandwidth may be + * configured to allow for other measurements types with different + * bandwidth requirement in the same measurement. + * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT: u32 attribute indicating + * the maximum bursts exponent that can be used (if not present anything + * is valid) + * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST: u32 attribute indicating + * the maximum FTMs per burst (if not present anything is valid) + * @NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED: flag attribute indicating if + * trigger based ranging measurement is supported + * @NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED: flag attribute indicating + * if non trigger based ranging measurement is supported + * + * @NUM_NL80211_PMSR_FTM_CAPA_ATTR: internal + * @NL80211_PMSR_FTM_CAPA_ATTR_MAX: highest attribute number + */ +enum nl80211_peer_measurement_ftm_capa { + __NL80211_PMSR_FTM_CAPA_ATTR_INVALID, + + NL80211_PMSR_FTM_CAPA_ATTR_ASAP, + NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP, + NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI, + NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC, + NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES, + NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS, + NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT, + NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST, + NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED, + NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED, + + /* keep last */ + NUM_NL80211_PMSR_FTM_CAPA_ATTR, + NL80211_PMSR_FTM_CAPA_ATTR_MAX = NUM_NL80211_PMSR_FTM_CAPA_ATTR - 1 +}; + +/** + * enum nl80211_peer_measurement_ftm_req - FTM request attributes + * @__NL80211_PMSR_FTM_REQ_ATTR_INVALID: invalid + * + * @NL80211_PMSR_FTM_REQ_ATTR_ASAP: ASAP mode requested (flag) + * @NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE: preamble type (see + * &enum nl80211_preamble), optional for DMG (u32) + * @NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP: number of bursts exponent as in + * 802.11-2016 9.4.2.168 "Fine Timing Measurement Parameters element" + * (u8, 0-15, optional with default 15 i.e. "no preference") + * @NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD: interval between bursts in units + * of 100ms (u16, optional with default 0) + * @NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION: burst duration, as in 802.11-2016 + * Table 9-257 "Burst Duration field encoding" (u8, 0-15, optional with + * default 15 i.e. "no preference") + * @NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST: number of successful FTM frames + * requested per burst + * (u8, 0-31, optional with default 0 i.e. "no preference") + * @NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES: number of FTMR frame retries + * (u8, default 3) + * @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI: request LCI data (flag) + * @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC: request civic location data + * (flag) + * @NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED: request trigger based ranging + * measurement (flag). + * This attribute and %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED are + * mutually exclusive. + * if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor + * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based + * ranging will be used. + * @NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED: request non trigger based + * ranging measurement (flag) + * This attribute and %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED are + * mutually exclusive. + * if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor + * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based + * ranging will be used. + * @NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK: negotiate for LMR feedback. Only + * valid if either %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED or + * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set. + * @NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR: optional. The BSS color of the + * responder. Only valid if %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED + * or %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED is set. + * + * @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal + * @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number + */ +enum nl80211_peer_measurement_ftm_req { + __NL80211_PMSR_FTM_REQ_ATTR_INVALID, + + NL80211_PMSR_FTM_REQ_ATTR_ASAP, + NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE, + NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP, + NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD, + NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION, + NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST, + NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES, + NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI, + NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC, + NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED, + NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED, + NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK, + NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR, + + /* keep last */ + NUM_NL80211_PMSR_FTM_REQ_ATTR, + NL80211_PMSR_FTM_REQ_ATTR_MAX = NUM_NL80211_PMSR_FTM_REQ_ATTR - 1 +}; + +/** + * enum nl80211_peer_measurement_ftm_failure_reasons - FTM failure reasons + * @NL80211_PMSR_FTM_FAILURE_UNSPECIFIED: unspecified failure, not used + * @NL80211_PMSR_FTM_FAILURE_NO_RESPONSE: no response from the FTM responder + * @NL80211_PMSR_FTM_FAILURE_REJECTED: FTM responder rejected measurement + * @NL80211_PMSR_FTM_FAILURE_WRONG_CHANNEL: we already know the peer is + * on a different channel, so can't measure (if we didn't know, we'd + * try and get no response) + * @NL80211_PMSR_FTM_FAILURE_PEER_NOT_CAPABLE: peer can't actually do FTM + * @NL80211_PMSR_FTM_FAILURE_INVALID_TIMESTAMP: invalid T1/T4 timestamps + * received + * @NL80211_PMSR_FTM_FAILURE_PEER_BUSY: peer reports busy, you may retry + * later (see %NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME) + * @NL80211_PMSR_FTM_FAILURE_BAD_CHANGED_PARAMS: parameters were changed + * by the peer and are no longer supported + */ +enum nl80211_peer_measurement_ftm_failure_reasons { + NL80211_PMSR_FTM_FAILURE_UNSPECIFIED, + NL80211_PMSR_FTM_FAILURE_NO_RESPONSE, + NL80211_PMSR_FTM_FAILURE_REJECTED, + NL80211_PMSR_FTM_FAILURE_WRONG_CHANNEL, + NL80211_PMSR_FTM_FAILURE_PEER_NOT_CAPABLE, + NL80211_PMSR_FTM_FAILURE_INVALID_TIMESTAMP, + NL80211_PMSR_FTM_FAILURE_PEER_BUSY, + NL80211_PMSR_FTM_FAILURE_BAD_CHANGED_PARAMS, +}; + +/** + * enum nl80211_peer_measurement_ftm_resp - FTM response attributes + * @__NL80211_PMSR_FTM_RESP_ATTR_INVALID: invalid + * + * @NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON: FTM-specific failure reason + * (u32, optional) + * @NL80211_PMSR_FTM_RESP_ATTR_BURST_INDEX: optional, if bursts are reported + * as separate results then it will be the burst index 0...(N-1) and + * the top level will indicate partial results (u32) + * @NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS: number of FTM Request frames + * transmitted (u32, optional) + * @NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES: number of FTM Request frames + * that were acknowleged (u32, optional) + * @NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME: retry time received from the + * busy peer (u32, seconds) + * @NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP: actual number of bursts exponent + * used by the responder (similar to request, u8) + * @NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION: actual burst duration used by + * the responder (similar to request, u8) + * @NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST: actual FTMs per burst used + * by the responder (similar to request, u8) + * @NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG: average RSSI across all FTM action + * frames (optional, s32, 1/2 dBm) + * @NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD: RSSI spread across all FTM action + * frames (optional, s32, 1/2 dBm) + * @NL80211_PMSR_FTM_RESP_ATTR_TX_RATE: bitrate we used for the response to the + * FTM action frame (optional, nested, using &enum nl80211_rate_info + * attributes) + * @NL80211_PMSR_FTM_RESP_ATTR_RX_RATE: bitrate the responder used for the FTM + * action frame (optional, nested, using &enum nl80211_rate_info attrs) + * @NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG: average RTT (s64, picoseconds, optional + * but one of RTT/DIST must be present) + * @NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE: RTT variance (u64, ps^2, note that + * standard deviation is the square root of variance, optional) + * @NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD: RTT spread (u64, picoseconds, + * optional) + * @NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG: average distance (s64, mm, optional + * but one of RTT/DIST must be present) + * @NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE: distance variance (u64, mm^2, note + * that standard deviation is the square root of variance, optional) + * @NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD: distance spread (u64, mm, optional) + * @NL80211_PMSR_FTM_RESP_ATTR_LCI: LCI data from peer (binary, optional); + * this is the contents of the Measurement Report Element (802.11-2016 + * 9.4.2.22.1) starting with the Measurement Token, with Measurement + * Type 8. + * @NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC: civic location data from peer + * (binary, optional); + * this is the contents of the Measurement Report Element (802.11-2016 + * 9.4.2.22.1) starting with the Measurement Token, with Measurement + * Type 11. + * @NL80211_PMSR_FTM_RESP_ATTR_PAD: ignore, for u64/s64 padding only + * + * @NUM_NL80211_PMSR_FTM_RESP_ATTR: internal + * @NL80211_PMSR_FTM_RESP_ATTR_MAX: highest attribute number + */ +enum nl80211_peer_measurement_ftm_resp { + __NL80211_PMSR_FTM_RESP_ATTR_INVALID, + + NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON, + NL80211_PMSR_FTM_RESP_ATTR_BURST_INDEX, + NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS, + NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES, + NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME, + NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP, + NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION, + NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST, + NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG, + NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD, + NL80211_PMSR_FTM_RESP_ATTR_TX_RATE, + NL80211_PMSR_FTM_RESP_ATTR_RX_RATE, + NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG, + NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE, + NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD, + NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG, + NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE, + NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD, + NL80211_PMSR_FTM_RESP_ATTR_LCI, + NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC, + NL80211_PMSR_FTM_RESP_ATTR_PAD, + + /* keep last */ + NUM_NL80211_PMSR_FTM_RESP_ATTR, + NL80211_PMSR_FTM_RESP_ATTR_MAX = NUM_NL80211_PMSR_FTM_RESP_ATTR - 1 +}; + +/** + * enum nl80211_obss_pd_attributes - OBSS packet detection attributes + * @__NL80211_HE_OBSS_PD_ATTR_INVALID: Invalid + * + * @NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET: the OBSS PD minimum tx power offset. + * @NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET: the OBSS PD maximum tx power offset. + * @NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET: the non-SRG OBSS PD maximum + * tx power offset. + * @NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP: bitmap that indicates the BSS color + * values used by members of the SRG. + * @NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP: bitmap that indicates the partial + * BSSID values used by members of the SRG. + * @NL80211_HE_OBSS_PD_ATTR_SR_CTRL: The SR Control field of SRP element. + * + * @__NL80211_HE_OBSS_PD_ATTR_LAST: Internal + * @NL80211_HE_OBSS_PD_ATTR_MAX: highest OBSS PD attribute. + */ +enum nl80211_obss_pd_attributes { + __NL80211_HE_OBSS_PD_ATTR_INVALID, + + NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET, + NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET, + NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET, + NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP, + NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP, + NL80211_HE_OBSS_PD_ATTR_SR_CTRL, + + /* keep last */ + __NL80211_HE_OBSS_PD_ATTR_LAST, + NL80211_HE_OBSS_PD_ATTR_MAX = __NL80211_HE_OBSS_PD_ATTR_LAST - 1, +}; + +/** + * enum nl80211_bss_color_attributes - BSS Color attributes + * @__NL80211_HE_BSS_COLOR_ATTR_INVALID: Invalid + * + * @NL80211_HE_BSS_COLOR_ATTR_COLOR: the current BSS Color. + * @NL80211_HE_BSS_COLOR_ATTR_DISABLED: is BSS coloring disabled. + * @NL80211_HE_BSS_COLOR_ATTR_PARTIAL: the AID equation to be used.. + * + * @__NL80211_HE_BSS_COLOR_ATTR_LAST: Internal + * @NL80211_HE_BSS_COLOR_ATTR_MAX: highest BSS Color attribute. + */ +enum nl80211_bss_color_attributes { + __NL80211_HE_BSS_COLOR_ATTR_INVALID, + + NL80211_HE_BSS_COLOR_ATTR_COLOR, + NL80211_HE_BSS_COLOR_ATTR_DISABLED, + NL80211_HE_BSS_COLOR_ATTR_PARTIAL, + + /* keep last */ + __NL80211_HE_BSS_COLOR_ATTR_LAST, + NL80211_HE_BSS_COLOR_ATTR_MAX = __NL80211_HE_BSS_COLOR_ATTR_LAST - 1, +}; + +/** + * enum nl80211_iftype_akm_attributes - interface type AKM attributes + * @__NL80211_IFTYPE_AKM_ATTR_INVALID: Invalid + * + * @NL80211_IFTYPE_AKM_ATTR_IFTYPES: nested attribute containing a flag + * attribute for each interface type that supports AKM suites specified in + * %NL80211_IFTYPE_AKM_ATTR_SUITES + * @NL80211_IFTYPE_AKM_ATTR_SUITES: an array of u32. Used to indicate supported + * AKM suites for the specified interface types. + * + * @__NL80211_IFTYPE_AKM_ATTR_LAST: Internal + * @NL80211_IFTYPE_AKM_ATTR_MAX: highest interface type AKM attribute. + */ +enum nl80211_iftype_akm_attributes { + __NL80211_IFTYPE_AKM_ATTR_INVALID, + + NL80211_IFTYPE_AKM_ATTR_IFTYPES, + NL80211_IFTYPE_AKM_ATTR_SUITES, + + /* keep last */ + __NL80211_IFTYPE_AKM_ATTR_LAST, + NL80211_IFTYPE_AKM_ATTR_MAX = __NL80211_IFTYPE_AKM_ATTR_LAST - 1, +}; + +/** + * enum nl80211_fils_discovery_attributes - FILS discovery configuration + * from IEEE Std 802.11ai-2016, Annex C.3 MIB detail. + * + * @__NL80211_FILS_DISCOVERY_ATTR_INVALID: Invalid + * + * @NL80211_FILS_DISCOVERY_ATTR_INT_MIN: Minimum packet interval (u32, TU). + * Allowed range: 0..10000 (TU = Time Unit) + * @NL80211_FILS_DISCOVERY_ATTR_INT_MAX: Maximum packet interval (u32, TU). + * Allowed range: 0..10000 (TU = Time Unit) + * @NL80211_FILS_DISCOVERY_ATTR_TMPL: Template data for FILS discovery action + * frame including the headers. + * + * @__NL80211_FILS_DISCOVERY_ATTR_LAST: Internal + * @NL80211_FILS_DISCOVERY_ATTR_MAX: highest attribute + */ +enum nl80211_fils_discovery_attributes { + __NL80211_FILS_DISCOVERY_ATTR_INVALID, + + NL80211_FILS_DISCOVERY_ATTR_INT_MIN, + NL80211_FILS_DISCOVERY_ATTR_INT_MAX, + NL80211_FILS_DISCOVERY_ATTR_TMPL, + + /* keep last */ + __NL80211_FILS_DISCOVERY_ATTR_LAST, + NL80211_FILS_DISCOVERY_ATTR_MAX = __NL80211_FILS_DISCOVERY_ATTR_LAST - 1 +}; + +/* + * FILS discovery template minimum length with action frame headers and + * mandatory fields. + */ +#define NL80211_FILS_DISCOVERY_TMPL_MIN_LEN 42 + +/** + * enum nl80211_unsol_bcast_probe_resp_attributes - Unsolicited broadcast probe + * response configuration. Applicable only in 6GHz. + * + * @__NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INVALID: Invalid + * + * @NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT: Maximum packet interval (u32, TU). + * Allowed range: 0..20 (TU = Time Unit). IEEE P802.11ax/D6.0 + * 26.17.2.3.2 (AP behavior for fast passive scanning). + * @NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL: Unsolicited broadcast probe response + * frame template (binary). + * + * @__NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST: Internal + * @NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX: highest attribute + */ +enum nl80211_unsol_bcast_probe_resp_attributes { + __NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INVALID, + + NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT, + NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL, + + /* keep last */ + __NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST, + NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX = + __NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST - 1 +}; + +/** + * enum nl80211_sae_pwe_mechanism - The mechanism(s) allowed for SAE PWE + * derivation. Applicable only when WPA3-Personal SAE authentication is + * used. + * + * @NL80211_SAE_PWE_UNSPECIFIED: not specified, used internally to indicate that + * attribute is not present from userspace. + * @NL80211_SAE_PWE_HUNT_AND_PECK: hunting-and-pecking loop only + * @NL80211_SAE_PWE_HASH_TO_ELEMENT: hash-to-element only + * @NL80211_SAE_PWE_BOTH: both hunting-and-pecking loop and hash-to-element + * can be used. + */ +enum nl80211_sae_pwe_mechanism { + NL80211_SAE_PWE_UNSPECIFIED, + NL80211_SAE_PWE_HUNT_AND_PECK, + NL80211_SAE_PWE_HASH_TO_ELEMENT, + NL80211_SAE_PWE_BOTH, +}; + +/** + * enum nl80211_sar_type - type of SAR specs + * + * @NL80211_SAR_TYPE_POWER: power limitation specified in 0.25dBm unit + * + */ +enum nl80211_sar_type { + NL80211_SAR_TYPE_POWER, + + /* add new type here */ + + /* Keep last */ + NUM_NL80211_SAR_TYPE, +}; + +/** + * enum nl80211_sar_attrs - Attributes for SAR spec + * + * @NL80211_SAR_ATTR_TYPE: the SAR type as defined in &enum nl80211_sar_type. + * + * @NL80211_SAR_ATTR_SPECS: Nested array of SAR power + * limit specifications. Each specification contains a set + * of %nl80211_sar_specs_attrs. + * + * For SET operation, it contains array of %NL80211_SAR_ATTR_SPECS_POWER + * and %NL80211_SAR_ATTR_SPECS_RANGE_INDEX. + * + * For sar_capa dump, it contains array of + * %NL80211_SAR_ATTR_SPECS_START_FREQ + * and %NL80211_SAR_ATTR_SPECS_END_FREQ. + * + * @__NL80211_SAR_ATTR_LAST: Internal + * @NL80211_SAR_ATTR_MAX: highest sar attribute + * + * These attributes are used with %NL80211_CMD_SET_SAR_SPEC + */ +enum nl80211_sar_attrs { + __NL80211_SAR_ATTR_INVALID, + + NL80211_SAR_ATTR_TYPE, + NL80211_SAR_ATTR_SPECS, + + __NL80211_SAR_ATTR_LAST, + NL80211_SAR_ATTR_MAX = __NL80211_SAR_ATTR_LAST - 1, +}; + +/** + * enum nl80211_sar_specs_attrs - Attributes for SAR power limit specs + * + * @NL80211_SAR_ATTR_SPECS_POWER: Required (s32)value to specify the actual + * power limit value in units of 0.25 dBm if type is + * NL80211_SAR_TYPE_POWER. (i.e., a value of 44 represents 11 dBm). + * 0 means userspace doesn't have SAR limitation on this associated range. + * + * @NL80211_SAR_ATTR_SPECS_RANGE_INDEX: Required (u32) value to specify the + * index of exported freq range table and the associated power limitation + * is applied to this range. + * + * Userspace isn't required to set all the ranges advertised by WLAN driver, + * and userspace can skip some certain ranges. These skipped ranges don't + * have SAR limitations, and they are same as setting the + * %NL80211_SAR_ATTR_SPECS_POWER to any unreasonable high value because any + * value higher than regulatory allowed value just means SAR power + * limitation is removed, but it's required to set at least one range. + * It's not allowed to set duplicated range in one SET operation. + * + * Every SET operation overwrites previous SET operation. + * + * @NL80211_SAR_ATTR_SPECS_START_FREQ: Required (u32) value to specify the start + * frequency of this range edge when registering SAR capability to wiphy. + * It's not a channel center frequency. The unit is kHz. + * + * @NL80211_SAR_ATTR_SPECS_END_FREQ: Required (u32) value to specify the end + * frequency of this range edge when registering SAR capability to wiphy. + * It's not a channel center frequency. The unit is kHz. + * + * @__NL80211_SAR_ATTR_SPECS_LAST: Internal + * @NL80211_SAR_ATTR_SPECS_MAX: highest sar specs attribute + */ +enum nl80211_sar_specs_attrs { + __NL80211_SAR_ATTR_SPECS_INVALID, + + NL80211_SAR_ATTR_SPECS_POWER, + NL80211_SAR_ATTR_SPECS_RANGE_INDEX, + NL80211_SAR_ATTR_SPECS_START_FREQ, + NL80211_SAR_ATTR_SPECS_END_FREQ, + + __NL80211_SAR_ATTR_SPECS_LAST, + NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1, +}; + +/** + * enum nl80211_mbssid_config_attributes - multiple BSSID (MBSSID) and enhanced + * multi-BSSID advertisements (EMA) in AP mode. + * Kernel uses some of these attributes to advertise driver's support for + * MBSSID and EMA. + * Remaining attributes should be used by the userspace to configure the + * features. + * + * @__NL80211_MBSSID_CONFIG_ATTR_INVALID: Invalid + * + * @NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES: Used by the kernel to advertise + * the maximum number of MBSSID interfaces supported by the driver. + * Driver should indicate MBSSID support by setting + * wiphy->mbssid_max_interfaces to a value more than or equal to 2. + * + * @NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY: Used by the kernel + * to advertise the maximum profile periodicity supported by the driver + * if EMA is enabled. Driver should indicate EMA support to the userspace + * by setting wiphy->ema_max_profile_periodicity to + * a non-zero value. + * + * @NL80211_MBSSID_CONFIG_ATTR_INDEX: Mandatory parameter to pass the index of + * this BSS (u8) in the multiple BSSID set. + * Value must be set to 0 for the transmitting interface and non-zero for + * all non-transmitting interfaces. The userspace will be responsible + * for using unique indices for the interfaces. + * Range: 0 to wiphy->mbssid_max_interfaces-1. + * + * @NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX: Mandatory parameter for + * a non-transmitted profile which provides the interface index (u32) of + * the transmitted profile. The value must match one of the interface + * indices advertised by the kernel. Optional if the interface being set up + * is the transmitting one, however, if provided then the value must match + * the interface index of the same. + * + * @NL80211_MBSSID_CONFIG_ATTR_EMA: Flag used to enable EMA AP feature. + * Setting this flag is permitted only if the driver advertises EMA support + * by setting wiphy->ema_max_profile_periodicity to non-zero. + * + * @__NL80211_MBSSID_CONFIG_ATTR_LAST: Internal + * @NL80211_MBSSID_CONFIG_ATTR_MAX: highest attribute + */ +enum nl80211_mbssid_config_attributes { + __NL80211_MBSSID_CONFIG_ATTR_INVALID, + + NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES, + NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY, + NL80211_MBSSID_CONFIG_ATTR_INDEX, + NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX, + NL80211_MBSSID_CONFIG_ATTR_EMA, + + /* keep last */ + __NL80211_MBSSID_CONFIG_ATTR_LAST, + NL80211_MBSSID_CONFIG_ATTR_MAX = __NL80211_MBSSID_CONFIG_ATTR_LAST - 1, +}; + +/** + * enum nl80211_ap_settings_flags - AP settings flags + * + * @NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT: AP supports external + * authentication. + * @NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT: Userspace supports SA Query + * procedures offload to driver. If driver advertises + * %NL80211_AP_SME_SA_QUERY_OFFLOAD in AP SME features, userspace shall + * ignore SA Query procedures and validations when this flag is set by + * userspace. + */ +enum nl80211_ap_settings_flags { + NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT = 1 << 0, + NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT = 1 << 1, }; #endif /* __LINUX_NL80211_H */ @@ -1,4 +1,3 @@ -#include <net/if.h> #include <errno.h> #include <string.h> @@ -7,63 +6,32 @@ SECTION(ocb); -static int join_ocb(struct nl80211_state *state, struct nl_cb *cb, +static int join_ocb(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { - unsigned long freq; - char *end; - int i; - static const struct { - const char *name; - unsigned int width; - } *chanmode_selected, chanmode[] = { - { .name = "5MHZ", - .width = NL80211_CHAN_WIDTH_5 }, - { .name = "10MHZ", - .width = NL80211_CHAN_WIDTH_10 }, - }; + struct chandef chandef; + int err, parsed; if (argc < 2) return 1; - /* freq */ - freq = strtoul(argv[0], &end, 10); - if (*end != '\0') - return 1; - - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); - argv++; - argc--; + err = parse_freqchan(&chandef, false, argc, argv, &parsed); - /* channel width */ - for (i = 0; i < ARRAY_SIZE(chanmode); i++) { - if (strcasecmp(chanmode[i].name, argv[0]) == 0) { - chanmode_selected = &chanmode[i]; - break; - } - } - if (chanmode_selected) { - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - chanmode_selected->width); - NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq); + if (err) + return err; - argv++; - argc--; - } else { - return 1; - } + err = put_chandef(msg, &chandef); + if (err) + return err; return 0; - -nla_put_failure: - return -ENOBUFS; } -COMMAND(ocb, join, "<freq in MHz> <5MHZ|10MHZ>", +COMMAND(ocb, join, "<freq in MHz> <5MHz|10MHz>", NL80211_CMD_JOIN_OCB, 0, CIB_NETDEV, join_ocb, "Join the OCB mode network."); -static int leave_ocb(struct nl80211_state *state, struct nl_cb *cb, +static int leave_ocb(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -9,12 +9,15 @@ #include "nl80211.h" #include "iw.h" -static int offchannel(struct nl80211_state *state, struct nl_cb *cb, +static int offchannel(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { char *end; + if (argc < 2) + return 1; + /* freq */ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, strtoul(argv[0], &end, 10)); @@ -1,7 +1,3 @@ -#include <net/if.h> -#include <errno.h> -#include <string.h> - #include <netlink/genl/genl.h> #include <netlink/genl/family.h> #include <netlink/genl/ctrl.h> @@ -13,7 +9,7 @@ SECTION(p2p); -static int handle_p2p_start(struct nl80211_state *state, struct nl_cb *cb, +static int handle_p2p_start(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -21,7 +17,7 @@ static int handle_p2p_start(struct nl80211_state *state, struct nl_cb *cb, } COMMAND(p2p, start, "", NL80211_CMD_START_P2P_DEVICE, 0, CIB_WDEV, handle_p2p_start, ""); -static int handle_p2p_stop(struct nl80211_state *state, struct nl_cb *cb, +static int handle_p2p_stop(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -1,7 +1,7 @@ #include <stdbool.h> #include <errno.h> -#include <net/if.h> #include <strings.h> +#include <unistd.h> #include <sys/param.h> #include <sys/stat.h> #include <fcntl.h> @@ -15,8 +15,159 @@ #include "nl80211.h" #include "iw.h" +struct channels_ctx { + int last_band; + bool width_40; + bool width_80; + bool width_160; +}; + +static char *dfs_state_name(enum nl80211_dfs_state state) +{ + switch (state) { + case NL80211_DFS_USABLE: + return "usable"; + case NL80211_DFS_AVAILABLE: + return "available"; + case NL80211_DFS_UNAVAILABLE: + return "unavailable"; + default: + return "unknown"; + } +} + +static int print_channels_handler(struct nl_msg *msg, void *arg) +{ + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct channels_ctx *ctx = arg; + struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; + struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; + struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; + struct nlattr *nl_band; + struct nlattr *nl_freq; + int rem_band, rem_freq; + + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + if (tb_msg[NL80211_ATTR_WIPHY_BANDS]) { + nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) { + if (ctx->last_band != nl_band->nla_type) { + printf("Band %d:\n", nl_band->nla_type + 1); + ctx->width_40 = false; + ctx->width_80 = false; + ctx->width_160 = false; + ctx->last_band = nl_band->nla_type; + } + + nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), nla_len(nl_band), NULL); + + if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) { + __u16 cap = nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]); + + if (cap & BIT(1)) + ctx->width_40 = true; + } + + if (tb_band[NL80211_BAND_ATTR_VHT_CAPA]) { + __u32 capa; + + ctx->width_80 = true; + + capa = nla_get_u32(tb_band[NL80211_BAND_ATTR_VHT_CAPA]); + switch ((capa >> 2) & 3) { + case 2: + /* width_80p80 = true; */ + /* fall through */ + case 1: + ctx->width_160 = true; + break; + } + } + + if (tb_band[NL80211_BAND_ATTR_FREQS]) { + nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { + uint32_t freq; + + nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), nla_len(nl_freq), NULL); + + if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) + continue; + freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); + printf("\t* %d MHz [%d] ", freq, ieee80211_frequency_to_channel(freq)); + + if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) { + printf("(disabled)\n"); + continue; + } + printf("\n"); + + if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) + printf("\t Maximum TX power: %.1f dBm\n", 0.01 * nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER])); + + /* If both flags are set assume an new kernel */ + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR] && tb_freq[__NL80211_FREQUENCY_ATTR_NO_IBSS]) { + printf("\t No IR\n"); + } else if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) { + printf("\t Passive scan\n"); + } else if (tb_freq[__NL80211_FREQUENCY_ATTR_NO_IBSS]){ + printf("\t No IBSS\n"); + } + + if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) + printf("\t Radar detection\n"); + + printf("\t Channel widths:"); + if (!tb_freq[NL80211_FREQUENCY_ATTR_NO_20MHZ]) + printf(" 20MHz"); + if (ctx->width_40 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS]) + printf(" HT40-"); + if (ctx->width_40 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS]) + printf(" HT40+"); + if (ctx->width_80 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_80MHZ]) + printf(" VHT80"); + if (ctx->width_160 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_160MHZ]) + printf(" VHT160"); + printf("\n"); + + if (!tb_freq[NL80211_FREQUENCY_ATTR_DISABLED] && tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) { + enum nl80211_dfs_state state = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]); + unsigned long time; + + printf("\t DFS state: %s", dfs_state_name(state)); + if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]) { + time = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]); + printf(" (for %lu sec)", time / 1000); + } + printf("\n"); + if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]) + printf("\t DFS CAC time: %u ms\n", + nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME])); + } + } + } + } + } + + return NL_SKIP; +} + +static int handle_channels(struct nl80211_state *state, struct nl_msg *msg, + int argc, char **argv, enum id_input id) +{ + static struct channels_ctx ctx = { + .last_band = -1, + }; + + nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP); + nlmsg_hdr(msg)->nlmsg_flags |= NLM_F_DUMP; + + register_handler(print_channels_handler, &ctx); + + return 0; +} +TOPLEVEL(channels, NULL, NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_channels, "Show available channels."); + static int handle_name(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -33,146 +184,205 @@ static int handle_name(struct nl80211_state *state, COMMAND(set, name, "<new name>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_name, "Rename this wireless device."); -static int handle_freqs(struct nl_msg *msg, int argc, char **argv) +static int handle_freq(struct nl80211_state *state, struct nl_msg *msg, + int argc, char **argv, + enum id_input id) { - static const struct { - const char *name; - unsigned int val; - } bwmap[] = { - { .name = "20", .val = NL80211_CHAN_WIDTH_20, }, - { .name = "40", .val = NL80211_CHAN_WIDTH_40, }, - { .name = "80", .val = NL80211_CHAN_WIDTH_80, }, - { .name = "80+80", .val = NL80211_CHAN_WIDTH_80P80, }, - { .name = "160", .val = NL80211_CHAN_WIDTH_160, }, - }; - uint32_t freq; - int i, bwval = NL80211_CHAN_WIDTH_20_NOHT; - char *end; + struct chandef chandef; + int res; - if (argc < 1) - return 1; + res = parse_freqchan(&chandef, false, argc, argv, NULL); + if (res) + return res; - for (i = 0; i < ARRAY_SIZE(bwmap); i++) { - if (strcasecmp(bwmap[i].name, argv[0]) == 0) { - bwval = bwmap[i].val; - break; - } - } + return put_chandef(msg, &chandef); +} - if (bwval == NL80211_CHAN_WIDTH_20_NOHT) - return 1; +COMMAND(set, freq, + "<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]\n" + "<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]", + NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq, + "Set frequency/channel the hardware is using, including HT\n" + "configuration."); +COMMAND(set, freq, + "<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]\n" + "<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]", + NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL); - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, bwval); +static int handle_chan(struct nl80211_state *state, struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + struct chandef chandef; + int res; - if (argc == 1) - return 0; + res = parse_freqchan(&chandef, true, argc, argv, NULL); + if (res) + return res; - /* center freq 1 */ - if (!*argv[1]) - return 1; - freq = strtoul(argv[1], &end, 10); - if (*end) - return 1; - NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq); + return put_chandef(msg, &chandef); +} +COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]", + NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL); +COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]", + NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL); - if (argc == 2) - return 0; - /* center freq 2 */ - if (!*argv[2]) - return 1; - freq = strtoul(argv[2], &end, 10); - if (*end) - return 1; - NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, freq); +struct cac_event { + int ret; + uint32_t freq; +}; - return 0; - nla_put_failure: - return -ENOBUFS; +static int print_cac_event(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + enum nl80211_radar_event event_type; + struct cac_event *cac_event = arg; + uint32_t freq; + + if (gnlh->cmd != NL80211_CMD_RADAR_DETECT) + return NL_SKIP; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb[NL80211_ATTR_RADAR_EVENT] || !tb[NL80211_ATTR_WIPHY_FREQ]) + return NL_SKIP; + + freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); + event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]); + if (freq != cac_event->freq) + return NL_SKIP; + + switch (event_type) { + case NL80211_RADAR_DETECTED: + printf("%d MHz: radar detected\n", freq); + break; + case NL80211_RADAR_CAC_FINISHED: + printf("%d MHz: CAC finished\n", freq); + break; + case NL80211_RADAR_CAC_ABORTED: + printf("%d MHz: CAC was aborted\n", freq); + break; + case NL80211_RADAR_NOP_FINISHED: + printf("%d MHz: NOP finished\n", freq); + break; + default: + printf("%d MHz: unknown radar event\n", freq); + } + cac_event->ret = 0; + + return NL_SKIP; } -static int handle_freqchan(struct nl_msg *msg, bool chan, - int argc, char **argv) +static int handle_cac_trigger(struct nl80211_state *state, + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) { - char *end; - static const struct { - const char *name; - unsigned int val; - } htmap[] = { - { .name = "HT20", .val = NL80211_CHAN_HT20, }, - { .name = "HT40+", .val = NL80211_CHAN_HT40PLUS, }, - { .name = "HT40-", .val = NL80211_CHAN_HT40MINUS, }, - }; - unsigned int htval = NL80211_CHAN_NO_HT; - unsigned int freq; - int i; + struct chandef chandef; + int res; - if (!argc || argc > 4) + if (argc < 2) return 1; - if (!*argv[0]) - return 1; - freq = strtoul(argv[0], &end, 10); - if (*end) + if (strcmp(argv[0], "channel") == 0) { + res = parse_freqchan(&chandef, true, argc - 1, argv + 1, NULL); + } else if (strcmp(argv[0], "freq") == 0) { + res = parse_freqchan(&chandef, false, argc - 1, argv + 1, NULL); + } else { return 1; - - if (chan) { - enum nl80211_band band; - band = freq <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; - freq = ieee80211_channel_to_frequency(freq, band); - } - - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); - - if (argc > 2) { - return handle_freqs(msg, argc - 1, argv + 1); - } else if (argc == 2) { - for (i = 0; i < ARRAY_SIZE(htmap); i++) { - if (strcasecmp(htmap[i].name, argv[1]) == 0) { - htval = htmap[i].val; - break; - } - } - if (htval == NL80211_CHAN_NO_HT) - return handle_freqs(msg, argc - 1, argv + 1); } - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, htval); + if (res) + return res; - return 0; - nla_put_failure: - return -ENOBUFS; + return put_chandef(msg, &chandef); } -static int handle_freq(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, - int argc, char **argv, - enum id_input id) +static int no_seq_check(struct nl_msg *msg, void *arg) { - return handle_freqchan(msg, false, argc, argv); + return NL_OK; } -COMMAND(set, freq, "<freq> [HT20|HT40+|HT40-]", - NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq, - "Set frequency/channel the hardware is using, including HT\n" - "configuration."); -COMMAND(set, freq, "<freq> [HT20|HT40+|HT40-]\n" - "<control freq> [20|40|80|80+80|160] [<center freq 1>] [<center freq 2>]", - NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL); -static int handle_chan(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, - int argc, char **argv, - enum id_input id) +static int handle_cac(struct nl80211_state *state, + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) { - return handle_freqchan(msg, true, argc, argv); + int err; + struct nl_cb *radar_cb; + struct chandef chandef; + struct cac_event cac_event; + char **cac_trigger_argv = NULL; + + radar_cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); + if (!radar_cb) + return 1; + + if (argc < 3) + return 1; + + if (strcmp(argv[2], "channel") == 0) { + err = parse_freqchan(&chandef, true, argc - 3, argv + 3, NULL); + } else if (strcmp(argv[2], "freq") == 0) { + err = parse_freqchan(&chandef, false, argc - 3, argv + 3, NULL); + } else { + err = 1; + } + if (err) + goto err_out; + + cac_trigger_argv = calloc(argc + 1, sizeof(char*)); + if (!cac_trigger_argv) { + err = -ENOMEM; + goto err_out; + } + + cac_trigger_argv[0] = argv[0]; + cac_trigger_argv[1] = "cac"; + cac_trigger_argv[2] = "trigger"; + memcpy(&cac_trigger_argv[3], &argv[2], (argc - 2) * sizeof(char*)); + + err = handle_cmd(state, id, argc + 1, cac_trigger_argv); + if (err) + goto err_out; + + cac_event.ret = 1; + cac_event.freq = chandef.control_freq; + + __prepare_listen_events(state); + nl_socket_set_cb(state->nl_sock, radar_cb); + + /* need to turn off sequence number checking */ + nl_cb_set(radar_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); + nl_cb_set(radar_cb, NL_CB_VALID, NL_CB_CUSTOM, print_cac_event, &cac_event); + while (cac_event.ret > 0) + nl_recvmsgs(state->nl_sock, radar_cb); + + err = 0; +err_out: + if (radar_cb) + nl_cb_put(radar_cb); + if (cac_trigger_argv) + free(cac_trigger_argv); + return err; } -COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]", - NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL); -COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]", - NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL); +TOPLEVEL(cac, "channel <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n" + "freq <freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n" + "freq <control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]", + 0, 0, CIB_NETDEV, handle_cac, NULL); +COMMAND(cac, trigger, + "channel <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n" + "freq <frequency> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n" + "freq <frequency> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]", + NL80211_CMD_RADAR_DETECT, 0, CIB_NETDEV, handle_cac_trigger, + "Start or trigger a channel availability check (CAC) looking to look for\n" + "radars on the given channel."); static int handle_fragmentation(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, + struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -204,7 +414,7 @@ COMMAND(set, frag, "<fragmentation threshold|off>", "Set fragmentation threshold."); static int handle_rts(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, + struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -236,7 +446,7 @@ COMMAND(set, rts, "<rts threshold|off>", "Set rts threshold."); static int handle_retry(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, + struct nl_msg *msg, int argc, char **argv, enum id_input id) { unsigned int retry_short = 0, retry_long = 0; @@ -302,7 +512,7 @@ COMMAND(set, retry, "[short <limit>] [long <limit>]", #ifndef NETNS_RUN_DIR #define NETNS_RUN_DIR "/var/run/netns" #endif -int netns_get_fd(const char *name) +static int netns_get_fd(const char *name) { char pathbuf[MAXPATHLEN]; const char *path, *ptr; @@ -318,13 +528,12 @@ int netns_get_fd(const char *name) } static int handle_netns(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { char *end; - int fd; + int fd = -1; if (argc < 1 || !*argv[0]) return 1; @@ -352,6 +561,8 @@ static int handle_netns(struct nl80211_state *state, return 1; nla_put_failure: + if (fd >= 0) + close(fd); return -ENOBUFS; } COMMAND(set, netns, "{ <pid> | name <nsname> }", @@ -362,7 +573,6 @@ COMMAND(set, netns, "{ <pid> | name <nsname> }", " or by absolute path (man ip-netns)\n"); static int handle_coverage(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -394,7 +604,6 @@ COMMAND(set, coverage, "<coverage class>", "Valid values: 0 - 255."); static int handle_distance(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -442,7 +651,6 @@ COMMAND(set, distance, "<auto|distance>", "Valid values: 0 - 114750"); static int handle_txpower(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -494,7 +702,6 @@ COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]", "Specify transmit power level and setting type."); static int handle_antenna(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -532,3 +739,119 @@ COMMAND(set, antenna, "<bitmap> | all | <tx bitmap> <rx bitmap>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna, "Set a bitmap of allowed antennas to use for TX and RX.\n" "The driver may reject antenna configurations it cannot support."); + +static int handle_set_txq(struct nl80211_state *state, + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + unsigned int argval; + char *end; + + if (argc != 2) + return 1; + + if (!*argv[0] || !*argv[1]) + return 1; + + argval = strtoul(argv[1], &end, 10); + + if (*end) + return 1; + + if (!argval) + return 1; + + if (strcmp("limit", argv[0]) == 0) + NLA_PUT_U32(msg, NL80211_ATTR_TXQ_LIMIT, argval); + else if (strcmp("memory_limit", argv[0]) == 0) + NLA_PUT_U32(msg, NL80211_ATTR_TXQ_MEMORY_LIMIT, argval); + else if (strcmp("quantum", argv[0]) == 0) + NLA_PUT_U32(msg, NL80211_ATTR_TXQ_QUANTUM, argval); + else + return -1; + + return 0; + nla_put_failure: + return -ENOBUFS; +} +COMMAND(set, txq, "limit <packets> | memory_limit <bytes> | quantum <bytes>", + NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_set_txq, + "Set TXQ parameters. The limit and memory_limit are global queue limits\n" + "for the whole phy. The quantum is the DRR scheduler quantum setting.\n" + "Valid values: 1 - 2**32"); + +static int print_txq_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *txqstats_info[NL80211_TXQ_STATS_MAX + 1], *txqinfo; + static struct nla_policy txqstats_policy[NL80211_TXQ_STATS_MAX + 1] = { + [NL80211_TXQ_STATS_BACKLOG_PACKETS] = { .type = NLA_U32 }, + [NL80211_TXQ_STATS_BACKLOG_BYTES] = { .type = NLA_U32 }, + [NL80211_TXQ_STATS_OVERLIMIT] = { .type = NLA_U32 }, + [NL80211_TXQ_STATS_OVERMEMORY] = { .type = NLA_U32 }, + [NL80211_TXQ_STATS_COLLISIONS] = { .type = NLA_U32 }, + [NL80211_TXQ_STATS_MAX_FLOWS] = { .type = NLA_U32 }, + }; + + nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + + if (attrs[NL80211_ATTR_TXQ_LIMIT]) + printf("Packet limit:\t\t%u pkts\n", + nla_get_u32(attrs[NL80211_ATTR_TXQ_LIMIT])); + if (attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]) + printf("Memory limit:\t\t%u bytes\n", + nla_get_u32(attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT])); + if (attrs[NL80211_ATTR_TXQ_QUANTUM]) + printf("Quantum:\t\t%u bytes\n", + nla_get_u32(attrs[NL80211_ATTR_TXQ_QUANTUM])); + + if (attrs[NL80211_ATTR_TXQ_STATS]) { + if (nla_parse_nested(txqstats_info, NL80211_TXQ_STATS_MAX, + attrs[NL80211_ATTR_TXQ_STATS], + txqstats_policy)) { + printf("failed to parse nested TXQ stats attributes!"); + return 0; + } + txqinfo = txqstats_info[NL80211_TXQ_STATS_MAX_FLOWS]; + if (txqinfo) + printf("Number of queues:\t%u\n", nla_get_u32(txqinfo)); + + txqinfo = txqstats_info[NL80211_TXQ_STATS_BACKLOG_PACKETS]; + if (txqinfo) + printf("Backlog:\t\t%u pkts\n", nla_get_u32(txqinfo)); + + txqinfo = txqstats_info[NL80211_TXQ_STATS_BACKLOG_BYTES]; + if (txqinfo) + printf("Memory usage:\t\t%u bytes\n", nla_get_u32(txqinfo)); + + txqinfo = txqstats_info[NL80211_TXQ_STATS_OVERLIMIT]; + if (txqinfo) + printf("Packet limit overflows:\t%u\n", nla_get_u32(txqinfo)); + + txqinfo = txqstats_info[NL80211_TXQ_STATS_OVERMEMORY]; + if (txqinfo) + printf("Memory limit overflows:\t%u\n", nla_get_u32(txqinfo)); + txqinfo = txqstats_info[NL80211_TXQ_STATS_COLLISIONS]; + if (txqinfo) + printf("Hash collisions:\t%u\n", nla_get_u32(txqinfo)); + } + return NL_SKIP; +} + +static int handle_get_txq(struct nl80211_state *state, + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP); + nlmsg_hdr(msg)->nlmsg_flags |= NLM_F_DUMP; + register_handler(print_txq_handler, NULL); + return 0; +} +COMMAND(get, txq, "", + NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_get_txq, + "Get TXQ parameters."); @@ -9,17 +9,14 @@ #include "iw.h" static int set_power_save(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { enum nl80211_ps_state ps_state; - if (argc != 1) { - printf("Invalid parameters!\n"); - return 2; - } + if (argc != 1) + return 1; if (strcmp(argv[0], "on") == 0) ps_state = NL80211_PS_ENABLED; @@ -70,16 +67,14 @@ static int print_power_save_handler(struct nl_msg *msg, void *arg) } static int get_power_save(struct nl80211_state *state, - struct nl_cb *cb, - struct nl_msg *msg, - int argc, char **argv, - enum id_input id) + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) { - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, - print_power_save_handler, NULL); + register_handler(print_power_save_handler, NULL); return 0; } -COMMAND(get, power_save, "<param>", +COMMAND(get, power_save, "", NL80211_CMD_GET_POWER_SAVE, 0, CIB_NETDEV, get_power_save, "Retrieve power save state."); @@ -1,4 +1,3 @@ -#include <net/if.h> #include <errno.h> #include <string.h> #include <stdbool.h> @@ -76,7 +75,6 @@ static const char *dfs_domain_name(enum nl80211_dfs_regions region) } static int handle_reg_set(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -206,11 +204,13 @@ static int print_reg_handler(struct nl_msg *msg, void *arg) PARSE_FLAG(NL80211_RRF_DFS, "DFS"); PARSE_FLAG(NL80211_RRF_PTP_ONLY, "PTP-ONLY"); PARSE_FLAG(NL80211_RRF_AUTO_BW, "AUTO-BW"); - PARSE_FLAG(NL80211_RRF_GO_CONCURRENT, "GO-CONCURRENT"); + PARSE_FLAG(NL80211_RRF_IR_CONCURRENT, "IR-CONCURRENT"); PARSE_FLAG(NL80211_RRF_NO_HT40MINUS, "NO-HT40MINUS"); PARSE_FLAG(NL80211_RRF_NO_HT40PLUS, "NO-HT40PLUS"); PARSE_FLAG(NL80211_RRF_NO_80MHZ, "NO-80MHZ"); PARSE_FLAG(NL80211_RRF_NO_160MHZ, "NO-160MHZ"); + PARSE_FLAG(NL80211_RRF_NO_HE, "NO-HE"); + PARSE_FLAG(NL80211_RRF_NO_320MHZ, "NO-320MHZ"); /* Kernels that support NO_IR always turn on both flags */ if ((flags & NL80211_RRF_NO_IR) && (flags & __NL80211_RRF_NO_IBSS)) { @@ -229,17 +229,15 @@ static int print_reg_handler(struct nl_msg *msg, void *arg) } static int handle_reg_dump(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_reg_handler, NULL); + register_handler(print_reg_handler, NULL); return 0; } static int handle_reg_get(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -247,19 +245,39 @@ static int handle_reg_get(struct nl80211_state *state, char *dump_args[] = { "reg", "dump" }; int err; - err = handle_cmd(state, CIB_NONE, 2, dump_args); - /* dump might fail since it's not supported on older kernels */ - if (err == -EOPNOTSUPP) { - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_reg_handler, - NULL); + /* + * If PHY was specifically given, get the PHY specific regulatory + * information. Otherwise, dump the entire regulatory information. + */ + if (id == II_PHY_IDX || id == II_PHY_NAME) { + register_handler(print_reg_handler, NULL); return 0; } - return err; + err = handle_cmd(state, II_NONE, 2, dump_args); + + /* + * dump might fail since it's not supported on older kernels, + * in that case the handler is still registered already + */ + if (err == -EOPNOTSUPP) + return 0; + + return err ?: HANDLER_RET_DONE; } COMMAND(reg, get, NULL, NL80211_CMD_GET_REG, 0, CIB_NONE, handle_reg_get, "Print out the kernel's current regulatory domain information."); -COMMAND(reg, get, NULL, NL80211_CMD_GET_REG, 0, CIB_PHY, handle_reg_get, +COMMAND(reg, get, NULL, NL80211_CMD_GET_REG, 0, CIB_PHY, handle_reg_dump, "Print out the devices' current regulatory domain information."); HIDDEN(reg, dump, NULL, NL80211_CMD_GET_REG, NLM_F_DUMP, CIB_NONE, handle_reg_dump); + +static int handle_reg_reload(struct nl80211_state *state, + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + return 0; +} +COMMAND(reg, reload, NULL, NL80211_CMD_RELOAD_REGDB, 0, CIB_NONE, + handle_reg_reload, "Reload the kernel's regulatory database."); @@ -1,4 +1,3 @@ -#include <net/if.h> #include <errno.h> #include <string.h> @@ -13,7 +12,7 @@ SECTION(roc); -static int handle_roc_start(struct nl80211_state *state, struct nl_cb *cb, +static int handle_roc_start(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -0,0 +1,71 @@ +#include <errno.h> +#include <string.h> + +#include <netlink/genl/genl.h> +#include <netlink/msg.h> +#include <netlink/attr.h> + +#include "nl80211.h" +#include "iw.h" + +static int set_sar_specs(struct nl80211_state *state, + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + struct nlattr *nl_sar, *nl_specs, *nl_sub; + enum nl80211_sar_type type; + __u32 idx; + __s32 pwr; + char *tmp; + int count, i; + + if (argc <= 1) + return -EINVAL; + + type = atoi(argv[0]); + + nl_sar = nla_nest_start(msg, NL80211_ATTR_SAR_SPEC); + if (!nl_sar) + goto nla_put_failure; + + NLA_PUT_U32(msg, NL80211_SAR_ATTR_TYPE, type); + + nl_specs = nla_nest_start(msg, NL80211_SAR_ATTR_SPECS); + if (!nl_specs) + goto nla_put_failure; + + for (i = 1; i < argc; i++) { + tmp = strchr(argv[i], ':'); + if (!tmp) + return -EINVAL; + + if (tmp != strrchr(argv[i], ':')) + return -EINVAL; + + count = sscanf(argv[i], "%u:%d", &idx, &pwr); + if (count != 2) + return -EINVAL; + + nl_sub = nla_nest_start(msg, i - 1); + if (!nl_sub) + goto nla_put_failure; + + NLA_PUT_U32(msg, NL80211_SAR_ATTR_SPECS_RANGE_INDEX, idx); + NLA_PUT_S32(msg, NL80211_SAR_ATTR_SPECS_POWER, pwr); + + nla_nest_end(msg, nl_sub); + } + + nla_nest_end(msg, nl_specs); + nla_nest_end(msg, nl_sar); + + return 0; + + nla_put_failure: + return -ENOBUFS; +} + +COMMAND(set, sar_specs, "<sar type> <range index:sar power>*", + NL80211_CMD_SET_SAR_SPECS, 0, CIB_PHY, set_sar_specs, + "Set SAR specs corresponding to SAR capa of wiphy."); @@ -1,7 +1,6 @@ #include <net/if.h> #include <errno.h> #include <string.h> -#include <ctype.h> #include <stdbool.h> #include <netlink/genl/genl.h> @@ -70,51 +69,24 @@ union ieee80211_country_ie_triplet { } __attribute__ ((packed)) ext; } __attribute__ ((packed)); -static int parse_random_mac_addr(struct nl_msg *msg, char *arg) -{ - char *a_addr, *a_mask, *sep; - unsigned char addr[ETH_ALEN], mask[ETH_ALEN]; - char *addrs = arg + 9; - - if (*addrs != '=') - return 0; - - addrs++; - sep = strchr(addrs, '/'); - a_addr = addrs; - - if (!sep) - return 1; - - *sep = 0; - a_mask = sep + 1; - if (mac_addr_a2n(addr, a_addr) || mac_addr_a2n(mask, a_mask)) - return 1; - - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - NLA_PUT(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN, mask); - - return 0; - nla_put_failure: - return -ENOBUFS; -} - int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv) { struct nl_msg *matchset = NULL, *freqs = NULL, *ssids = NULL; - struct nlattr *match = NULL; + struct nl_msg *scan_plans = NULL; + struct nlattr *match = NULL, *plan = NULL; enum { ND_TOPLEVEL, ND_MATCH, ND_FREQS, ND_ACTIVE, + ND_PLANS, } parse_state = ND_TOPLEVEL; int c = *argc; char *end, **v = *argv; int err = 0, i = 0; - unsigned int freq, interval = 0, delay = 0; + unsigned int freq, interval = 0, delay = 0, iterations = 0; bool have_matchset = false, have_freqs = false, have_ssids = false; - bool have_active = false, have_passive = false; + bool have_active = false, have_passive = false, have_plans = false; uint32_t flags = 0; matchset = nlmsg_alloc(); @@ -135,6 +107,12 @@ int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv) goto out; } + scan_plans = nlmsg_alloc(); + if (!scan_plans) { + err = -ENOBUFS; + goto out; + } + while (c) { switch (parse_state) { case ND_TOPLEVEL: @@ -145,7 +123,7 @@ int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv) goto nla_put_failure; } - if (interval) { + if (interval || have_plans) { err = -EINVAL; goto nla_put_failure; } @@ -157,6 +135,15 @@ int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv) NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval); + } else if (!strcmp(v[0], "scan_plans")) { + parse_state = ND_PLANS; + if (have_plans || interval) { + err = -EINVAL; + goto nla_put_failure; + } + + have_plans = true; + i = 0; } else if (!strcmp(v[0], "delay")) { c--; v++; if (c == 0) { @@ -212,11 +199,13 @@ int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv) } else if (!strncmp(v[0], "randomise", 9) || !strncmp(v[0], "randomize", 9)) { flags |= NL80211_SCAN_FLAG_RANDOM_ADDR; - if (c > 0) { - err = parse_random_mac_addr(msg, v[0]); - if (err) - goto nla_put_failure; - } + err = parse_random_mac_addr(msg, v[0] + 9); + if (err) + goto nla_put_failure; + } else if (!strncmp(v[0], "coloc", 5)) { + flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ; + } else if (!strncmp(v[0], "flush", 5)) { + flags |= NL80211_SCAN_FLAG_FLUSH; } else { /* this element is not for us, so * return to continue parsing. @@ -310,6 +299,47 @@ int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv) parse_state = ND_TOPLEVEL; } break; + case ND_PLANS: + iterations = 0; + interval = strtoul(v[0], &end, 10); + if (*end) { + char *iter; + + if (*end != ':') { + err = -EINVAL; + goto nla_put_failure; + } + + iter = ++end; + iterations = strtoul(iter, &end, 10); + if (*end || !iterations) { + err = -EINVAL; + goto nla_put_failure; + } + } + + plan = nla_nest_start(scan_plans, i + 1); + if (!plan) { + err = -ENOBUFS; + goto nla_put_failure; + } + + NLA_PUT_U32(scan_plans, + NL80211_SCHED_SCAN_PLAN_INTERVAL, + interval); + + if (iterations) + NLA_PUT_U32(scan_plans, + NL80211_SCHED_SCAN_PLAN_ITERATIONS, + iterations); + else + parse_state = ND_TOPLEVEL; + + nla_nest_end(scan_plans, plan); + plan = NULL; + i++; + c--; v++; + break; } } @@ -321,23 +351,26 @@ int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv) nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs); if (have_matchset) nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH, matchset); + if (have_plans) + nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_PLANS, scan_plans); if (flags) NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, flags); nla_put_failure: if (match) nla_nest_end(msg, match); +out: nlmsg_free(freqs); nlmsg_free(matchset); + nlmsg_free(scan_plans); + nlmsg_free(ssids); -out: *argc = c; *argv = v; return err; } static int handle_scan(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -352,12 +385,15 @@ static int handle_scan(struct nl80211_state *state, IES, SSID, MESHID, + DURATION, DONE, } parse = NONE; int freq; + unsigned int duration = 0; bool passive = false, have_ssids = false, have_freqs = false; + bool duration_mandatory = false; size_t ies_len = 0, meshid_len = 0; - unsigned char *ies = NULL, *meshid = NULL, *tmpies; + unsigned char *ies = NULL, *meshid = NULL, *tmpies = NULL; unsigned int flags = 0; ssids = nlmsg_alloc(); @@ -389,10 +425,16 @@ static int handle_scan(struct nl80211_state *state, } else if (strcmp(argv[i], "ap-force") == 0) { flags |= NL80211_SCAN_FLAG_AP; break; + } else if (strcmp(argv[i], "coloc") == 0) { + flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ; + break; + } else if (strcmp(argv[i], "duration-mandatory") == 0) { + duration_mandatory = true; + break; } else if (strncmp(argv[i], "randomise", 9) == 0 || strncmp(argv[i], "randomize", 9) == 0) { flags |= NL80211_SCAN_FLAG_RANDOM_ADDR; - err = parse_random_mac_addr(msg, argv[i]); + err = parse_random_mac_addr(msg, argv[i] + 9); if (err) goto nla_put_failure; break; @@ -407,9 +449,14 @@ static int handle_scan(struct nl80211_state *state, } else if (strcmp(argv[i], "meshid") == 0) { parse = MESHID; break; + } else if (strcmp(argv[i], "duration") == 0) { + parse = DURATION; + break; } + /* fall through - this is an error */ case DONE: - return 1; + err = 1; + goto nla_put_failure; case FREQ: freq = strtoul(argv[i], &eptr, 10); if (eptr != argv[i] + strlen(argv[i])) { @@ -421,6 +468,8 @@ static int handle_scan(struct nl80211_state *state, NLA_PUT_U32(freqs, i, freq); break; case IES: + if (ies) + free(ies); ies = parse_hex(argv[i], &ies_len); if (!ies) goto nla_put_failure; @@ -440,6 +489,10 @@ static int handle_scan(struct nl80211_state *state, meshid_len += 2; parse = NONE; break; + case DURATION: + duration = strtoul(argv[i], &eptr, 10); + parse = NONE; + break; } } @@ -447,16 +500,12 @@ static int handle_scan(struct nl80211_state *state, tmpies = (unsigned char *) malloc(ies_len + meshid_len); if (!tmpies) goto nla_put_failure; - if (ies) { + if (ies) memcpy(tmpies, ies, ies_len); - free(ies); - } - if (meshid) { + if (meshid) memcpy(&tmpies[ies_len], meshid, meshid_len); - free(meshid); - } - NLA_PUT(msg, NL80211_ATTR_IE, ies_len + meshid_len, tmpies); - free(tmpies); + if (nla_put(msg, NL80211_ATTR_IE, ies_len + meshid_len, tmpies) < 0) + goto nla_put_failure; } if (!have_ssids) @@ -466,13 +515,32 @@ static int handle_scan(struct nl80211_state *state, if (have_freqs) nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs); + else + flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ; if (flags) NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, flags); + if (duration) + NLA_PUT_U16(msg, NL80211_ATTR_MEASUREMENT_DURATION, duration); + if (duration_mandatory) { + if (duration) { + NLA_PUT_FLAG(msg, + NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY); + } else { + err = -EINVAL; + goto nla_put_failure; + } + } err = 0; nla_put_failure: nlmsg_free(ssids); nlmsg_free(freqs); + if (meshid) + free(meshid); + if (ies) + free(ies); + if (tmpies) + free(tmpies); return err; } @@ -484,7 +552,13 @@ static void tab_on_first(bool *first) *first = false; } -static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data) +struct print_ies_data { + unsigned char *ie; + int ielen; +}; + +static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) { printf(" "); print_ssid_escaped(len, data); @@ -494,7 +568,9 @@ static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data) #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127 -static void print_supprates(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_supprates(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) { int i; @@ -515,7 +591,63 @@ static void print_supprates(const uint8_t type, uint8_t len, const uint8_t *data printf("\n"); } -static void print_ds(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_rm_enabled_capabilities(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) +{ + __u64 capa = ((__u64) data[0]) | + ((__u64) data[1]) << 8 | + ((__u64) data[2]) << 16 | + ((__u64) data[3]) << 24 | + ((__u64) data[4]) << 32; + + printf("\n"); + printf("\t\tCapabilities: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + data[0], data[1], + data[2], data[3], + data[4]); + +#define PRINT_RM_CAPA(_bit, _str) \ + do { \ + if (capa & BIT(_bit)) \ + printf("\t\t\t" _str "\n"); \ + } while (0) + + PRINT_RM_CAPA(0, "Link Measurement"); + PRINT_RM_CAPA(1, "Neighbor Report"); + PRINT_RM_CAPA(2, "Parallel Measurements"); + PRINT_RM_CAPA(3, "Repeated Measurements"); + PRINT_RM_CAPA(4, "Beacon Passive Measurement"); + PRINT_RM_CAPA(5, "Beacon Active Measurement"); + PRINT_RM_CAPA(6, "Beacon Table Measurement"); + PRINT_RM_CAPA(7, "Beacon Measurement Reporting Conditions"); + PRINT_RM_CAPA(8, "Frame Measurement"); + PRINT_RM_CAPA(9, "Channel Load"); + PRINT_RM_CAPA(10, "Noise Histogram Measurement"); + PRINT_RM_CAPA(11, "Statistics Measurement"); + PRINT_RM_CAPA(12, "LCI Measurement"); + PRINT_RM_CAPA(13, "LCI Azimuth"); + PRINT_RM_CAPA(14, "Transmit Stream/Category Measurement"); + PRINT_RM_CAPA(15, "Triggered Transmit Stream/Category"); + PRINT_RM_CAPA(16, "AP Channel Report"); + PRINT_RM_CAPA(17, "RM MIB Capability"); + + PRINT_RM_CAPA(27, "Measurement Pilot Transmission Information"); + PRINT_RM_CAPA(28, "Neighbor Report TSF Offset"); + PRINT_RM_CAPA(29, "RCPI Measurement"); + PRINT_RM_CAPA(30, "RSNI Measurement"); + PRINT_RM_CAPA(31, "BSS Average Access Delay"); + PRINT_RM_CAPA(32, "BSS Available Admission"); + PRINT_RM_CAPA(33, "Antenna"); + PRINT_RM_CAPA(34, "FTM Range Report"); + PRINT_RM_CAPA(35, "Civic Location Measurement"); + + printf("\t\tNonoperating Channel Max Measurement Duration: %i\n", data[3] >> 5); + printf("\t\tMeasurement Pilot Capability: %i\n", data[4] & 7); +} + +static void print_ds(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) { printf(" channel %d\n", data[0]); } @@ -534,7 +666,8 @@ static const char *country_env_str(char environment) } } -static void print_country(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_country(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) { printf(" %.*s", 2, data); @@ -579,18 +712,23 @@ static void print_country(const uint8_t type, uint8_t len, const uint8_t *data) return; } -static void print_powerconstraint(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_powerconstraint(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) { printf(" %d dB\n", data[0]); } -static void print_tpcreport(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_tpcreport(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) { printf(" TX power: %d dBm\n", data[0]); /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */ } -static void print_erp(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_erp(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) { if (data[0] == 0x00) printf(" <no flags>"); @@ -603,6 +741,21 @@ static void print_erp(const uint8_t type, uint8_t len, const uint8_t *data) printf("\n"); } +static void print_ap_channel_report(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) +{ + uint8_t oper_class = data[0]; + int i; + + printf("\n"); + printf("\t\t * operating class: %d\n", oper_class); + printf("\t\t * channel(s):"); + for (i = 1; i < len; ++i) { + printf(" %d", data[i]); + } + printf("\n"); +} + static void print_cipher(const uint8_t *data) { if (memcmp(data, ms_oui, 3) == 0) { @@ -701,6 +854,36 @@ static void print_auth(const uint8_t *data) case 7: printf("TDLS/TPK"); break; + case 8: + printf("SAE"); + break; + case 9: + printf("FT/SAE"); + break; + case 11: + printf("IEEE 802.1X/SUITE-B"); + break; + case 12: + printf("IEEE 802.1X/SUITE-B-192"); + break; + case 13: + printf("FT/IEEE 802.1X/SHA-384"); + break; + case 14: + printf("FILS/SHA-256"); + break; + case 15: + printf("FILS/SHA-384"); + break; + case 16: + printf("FT/FILS/SHA-256"); + break; + case 17: + printf("FT/FILS/SHA-384"); + break; + case 18: + printf("OWE"); + break; default: printf("%.02x-%.02x-%.02x:%d", data[0], data[1] ,data[2], data[3]); @@ -711,6 +894,9 @@ static void print_auth(const uint8_t *data) case 1: printf("OSEN"); break; + case 2: + printf("DPP"); + break; default: printf("%.02x-%.02x-%.02x:%d", data[0], data[1] ,data[2], data[3]); @@ -841,6 +1027,8 @@ static void _print_rsn_ie(const char *defcipher, const char *defauth, printf(" SPP-AMSDU-capable"); if (capa & 0x0800) printf(" SPP-AMSDU-required"); + if (capa & 0x2000) + printf(" Extended-Key-ID"); printf(" (0x%.4x)\n", capa); data += 2; len -= 2; @@ -893,12 +1081,14 @@ static void print_osen_ie(const char *defcipher, const char *defauth, _print_rsn_ie(defcipher, defauth, len, data, 1); } -static void print_rsn(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_rsn(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) { print_rsn_ie("CCMP", "IEEE 802.1X", len, data); } -static void print_ht_capa(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_ht_capa(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) { printf("\n"); print_ht_capability(data[0] | (data[1] << 8)); @@ -941,7 +1131,9 @@ static const char* vgroup_11u(uint8_t t) } } -static void print_interworking(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_interworking(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) { /* See Section 7.3.2.92 in the 802.11u spec. */ printf("\n"); @@ -965,14 +1157,16 @@ static void print_interworking(const uint8_t type, uint8_t len, const uint8_t *d printf("\t\tVenue Type: %i\n", (int)(data[2])); } if (len == 9) - printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n", + printf("\t\tHESSID: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", data[3], data[4], data[5], data[6], data[7], data[8]); else if (len == 7) - printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n", + printf("\t\tHESSID: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", data[1], data[2], data[3], data[4], data[5], data[6]); } -static void print_11u_advert(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_11u_advert(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) { /* See Section 7.3.2.93 in the 802.11u spec. */ /* TODO: This code below does not decode private protocol IDs */ @@ -1004,7 +1198,8 @@ static void print_11u_advert(const uint8_t type, uint8_t len, const uint8_t *dat } } -static void print_11u_rcon(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_11u_rcon(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) { /* See Section 7.3.2.96 in the 802.11u spec. */ int idx = 0; @@ -1024,7 +1219,7 @@ static void print_11u_rcon(const uint8_t type, uint8_t len, const uint8_t *data) printf("Invalid IE length.\n"); } else { for (idx = 0; idx < ln0; idx++) { - printf("%02hx", data[2 + idx]); + printf("%02hhx", data[2 + idx]); } printf("\n"); } @@ -1036,7 +1231,7 @@ static void print_11u_rcon(const uint8_t type, uint8_t len, const uint8_t *data) printf("Invalid IE length.\n"); } else { for (idx = 0; idx < ln1; idx++) { - printf("%02hx", data[2 + ln0 + idx]); + printf("%02hhx", data[2 + ln0 + idx]); } printf("\n"); } @@ -1048,13 +1243,43 @@ static void print_11u_rcon(const uint8_t type, uint8_t len, const uint8_t *data) printf("Invalid IE length.\n"); } else { for (idx = 0; idx < ln2; idx++) { - printf("%02hx", data[2 + ln0 + ln1 + idx]); + printf("%02hhx", data[2 + ln0 + ln1 + idx]); } printf("\n"); } } } +static void print_tx_power_envelope(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) +{ + const uint8_t local_max_tx_power_count = data[0] & 7; + const uint8_t local_max_tx_power_unit_interp = (data[0] >> 3) & 7; + int i; + static const char *power_names[] = { + "Local Maximum Transmit Power For 20 MHz", + "Local Maximum Transmit Power For 40 MHz", + "Local Maximum Transmit Power For 80 MHz", + "Local Maximum Transmit Power For 160/80+80 MHz", + }; + + printf("\n"); + + if (local_max_tx_power_count + 2 != len) + return; + if (local_max_tx_power_unit_interp != 0) + return; + for (i = 0; i < local_max_tx_power_count + 1; ++i) { + int8_t power_val = ((int8_t)data[1 + i]) >> 1; + int8_t point5 = data[1 + i] & 1; + if (point5) + printf("\t\t * %s: %i.5 dBm\n", power_names[i], power_val); + else + printf("\t\t * %s: %i dBm\n", power_names[i], power_val); + } +} + static const char *ht_secondary_offset[4] = { "no secondary", "above", @@ -1062,7 +1287,8 @@ static const char *ht_secondary_offset[4] = { "below", }; -static void print_ht_op(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_ht_op(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) { static const char *protection[4] = { "no", @@ -1092,11 +1318,23 @@ static void print_ht_op(const uint8_t type, uint8_t len, const uint8_t *data) printf("\t\t * PCO phase: %d\n", (data[5] & 0x8) >> 3); } -static void print_capabilities(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_capabilities(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) { - int i, base, bit; - bool first = true; + int i, base, bit, si_duration = 0, max_amsdu = 0; + bool s_psmp_support = false, is_vht_cap = false; + unsigned char *ie = ie_buffer->ie; + int ielen = ie_buffer->ielen; + while (ielen >= 2 && ielen >= ie[1]) { + if (ie[0] == 191) { + is_vht_cap = true; + break; + } + ielen -= ie[1] + 2; + ie += ie[1] + 2; + } for (i = 0; i < len; i++) { base = i * 8; @@ -1105,13 +1343,21 @@ static void print_capabilities(const uint8_t type, uint8_t len, const uint8_t *d if (!(data[i] & (1 << bit))) continue; - if (!first) - printf(","); - else - first = false; + printf("\n\t\t *"); #define CAPA(bit, name) case bit: printf(" " name); break +/* if the capability 'cap' exists add 'val' to 'sum' + * otherwise print 'Reserved' */ +#define ADD_BIT_VAL(bit, cap, sum, val) case (bit): do { \ + if (!(cap)) { \ + printf(" Reserved"); \ + break; \ + } \ + sum += val; \ + break; \ +} while (0) + switch (bit + base) { CAPA(0, "HT Information Exchange Supported"); CAPA(1, "reserved (On-demand Beacon)"); @@ -1119,7 +1365,12 @@ static void print_capabilities(const uint8_t type, uint8_t len, const uint8_t *d CAPA(3, "reserved (Wave Indication)"); CAPA(4, "PSMP Capability"); CAPA(5, "reserved (Service Interval Granularity)"); - CAPA(6, "S-PSMP Capability"); + + case 6: + s_psmp_support = true; + printf(" S-PSMP Capability"); + break; + CAPA(7, "Event"); CAPA(8, "Diagnostics"); CAPA(9, "Multicast Diagnostics"); @@ -1154,23 +1405,82 @@ static void print_capabilities(const uint8_t type, uint8_t len, const uint8_t *d CAPA(38, "TDLS Prohibited"); CAPA(39, "TDLS Channel Switching Prohibited"); CAPA(40, "Reject Unadmitted Frame"); + + ADD_BIT_VAL(41, s_psmp_support, si_duration, 1); + ADD_BIT_VAL(42, s_psmp_support, si_duration, 2); + ADD_BIT_VAL(43, s_psmp_support, si_duration, 4); + CAPA(44, "Identifier Location"); CAPA(45, "U-APSD Coexistence"); CAPA(46, "WNM-Notification"); CAPA(47, "Reserved"); CAPA(48, "UTF-8 SSID"); + CAPA(49, "QMFActivated"); + CAPA(50, "QMFReconfigurationActivated"); + CAPA(51, "Robust AV Streaming"); + CAPA(52, "Advanced GCR"); + CAPA(53, "Mesh GCR"); + CAPA(54, "SCS"); + CAPA(55, "QLoad Report"); + CAPA(56, "Alternate EDCA"); + CAPA(57, "Unprotected TXOP Negotiation"); + CAPA(58, "Protected TXOP egotiation"); + CAPA(59, "Reserved"); + CAPA(60, "Protected QLoad Report"); + CAPA(61, "TDLS Wider Bandwidth"); + CAPA(62, "Operating Mode Notification"); + + ADD_BIT_VAL(63, is_vht_cap, max_amsdu, 1); + ADD_BIT_VAL(64, is_vht_cap, max_amsdu, 2); + + CAPA(65, "Channel Schedule Management"); + CAPA(66, "Geodatabase Inband Enabling Signal"); + CAPA(67, "Network Channel Control"); + CAPA(68, "White Space Map"); + CAPA(69, "Channel Availability Query"); + CAPA(70, "FTM Responder"); + CAPA(71, "FTM Initiator"); + CAPA(72, "Reserved"); + CAPA(73, "Extended Spectrum Management Capable"); + CAPA(74, "Reserved"); default: printf(" %d", bit); break; } +#undef ADD_BIT_VAL #undef CAPA } } + if (s_psmp_support) + printf("\n\t\t * Service Interval Granularity is %d ms", + (si_duration + 1) * 5); + + if (is_vht_cap) { + printf("\n\t\t * Max Number Of MSDUs In A-MSDU is "); + switch (max_amsdu) { + case 0: + printf("unlimited"); + break; + case 1: + printf("32"); + break; + case 2: + printf("16"); + break; + case 3: + printf("8"); + break; + default: + break; + } + } + printf("\n"); } -static void print_tim(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_tim(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) { printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x " "Bitmap[0] 0x%x", @@ -1180,20 +1490,23 @@ static void print_tim(const uint8_t type, uint8_t len, const uint8_t *data) printf("\n"); } -static void print_ibssatim(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_ibssatim(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) { - printf(" %d TUs", (data[1] << 8) + data[0]); + printf(" %d TUs\n", (data[1] << 8) + data[0]); } -static void print_vht_capa(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_vht_capa(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) { printf("\n"); - print_vht_info(data[0] | (data[1] << 8) | - (data[2] << 16) | (data[3] << 24), + print_vht_info((__u32) data[0] | ((__u32)data[1] << 8) | + ((__u32)data[2] << 16) | ((__u32)data[3] << 24), data + 4); } -static void print_vht_oper(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_vht_oper(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) { const char *chandwidths[] = { [0] = "20 or 40 MHz", @@ -1210,7 +1523,92 @@ static void print_vht_oper(const uint8_t type, uint8_t len, const uint8_t *data) printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data[4], data[3]); } -static void print_obss_scan_params(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_supp_op_classes(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) +{ + uint8_t *p = (uint8_t*) data; + const uint8_t *next_data = p + len; + int zero_delimiter = 0; + int one_hundred_thirty_delimiter = 0; + + printf("\n"); + printf("\t\t * current operating class: %d\n", *p); + while (++p < next_data) { + if (*p == 130) { + one_hundred_thirty_delimiter = 1; + break; + } + if (*p == 0) { + zero_delimiter = 0; + break; + } + printf("\t\t * operating class: %d\n", *p); + } + if (one_hundred_thirty_delimiter) + while (++p < next_data) { + printf("\t\t * current operating class extension: %d\n", *p); + } + if (zero_delimiter) + while (++p < next_data - 1) { + printf("\t\t * operating class tuple: %d %d\n", p[0], p[1]); + if (*p == 0) + break; + } +} + +static void print_measurement_pilot_tx(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) +{ + uint8_t *p, len_remaining; + + printf("\n"); + printf("\t\t * interval: %d TUs\n", data[0]); + + if (len <= 1) + return; + + p = (uint8_t *) data + 1; + len_remaining = len - 1; + + while (len_remaining >=5) { + uint8_t subelement_id = *p, len, *end; + + p++; + len = *p; + p++; + end = p + len; + + len_remaining -= 2; + + /* 802.11-2016 only allows vendor specific elements */ + if (subelement_id != 221) { + printf("\t\t * <Invalid subelement ID %d>\n", subelement_id); + return; + } + + if (len < 3 || len > len_remaining) { + printf(" <Parse error, element too short>\n"); + return; + } + + printf("\t\t * vendor specific: OUI %.2x:%.2x:%.2x, data:", + p[0], p[1], p[2]); + /* add only two here and use ++p in while loop */ + p += 2; + + while (++p < end) + printf(" %.2x", *p); + printf("\n"); + + len_remaining -= len; + } +} + +static void print_obss_scan_params(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) { printf("\n"); printf("\t\t * passive dwell: %d TUs\n", (data[1] << 8) | data[0]); @@ -1223,7 +1621,9 @@ static void print_obss_scan_params(const uint8_t type, uint8_t len, const uint8_ ((data[13] << 8) | data[12]) / 100, ((data[13] << 8) | data[12]) % 100); } -static void print_secchan_offs(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_secchan_offs(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) { if (data[0] < ARRAY_SIZE(ht_secondary_offset)) printf(" %s (%d)\n", ht_secondary_offset[data[0]], data[0]); @@ -1231,7 +1631,8 @@ static void print_secchan_offs(const uint8_t type, uint8_t len, const uint8_t *d printf(" %d\n", data[0]); } -static void print_bss_load(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_bss_load(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) { printf("\n"); printf("\t\t * station count: %d\n", (data[1] << 8) | data[0]); @@ -1239,7 +1640,9 @@ static void print_bss_load(const uint8_t type, uint8_t len, const uint8_t *data) printf("\t\t * available admission capacity: %d [*32us]\n", (data[4] << 8) | data[3]); } -static void print_mesh_conf(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_mesh_conf(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) { printf("\n"); printf("\t\t * Active Path Selection Protocol ID: %d\n", data[0]); @@ -1272,13 +1675,15 @@ static void print_mesh_conf(const uint8_t type, uint8_t len, const uint8_t *data struct ie_print { const char *name; - void (*print)(const uint8_t type, uint8_t len, const uint8_t *data); + void (*print)(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer); uint8_t minlen, maxlen; uint8_t flags; }; -static void print_ie(const struct ie_print *p, const uint8_t type, - uint8_t len, const uint8_t *data) +static void print_ie(const struct ie_print *p, const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) { int i; @@ -1299,7 +1704,7 @@ static void print_ie(const struct ie_print *p, const uint8_t type, return; } - p->print(type, len, data); + p->print(type, len, data, ie_buffer); } #define PRINT_IGN { \ @@ -1322,6 +1727,9 @@ static const struct ie_print ieprinters[] = { [42] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), }, [45] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), }, [47] = { "ERP D4.0", print_erp, 1, 255, BIT(PRINT_SCAN), }, + [51] = { "AP Channel Report", print_ap_channel_report, 1, 255, BIT(PRINT_SCAN), }, + [59] = { "Supported operating classes", print_supp_op_classes, 1, 255, BIT(PRINT_SCAN), }, + [66] = { "Measurement Pilot Transmission", print_measurement_pilot_tx, 1, 255, BIT(PRINT_SCAN), }, [74] = { "Overlapping BSS scan params", print_obss_scan_params, 14, 255, BIT(PRINT_SCAN), }, [61] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), }, [62] = { "Secondary Channel Offset", print_secchan_offs, 1, 1, BIT(PRINT_SCAN), }, @@ -1329,20 +1737,25 @@ static const struct ie_print ieprinters[] = { [192] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), }, [48] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), }, [50] = { "Extended supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), }, + [70] = { "RM enabled capabilities", print_rm_enabled_capabilities, 5, 5, BIT(PRINT_SCAN), }, [113] = { "MESH Configuration", print_mesh_conf, 7, 7, BIT(PRINT_SCAN), }, [114] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), }, [127] = { "Extended capabilities", print_capabilities, 0, 255, BIT(PRINT_SCAN), }, [107] = { "802.11u Interworking", print_interworking, 0, 255, BIT(PRINT_SCAN), }, [108] = { "802.11u Advertisement", print_11u_advert, 0, 255, BIT(PRINT_SCAN), }, - [111] = { "802.11u Roaming Consortium", print_11u_rcon, 0, 255, BIT(PRINT_SCAN), }, + [111] = { "802.11u Roaming Consortium", print_11u_rcon, 2, 255, BIT(PRINT_SCAN), }, + [195] = { "Transmit Power Envelope", print_tx_power_envelope, 2, 5, BIT(PRINT_SCAN), }, }; -static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) { print_rsn_ie("TKIP", "IEEE 802.1X", len, data); } -static void print_wifi_osen(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_wifi_osen(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) { print_osen_ie("OSEN", "OSEN", len, data); } @@ -1389,7 +1802,8 @@ static bool print_wifi_wmm_param(const uint8_t *data, uint8_t len) return false; } -static void print_wifi_wmm(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_wifi_wmm(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) { int i; @@ -1431,7 +1845,8 @@ static const char * wifi_wps_dev_passwd_id(uint16_t id) } } -static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data) +static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) { bool first = true; __u16 subtype, sublen; @@ -1439,12 +1854,17 @@ static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data) while (len >= 4) { subtype = (data[0] << 8) + data[1]; sublen = (data[2] << 8) + data[3]; - if (sublen > len) + if (sublen > len - 4) break; switch (subtype) { case 0x104a: tab_on_first(&first); + if (sublen < 1) { + printf("\t * Version: (invalid " + "length %d)\n", sublen); + break; + } printf("\t * Version: %d.%d\n", data[4] >> 4, data[4] & 0xF); break; case 0x1011: @@ -1455,8 +1875,8 @@ static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data) uint16_t id; tab_on_first(&first); if (sublen != 2) { - printf("\t * Device Password ID: (invalid " - "length %d)\n", sublen); + printf("\t * Device Password ID: (invalid length %d)\n", + sublen); break; } id = data[4] << 8 | data[5]; @@ -1477,20 +1897,41 @@ static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data) printf("\t * Model Number: %.*s\n", sublen, data + 4); break; case 0x103b: { - __u8 val = data[4]; + __u8 val; + + if (sublen < 1) { + printf("\t * Response Type: (invalid length %d)\n", + sublen); + break; + } + val = data[4]; tab_on_first(&first); printf("\t * Response Type: %d%s\n", val, val == 3 ? " (AP)" : ""); break; } case 0x103c: { - __u8 val = data[4]; + __u8 val; + + if (sublen < 1) { + printf("\t * RF Bands: (invalid length %d)\n", + sublen); + break; + } + val = data[4]; tab_on_first(&first); printf("\t * RF Bands: 0x%x\n", val); break; } case 0x1041: { - __u8 val = data[4]; + __u8 val; + + if (sublen < 1) { + printf("\t * Selected Registrar: (invalid length %d)\n", + sublen); + break; + } + val = data[4]; tab_on_first(&first); printf("\t * Selected Registrar: 0x%x\n", val); break; @@ -1500,7 +1941,14 @@ static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data) printf("\t * Serial Number: %.*s\n", sublen, data + 4); break; case 0x1044: { - __u8 val = data[4]; + __u8 val; + + if (sublen < 1) { + printf("\t * Wi-Fi Protected Setup State: (invalid length %d)\n", + sublen); + break; + } + val = data[4]; tab_on_first(&first); printf("\t * Wi-Fi Protected Setup State: %d%s%s\n", val, @@ -1522,11 +1970,26 @@ static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data) data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19]); break; + case 0x1049: + tab_on_first(&first); + if (sublen == 6 && + data[4] == 0x00 && + data[5] == 0x37 && + data[6] == 0x2a && + data[7] == 0x00 && + data[8] == 0x01) { + uint8_t v2 = data[9]; + printf("\t * Version2: %d.%d\n", v2 >> 4, v2 & 0xf); + } else { + printf("\t * Unknown vendor extension. len=%u\n", + sublen); + } + break; case 0x1054: { tab_on_first(&first); if (sublen != 8) { - printf("\t * Primary Device Type: (invalid " - "length %d)\n", sublen); + printf("\t * Primary Device Type: (invalid length %d)\n", + sublen); break; } printf("\t * Primary Device Type: " @@ -1537,15 +2000,29 @@ static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data) break; } case 0x1057: { - __u8 val = data[4]; + __u8 val; tab_on_first(&first); + if (sublen < 1) { + printf("\t * AP setup locked: (invalid length %d)\n", + sublen); + break; + } + val = data[4]; printf("\t * AP setup locked: 0x%.2x\n", val); break; } case 0x1008: case 0x1053: { - __u16 meth = (data[4] << 8) + data[5]; - bool comma = false; + __u16 meth; + bool comma; + + if (sublen < 2) { + printf("\t * Config methods: (invalid length %d)\n", + sublen); + break; + } + meth = (data[4] << 8) + data[5]; + comma = false; tab_on_first(&first); printf("\t * %sConfig methods:", subtype == 0x1053 ? "Selected Registrar ": ""); @@ -1607,7 +2084,9 @@ static const struct ie_print wifiprinters[] = { [4] = { "WPS", print_wifi_wps, 0, 255, BIT(PRINT_SCAN), }, }; -static inline void print_p2p(const uint8_t type, uint8_t len, const uint8_t *data) +static inline void print_p2p(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) { bool first = true; __u8 subtype; @@ -1635,7 +2114,7 @@ static inline void print_p2p(const uint8_t type, uint8_t len, const uint8_t *dat printf("\t * malformed device info\n"); break; } - /* fall through for now */ + /* fall through */ case 0x00: /* status */ case 0x01: /* minor reason */ case 0x03: /* device ID */ @@ -1655,7 +2134,7 @@ static inline void print_p2p(const uint8_t type, uint8_t len, const uint8_t *dat case 0x12: /* invitation flags */ case 0xdd: /* vendor specific */ default: { - const __u8 *subdata = data + 4; + const __u8 *subdata = data + 3; __u16 tmplen = sublen; tab_on_first(&first); @@ -1687,7 +2166,9 @@ static inline void print_p2p(const uint8_t type, uint8_t len, const uint8_t *dat } } -static inline void print_hs20_ind(const uint8_t type, uint8_t len, const uint8_t *data) +static inline void print_hs20_ind(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) { /* I can't find the spec for this...just going off what wireshark uses. */ printf("\n"); @@ -1697,10 +2178,39 @@ static inline void print_hs20_ind(const uint8_t type, uint8_t len, const uint8_t printf("\t\tUnexpected length: %i\n", len); } +static void print_wifi_owe_tarns(const uint8_t type, uint8_t len, + const uint8_t *data, + const struct print_ies_data *ie_buffer) +{ + char mac_addr[20]; + int ssid_len; + + printf("\n"); + if (len < 7) + return; + + mac_addr_n2a(mac_addr, data); + printf("\t\tBSSID: %s\n", mac_addr); + + ssid_len = data[6]; + if (ssid_len > len - 7) + return; + printf("\t\tSSID: "); + print_ssid_escaped(ssid_len, data + 7); + printf("\n"); + + /* optional elements */ + if (len >= ssid_len + 9) { + printf("\t\tBand Info: %u\n", data[ssid_len + 7]); + printf("\t\tChannel Info: %u\n", data[ssid_len + 8]); + } +} + static const struct ie_print wfa_printers[] = { [9] = { "P2P", print_p2p, 2, 255, BIT(PRINT_SCAN), }, [16] = { "HotSpot 2.0 Indication", print_hs20_ind, 1, 255, BIT(PRINT_SCAN), }, [18] = { "HotSpot 2.0 OSEN", print_wifi_osen, 1, 255, BIT(PRINT_SCAN), }, + [28] = { "OWE Transition Mode", print_wifi_owe_tarns, 7, 255, BIT(PRINT_SCAN), }, }; static void print_vendor(unsigned char len, unsigned char *data, @@ -1720,7 +2230,9 @@ static void print_vendor(unsigned char len, unsigned char *data, if (data[3] < ARRAY_SIZE(wifiprinters) && wifiprinters[data[3]].name && wifiprinters[data[3]].flags & BIT(ptype)) { - print_ie(&wifiprinters[data[3]], data[3], len - 4, data + 4); + print_ie(&wifiprinters[data[3]], + data[3], len - 4, data + 4, + NULL); return; } if (!unknown) @@ -1736,7 +2248,9 @@ static void print_vendor(unsigned char len, unsigned char *data, if (data[3] < ARRAY_SIZE(wfa_printers) && wfa_printers[data[3]].name && wfa_printers[data[3]].flags & BIT(ptype)) { - print_ie(&wfa_printers[data[3]], data[3], len - 4, data + 4); + print_ie(&wfa_printers[data[3]], + data[3], len - 4, data + 4, + NULL); return; } if (!unknown) @@ -1758,16 +2272,64 @@ static void print_vendor(unsigned char len, unsigned char *data, printf("\n"); } +static void print_he_capa(const uint8_t type, uint8_t len, const uint8_t *data, + const struct print_ies_data *ie_buffer) +{ + printf("\n"); + print_he_capability(data, len); +} + +static const struct ie_print ext_printers[] = { + [35] = { "HE capabilities", print_he_capa, 21, 54, BIT(PRINT_SCAN), }, +}; + +static void print_extension(unsigned char len, unsigned char *ie, + bool unknown, enum print_ie_type ptype) +{ + unsigned char tag; + + if (len < 1) { + printf("\tExtension IE: <empty>\n"); + return; + } + + tag = ie[0]; + if (tag < ARRAY_SIZE(ext_printers) && ext_printers[tag].name && + ext_printers[tag].flags & BIT(ptype)) { + print_ie(&ext_printers[tag], tag, len - 1, ie + 1, NULL); + return; + } + + if (unknown) { + int i; + + printf("\tUnknown Extension ID (%d):", ie[0]); + for (i = 1; i < len; i++) + printf(" %.2x", ie[i]); + printf("\n"); + } +} + void print_ies(unsigned char *ie, int ielen, bool unknown, enum print_ie_type ptype) { - while (ielen >= 2 && ielen >= ie[1]) { + struct print_ies_data ie_buffer = { + .ie = ie, + .ielen = ielen }; + + if (ie == NULL || ielen < 0) + return; + + while (ielen >= 2 && ielen - 2 >= ie[1]) { if (ie[0] < ARRAY_SIZE(ieprinters) && ieprinters[ie[0]].name && ieprinters[ie[0]].flags & BIT(ptype)) { - print_ie(&ieprinters[ie[0]], ie[0], ie[1], ie + 2); + print_ie(&ieprinters[ie[0]], + ie[0], ie[1], ie + 2, &ie_buffer); } else if (ie[0] == 221 /* vendor */) { print_vendor(ie[1], ie + 2, unknown, ptype); + } else if (ie[0] == 255 /* extension */) { + print_extension(ie[1], ie + 2, unknown, ptype); } else if (unknown) { int i; @@ -1911,6 +2473,12 @@ static int print_bss_handler(struct nl_msg *msg, void *arg) } printf("\n"); + if (bss[NL80211_BSS_LAST_SEEN_BOOTTIME]) { + unsigned long long bt; + bt = (unsigned long long)nla_get_u64(bss[NL80211_BSS_LAST_SEEN_BOOTTIME]); + printf("\tlast seen: %llu.%.3llus [boottime]\n", bt/1000000000, (bt%1000000000)/1000000); + } + if (bss[NL80211_BSS_TSF]) { unsigned long long tsf; tsf = (unsigned long long)nla_get_u64(bss[NL80211_BSS_TSF]); @@ -1950,11 +2518,16 @@ static int print_bss_handler(struct nl_msg *msg, void *arg) } if (bss[NL80211_BSS_INFORMATION_ELEMENTS] && show--) { - if (bss[NL80211_BSS_BEACON_IES]) + struct nlattr *ies = bss[NL80211_BSS_INFORMATION_ELEMENTS]; + struct nlattr *bcnies = bss[NL80211_BSS_BEACON_IES]; + + if (bss[NL80211_BSS_PRESP_DATA] || + (bcnies && (nla_len(ies) != nla_len(bcnies) || + memcmp(nla_data(ies), nla_data(bcnies), + nla_len(ies))))) printf("\tInformation elements from Probe Response " "frame:\n"); - print_ies(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]), - nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), + print_ies(nla_data(ies), nla_len(ies), params->unknown, params->type); } if (bss[NL80211_BSS_BEACON_IES] && show--) { @@ -1970,7 +2543,6 @@ static int print_bss_handler(struct nl_msg *msg, void *arg) static struct scan_params scan_params; static int handle_scan_dump(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -1987,13 +2559,11 @@ static int handle_scan_dump(struct nl80211_state *state, scan_params.type = PRINT_SCAN; - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_bss_handler, - &scan_params); + register_handler(print_bss_handler, &scan_params); return 0; } static int handle_scan_combined(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -2010,6 +2580,7 @@ static int handle_scan_combined(struct nl80211_state *state, NL80211_CMD_SCAN_ABORTED, }; int trig_argc, dump_argc, err; + int i; if (argc >= 3 && !strcmp(argv[2], "-u")) { dump_argc = 4; @@ -2027,7 +2598,7 @@ static int handle_scan_combined(struct nl80211_state *state, trig_argv[0] = argv[0]; trig_argv[1] = "scan"; trig_argv[2] = "trigger"; - int i; + for (i = 0; i < argc - 2 - (dump_argc - 3); i++) trig_argv[i + 3] = argv[i + 2 + (dump_argc - 3)]; err = handle_cmd(state, id, trig_argc, trig_argv); @@ -2068,7 +2639,7 @@ static int handle_scan_combined(struct nl80211_state *state, dump_argv[0] = argv[0]; return handle_cmd(state, id, dump_argc, dump_argv); } -TOPLEVEL(scan, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", 0, 0, +TOPLEVEL(scan, "[-u] [freq <freq>*] [duration <dur>] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force,duration-mandatory] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", 0, 0, CIB_NETDEV, handle_scan_combined, "Scan on the given frequencies and probe for the given SSIDs\n" "(or wildcard if not given) unless passive scanning is requested.\n" @@ -2078,20 +2649,32 @@ COMMAND(scan, dump, "[-u]", NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump, "Dump the current scan results. If -u is specified, print unknown\n" "data in scan results."); -COMMAND(scan, trigger, "[freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", +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]", NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan, "Trigger a scan on the given frequencies with probing for the given\n" - "SSIDs (or wildcard if not given) unless passive scanning is requested."); + "SSIDs (or wildcard if not given) unless passive scanning is requested.\n" + "Duration(in TUs), if specified, will be used to set dwell times.\n"); + +static int handle_scan_abort(struct nl80211_state *state, + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + return 0; +} +COMMAND(scan, abort, "", + NL80211_CMD_ABORT_SCAN, 0, CIB_NETDEV, handle_scan_abort, + "Abort ongoing scan"); static int handle_start_sched_scan(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, + struct nl_msg *msg, int argc, char **argv, enum id_input id) { return parse_sched_scan(msg, &argc, &argv); } -static int handle_stop_sched_scan(struct nl80211_state *state, struct nl_cb *cb, +static int handle_stop_sched_scan(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { diff --git a/sha256.c b/sha256.c new file mode 100644 index 0000000..4a43df8 --- /dev/null +++ b/sha256.c @@ -0,0 +1,205 @@ +#include "sha256.h" + +/** + * SHA256 Hashing + * @addr: pointers to the data area + * @len: Lengths of the data block + * @res: Buffer for the digest + * Returns: 0 on success, -1 of failure + */ +int sha256(const unsigned char *addr, const size_t len, + unsigned char *res) +{ + struct sha256_state ctx; + + sha256_init(&ctx); + + if (sha256_process(&ctx, addr, len) || sha256_done(&ctx, res)) + return -1; + + return 0; +} + +/** ===== start - public domain SHA256 implementation ===== */ + +/** This is based on SHA256 implementation in LibTomCrypt that was released into + * public domain by Tom St Denis. + */ + +/** the K array */ +static const unsigned long K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, + 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, + 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, + 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, + 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, + 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, + 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, + 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, + 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + + +/** Various logical functions */ +#define RORc(x, y) \ +(((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \ +((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) +#define Ch(x, y, z) (z ^ (x & (y ^ z))) +#define Maj(x, y, z) (((x | y) & z) | (x & y)) +#define S(x, n) RORc((x), (n)) +#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +/* compress 512-bits */ +static int sha256_compress(struct sha256_state *md, const unsigned char *buf) +{ + __u32 S[8], W[64], t0, t1; + __u32 t; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) + S[i] = md->state[i]; + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) + W[i] = LOAD32B(buf + (4 * i)); + + /* fill W[16..63] */ + for (i = 16; i < 64; i++) + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + + /* Compress */ +#define RND(a, b, c, d, e, f, g, h, i) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + for (i = 0; i < 64; ++i) { + RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i); + t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; + S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; + } + + /* feedback */ + for (i = 0; i < 8; i++) + md->state[i] = md->state[i] + S[i]; + + return 0; +} + + +/* Initialize the hash state */ +void sha256_init(struct sha256_state *md) +{ + md->curlen = 0; + md->length = 0; + md->state[0] = 0x6A09E667UL; + md->state[1] = 0xBB67AE85UL; + md->state[2] = 0x3C6EF372UL; + md->state[3] = 0xA54FF53AUL; + md->state[4] = 0x510E527FUL; + md->state[5] = 0x9B05688CUL; + md->state[6] = 0x1F83D9ABUL; + md->state[7] = 0x5BE0CD19UL; +} + +/** + * Process a block of memory though the hash + * @param md The hash state + * @param in The data to hash + * @param inlen The length of the data (octets) + * @return CRYPT_OK if successful +*/ +int sha256_process(struct sha256_state *md, const unsigned char *in, + unsigned long inlen) +{ + unsigned long n; + + if (md->curlen >= sizeof(md->buf)) + return -1; + + while (inlen > 0) { + if (md->curlen == 0 && inlen >= SHA256_BLOCK_SIZE) { + if (sha256_compress(md, (unsigned char *) in) < 0) + return -1; + md->length += SHA256_BLOCK_SIZE * 8; + in += SHA256_BLOCK_SIZE; + inlen -= SHA256_BLOCK_SIZE; + } else { + n = MIN(inlen, (SHA256_BLOCK_SIZE - md->curlen)); + memcpy(md->buf + md->curlen, in, n); + md->curlen += n; + in += n; + inlen -= n; + if (md->curlen == SHA256_BLOCK_SIZE) { + if (sha256_compress(md, md->buf) < 0) + return -1; + md->length += 8 * SHA256_BLOCK_SIZE; + md->curlen = 0; + } + } + } + + return 0; +} + + +/** + * Terminate the hash to get the digest + * @param md The hash state + * @param out [out] The destination of the hash (32 bytes) + * @return CRYPT_OK if successful +*/ +int sha256_done(struct sha256_state *md, unsigned char *out) +{ + int i; + + if (md->curlen >= sizeof(md->buf)) + return -1; + + /* increase the length of the message */ + md->length += md->curlen * 8; + + /* append the '1' bit */ + md->buf[md->curlen++] = (unsigned char) 0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->curlen > 56) { + while (md->curlen < SHA256_BLOCK_SIZE) + md->buf[md->curlen++] = (unsigned char) 0; + + sha256_compress(md, md->buf); + md->curlen = 0; + } + + /* pad up to 56 bytes of zeroes */ + while (md->curlen < 56) + md->buf[md->curlen++] = (unsigned char) 0; + + /* store length */ + STORE64B(md->buf + 56, md->length); + sha256_compress(md, md->buf); + + /* copy output */ + for (i = 0; i < 8; i++) + STORE32B(out + (4 * i), md->state[i]); + + return 0; +} + +/* ===== end - public domain SHA256 implementation ===== */ diff --git a/sha256.h b/sha256.h new file mode 100644 index 0000000..d3eb3c0 --- /dev/null +++ b/sha256.h @@ -0,0 +1,61 @@ +#ifndef SHA256 +#define SHA256 + +#include "iw.h" +#define SHA256_BLOCK_SIZE 64 + +#define LOAD32B(addr) \ + ((__u32)((addr)[0] << 24) | ((addr)[1] << 16) | \ + ((addr)[2] << 8) | (addr)[3]) + +#define STORE64B(addr, data) \ +do { (addr)[0] = (__u8)((data) >> 56); (addr)[1] = (__u8)((data) >> 48); \ + (addr)[2] = (__u8)((data) >> 40); (addr)[3] = (__u8)((data) >> 32); \ + (addr)[4] = (__u8)((data) >> 24); (addr)[5] = (__u8)((data) >> 16); \ + (addr)[6] = (__u8)((data) >> 8); (addr)[7] = (__u8)((data) & 0xff); \ + } while (0) + +#define STORE32B(addr, data) \ +do { (addr)[0] = (__u8)(((data) >> 24) & 0xff); \ + (addr)[1] = (__u8)(((data) >> 16) & 0xff); \ + (addr)[2] = (__u8)(((data) >> 8) & 0xff); \ + (addr)[3] = (__u8)((data) & 0xff); } while (0) + +struct sha256_state { + __u64 length; + __u32 state[8], curlen; + __u8 buf[SHA256_BLOCK_SIZE]; +}; + +/** + * SHA256 Hashing + * @addr: pointers to the data area + * @len: Lengths of the data block + * @res: Buffer for the digest + * Returns: 0 on success, -1 of failure + */ +int sha256(const unsigned char *addr, const size_t len, + unsigned char *res); + +/* Initialize the hash state */ +void sha256_init(struct sha256_state *md); + +/** + * Process a block of memory though the hash + * @param md The hash state + * @param in The data to hash + * @param inlen The length of the data (octets) + * @return CRYPT_OK if successful +*/ +int sha256_process(struct sha256_state *md, const unsigned char *in, + unsigned long inlen); + +/** + * Terminate the hash to get the digest + * @param md The hash state + * @param out [out] The destination of the hash (32 bytes) + * @return CRYPT_OK if successful +*/ +int sha256_done(struct sha256_state *md, unsigned char *out); + +#endif @@ -7,6 +7,7 @@ #include <netlink/genl/ctrl.h> #include <netlink/msg.h> #include <netlink/attr.h> +#include <time.h> #include "nl80211.h" #include "iw.h" @@ -43,6 +44,158 @@ static void print_power_mode(struct nlattr *a) } } +int parse_txq_stats(char *buf, int buflen, struct nlattr *tid_stats_attr, int header, + int tid, const char *indent) +{ + struct nlattr *txqstats_info[NL80211_TXQ_STATS_MAX + 1], *txqinfo; + static struct nla_policy txqstats_policy[NL80211_TXQ_STATS_MAX + 1] = { + [NL80211_TXQ_STATS_BACKLOG_BYTES] = { .type = NLA_U32 }, + [NL80211_TXQ_STATS_BACKLOG_PACKETS] = { .type = NLA_U32 }, + [NL80211_TXQ_STATS_FLOWS] = { .type = NLA_U32 }, + [NL80211_TXQ_STATS_DROPS] = { .type = NLA_U32 }, + [NL80211_TXQ_STATS_ECN_MARKS] = { .type = NLA_U32 }, + [NL80211_TXQ_STATS_OVERLIMIT] = { .type = NLA_U32 }, + [NL80211_TXQ_STATS_COLLISIONS] = { .type = NLA_U32 }, + [NL80211_TXQ_STATS_TX_BYTES] = { .type = NLA_U32 }, + [NL80211_TXQ_STATS_TX_PACKETS] = { .type = NLA_U32 }, + }; + char *pos = buf; + if (nla_parse_nested(txqstats_info, NL80211_TXQ_STATS_MAX, tid_stats_attr, + txqstats_policy)) { + printf("failed to parse nested TXQ stats attributes!"); + return 0; + } + + if (header) + pos += snprintf(buf, buflen, "\n%s\t%s\tqsz-byt\t" + "qsz-pkt\tflows\tdrops\tmarks\toverlmt\t" + "hashcol\ttx-bytes\ttx-packets", indent, + tid >= 0 ? "TID" : ""); + + pos += snprintf(pos, buflen - (pos - buf), "\n%s\t", indent); + if (tid >= 0) + pos += snprintf(pos, buflen - (pos - buf), "%d", tid); + +#define PRINT_STAT(key, spacer) do { \ + txqinfo = txqstats_info[NL80211_TXQ_STATS_ ## key]; \ + pos += snprintf(pos, buflen - (pos - buf), spacer); \ + if (txqinfo) \ + pos += snprintf(pos, buflen - (pos - buf), "%u", \ + nla_get_u32(txqinfo)); \ + } while (0) + + + PRINT_STAT(BACKLOG_BYTES, "\t"); + PRINT_STAT(BACKLOG_PACKETS, "\t"); + PRINT_STAT(FLOWS, "\t"); + PRINT_STAT(DROPS, "\t"); + PRINT_STAT(ECN_MARKS, "\t"); + PRINT_STAT(OVERLIMIT, "\t"); + PRINT_STAT(COLLISIONS, "\t"); + PRINT_STAT(TX_BYTES, "\t"); + PRINT_STAT(TX_PACKETS, "\t\t"); + +#undef PRINT_STAT + + return pos - buf; + +} + +static void parse_tid_stats(struct nlattr *tid_stats_attr) +{ + struct nlattr *stats_info[NL80211_TID_STATS_MAX + 1], *tidattr, *info; + static struct nla_policy stats_policy[NL80211_TID_STATS_MAX + 1] = { + [NL80211_TID_STATS_RX_MSDU] = { .type = NLA_U64 }, + [NL80211_TID_STATS_TX_MSDU] = { .type = NLA_U64 }, + [NL80211_TID_STATS_TX_MSDU_RETRIES] = { .type = NLA_U64 }, + [NL80211_TID_STATS_TX_MSDU_FAILED] = { .type = NLA_U64 }, + [NL80211_TID_STATS_TXQ_STATS] = { .type = NLA_NESTED }, + }; + int rem, i = 0; + char txqbuf[2000] = {}, *pos = txqbuf; + int buflen = sizeof(txqbuf), foundtxq = 0; + + printf("\n\tMSDU:\n\t\tTID\trx\ttx\ttx retries\ttx failed"); + nla_for_each_nested(tidattr, tid_stats_attr, rem) { + if (nla_parse_nested(stats_info, NL80211_TID_STATS_MAX, + tidattr, stats_policy)) { + printf("failed to parse nested stats attributes!"); + return; + } + printf("\n\t\t%d", i); + info = stats_info[NL80211_TID_STATS_RX_MSDU]; + if (info) + printf("\t%llu", (unsigned long long)nla_get_u64(info)); + info = stats_info[NL80211_TID_STATS_TX_MSDU]; + if (info) + printf("\t%llu", (unsigned long long)nla_get_u64(info)); + info = stats_info[NL80211_TID_STATS_TX_MSDU_RETRIES]; + if (info) + printf("\t%llu", (unsigned long long)nla_get_u64(info)); + info = stats_info[NL80211_TID_STATS_TX_MSDU_FAILED]; + if (info) + printf("\t\t%llu", (unsigned long long)nla_get_u64(info)); + info = stats_info[NL80211_TID_STATS_TXQ_STATS]; + if (info) { + pos += parse_txq_stats(pos, buflen - (pos - txqbuf), info, !foundtxq, i, "\t"); + foundtxq = 1; + } + + i++; + } + + if (foundtxq) + printf("\n\tTXQs:%s", txqbuf); +} + +static void parse_bss_param(struct nlattr *bss_param_attr) +{ + struct nlattr *bss_param_info[NL80211_STA_BSS_PARAM_MAX + 1], *info; + static struct nla_policy bss_poilcy[NL80211_STA_BSS_PARAM_MAX + 1] = { + [NL80211_STA_BSS_PARAM_CTS_PROT] = { .type = NLA_FLAG }, + [NL80211_STA_BSS_PARAM_SHORT_PREAMBLE] = { .type = NLA_FLAG }, + [NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME] = { .type = NLA_FLAG }, + [NL80211_STA_BSS_PARAM_DTIM_PERIOD] = { .type = NLA_U8 }, + [NL80211_STA_BSS_PARAM_BEACON_INTERVAL] = { .type = NLA_U16 }, + }; + + if (nla_parse_nested(bss_param_info, NL80211_STA_BSS_PARAM_MAX, + bss_param_attr, bss_poilcy)) { + printf("failed to parse nested bss param attributes!"); + } + + info = bss_param_info[NL80211_STA_BSS_PARAM_DTIM_PERIOD]; + if (info) + printf("\n\tDTIM period:\t%u", nla_get_u8(info)); + info = bss_param_info[NL80211_STA_BSS_PARAM_BEACON_INTERVAL]; + if (info) + printf("\n\tbeacon interval:%u", nla_get_u16(info)); + info = bss_param_info[NL80211_STA_BSS_PARAM_CTS_PROT]; + if (info) { + printf("\n\tCTS protection:"); + if (nla_get_u16(info)) + printf("\tyes"); + else + printf("\tno"); + } + info = bss_param_info[NL80211_STA_BSS_PARAM_SHORT_PREAMBLE]; + if (info) { + printf("\n\tshort preamble:"); + if (nla_get_u16(info)) + printf("\tyes"); + else + printf("\tno"); + } + info = bss_param_info[NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME]; + if (info) { + printf("\n\tshort slot time:"); + if (nla_get_u16(info)) + printf("yes"); + else + printf("no"); + } +} + void parse_bitrate(struct nlattr *bitrate_attr, char *buf, int buflen) { int rate = 0; @@ -69,6 +222,8 @@ void parse_bitrate(struct nlattr *bitrate_attr, char *buf, int buflen) if (rate > 0) pos += snprintf(pos, buflen - (pos - buf), "%d.%d MBit/s", rate / 10, rate % 10); + else + pos += snprintf(pos, buflen - (pos - buf), "(unknown)"); if (rinfo[NL80211_RATE_INFO_MCS]) pos += snprintf(pos, buflen - (pos - buf), @@ -84,11 +239,40 @@ void parse_bitrate(struct nlattr *bitrate_attr, char *buf, int buflen) pos += snprintf(pos, buflen - (pos - buf), " 80P80MHz"); if (rinfo[NL80211_RATE_INFO_160_MHZ_WIDTH]) pos += snprintf(pos, buflen - (pos - buf), " 160MHz"); + if (rinfo[NL80211_RATE_INFO_320_MHZ_WIDTH]) + pos += snprintf(pos, buflen - (pos - buf), " 320MHz"); if (rinfo[NL80211_RATE_INFO_SHORT_GI]) pos += snprintf(pos, buflen - (pos - buf), " short GI"); if (rinfo[NL80211_RATE_INFO_VHT_NSS]) pos += snprintf(pos, buflen - (pos - buf), " VHT-NSS %d", nla_get_u8(rinfo[NL80211_RATE_INFO_VHT_NSS])); + if (rinfo[NL80211_RATE_INFO_HE_MCS]) + pos += snprintf(pos, buflen - (pos - buf), + " HE-MCS %d", nla_get_u8(rinfo[NL80211_RATE_INFO_HE_MCS])); + if (rinfo[NL80211_RATE_INFO_HE_NSS]) + pos += snprintf(pos, buflen - (pos - buf), + " HE-NSS %d", nla_get_u8(rinfo[NL80211_RATE_INFO_HE_NSS])); + if (rinfo[NL80211_RATE_INFO_HE_GI]) + pos += snprintf(pos, buflen - (pos - buf), + " HE-GI %d", nla_get_u8(rinfo[NL80211_RATE_INFO_HE_GI])); + if (rinfo[NL80211_RATE_INFO_HE_DCM]) + pos += snprintf(pos, buflen - (pos - buf), + " HE-DCM %d", nla_get_u8(rinfo[NL80211_RATE_INFO_HE_DCM])); + if (rinfo[NL80211_RATE_INFO_HE_RU_ALLOC]) + pos += snprintf(pos, buflen - (pos - buf), + " HE-RU-ALLOC %d", nla_get_u8(rinfo[NL80211_RATE_INFO_HE_RU_ALLOC])); + if (rinfo[NL80211_RATE_INFO_EHT_MCS]) + pos += snprintf(pos, buflen - (pos - buf), + " EHT-MCS %d", nla_get_u8(rinfo[NL80211_RATE_INFO_EHT_MCS])); + if (rinfo[NL80211_RATE_INFO_EHT_NSS]) + pos += snprintf(pos, buflen - (pos - buf), + " EHT-NSS %d", nla_get_u8(rinfo[NL80211_RATE_INFO_EHT_NSS])); + if (rinfo[NL80211_RATE_INFO_EHT_GI]) + pos += snprintf(pos, buflen - (pos - buf), + " EHT-GI %d", nla_get_u8(rinfo[NL80211_RATE_INFO_EHT_GI])); + if (rinfo[NL80211_RATE_INFO_EHT_RU_ALLOC]) + pos += snprintf(pos, buflen - (pos - buf), + " EHT-RU-ALLOC %d", nla_get_u8(rinfo[NL80211_RATE_INFO_EHT_RU_ALLOC])); } static char *get_chain_signal(struct nlattr *attr_list) @@ -129,8 +313,11 @@ static int print_sta_handler(struct nl_msg *msg, void *arg) [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 }, [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, + [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 }, + [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 }, [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_BEACON_RX] = { .type = NLA_U64}, [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, [NL80211_STA_INFO_T_OFFSET] = { .type = NLA_U64 }, [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED }, @@ -140,6 +327,8 @@ static int print_sta_handler(struct nl_msg *msg, void *arg) [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 }, [NL80211_STA_INFO_TX_RETRIES] = { .type = NLA_U32 }, [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 }, + [NL80211_STA_INFO_BEACON_LOSS] = { .type = NLA_U32}, + [NL80211_STA_INFO_RX_DROP_MISC] = { .type = NLA_U64}, [NL80211_STA_INFO_STA_FLAGS] = { .minlen = sizeof(struct nl80211_sta_flag_update) }, [NL80211_STA_INFO_LOCAL_PM] = { .type = NLA_U32}, @@ -147,8 +336,23 @@ static int print_sta_handler(struct nl_msg *msg, void *arg) [NL80211_STA_INFO_NONPEER_PM] = { .type = NLA_U32}, [NL80211_STA_INFO_CHAIN_SIGNAL] = { .type = NLA_NESTED }, [NL80211_STA_INFO_CHAIN_SIGNAL_AVG] = { .type = NLA_NESTED }, + [NL80211_STA_INFO_TID_STATS] = { .type = NLA_NESTED }, + [NL80211_STA_INFO_BSS_PARAM] = { .type = NLA_NESTED }, + [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 }, + [NL80211_STA_INFO_TX_DURATION] = { .type = NLA_U64 }, + [NL80211_STA_INFO_ACK_SIGNAL] = {.type = NLA_U8 }, + [NL80211_STA_INFO_ACK_SIGNAL_AVG] = { .type = NLA_U8 }, + [NL80211_STA_INFO_AIRTIME_LINK_METRIC] = { .type = NLA_U32 }, + [NL80211_STA_INFO_CONNECTED_TO_AS] = { .type = NLA_U8 }, + [NL80211_STA_INFO_CONNECTED_TO_GATE] = { .type = NLA_U8 }, }; char *chain; + struct timeval now; + unsigned long long now_ms; + + gettimeofday(&now, NULL); + now_ms = now.tv_sec * 1000ULL; + now_ms += (now.tv_usec / 1000); nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); @@ -177,15 +381,21 @@ static int print_sta_handler(struct nl_msg *msg, void *arg) if (sinfo[NL80211_STA_INFO_INACTIVE_TIME]) printf("\n\tinactive time:\t%u ms", nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME])); - if (sinfo[NL80211_STA_INFO_RX_BYTES]) + if (sinfo[NL80211_STA_INFO_RX_BYTES64]) + printf("\n\trx bytes:\t%llu", + (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_RX_BYTES64])); + else if (sinfo[NL80211_STA_INFO_RX_BYTES]) printf("\n\trx bytes:\t%u", - nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES])); + nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES])); if (sinfo[NL80211_STA_INFO_RX_PACKETS]) printf("\n\trx packets:\t%u", nla_get_u32(sinfo[NL80211_STA_INFO_RX_PACKETS])); - if (sinfo[NL80211_STA_INFO_TX_BYTES]) + if (sinfo[NL80211_STA_INFO_TX_BYTES64]) + printf("\n\ttx bytes:\t%llu", + (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_TX_BYTES64])); + else if (sinfo[NL80211_STA_INFO_TX_BYTES]) printf("\n\ttx bytes:\t%u", - nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES])); + nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES])); if (sinfo[NL80211_STA_INFO_TX_PACKETS]) printf("\n\ttx packets:\t%u", nla_get_u32(sinfo[NL80211_STA_INFO_TX_PACKETS])); @@ -195,6 +405,15 @@ static int print_sta_handler(struct nl_msg *msg, void *arg) if (sinfo[NL80211_STA_INFO_TX_FAILED]) printf("\n\ttx failed:\t%u", nla_get_u32(sinfo[NL80211_STA_INFO_TX_FAILED])); + if (sinfo[NL80211_STA_INFO_BEACON_LOSS]) + printf("\n\tbeacon loss:\t%u", + nla_get_u32(sinfo[NL80211_STA_INFO_BEACON_LOSS])); + if (sinfo[NL80211_STA_INFO_BEACON_RX]) + printf("\n\tbeacon rx:\t%llu", + (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_BEACON_RX])); + if (sinfo[NL80211_STA_INFO_RX_DROP_MISC]) + printf("\n\trx drop misc:\t%llu", + (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_RX_DROP_MISC])); chain = get_chain_signal(sinfo[NL80211_STA_INFO_CHAIN_SIGNAL]); if (sinfo[NL80211_STA_INFO_SIGNAL]) @@ -208,9 +427,12 @@ static int print_sta_handler(struct nl_msg *msg, void *arg) (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]), chain); + if (sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]) + printf("\n\tbeacon signal avg:\t%d dBm", + (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG])); if (sinfo[NL80211_STA_INFO_T_OFFSET]) - printf("\n\tToffset:\t%lld us", - (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_T_OFFSET])); + printf("\n\tToffset:\t%llu us", + (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_T_OFFSET])); if (sinfo[NL80211_STA_INFO_TX_BITRATE]) { char buf[100]; @@ -219,6 +441,10 @@ static int print_sta_handler(struct nl_msg *msg, void *arg) printf("\n\ttx bitrate:\t%s", buf); } + if (sinfo[NL80211_STA_INFO_TX_DURATION]) + printf("\n\ttx duration:\t%lld us", + (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_TX_DURATION])); + if (sinfo[NL80211_STA_INFO_RX_BITRATE]) { char buf[100]; @@ -226,6 +452,22 @@ static int print_sta_handler(struct nl_msg *msg, void *arg) printf("\n\trx bitrate:\t%s", buf); } + if (sinfo[NL80211_STA_INFO_RX_DURATION]) + printf("\n\trx duration:\t%lld us", + (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_RX_DURATION])); + + if (sinfo[NL80211_STA_INFO_ACK_SIGNAL]) + printf("\n\tlast ack signal:%d dBm", + (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_ACK_SIGNAL])); + + if (sinfo[NL80211_STA_INFO_ACK_SIGNAL_AVG]) + printf("\n\tavg ack signal:\t%d dBm", + (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_ACK_SIGNAL_AVG])); + + if (sinfo[NL80211_STA_INFO_AIRTIME_WEIGHT]) { + printf("\n\tairtime weight: %d", nla_get_u16(sinfo[NL80211_STA_INFO_AIRTIME_WEIGHT])); + } + if (sinfo[NL80211_STA_INFO_EXPECTED_THROUGHPUT]) { uint32_t thr; @@ -272,6 +514,18 @@ static int print_sta_handler(struct nl_msg *msg, void *arg) } printf("\n\tmesh plink:\t%s", state_name); } + if (sinfo[NL80211_STA_INFO_AIRTIME_LINK_METRIC]) + printf("\n\tmesh airtime link metric: %d", + nla_get_u32(sinfo[NL80211_STA_INFO_AIRTIME_LINK_METRIC])); + if (sinfo[NL80211_STA_INFO_CONNECTED_TO_GATE]) + printf("\n\tmesh connected to gate:\t%s", + nla_get_u8(sinfo[NL80211_STA_INFO_CONNECTED_TO_GATE]) ? + "yes" : "no"); + if (sinfo[NL80211_STA_INFO_CONNECTED_TO_AS]) + printf("\n\tmesh connected to auth server:\t%s", + nla_get_u8(sinfo[NL80211_STA_INFO_CONNECTED_TO_AS]) ? + "yes" : "no"); + if (sinfo[NL80211_STA_INFO_LOCAL_PM]) { printf("\n\tmesh local PS mode:\t"); print_power_mode(sinfo[NL80211_STA_INFO_LOCAL_PM]); @@ -305,6 +559,14 @@ static int print_sta_handler(struct nl_msg *msg, void *arg) printf("no"); } + if (sta_flags->mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) { + printf("\n\tassociated:\t"); + if (sta_flags->set & BIT(NL80211_STA_FLAG_ASSOCIATED)) + printf("yes"); + else + printf("no"); + } + if (sta_flags->mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { printf("\n\tpreamble:\t"); if (sta_flags->set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) @@ -338,16 +600,36 @@ static int print_sta_handler(struct nl_msg *msg, void *arg) } } + if (sinfo[NL80211_STA_INFO_TID_STATS] && arg != NULL && + !strcmp((char *)arg, "-v")) + parse_tid_stats(sinfo[NL80211_STA_INFO_TID_STATS]); + if (sinfo[NL80211_STA_INFO_BSS_PARAM]) + parse_bss_param(sinfo[NL80211_STA_INFO_BSS_PARAM]); if (sinfo[NL80211_STA_INFO_CONNECTED_TIME]) printf("\n\tconnected time:\t%u seconds", nla_get_u32(sinfo[NL80211_STA_INFO_CONNECTED_TIME])); + if (sinfo[NL80211_STA_INFO_ASSOC_AT_BOOTTIME]) { + unsigned long long bt; + struct timespec now_ts; + unsigned long long boot_ns; + unsigned long long assoc_at_ms; + + clock_gettime(CLOCK_BOOTTIME, &now_ts); + boot_ns = now_ts.tv_sec * 1000000000ULL; + boot_ns += now_ts.tv_nsec; + + bt = (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_ASSOC_AT_BOOTTIME]); + printf("\n\tassociated at [boottime]:\t%llu.%.3llus", + bt/1000000000, (bt%1000000000)/1000000); + assoc_at_ms = now_ms - ((boot_ns - bt) / 1000000); + printf("\n\tassociated at:\t%llu ms", assoc_at_ms); + } - printf("\n"); + printf("\n\tcurrent time:\t%llu ms\n", now_ms); return NL_SKIP; } static int handle_station_get(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -370,7 +652,7 @@ static int handle_station_get(struct nl80211_state *state, NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_sta_handler, NULL); + register_handler(print_sta_handler, NULL); return 0; nla_put_failure: @@ -379,13 +661,74 @@ static int handle_station_get(struct nl80211_state *state, COMMAND(station, get, "<MAC address>", NL80211_CMD_GET_STATION, 0, CIB_NETDEV, handle_station_get, "Get information for a specific station."); -COMMAND(station, del, "<MAC address>", - NL80211_CMD_DEL_STATION, 0, CIB_NETDEV, handle_station_get, - "Remove the given station entry (use with caution!)"); + +static int handle_station_del(struct nl80211_state *state, + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + char *end; + unsigned char mac_addr[ETH_ALEN]; + int subtype; + int reason_code; + + if (argc < 1) + return 1; + + if (mac_addr_a2n(mac_addr, argv[0])) { + fprintf(stderr, "invalid mac address\n"); + return 2; + } + + argc--; + argv++; + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); + + if (argc > 1 && strcmp(argv[0], "subtype") == 0) { + argv++; + argc--; + + subtype = strtod(argv[0], &end); + if (*end != '\0') + return 1; + + NLA_PUT_U8(msg, NL80211_ATTR_MGMT_SUBTYPE, subtype); + argv++; + argc--; + } + + if (argc > 1 && strcmp(argv[0], "reason-code") == 0) { + argv++; + argc--; + + reason_code = strtod(argv[0], &end); + if (*end != '\0') + return 1; + + NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code); + argv++; + argc--; + } + + if (argc) + return 1; + + register_handler(print_sta_handler, NULL); + + return 0; + nla_put_failure: + return -ENOBUFS; +} +COMMAND(station, del, "<MAC address> [subtype <subtype>] [reason-code <code>]", + NL80211_CMD_DEL_STATION, 0, CIB_NETDEV, handle_station_del, + "Remove the given station entry (use with caution!)\n" + "Example subtype values: 0xA (disassociation), 0xC (deauthentication)"); static const struct cmd *station_set_plink; static const struct cmd *station_set_vlan; static const struct cmd *station_set_mesh_power_mode; +static const struct cmd *station_set_airtime_weight; +static const struct cmd *station_set_txpwr; static const struct cmd *select_station_cmd(int argc, char **argv) { @@ -397,11 +740,14 @@ static const struct cmd *select_station_cmd(int argc, char **argv) return station_set_vlan; if (strcmp(argv[1], "mesh_power_mode") == 0) return station_set_mesh_power_mode; + if (strcmp(argv[1], "airtime_weight") == 0) + return station_set_airtime_weight; + if (strcmp(argv[1], "txpwr") == 0) + return station_set_txpwr; return NULL; } static int handle_station_set_plink(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -451,7 +797,6 @@ COMMAND_ALIAS(station, set, "<MAC address> plink_action <open|block>", select_station_cmd, station_set_plink); static int handle_station_set_vlan(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -499,7 +844,6 @@ COMMAND_ALIAS(station, set, "<MAC address> vlan <ifindex>", select_station_cmd, station_set_vlan); static int handle_station_set_mesh_power_mode(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) @@ -551,15 +895,128 @@ COMMAND_ALIAS(station, set, "<MAC address> mesh_power_mode " "Set link-specific mesh power mode for this station", select_station_cmd, station_set_mesh_power_mode); +static int handle_station_set_airtime_weight(struct nl80211_state *state, + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + unsigned char mac_addr[ETH_ALEN]; + unsigned long airtime_weight = 0; + char *err = NULL; + + if (argc < 3) + return 1; + + if (mac_addr_a2n(mac_addr, argv[0])) { + fprintf(stderr, "invalid mac address\n"); + return 2; + } + argc--; + argv++; + + if (strcmp("airtime_weight", argv[0]) != 0) + return 1; + argc--; + argv++; + + airtime_weight = strtoul(argv[0], &err, 0); + if (err && *err) { + fprintf(stderr, "invalid airtime weight\n"); + return 2; + } + argc--; + argv++; + + if (argc) + return 1; + + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); + NLA_PUT_U16(msg, NL80211_ATTR_AIRTIME_WEIGHT, airtime_weight); + + return 0; + nla_put_failure: + return -ENOBUFS; + +} +COMMAND_ALIAS(station, set, "<MAC address> airtime_weight <weight>", + NL80211_CMD_SET_STATION, 0, CIB_NETDEV, handle_station_set_airtime_weight, + "Set airtime weight for this station.", + select_station_cmd, station_set_airtime_weight); + +static int handle_station_set_txpwr(struct nl80211_state *state, + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + enum nl80211_tx_power_setting type; + unsigned char mac_addr[ETH_ALEN]; + int sta_txpwr = 0; + char *err = NULL; + + if (argc != 3 && argc != 4) + return 1; + + if (mac_addr_a2n(mac_addr, argv[0])) { + fprintf(stderr, "invalid mac address\n"); + return 2; + } + + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); + argc--; + argv++; + + if (strcmp("txpwr", argv[0]) != 0) + return 1; + argc--; + argv++; + + if (!strcmp(argv[0], "auto")) + type = NL80211_TX_POWER_AUTOMATIC; + else if (!strcmp(argv[0], "limit")) + type = NL80211_TX_POWER_LIMITED; + else { + printf("Invalid parameter: %s\n", argv[0]); + return 2; + } + + NLA_PUT_U8(msg, NL80211_ATTR_STA_TX_POWER_SETTING, type); + + if (type != NL80211_TX_POWER_AUTOMATIC) { + if (argc != 2) { + printf("Missing TX power level argument.\n"); + return 2; + } + + argc--; + argv++; + + sta_txpwr = strtoul(argv[0], &err, 0); + NLA_PUT_U16(msg, NL80211_ATTR_STA_TX_POWER, sta_txpwr); + } + + argc--; + argv++; + + if (argc) + return 1; + + return 0; + nla_put_failure: + return -ENOBUFS; +} +COMMAND_ALIAS(station, set, "<MAC address> txpwr <auto|limit> [<tx power dBm>]", + NL80211_CMD_SET_STATION, 0, CIB_NETDEV, handle_station_set_txpwr, + "Set Tx power for this station.", + select_station_cmd, station_set_txpwr); + static int handle_station_dump(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_sta_handler, NULL); + register_handler(print_sta_handler, *argv); return 0; } -COMMAND(station, dump, NULL, +COMMAND(station, dump, "[-v]", NL80211_CMD_GET_STATION, NLM_F_DUMP, CIB_NETDEV, handle_station_dump, "List all stations known, e.g. the AP on managed interfaces"); @@ -1,6 +1,4 @@ #include <net/if.h> -#include <errno.h> -#include <string.h> #include <netlink/genl/genl.h> #include <netlink/genl/family.h> @@ -69,15 +67,24 @@ static int print_survey_handler(struct nl_msg *msg, void *arg) } static int handle_survey_dump(struct nl80211_state *state, - struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_survey_handler, NULL); + if (argc > 1) + return HANDLER_RET_USAGE; + + if (argc) { + if (!strcmp(argv[0], "--radio")) + nla_put_flag(msg, NL80211_ATTR_SURVEY_RADIO_STATS); + else + return HANDLER_RET_USAGE; + } + + register_handler(print_survey_handler, NULL); return 0; } -COMMAND(survey, dump, NULL, +COMMAND(survey, dump, "[--radio]", NL80211_CMD_GET_SURVEY, NLM_F_DUMP, CIB_NETDEV, handle_survey_dump, "List all gathered channel survey data"); @@ -5,7 +5,7 @@ #include "iw.h" #include "nl80211.h" -void mac_addr_n2a(char *mac_addr, unsigned char *arg) +void mac_addr_n2a(char *mac_addr, const unsigned char *arg) { int i, l; @@ -134,6 +134,7 @@ static const char *ifmodes[NL80211_IFTYPE_MAX + 1] = { "P2P-GO", "P2P-device", "outside context of a BSS", + "NAN", }; static char modebuf[100]; @@ -180,6 +181,7 @@ static const char *commands[NL80211_CMD_MAX + 1] = { [NL80211_CMD_REQ_SET_REG] = "req_set_reg", [NL80211_CMD_GET_MESH_CONFIG] = "get_mesh_config", [NL80211_CMD_SET_MESH_CONFIG] = "set_mesh_config", + [NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */] = "set_mgmt_extra_ie /* reserved; not used */", [NL80211_CMD_GET_REG] = "get_reg", [NL80211_CMD_GET_SCAN] = "get_scan", [NL80211_CMD_TRIGGER_SCAN] = "trigger_scan", @@ -260,6 +262,43 @@ static const char *commands[NL80211_CMD_MAX + 1] = { [NL80211_CMD_JOIN_OCB] = "join_ocb", [NL80211_CMD_LEAVE_OCB] = "leave_ocb", [NL80211_CMD_CH_SWITCH_STARTED_NOTIFY] = "ch_switch_started_notify", + [NL80211_CMD_TDLS_CHANNEL_SWITCH] = "tdls_channel_switch", + [NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH] = "tdls_cancel_channel_switch", + [NL80211_CMD_WIPHY_REG_CHANGE] = "wiphy_reg_change", + [NL80211_CMD_ABORT_SCAN] = "abort_scan", + [NL80211_CMD_START_NAN] = "start_nan", + [NL80211_CMD_STOP_NAN] = "stop_nan", + [NL80211_CMD_ADD_NAN_FUNCTION] = "add_nan_function", + [NL80211_CMD_DEL_NAN_FUNCTION] = "del_nan_function", + [NL80211_CMD_CHANGE_NAN_CONFIG] = "change_nan_config", + [NL80211_CMD_NAN_MATCH] = "nan_match", + [NL80211_CMD_SET_MULTICAST_TO_UNICAST] = "set_multicast_to_unicast", + [NL80211_CMD_UPDATE_CONNECT_PARAMS] = "update_connect_params", + [NL80211_CMD_SET_PMK] = "set_pmk", + [NL80211_CMD_DEL_PMK] = "del_pmk", + [NL80211_CMD_PORT_AUTHORIZED] = "port_authorized", + [NL80211_CMD_RELOAD_REGDB] = "reload_regdb", + [NL80211_CMD_EXTERNAL_AUTH] = "external_auth", + [NL80211_CMD_STA_OPMODE_CHANGED] = "sta_opmode_changed", + [NL80211_CMD_CONTROL_PORT_FRAME] = "control_port_frame", + [NL80211_CMD_GET_FTM_RESPONDER_STATS] = "get_ftm_responder_stats", + [NL80211_CMD_PEER_MEASUREMENT_START] = "peer_measurement_start", + [NL80211_CMD_PEER_MEASUREMENT_RESULT] = "peer_measurement_result", + [NL80211_CMD_PEER_MEASUREMENT_COMPLETE] = "peer_measurement_complete", + [NL80211_CMD_NOTIFY_RADAR] = "notify_radar", + [NL80211_CMD_UPDATE_OWE_INFO] = "update_owe_info", + [NL80211_CMD_PROBE_MESH_LINK] = "probe_mesh_link", + [NL80211_CMD_SET_TID_CONFIG] = "set_tid_config", + [NL80211_CMD_UNPROT_BEACON] = "unprot_beacon", + [NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS] = "control_port_frame_tx_status", + [NL80211_CMD_SET_SAR_SPECS] = "set_sar_specs", + [NL80211_CMD_OBSS_COLOR_COLLISION] = "obss_color_collision", + [NL80211_CMD_COLOR_CHANGE_REQUEST] = "color_change_request", + [NL80211_CMD_COLOR_CHANGE_STARTED] = "color_change_started", + [NL80211_CMD_COLOR_CHANGE_ABORTED] = "color_change_aborted", + [NL80211_CMD_COLOR_CHANGE_COMPLETED] = "color_change_completed", + [NL80211_CMD_SET_FILS_AAD] = "set_fils_aad", + [NL80211_CMD_ASSOC_COMEBACK] = "assoc_comeback", }; static char cmdbuf[100]; @@ -291,8 +330,15 @@ int ieee80211_channel_to_frequency(int chan, enum nl80211_band band) else return 5000 + chan * 5; break; + case NL80211_BAND_6GHZ: + /* see 802.11ax D6.1 27.3.23.2 */ + if (chan == 2) + return 5935; + if (chan <= 253) + return 5950 + chan * 5; + break; case NL80211_BAND_60GHZ: - if (chan < 5) + if (chan < 7) return 56160 + chan * 2160; break; default: @@ -306,13 +352,19 @@ int ieee80211_frequency_to_channel(int freq) /* see 802.11-2007 17.3.8.3.2 and Annex J */ if (freq == 2484) return 14; + /* see 802.11ax D6.1 27.3.23.2 and Annex E */ + else if (freq == 5935) + return 2; else if (freq < 2484) return (freq - 2407) / 5; else if (freq >= 4910 && freq <= 4980) return (freq - 4000) / 5; - else if (freq <= 45000) /* DMG band lower limit */ + else if (freq < 5950) return (freq - 5000) / 5; - else if (freq >= 58320 && freq <= 64800) + else if (freq <= 45000) /* DMG band lower limit */ + /* see 802.11ax D6.1 27.3.23.2 */ + return (freq - 5950) / 5; + else if (freq >= 58320 && freq <= 70200) return (freq - 56160) / 2160; else return 0; @@ -342,7 +394,7 @@ static int hex2num(char digit) return tolower(digit) - 'a' + 10; } -static int hex2byte(char *hex) +static int hex2byte(const char *hex) { int d1, d2; @@ -355,7 +407,7 @@ static int hex2byte(char *hex) return (d1 << 4) | d2; } -static char *hex2bin(char *hex, char *buf) +char *hex2bin(const char *hex, char *buf) { char *result = buf; int d; @@ -372,16 +424,103 @@ static char *hex2bin(char *hex, char *buf) return result; } -int parse_keys(struct nl_msg *msg, char **argv, int argc) +static int parse_akm_suite(const char *cipher_str) +{ + + if (!strcmp(cipher_str, "PSK")) + return 0x000FAC02; + if (!strcmp(cipher_str, "FT/PSK")) + return 0x000FAC03; + if (!strcmp(cipher_str, "PSK/SHA-256")) + return 0x000FAC06; + return -EINVAL; +} + +static int parse_cipher_suite(const char *cipher_str) +{ + + if (!strcmp(cipher_str, "TKIP")) + return WLAN_CIPHER_SUITE_TKIP; + if (!strcmp(cipher_str, "CCMP") || !strcmp(cipher_str, "CCMP-128")) + return WLAN_CIPHER_SUITE_CCMP; + if (!strcmp(cipher_str, "GCMP") || !strcmp(cipher_str, "GCMP-128")) + return WLAN_CIPHER_SUITE_GCMP; + if (!strcmp(cipher_str, "GCMP-256")) + return WLAN_CIPHER_SUITE_GCMP_256; + if (!strcmp(cipher_str, "CCMP-256")) + return WLAN_CIPHER_SUITE_CCMP_256; + return -EINVAL; +} + +int parse_keys(struct nl_msg *msg, char **argv[], int *argc) { struct nlattr *keys; int i = 0; bool have_default = false; + char *arg = **argv; char keybuf[13]; + int pos = 0; - if (!argc) + if (!*argc) return 1; + if (!memcmp(&arg[pos], "psk", 3)) { + char psk_keybuf[32]; + int cipher_suite, akm_suite; + + if (*argc < 4) + goto explain; + + pos+=3; + if (arg[pos] != ':') + goto explain; + pos++; + + NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, NL80211_WPA_VERSION_2); + + if (strlen(&arg[pos]) != (sizeof(psk_keybuf) * 2) || !hex2bin(&arg[pos], psk_keybuf)) { + printf("Bad PSK\n"); + return -EINVAL; + } + + NLA_PUT(msg, NL80211_ATTR_PMK, 32, psk_keybuf); + NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, NL80211_AUTHTYPE_OPEN_SYSTEM); + + *argv += 1; + *argc -= 1; + arg = **argv; + + akm_suite = parse_akm_suite(arg); + if (akm_suite < 0) + goto explain; + + NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, akm_suite); + + *argv += 1; + *argc -= 1; + arg = **argv; + + cipher_suite = parse_cipher_suite(arg); + if (cipher_suite < 0) + goto explain; + + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher_suite); + + *argv += 1; + *argc -= 1; + arg = **argv; + + cipher_suite = parse_cipher_suite(arg); + if (cipher_suite < 0) + goto explain; + + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher_suite); + + *argv += 1; + *argc -= 1; + return 0; + } + NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY); keys = nla_nest_start(msg, NL80211_ATTR_KEYS); @@ -389,11 +528,13 @@ int parse_keys(struct nl_msg *msg, char **argv, int argc) return -ENOBUFS; do { - char *arg = *argv; - int pos = 0, keylen; + int keylen; struct nlattr *key = nla_nest_start(msg, ++i); char *keydata; + arg = **argv; + pos = 0; + if (!key) return -ENOBUFS; @@ -414,14 +555,18 @@ int parse_keys(struct nl_msg *msg, char **argv, int argc) switch (strlen(keydata)) { case 10: keydata = hex2bin(keydata, keybuf); + /* fall through */ case 5: - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, 0x000FAC01); + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, + WLAN_CIPHER_SUITE_WEP40); keylen = 5; break; case 26: keydata = hex2bin(keydata, keybuf); + /* fall through */ case 13: - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, 0x000FAC05); + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, + WLAN_CIPHER_SUITE_WEP104); keylen = 13; break; default: @@ -433,15 +578,15 @@ int parse_keys(struct nl_msg *msg, char **argv, int argc) NLA_PUT(msg, NL80211_KEY_DATA, keylen, keydata); - argv++; - argc--; + *argv += 1; + *argc -= 1; /* one key should be TX key */ - if (!have_default && !argc) + if (!have_default && !*argc) NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); nla_nest_end(msg, key); - } while (argc); + } while (*argc); nla_nest_end(msg, keys); @@ -454,10 +599,300 @@ int parse_keys(struct nl_msg *msg, char **argv, int argc) " 'index:' is a single digit (0-3)\n" " 'data' must be 5 or 13 ascii chars\n" " or 10 or 26 hex digits\n" - "for example: d:2:6162636465 is the same as d:2:abcde\n"); + "for example: d:2:6162636465 is the same as d:2:abcde\n" + "or psk:data <AKM Suite> <pairwise CIPHER> <groupwise CIPHER> where\n" + " 'data' is the PSK (output of wpa_passphrase and the CIPHER can be CCMP or GCMP\n" + "for example: psk:0123456789abcdef PSK CCMP CCMP\n" + "The allowed AKM suites are PSK, FT/PSK, PSK/SHA-256\n" + "The allowed Cipher suites are TKIP, CCMP, GCMP, GCMP-256, CCMP-256\n"); return 2; } +enum nl80211_chan_width str_to_bw(const char *str) +{ + static const struct { + const char *name; + unsigned int val; + } bwmap[] = { + { .name = "5", .val = NL80211_CHAN_WIDTH_5, }, + { .name = "10", .val = NL80211_CHAN_WIDTH_10, }, + { .name = "20", .val = NL80211_CHAN_WIDTH_20, }, + { .name = "40", .val = NL80211_CHAN_WIDTH_40, }, + { .name = "80", .val = NL80211_CHAN_WIDTH_80, }, + { .name = "80+80", .val = NL80211_CHAN_WIDTH_80P80, }, + { .name = "160", .val = NL80211_CHAN_WIDTH_160, }, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(bwmap); i++) { + if (strcasecmp(bwmap[i].name, str) == 0) + return bwmap[i].val; + } + + return NL80211_CHAN_WIDTH_20_NOHT; +} + +static int parse_freqs(struct chandef *chandef, int argc, char **argv, + int *parsed) +{ + uint32_t freq; + char *end; + bool need_cf1 = false, need_cf2 = false; + + if (argc < 1) + return 0; + + chandef->width = str_to_bw(argv[0]); + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20_NOHT: + /* First argument was not understood, give up gracefully. */ + return 0; + case NL80211_CHAN_WIDTH_20: + case NL80211_CHAN_WIDTH_5: + case NL80211_CHAN_WIDTH_10: + break; + case NL80211_CHAN_WIDTH_80P80: + need_cf2 = true; + /* fall through */ + case NL80211_CHAN_WIDTH_40: + case NL80211_CHAN_WIDTH_80: + case NL80211_CHAN_WIDTH_160: + case NL80211_CHAN_WIDTH_320: + need_cf1 = true; + break; + case NL80211_CHAN_WIDTH_1: + case NL80211_CHAN_WIDTH_2: + case NL80211_CHAN_WIDTH_4: + case NL80211_CHAN_WIDTH_8: + case NL80211_CHAN_WIDTH_16: + /* can't happen yet */ + break; + } + + *parsed += 1; + + if (!need_cf1) + return 0; + + if (argc < 2) + return 1; + + /* center freq 1 */ + if (!*argv[1]) + return 1; + freq = strtoul(argv[1], &end, 10); + if (*end) + return 1; + *parsed += 1; + + chandef->center_freq1 = freq; + + if (!need_cf2) + return 0; + + if (argc < 3) + return 1; + + /* center freq 2 */ + if (!*argv[2]) + return 1; + freq = strtoul(argv[2], &end, 10); + if (*end) + return 1; + chandef->center_freq2 = freq; + + *parsed += 1; + + return 0; +} + + +/** + * parse_freqchan - Parse frequency or channel definition + * + * @chandef: chandef structure to be filled in + * @chan: Boolean whether to parse a channel or frequency based specifier + * @argc: Number of arguments + * @argv: Array of string arguments + * @parsed: Pointer to return the number of used arguments, or NULL to error + * out if any argument is left unused. + * + * The given chandef structure will be filled in from the command line + * arguments. argc/argv will be updated so that further arguments from the + * command line can be parsed. + * + * Note that despite the fact that the function knows how many center freqs + * are needed, there's an ambiguity if the next argument after this is an + * integer argument, since the valid channel width values are interpreted + * as such, rather than a following argument. This can be avoided by the + * user by giving "NOHT" instead. + * + * The working specifier if chan is set are: + * <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz] + * + * And if frequency is set: + * <freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz] + * <control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]] + * + * If the mode/channel width is not given the NOHT is assumed. + * + * Return: Number of used arguments, zero or negative error number otherwise + */ +int parse_freqchan(struct chandef *chandef, bool chan, int argc, char **argv, + int *parsed) +{ + char *end; + static const struct chanmode chanmode[] = { + { .name = "HT20", + .width = NL80211_CHAN_WIDTH_20, + .freq1_diff = 0, + .chantype = NL80211_CHAN_HT20 }, + { .name = "HT40+", + .width = NL80211_CHAN_WIDTH_40, + .freq1_diff = 10, + .chantype = NL80211_CHAN_HT40PLUS }, + { .name = "HT40-", + .width = NL80211_CHAN_WIDTH_40, + .freq1_diff = -10, + .chantype = NL80211_CHAN_HT40MINUS }, + { .name = "NOHT", + .width = NL80211_CHAN_WIDTH_20_NOHT, + .freq1_diff = 0, + .chantype = NL80211_CHAN_NO_HT }, + { .name = "5MHz", + .width = NL80211_CHAN_WIDTH_5, + .freq1_diff = 0, + .chantype = -1 }, + { .name = "10MHz", + .width = NL80211_CHAN_WIDTH_10, + .freq1_diff = 0, + .chantype = -1 }, + { .name = "80MHz", + .width = NL80211_CHAN_WIDTH_80, + .freq1_diff = 0, + .chantype = -1 }, + { .name = "160MHz", + .width = NL80211_CHAN_WIDTH_160, + .freq1_diff = 0, + .chantype = -1 }, + { .name = "320MHz", + .width = NL80211_CHAN_WIDTH_320, + .freq1_diff = 0, + .chantype = -1 }, + }; + const struct chanmode *chanmode_selected = NULL; + unsigned int freq; + unsigned int i; + int _parsed = 0; + int res = 0; + + if (argc < 1) + return 1; + + if (!argv[0]) + goto out; + freq = strtoul(argv[0], &end, 10); + if (*end) { + res = 1; + goto out; + } + + _parsed += 1; + + memset(chandef, 0, sizeof(struct chandef)); + + if (chan) { + enum nl80211_band band; + + band = freq <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; + freq = ieee80211_channel_to_frequency(freq, band); + } + chandef->control_freq = freq; + /* Assume 20MHz NOHT channel for now. */ + chandef->center_freq1 = freq; + + /* Try to parse HT mode definitions */ + if (argc > 1) { + for (i = 0; i < ARRAY_SIZE(chanmode); i++) { + if (strcasecmp(chanmode[i].name, argv[1]) == 0) { + chanmode_selected = &chanmode[i]; + _parsed += 1; + break; + } + } + } + + /* channel mode given, use it and return. */ + if (chanmode_selected) { + chandef->center_freq1 = get_cf1(chanmode_selected, freq); + chandef->width = chanmode_selected->width; + goto out; + } + + /* This was a only a channel definition, nothing further may follow. */ + if (chan) + goto out; + + res = parse_freqs(chandef, argc - 1, argv + 1, &_parsed); + + out: + /* Error out if parsed is NULL. */ + if (!parsed && _parsed != argc) + return 1; + + if (parsed) + *parsed = _parsed; + + return res; +} + +int put_chandef(struct nl_msg *msg, struct chandef *chandef) +{ + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, chandef->control_freq); + NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width); + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20_NOHT: + NLA_PUT_U32(msg, + NL80211_ATTR_WIPHY_CHANNEL_TYPE, + NL80211_CHAN_NO_HT); + break; + case NL80211_CHAN_WIDTH_20: + NLA_PUT_U32(msg, + NL80211_ATTR_WIPHY_CHANNEL_TYPE, + NL80211_CHAN_HT20); + break; + case NL80211_CHAN_WIDTH_40: + if (chandef->control_freq > chandef->center_freq1) + NLA_PUT_U32(msg, + NL80211_ATTR_WIPHY_CHANNEL_TYPE, + NL80211_CHAN_HT40MINUS); + else + NLA_PUT_U32(msg, + NL80211_ATTR_WIPHY_CHANNEL_TYPE, + NL80211_CHAN_HT40PLUS); + break; + default: + break; + } + + if (chandef->center_freq1) + NLA_PUT_U32(msg, + NL80211_ATTR_CENTER_FREQ1, + chandef->center_freq1); + + if (chandef->center_freq2) + NLA_PUT_U32(msg, + NL80211_ATTR_CENTER_FREQ2, + chandef->center_freq2); + + return 0; + + nla_put_failure: + return -ENOBUFS; +} + static void print_mcs_index(const __u8 *mcs) { int mcs_bit, prev_bit = -2, prev_cont = 0; @@ -711,9 +1146,513 @@ void print_vht_info(__u32 capa, const __u8 *mcs) printf("\t\tVHT TX highest supported: %d Mbps\n", tmp & 0x1fff); } -void iw_hexdump(const char *prefix, const __u8 *buf, size_t size) +static void __print_he_capa(const __u16 *mac_cap, + const __u16 *phy_cap, + const __u16 *mcs_set, size_t mcs_len, + const __u8 *ppet, int ppet_len, + bool indent) { + size_t mcs_used; int i; + const char *pre = indent ? "\t" : ""; + + #define PRINT_HE_CAP(_var, _idx, _bit, _str) \ + do { \ + if (_var[_idx] & BIT(_bit)) \ + printf("%s\t\t\t" _str "\n", pre); \ + } while (0) + + #define PRINT_HE_CAP_MASK(_var, _idx, _shift, _mask, _str) \ + do { \ + if ((_var[_idx] >> _shift) & _mask) \ + printf("%s\t\t\t" _str ": %d\n", pre, (_var[_idx] >> _shift) & _mask); \ + } while (0) + + #define PRINT_HE_MAC_CAP(...) PRINT_HE_CAP(mac_cap, __VA_ARGS__) + #define PRINT_HE_MAC_CAP_MASK(...) PRINT_HE_CAP_MASK(mac_cap, __VA_ARGS__) + #define PRINT_HE_PHY_CAP(...) PRINT_HE_CAP(phy_cap, __VA_ARGS__) + #define PRINT_HE_PHY_CAP0(_idx, _bit, ...) PRINT_HE_CAP(phy_cap, _idx, _bit + 8, __VA_ARGS__) + #define PRINT_HE_PHY_CAP_MASK(...) PRINT_HE_CAP_MASK(phy_cap, __VA_ARGS__) + + printf("%s\t\tHE MAC Capabilities (0x", pre); + for (i = 0; i < 3; i++) + printf("%04x", mac_cap[i]); + printf("):\n"); + + PRINT_HE_MAC_CAP(0, 0, "+HTC HE Supported"); + PRINT_HE_MAC_CAP(0, 1, "TWT Requester"); + PRINT_HE_MAC_CAP(0, 2, "TWT Responder"); + PRINT_HE_MAC_CAP_MASK(0, 3, 0x3, "Dynamic BA Fragementation Level"); + PRINT_HE_MAC_CAP_MASK(0, 5, 0x7, "Maximum number of MSDUS Fragments"); + PRINT_HE_MAC_CAP_MASK(0, 8, 0x3, "Minimum Payload size of 128 bytes"); + PRINT_HE_MAC_CAP_MASK(0, 10, 0x3, "Trigger Frame MAC Padding Duration"); + PRINT_HE_MAC_CAP_MASK(0, 12, 0x7, "Multi-TID Aggregation Support"); + + PRINT_HE_MAC_CAP(1, 1, "All Ack"); + PRINT_HE_MAC_CAP(1, 2, "TRS"); + PRINT_HE_MAC_CAP(1, 3, "BSR"); + PRINT_HE_MAC_CAP(1, 4, "Broadcast TWT"); + PRINT_HE_MAC_CAP(1, 5, "32-bit BA Bitmap"); + PRINT_HE_MAC_CAP(1, 6, "MU Cascading"); + PRINT_HE_MAC_CAP(1, 7, "Ack-Enabled Aggregation"); + PRINT_HE_MAC_CAP(1, 9, "OM Control"); + PRINT_HE_MAC_CAP(1, 10, "OFDMA RA"); + PRINT_HE_MAC_CAP_MASK(1, 11, 0x3, "Maximum A-MPDU Length Exponent"); + PRINT_HE_MAC_CAP(1, 13, "A-MSDU Fragmentation"); + PRINT_HE_MAC_CAP(1, 14, "Flexible TWT Scheduling"); + PRINT_HE_MAC_CAP(1, 15, "RX Control Frame to MultiBSS"); + + PRINT_HE_MAC_CAP(2, 0, "BSRP BQRP A-MPDU Aggregation"); + PRINT_HE_MAC_CAP(2, 1, "QTP"); + PRINT_HE_MAC_CAP(2, 2, "BQR"); + PRINT_HE_MAC_CAP(2, 3, "SRP Responder Role"); + PRINT_HE_MAC_CAP(2, 4, "NDP Feedback Report"); + PRINT_HE_MAC_CAP(2, 5, "OPS"); + PRINT_HE_MAC_CAP(2, 6, "A-MSDU in A-MPDU"); + PRINT_HE_MAC_CAP_MASK(2, 7, 7, "Multi-TID Aggregation TX"); + PRINT_HE_MAC_CAP(2, 10, "HE Subchannel Selective Transmission"); + PRINT_HE_MAC_CAP(2, 11, "UL 2x996-Tone RU"); + PRINT_HE_MAC_CAP(2, 12, "OM Control UL MU Data Disable RX"); + + printf("%s\t\tHE PHY Capabilities: (0x", pre); + for (i = 0; i < 11; i++) + printf("%02x", ((__u8 *)phy_cap)[i + 1]); + printf("):\n"); + + PRINT_HE_PHY_CAP0(0, 1, "HE40/2.4GHz"); + PRINT_HE_PHY_CAP0(0, 2, "HE40/HE80/5GHz"); + PRINT_HE_PHY_CAP0(0, 3, "HE160/5GHz"); + PRINT_HE_PHY_CAP0(0, 4, "HE160/HE80+80/5GHz"); + PRINT_HE_PHY_CAP0(0, 5, "242 tone RUs/2.4GHz"); + PRINT_HE_PHY_CAP0(0, 6, "242 tone RUs/5GHz"); + + PRINT_HE_PHY_CAP_MASK(1, 0, 0xf, "Punctured Preamble RX"); + PRINT_HE_PHY_CAP_MASK(1, 4, 0x1, "Device Class"); + PRINT_HE_PHY_CAP(1, 5, "LDPC Coding in Payload"); + PRINT_HE_PHY_CAP(1, 6, "HE SU PPDU with 1x HE-LTF and 0.8us GI"); + PRINT_HE_PHY_CAP_MASK(1, 7, 0x3, "Midamble Rx Max NSTS"); + PRINT_HE_PHY_CAP(1, 9, "NDP with 4x HE-LTF and 3.2us GI"); + PRINT_HE_PHY_CAP(1, 10, "STBC Tx <= 80MHz"); + PRINT_HE_PHY_CAP(1, 11, "STBC Rx <= 80MHz"); + PRINT_HE_PHY_CAP(1, 12, "Doppler Tx"); + PRINT_HE_PHY_CAP(1, 13, "Doppler Rx"); + PRINT_HE_PHY_CAP(1, 14, "Full Bandwidth UL MU-MIMO"); + PRINT_HE_PHY_CAP(1, 15, "Partial Bandwidth UL MU-MIMO"); + + PRINT_HE_PHY_CAP_MASK(2, 0, 0x3, "DCM Max Constellation"); + PRINT_HE_PHY_CAP_MASK(2, 2, 0x1, "DCM Max NSS Tx"); + PRINT_HE_PHY_CAP_MASK(2, 3, 0x3, "DCM Max Constellation Rx"); + PRINT_HE_PHY_CAP_MASK(2, 5, 0x1, "DCM Max NSS Rx"); + PRINT_HE_PHY_CAP(2, 6, "Rx HE MU PPDU from Non-AP STA"); + PRINT_HE_PHY_CAP(2, 7, "SU Beamformer"); + PRINT_HE_PHY_CAP(2, 8, "SU Beamformee"); + PRINT_HE_PHY_CAP(2, 9, "MU Beamformer"); + PRINT_HE_PHY_CAP_MASK(2, 10, 0x7, "Beamformee STS <= 80Mhz"); + PRINT_HE_PHY_CAP_MASK(2, 13, 0x7, "Beamformee STS > 80Mhz"); + + PRINT_HE_PHY_CAP_MASK(3, 0, 0x7, "Sounding Dimensions <= 80Mhz"); + PRINT_HE_PHY_CAP_MASK(3, 3, 0x7, "Sounding Dimensions > 80Mhz"); + PRINT_HE_PHY_CAP(3, 6, "Ng = 16 SU Feedback"); + PRINT_HE_PHY_CAP(3, 7, "Ng = 16 MU Feedback"); + PRINT_HE_PHY_CAP(3, 8, "Codebook Size SU Feedback"); + PRINT_HE_PHY_CAP(3, 9, "Codebook Size MU Feedback"); + PRINT_HE_PHY_CAP(3, 10, "Triggered SU Beamforming Feedback"); + PRINT_HE_PHY_CAP(3, 11, "Triggered MU Beamforming Feedback"); + PRINT_HE_PHY_CAP(3, 12, "Triggered CQI Feedback"); + PRINT_HE_PHY_CAP(3, 13, "Partial Bandwidth Extended Range"); + PRINT_HE_PHY_CAP(3, 14, "Partial Bandwidth DL MU-MIMO"); + PRINT_HE_PHY_CAP(3, 15, "PPE Threshold Present"); + + PRINT_HE_PHY_CAP(4, 0, "SRP-based SR"); + PRINT_HE_PHY_CAP(4, 1, "Power Boost Factor ar"); + PRINT_HE_PHY_CAP(4, 2, "HE SU PPDU & HE PPDU 4x HE-LTF 0.8us GI"); + PRINT_HE_PHY_CAP_MASK(4, 3, 0x7, "Max NC"); + PRINT_HE_PHY_CAP(4, 6, "STBC Tx > 80MHz"); + PRINT_HE_PHY_CAP(4, 7, "STBC Rx > 80MHz"); + PRINT_HE_PHY_CAP(4, 8, "HE ER SU PPDU 4x HE-LTF 0.8us GI"); + PRINT_HE_PHY_CAP(4, 9, "20MHz in 40MHz HE PPDU 2.4GHz"); + PRINT_HE_PHY_CAP(4, 10, "20MHz in 160/80+80MHz HE PPDU"); + PRINT_HE_PHY_CAP(4, 11, "80MHz in 160/80+80MHz HE PPDU"); + PRINT_HE_PHY_CAP(4, 12, "HE ER SU PPDU 1x HE-LTF 0.8us GI"); + PRINT_HE_PHY_CAP(4, 13, "Midamble Rx 2x & 1x HE-LTF"); + PRINT_HE_PHY_CAP_MASK(4, 14, 0x3, "DCM Max BW"); + + PRINT_HE_PHY_CAP(5, 0, "Longer Than 16HE SIG-B OFDM Symbols"); + PRINT_HE_PHY_CAP(5, 1, "Non-Triggered CQI Feedback"); + PRINT_HE_PHY_CAP(5, 2, "TX 1024-QAM"); + PRINT_HE_PHY_CAP(5, 3, "RX 1024-QAM"); + PRINT_HE_PHY_CAP(5, 4, "RX Full BW SU Using HE MU PPDU with Compression SIGB"); + PRINT_HE_PHY_CAP(5, 5, "RX Full BW SU Using HE MU PPDU with Non-Compression SIGB"); + + mcs_used = 0; + for (i = 0; i < 3; i++) { + __u8 phy_cap_support[] = { BIT(1) | BIT(2), BIT(3), BIT(4) }; + char *bw[] = { "<= 80", "160", "80+80" }; + int j; + + if ((phy_cap[0] & (phy_cap_support[i] << 8)) == 0) + continue; + + /* Supports more, but overflow? Abort. */ + if ((i * 2 + 2) * sizeof(mcs_set[0]) >= mcs_len) + return; + + for (j = 0; j < 2; j++) { + int k; + printf("%s\t\tHE %s MCS and NSS set %s MHz\n", pre, j ? "TX" : "RX", bw[i]); + for (k = 0; k < 8; k++) { + __u16 mcs = mcs_set[(i * 2) + j]; + mcs >>= k * 2; + mcs &= 0x3; + printf("%s\t\t\t%d streams: ", pre, k + 1); + if (mcs == 3) + printf("not supported\n"); + else + printf("MCS 0-%d\n", 7 + (mcs * 2)); + } + + } + mcs_used += 2 * sizeof(mcs_set[0]); + } + + /* Caller didn't provide ppet; infer it, if there's trailing space. */ + if (!ppet) { + ppet = (const void *)((const __u8 *)mcs_set + mcs_used); + if (mcs_used < mcs_len) + ppet_len = mcs_len - mcs_used; + else + ppet_len = 0; + } + + if (ppet_len && (phy_cap[3] & BIT(15))) { + printf("%s\t\tPPE Threshold ", pre); + for (i = 0; i < ppet_len; i++) + if (ppet[i]) + printf("0x%02x ", ppet[i]); + printf("\n"); + } +} + +void print_iftype_list(const char *name, const char *pfx, struct nlattr *attr) +{ + struct nlattr *ift; + int rem; + + printf("%s:\n", name); + nla_for_each_nested(ift, attr, rem) + printf("%s * %s\n", pfx, iftype_name(nla_type(ift))); +} + +void print_iftype_line(struct nlattr *attr) +{ + struct nlattr *ift; + bool first = true; + int rem; + + nla_for_each_nested(ift, attr, rem) { + if (first) + first = false; + else + printf(", "); + printf("%s", iftype_name(nla_type(ift))); + } +} + +void print_he_info(struct nlattr *nl_iftype) +{ + struct nlattr *tb[NL80211_BAND_IFTYPE_ATTR_MAX + 1]; + __u16 mac_cap[3] = { 0 }; + __u16 phy_cap[6] = { 0 }; + __u16 mcs_set[6] = { 0 }; + __u8 ppet[25] = { 0 }; + size_t len; + int mcs_len = 0, ppet_len = 0; + + nla_parse(tb, NL80211_BAND_IFTYPE_ATTR_MAX, + nla_data(nl_iftype), nla_len(nl_iftype), NULL); + + if (!tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES]) + return; + + printf("\t\tHE Iftypes: "); + print_iftype_line(tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES]); + printf("\n"); + + if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]); + if (len > sizeof(mac_cap)) + len = sizeof(mac_cap); + memcpy(mac_cap, + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]), + len); + } + + if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]); + + if (len > sizeof(phy_cap) - 1) + len = sizeof(phy_cap) - 1; + memcpy(&((__u8 *)phy_cap)[1], + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]), + len); + } + + if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]); + if (len > sizeof(mcs_set)) + len = sizeof(mcs_set); + memcpy(mcs_set, + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]), + len); + mcs_len = len; + } + + if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]); + if (len > sizeof(ppet)) + len = sizeof(ppet); + memcpy(ppet, + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]), + len); + ppet_len = len; + } + + __print_he_capa(mac_cap, phy_cap, mcs_set, mcs_len, ppet, ppet_len, + true); +} + +static void __print_eht_capa(int band, + const __u8 *mac_cap, + const __u32 *phy_cap, + const __u8 *mcs_set, size_t mcs_len, + const __u8 *ppet, size_t ppet_len, + const __u16 *he_phy_cap, + bool indent) +{ + unsigned int i; + const char *pre = indent ? "\t" : ""; + const char *mcs[] = { "0-7", "8-9", "10-11", "12-13"}; + + #define PRINT_EHT_CAP(_var, _idx, _bit, _str) \ + do { \ + if (_var[_idx] & BIT(_bit)) \ + printf("%s\t\t\t" _str "\n", pre); \ + } while (0) + + #define PRINT_EHT_CAP_MASK(_var, _idx, _shift, _mask, _str) \ + do { \ + if ((_var[_idx] >> _shift) & _mask) \ + printf("%s\t\t\t" _str ": %d\n", pre, (_var[_idx] >> _shift) & _mask); \ + } while (0) + + #define PRINT_EHT_MAC_CAP(...) PRINT_EHT_CAP(mac_cap, __VA_ARGS__) + #define PRINT_EHT_PHY_CAP(...) PRINT_EHT_CAP(phy_cap, __VA_ARGS__) + #define PRINT_EHT_PHY_CAP_MASK(...) PRINT_EHT_CAP_MASK(phy_cap, __VA_ARGS__) + + printf("%s\t\tEHT MAC Capabilities (0x", pre); + for (i = 0; i < 2; i++) + printf("%02x", mac_cap[i]); + printf("):\n"); + + PRINT_EHT_MAC_CAP(0, 0, "NSEP priority access Supported"); + PRINT_EHT_MAC_CAP(0, 1, "EHT OM Control Supported"); + PRINT_EHT_MAC_CAP(0, 2, "Triggered TXOP Sharing Supported"); + PRINT_EHT_MAC_CAP(0, 3, "ARR Supported"); + + printf("%s\t\tEHT PHY Capabilities: (0x", pre); + for (i = 0; i < 8; i++) + printf("%02x", ((__u8 *)phy_cap)[i]); + printf("):\n"); + + PRINT_EHT_PHY_CAP(0, 1, "320MHz in 6GHz Supported"); + PRINT_EHT_PHY_CAP(0, 2, "242-tone RU in BW wider than 20MHz Supported"); + PRINT_EHT_PHY_CAP(0, 3, "NDP With EHT-LTF And 3.2 µs GI"); + PRINT_EHT_PHY_CAP(0, 4, "Partial Bandwidth UL MU-MIMO"); + PRINT_EHT_PHY_CAP(0, 5, "SU Beamformer"); + PRINT_EHT_PHY_CAP(0, 6, "SU Beamformee"); + PRINT_EHT_PHY_CAP_MASK(0, 7, 0x7, "Beamformee SS (80MHz)"); + PRINT_EHT_PHY_CAP_MASK(0, 10, 0x7, "Beamformee SS (160MHz)"); + PRINT_EHT_PHY_CAP_MASK(0, 13, 0x7, "Beamformee SS (320MHz)"); + + PRINT_EHT_PHY_CAP_MASK(0, 16, 0x7, "Number Of Sounding Dimensions (80MHz)"); + PRINT_EHT_PHY_CAP_MASK(0, 19, 0x7, "Number Of Sounding Dimensions (160MHz)"); + PRINT_EHT_PHY_CAP_MASK(0, 22, 0x7, "Number Of Sounding Dimensions (320MHz)"); + PRINT_EHT_PHY_CAP(0, 25, "Ng = 16 SU Feedback"); + PRINT_EHT_PHY_CAP(0, 26, "Ng = 16 MU Feedback"); + PRINT_EHT_PHY_CAP(0, 27, "Codebook size (4, 2) SU Feedback"); + PRINT_EHT_PHY_CAP(0, 28, "Codebook size (7, 5) MU Feedback"); + PRINT_EHT_PHY_CAP(0, 29, "Triggered SU Beamforming Feedback"); + PRINT_EHT_PHY_CAP(0, 30, "Triggered MU Beamforming Partial BW Feedback"); + PRINT_EHT_PHY_CAP(0, 31, "Triggered CQI Feedback"); + + PRINT_EHT_PHY_CAP(1, 0, "Partial Bandwidth DL MU-MIMO"); + PRINT_EHT_PHY_CAP(1, 1, "PSR-Based SR Support"); + PRINT_EHT_PHY_CAP(1, 2, "Power Boost Factor Support"); + PRINT_EHT_PHY_CAP(1, 3, "EHT MU PPDU With 4 EHT-LTF And 0.8 µs GI"); + PRINT_EHT_PHY_CAP_MASK(1, 4, 0xf, "Max Nc"); + PRINT_EHT_PHY_CAP(1, 8, "Non-Triggered CQI Feedback"); + + PRINT_EHT_PHY_CAP(1, 9, "Tx 1024-QAM And 4096-QAM < 242-tone RU"); + PRINT_EHT_PHY_CAP(1, 10, "Rx 1024-QAM And 4096-QAM < 242-tone RU"); + PRINT_EHT_PHY_CAP(1, 11, "PPE Thresholds Present"); + PRINT_EHT_PHY_CAP_MASK(1, 12, 0x3, "Common Nominal Packet Padding"); + PRINT_EHT_PHY_CAP_MASK(1, 14, 0x1f, "Maximum Number Of Supported EHT-LTFs"); + PRINT_EHT_PHY_CAP_MASK(1, 19, 0xf, "Support of MCS 15"); + PRINT_EHT_PHY_CAP(1, 23, "Support Of EHT DUP In 6 GHz"); + PRINT_EHT_PHY_CAP(1, 24, "Support For 20MHz Rx NDP With Wider Bandwidth"); + PRINT_EHT_PHY_CAP(1, 25, "Non-OFDMA UL MU-MIMO (80MHz)"); + PRINT_EHT_PHY_CAP(1, 26, "Non-OFDMA UL MU-MIMO (160MHz)"); + PRINT_EHT_PHY_CAP(1, 27, "Non-OFDMA UL MU-MIMO (320MHz)"); + PRINT_EHT_PHY_CAP(1, 28, "MU Beamformer (80MHz)"); + PRINT_EHT_PHY_CAP(1, 29, "MU Beamformer (160MHz)"); + PRINT_EHT_PHY_CAP(1, 30, "MU Beamformer (320MHz)"); + + printf("%s\t\tEHT MCS/NSS: (0x", pre); + for (i = 0; i < mcs_len; i++) + printf("%02x", ((__u8 *)mcs_set)[i]); + printf("):\n"); + + if (!(he_phy_cap[0] & ((BIT(2) | BIT(3) | BIT(4)) << 8))){ + for (i = 0; i < 4; i++) + printf("%s\t\tEHT bw=20 MHz, max NSS for MCS %s: Rx=%u, Tx=%u\n", + pre, mcs[i], + mcs_set[i] & 0xf, mcs_set[i] >> 4); + } + + mcs_set += 4; + if (he_phy_cap[0] & (BIT(2) << 8)) { + for (i = 0; i < 3; i++) + printf("%s\t\tEHT bw <= 80 MHz, max NSS for MCS %s: Rx=%u, Tx=%u\n", + pre, mcs[i + 1], + mcs_set[i] & 0xf, mcs_set[i] >> 4); + + } + + mcs_set += 3; + if (he_phy_cap[0] & (BIT(3) << 8)) { + for (i = 0; i < 3; i++) + printf("%s\t\tEHT bw=160 MHz, max NSS for MCS %s: Rx=%u, Tx=%u\n", + pre, mcs[i + 1], + mcs_set[i] & 0xf, mcs_set[i] >> 4); + + } + + mcs_set += 3; + if (band == NL80211_BAND_6GHZ && (phy_cap[0] & BIT(1))) { + for (i = 0; i < 3; i++) + printf("%s\t\tEHT bw=320 MHz, max NSS for MCS %s: Rx=%u, Tx=%u\n", + pre, mcs[i + 1], + mcs_set[i] & 0xf, mcs_set[i] >> 4); + + } + + if (ppet && ppet_len && (phy_cap[1] & BIT(11))) { + printf("%s\t\tEHT PPE Thresholds ", pre); + for (i = 0; i < ppet_len; i++) + if (ppet[i]) + printf("0x%02x ", ppet[i]); + printf("\n"); + } +} + +void print_eht_info(struct nlattr *nl_iftype, int band) +{ + struct nlattr *tb[NL80211_BAND_IFTYPE_ATTR_MAX + 1]; + __u8 mac_cap[2] = { 0 }; + __u32 phy_cap[2] = { 0 }; + __u8 mcs_set[13] = { 0 }; + __u8 ppet[31] = { 0 }; + __u16 he_phy_cap[6] = { 0 }; + size_t len, mcs_len = 0, ppet_len = 0; + + nla_parse(tb, NL80211_BAND_IFTYPE_ATTR_MAX, + nla_data(nl_iftype), nla_len(nl_iftype), NULL); + + if (!tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES]) + return; + + printf("\t\tEHT Iftypes: "); + print_iftype_line(tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES]); + printf("\n"); + + if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC]); + if (len > sizeof(mac_cap)) + len = sizeof(mac_cap); + memcpy(mac_cap, + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC]), + len); + } + + if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]); + + if (len > sizeof(phy_cap)) + len = sizeof(phy_cap); + + memcpy(phy_cap, + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]), + len); + } + + if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET]); + if (len > sizeof(mcs_set)) + len = sizeof(mcs_set); + memcpy(mcs_set, + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET]), + len); + + // Assume that all parts of the MCS set are present + mcs_len = sizeof(mcs_set); + } + + if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE]); + if (len > sizeof(ppet)) + len = sizeof(ppet); + memcpy(ppet, + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE]), + len); + ppet_len = len; + } + + if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]); + + if (len > sizeof(he_phy_cap) - 1) + len = sizeof(he_phy_cap) - 1; + memcpy(&((__u8 *)he_phy_cap)[1], + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]), + len); + } + + __print_eht_capa(band, mac_cap, phy_cap, mcs_set, mcs_len, ppet, ppet_len, + he_phy_cap, true); +} + +void print_he_capability(const uint8_t *ie, int len) +{ + const void *mac_cap, *phy_cap, *mcs_set; + int mcs_len; + int i = 0; + + mac_cap = &ie[i]; + i += 6; + + phy_cap = &ie[i]; + i += 11; + + mcs_set = &ie[i]; + mcs_len = len - i; + + __print_he_capa(mac_cap, (const void *)((const __u8 *)phy_cap - 1), + mcs_set, mcs_len, NULL, 0, false); +} + +void iw_hexdump(const char *prefix, const __u8 *buf, size_t size) +{ + size_t i; printf("%s: ", prefix); for (i = 0; i < size; i++) { @@ -723,3 +1662,83 @@ void iw_hexdump(const char *prefix, const __u8 *buf, size_t size) } printf("\n\n"); } + +int get_cf1(const struct chanmode *chanmode, unsigned long freq) +{ + unsigned int cf1 = freq, j; + unsigned int bw80[] = { 5180, 5260, 5500, 5580, 5660, 5745, + 5955, 6035, 6115, 6195, 6275, 6355, + 6435, 6515, 6595, 6675, 6755, 6835, + 6195, 6995 }; + unsigned int bw160[] = { 5180, 5500, 5955, 6115, 6275, 6435, + 6595, 6755, 6915 }; + + switch (chanmode->width) { + case NL80211_CHAN_WIDTH_80: + /* setup center_freq1 */ + for (j = 0; j < ARRAY_SIZE(bw80); j++) { + if (freq >= bw80[j] && freq < bw80[j] + 80) + break; + } + + if (j == ARRAY_SIZE(bw80)) + break; + + cf1 = bw80[j] + 30; + break; + case NL80211_CHAN_WIDTH_160: + /* setup center_freq1 */ + for (j = 0; j < ARRAY_SIZE(bw160); j++) { + if (freq >= bw160[j] && freq < bw160[j] + 160) + break; + } + + if (j == ARRAY_SIZE(bw160)) + break; + + cf1 = bw160[j] + 70; + break; + default: + cf1 = freq + chanmode->freq1_diff; + break; + } + + return cf1; +} + +int parse_random_mac_addr(struct nl_msg *msg, char *addrs) +{ + char *a_addr, *a_mask, *sep; + unsigned char addr[ETH_ALEN], mask[ETH_ALEN]; + + if (!*addrs) { + /* randomise all but the multicast bit */ + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, + "\x00\x00\x00\x00\x00\x00"); + NLA_PUT(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN, + "\x01\x00\x00\x00\x00\x00"); + return 0; + } + + if (*addrs != '=') + return 1; + + addrs++; + sep = strchr(addrs, '/'); + a_addr = addrs; + + if (!sep) + return 1; + + *sep = 0; + a_mask = sep + 1; + if (mac_addr_a2n(addr, a_addr) || mac_addr_a2n(mask, a_mask)) + return 1; + + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + NLA_PUT(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN, mask); + + return 0; + nla_put_failure: + return -ENOBUFS; +} @@ -1,4 +1,3 @@ -#include <net/if.h> #include <errno.h> #include <string.h> @@ -13,9 +12,37 @@ SECTION(vendor); +static int print_vendor_response(struct nl_msg *msg, void *arg) +{ + struct nlattr *attr; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + bool print_ascii = (bool) arg; + uint8_t *data; + int len; + + attr = nla_find(genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), + NL80211_ATTR_VENDOR_DATA); + if (!attr) { + fprintf(stderr, "vendor data attribute missing!\n"); + return NL_SKIP; + } + + data = (uint8_t *) nla_data(attr); + len = nla_len(attr); + + if (print_ascii) + iw_hexdump("vendor response", data, len); + else + fwrite(data, 1, len, stdout); + + return NL_OK; +} + static int read_file(FILE *file, char *buf, size_t size) { - int data, count = 0; + size_t count = 0; + int data; while ((data = fgetc(file)) != EOF) { if (count >= size) @@ -27,10 +54,10 @@ static int read_file(FILE *file, char *buf, size_t size) return count; } -static int read_hex(int argc, char **argv, char *buf, size_t size) +static int read_hex(unsigned int argc, char **argv, char *buf, size_t size) { - int i, res; - unsigned int data; + unsigned int i, data; + int res; if (argc > size) return -EINVAL; @@ -45,7 +72,7 @@ static int read_hex(int argc, char **argv, char *buf, size_t size) return argc; } -static int handle_vendor(struct nl80211_state *state, struct nl_cb *cb, +static int handle_vendor(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -56,15 +83,19 @@ static int handle_vendor(struct nl80211_state *state, struct nl_cb *cb, FILE *file = NULL; if (argc < 3) - return -EINVAL; + return 1; res = sscanf(argv[0], "0x%x", &oui); - if (res != 1) - return -EINVAL; + if (res != 1) { + printf("Vendor command must start with 0x\n"); + return 2; + } res = sscanf(argv[1], "0x%x", &subcmd); - if (res != 1) - return -EINVAL; + if (res != 1) { + printf("Sub command must start with 0x\n"); + return 2; + } if (!strcmp(argv[2], "-")) file = stdin; @@ -76,7 +107,8 @@ static int handle_vendor(struct nl80211_state *state, struct nl_cb *cb, if (file) { count = read_file(file, buf, sizeof(buf)); - fclose(file); + if (file != stdin) + fclose(file); } else count = read_hex(argc - 2, &argv[2], buf, sizeof(buf)); @@ -89,7 +121,27 @@ static int handle_vendor(struct nl80211_state *state, struct nl_cb *cb, return 0; nla_put_failure: + if (file && file != stdin) + fclose(file); return -ENOBUFS; } +static int handle_vendor_recv(struct nl80211_state *state, + struct nl_msg *msg, int argc, + char **argv, enum id_input id) +{ + register_handler(print_vendor_response, (void *) true); + return handle_vendor(state, msg, argc, argv, id); +} + +static int handle_vendor_recv_bin(struct nl80211_state *state, + struct nl_msg *msg, int argc, + char **argv, enum id_input id) +{ + register_handler(print_vendor_response, (void *) false); + return handle_vendor(state, msg, argc, argv, id); +} + COMMAND(vendor, send, "<oui> <subcmd> <filename|-|hex data>", NL80211_CMD_VENDOR, 0, CIB_NETDEV, handle_vendor, ""); +COMMAND(vendor, recv, "<oui> <subcmd> <filename|-|hex data>", NL80211_CMD_VENDOR, 0, CIB_NETDEV, handle_vendor_recv, ""); +COMMAND(vendor, recvbin, "<oui> <subcmd> <filename|-|hex data>", NL80211_CMD_VENDOR, 0, CIB_NETDEV, handle_vendor_recv_bin, ""); @@ -1,22 +1,40 @@ #!/bin/sh -VERSION="4.1" +VERSION="5.16" OUT="$1" -if [ -d .git ] && head=`git rev-parse --verify HEAD 2>/dev/null`; then - git update-index --refresh --unmerged > /dev/null - descr=$(git describe --match=v*) +# get the absolute path for the OUT file +OUT_NAME=$(basename ${OUT}) +OUT_DIR=$(cd $(dirname ${OUT}); pwd) +OUT="${OUT_DIR}/${OUT_NAME}" + +# the version check should be under the source directory +# where this script is located, instead of the currect directory +# where this script is excuted. +SRC_DIR=$(dirname $0) +SRC_DIR=$(cd ${SRC_DIR}; pwd) +cd "${SRC_DIR}" - # on git builds check that the version number above - # is correct... - [ "${descr%%-*}" = "v$VERSION" ] || exit 2 +v="" +if [ -d .git ] && head=`git rev-parse --verify HEAD 2>/dev/null`; then + git update-index --refresh --unmerged > /dev/null + descr=$(git describe --match=v* 2>/dev/null) + if [ $? -eq 0 ]; then + # on git builds check that the version number above + # is correct... + if [ "${descr%%-*}" = "v$VERSION" ]; then + v="${descr#v}" + if git diff-index --name-only HEAD | read dummy ; then + v="$v"-dirty + fi + fi + fi +fi - v="${descr#v}" - if git diff-index --name-only HEAD | read dummy ; then - v="$v"-dirty - fi -else - v="$VERSION" +# set to the default version when failed to get the version +# information with git +if [ -z "${v}" ]; then + v="$VERSION" fi echo '#include "iw.h"' > "$OUT" @@ -1,4 +1,3 @@ -#include <net/if.h> #include <errno.h> #include <string.h> #include <stdio.h> @@ -160,8 +159,12 @@ static int wowlan_parse_tcp_file(struct nl_msg *msg, const char *fn) tok->offset = atoi(offs); memcpy(tok->token_stream, stream, stream_len); - NLA_PUT(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, - sizeof(*tok) + stream_len, tok); + if (nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, + sizeof(*tok) + stream_len, tok) < 0) { + free(stream); + free(tok); + goto nla_put_failure; + } free(stream); free(tok); } else { @@ -177,7 +180,8 @@ static int wowlan_parse_tcp_file(struct nl_msg *msg, const char *fn) err = -ENOBUFS; close: fclose(f); - nla_nest_end(msg, tcp); + if (tcp) + nla_nest_end(msg, tcp); return err; } @@ -197,7 +201,7 @@ static int wowlan_parse_net_detect(struct nl_msg *msg, int *argc, char ***argv) return err; } -static int handle_wowlan_enable(struct nl80211_state *state, struct nl_cb *cb, +static int handle_wowlan_enable(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -334,7 +338,7 @@ COMMAND(wowlan, enable, "[any] [disconnect] [magic-packet] [gtk-rekey-failure] [ " iw phy0 wowlan enable net-detect interval 5000 delay 30 freqs 2412 2422 matches ssid foo ssid bar"); -static int handle_wowlan_disable(struct nl80211_state *state, struct nl_cb *cb, +static int handle_wowlan_disable(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { @@ -388,9 +392,8 @@ static int print_wowlan_handler(struct nl_msg *msg, void *arg) int rem_match; printf(" * wake up on network detection\n"); - nla_parse(nd, NUM_NL80211_ATTR, - nla_data(trig[NL80211_WOWLAN_TRIG_NET_DETECT]), - nla_len(trig[NL80211_WOWLAN_TRIG_NET_DETECT]), NULL); + nla_parse_nested(nd, NL80211_ATTR_MAX, + trig[NL80211_WOWLAN_TRIG_NET_DETECT], NULL); if (nd[NL80211_ATTR_SCHED_SCAN_INTERVAL]) printf("\tscan interval: %u msecs\n", @@ -405,9 +408,8 @@ static int print_wowlan_handler(struct nl_msg *msg, void *arg) nla_for_each_nested(match, nd[NL80211_ATTR_SCHED_SCAN_MATCH], rem_match) { - nla_parse(tb, NUM_NL80211_ATTR, nla_data(match), - nla_len(match), - NULL); + nla_parse_nested(tb, NL80211_ATTR_MAX, match, + NULL); printf("\t\tSSID: "); print_ssid_escaped( nla_len(tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]), @@ -470,12 +472,11 @@ static int print_wowlan_handler(struct nl_msg *msg, void *arg) return NL_SKIP; } -static int handle_wowlan_show(struct nl80211_state *state, struct nl_cb *cb, +static int handle_wowlan_show(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, - print_wowlan_handler, NULL); + register_handler(print_wowlan_handler, NULL); return 0; } |