pax_global_header00006660000000000000000000000064121404127060014507gustar00rootroot0000000000000052 comment=fe424b2465118eca166b2e901b5a378bf9582fb0 iw-3.10/000077500000000000000000000000001214041270600120515ustar00rootroot00000000000000iw-3.10/.gitignore000066400000000000000000000000541214041270600140400ustar00rootroot00000000000000iw *~ *.o .config version.c iw.8.gz *-stamp iw-3.10/Android.mk000066400000000000000000000010501214041270600137560ustar00rootroot00000000000000LOCAL_PATH := $(call my-dir) IW_SOURCE_DIR := $(LOCAL_PATH) include $(CLEAR_VARS) NO_PKG_CONFIG=y include $(LOCAL_PATH)/Makefile LOCAL_SRC_FILES := $(patsubst %.o,%.c,$(OBJS)) android-nl.c LOCAL_C_INCLUDES := \ $(LOCAL_PATH) \ external/libnl-headers/ LOCAL_CFLAGS += -DCONFIG_LIBNL20 LOCAL_LDFLAGS := -Wl,--no-gc-sections #LOCAL_MODULE_TAGS := optional LOCAL_MODULE_TAGS := eng LOCAL_SHARED_LIBRARIES := libnl_2 LOCAL_MODULE := iw $(IW_SOURCE_DIR)/version.c: $(IW_SOURCE_DIR)/version.sh $(IW_SOURCE_DIR)/version.c include $(BUILD_EXECUTABLE) iw-3.10/COPYING000066400000000000000000000015211214041270600131030ustar00rootroot00000000000000Copyright (c) 2007, 2008 Johannes Berg Copyright (c) 2007 Andy Lutomirski Copyright (c) 2007 Mike Kershaw Copyright (c) 2008-2009 Luis R. Rodriguez Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. iw-3.10/Makefile000066400000000000000000000054361214041270600135210ustar00rootroot00000000000000MAKEFLAGS += --no-print-directory PREFIX ?= /usr SBINDIR ?= $(PREFIX)/sbin MANDIR ?= $(PREFIX)/share/man PKG_CONFIG ?= pkg-config 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 OBJS = iw.o genl.o event.o info.o phy.o \ interface.o ibss.o station.o survey.o util.o \ mesh.o mpath.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 roc.o p2p.o OBJS += sections.o OBJS-$(HWSIM) += hwsim.o OBJS += $(OBJS-y) $(OBJS-Y) ALL = iw ifeq ($(NO_PKG_CONFIG),) NL3xFOUND := $(shell $(PKG_CONFIG) --atleast-version=3.2 libnl-3.0 && echo Y) ifneq ($(NL3xFOUND),Y) NL31FOUND := $(shell $(PKG_CONFIG) --exact-version=3.1 libnl-3.1 && echo Y) ifneq ($(NL31FOUND),Y) NL3FOUND := $(shell $(PKG_CONFIG) --atleast-version=3 libnl-3.0 && echo Y) ifneq ($(NL3FOUND),Y) NL2FOUND := $(shell $(PKG_CONFIG) --atleast-version=2 libnl-2.0 && echo Y) ifneq ($(NL2FOUND),Y) NL1FOUND := $(shell $(PKG_CONFIG) --atleast-version=1 libnl-1 && echo Y) endif endif endif endif ifeq ($(NL1FOUND),Y) NLLIBNAME = libnl-1 endif ifeq ($(NL2FOUND),Y) CFLAGS += -DCONFIG_LIBNL20 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 NLLIBNAME = libnl-3.0 endif ifeq ($(NL3FOUND),Y) CFLAGS += -DCONFIG_LIBNL30 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 NLLIBNAME = libnl-3.1 endif 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)) endif # NO_PKG_CONFIG ifeq ($(V),1) Q= NQ=true else Q=@ NQ=echo 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 ' $@ $(Q)./version.sh $@ %.o: %.c iw.h nl80211.h @$(NQ) ' CC ' $@ $(Q)$(CC) $(CFLAGS) -c -o $@ $< iw: $(OBJS) @$(NQ) ' CC ' iw $(Q)$(CC) $(LDFLAGS) $(OBJS) $(LIBS) -o iw check: $(Q)$(MAKE) all CC="REAL_CC=$(CC) CHECK=\"sparse -Wall\" cgcc" %.gz: % @$(NQ) ' GZIP' $< $(Q)gzip < $< > $@ install: iw iw.8.gz @$(NQ) ' INST iw' $(Q)$(MKDIR) $(DESTDIR)$(SBINDIR) $(Q)$(INSTALL) -m 755 iw $(DESTDIR)$(SBINDIR) @$(NQ) ' INST iw.8' $(Q)$(MKDIR) $(DESTDIR)$(MANDIR)/man8/ $(Q)$(INSTALL) -m 644 iw.8.gz $(DESTDIR)$(MANDIR)/man8/ clean: $(Q)rm -f iw *.o *~ *.gz version.c *-stamp iw-3.10/README000066400000000000000000000007201214041270600127300ustar00rootroot00000000000000 This is 'iw', a tool to use nl80211. To build iw, just enter 'make'. If that fails, set the PKG_CONFIG_PATH environment variable to allow the Makefile 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. Please send all patches to Johannes Berg and CC linux-wireless@vger.kernel.org for community review. iw-3.10/android-nl.c000066400000000000000000000001631214041270600142440ustar00rootroot00000000000000#include int nla_put_flag(struct nl_msg *msg, int flag) { return nla_put(msg, flag, 0, NULL); } iw-3.10/bitrate.c000066400000000000000000000057701214041270600136600ustar00rootroot00000000000000#include #include "nl80211.h" #include "iw.h" static int handle_bitrates(struct nl80211_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { struct nlattr *nl_rates, *nl_band; int i; 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; uint8_t *legacy = NULL; int *n_legacy = NULL; bool have_mcs_24 = false, have_mcs_5 = false; uint8_t mcs_24[77], mcs_5[77]; int n_mcs_24 = 0, n_mcs_5 = 0; uint8_t *mcs = NULL; int *n_mcs = NULL; enum { S_NONE, S_LEGACY, S_MCS, } parser_state = S_NONE; for (i = 0; i < argc; i++) { char *end; double tmpd; long tmpl; if (strcmp(argv[i], "legacy-2.4") == 0) { if (have_legacy_24) return 1; parser_state = S_LEGACY; legacy = legacy_24; n_legacy = &n_legacy_24; have_legacy_24 = true; } else if (strcmp(argv[i], "legacy-5") == 0) { if (have_legacy_5) return 1; parser_state = S_LEGACY; legacy = legacy_5; n_legacy = &n_legacy_5; have_legacy_5 = true; } else if (strcmp(argv[i], "mcs-2.4") == 0) { if (have_mcs_24) return 1; parser_state = S_MCS; mcs = mcs_24; n_mcs = &n_mcs_24; have_mcs_24 = true; } else if (strcmp(argv[i], "mcs-5") == 0) { if (have_mcs_5) return 1; parser_state = S_MCS; mcs = mcs_5; n_mcs = &n_mcs_5; have_mcs_5 = true; } else switch (parser_state) { case S_LEGACY: tmpd = strtod(argv[i], &end); if (*end != '\0') return 1; if (tmpd < 1 || tmpd > 255 * 2) return 1; legacy[(*n_legacy)++] = tmpd * 2; break; case S_MCS: tmpl = strtol(argv[i], &end, 0); if (*end != '\0') return 1; if (tmpl < 0 || tmpl > 255) return 1; mcs[(*n_mcs)++] = tmpl; break; default: return 1; } } nl_rates = nla_nest_start(msg, NL80211_ATTR_TX_RATES); if (!nl_rates) goto nla_put_failure; if (have_legacy_24 || have_mcs_24) { nl_band = nla_nest_start(msg, NL80211_BAND_2GHZ); if (!nl_band) goto nla_put_failure; if (have_legacy_24) nla_put(msg, NL80211_TXRATE_LEGACY, n_legacy_24, legacy_24); if (have_mcs_24) nla_put(msg, NL80211_TXRATE_MCS, n_mcs_24, mcs_24); nla_nest_end(msg, nl_band); } if (have_legacy_5 || have_mcs_5) { nl_band = nla_nest_start(msg, NL80211_BAND_5GHZ); if (!nl_band) goto nla_put_failure; if (have_legacy_5) nla_put(msg, NL80211_TXRATE_LEGACY, n_legacy_5, legacy_5); if (have_mcs_5) nla_put(msg, NL80211_TXRATE_MCS, n_mcs_5, mcs_5); nla_nest_end(msg, nl_band); } nla_nest_end(msg, nl_rates); return 0; nla_put_failure: return -ENOBUFS; } #define DESCR_LEGACY "[legacy-<2.4|5> *]" #define DESCR DESCR_LEGACY " [mcs-<2.4|5> *]" COMMAND(set, bitrates, "[legacy-<2.4|5> *] [mcs-<2.4|5> *]", 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)."); iw-3.10/connect.c000066400000000000000000000112501214041270600136450ustar00rootroot00000000000000#include #include #include #include #include #include #include "nl80211.h" #include "iw.h" static int iw_conn(struct nl80211_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { char *end; unsigned char bssid[6]; int freq; if (argc < 1) return 1; /* SSID */ NLA_PUT(msg, NL80211_ATTR_SSID, strlen(argv[0]), argv[0]); argv++; argc--; /* freq */ if (argc) { freq = strtoul(argv[0], &end, 10); if (*end == '\0') { NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); argv++; argc--; } } /* bssid */ if (argc) { if (mac_addr_a2n(bssid, argv[0]) == 0) { NLA_PUT(msg, NL80211_ATTR_MAC, 6, bssid); 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; } static int disconnect(struct nl80211_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { return 0; } 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, struct nl_msg *msg, int argc, char **argv, enum id_input id) { char **conn_argv, *dev = argv[0]; static const __u32 cmds[] = { NL80211_CMD_CONNECT, }; struct print_event_args printargs = { }; int conn_argc, err; bool wait = false; int i; /* strip "wlan0 connect" */ argc -= 2; argv += 2; /* check -w */ if (argc && strcmp(argv[0], "-w") == 0) { wait = true; argc--; argv++; } conn_argc = 3 + argc; conn_argv = calloc(conn_argc, sizeof(*conn_argv)); if (!conn_argv) return -ENOMEM; err = __prepare_listen_events(state); if (err) return err; conn_argv[0] = dev; conn_argv[1] = "connect"; conn_argv[2] = "establish"; for (i = 0; i < argc; i++) conn_argv[i + 3] = argv[i]; err = handle_cmd(state, id, conn_argc, conn_argv); free(conn_argv); if (err) return err; if (!wait) return 0; /* * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION * * This code has a bug: * * It is possible for a connect result message from another * connect attempt to be processed here first, because we * start listening to the multicast group before starting * our own connect request, which may succeed but we get a * fail message from a previous attempt that raced with us, * or similar. * * The only proper way to fix this would be to listen to events * before sending the command, and for the kernel to send the * connect request or a cookie along with the event, so that you * can match up whether the connect _you_ requested was finished * or aborted. * * Alas, the kernel doesn't do that (yet). */ __do_listen_events(state, ARRAY_SIZE(cmds), cmds, &printargs); return 0; } TOPLEVEL(connect, "[-w] [] [] [key 0:abcde d:1:6162636465]", 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, struct nl_msg *msg, int argc, char **argv, enum id_input id) { char *end; unsigned char bssid[6]; int freq; bool need_key = false; if (argc < 4) return 1; /* SSID */ NLA_PUT(msg, NL80211_ATTR_SSID, strlen(argv[0]), argv[0]); argv++; argc--; /* bssid */ if (mac_addr_a2n(bssid, argv[0]) == 0) { NLA_PUT(msg, NL80211_ATTR_MAC, 6, bssid); argv++; argc--; } else { return 1; } /* FIXME */ 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--; freq = strtoul(argv[0], &end, 10); if (*end == '\0') { NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); argv++; argc--; } else { return 1; } if (!argc && need_key) return 1; if (argc && !need_key) return 1; 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; } TOPLEVEL(auth, " [key 0:abcde d:1:6162636465]", NL80211_CMD_AUTHENTICATE, 0, CIB_NETDEV, iw_auth, "Authenticate with the given network.\n"); iw-3.10/cqm.c000066400000000000000000000022441214041270600127770ustar00rootroot00000000000000#include #include #include #include #include #include #include "nl80211.h" #include "iw.h" static int iw_cqm_rssi(struct nl80211_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { struct nl_msg *cqm = NULL; int thold = 0; int hyst = 0; int ret = -ENOSPC; /* get the required args */ if (argc < 1 || argc > 2) return 1; if (strcmp(argv[0], "off")) { thold = atoi(argv[0]); if (thold == 0) return -EINVAL; if (argc == 2) hyst = atoi(argv[1]); } /* connection quality monitor attributes */ cqm = nlmsg_alloc(); NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, thold); NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hyst); nla_put_nested(msg, NL80211_ATTR_CQM, cqm); ret = 0; nla_put_failure: nlmsg_free(cqm); return ret; } TOPLEVEL(cqm, "", 0, 0, CIB_NETDEV, NULL, "Configure the WLAN connection quality monitor.\n"); COMMAND(cqm, rssi, " []", NL80211_CMD_SET_CQM, 0, CIB_NETDEV, iw_cqm_rssi, "Set connection quality monitor RSSI threshold.\n"); iw-3.10/event.c000066400000000000000000000444571214041270600133540ustar00rootroot00000000000000#include #include #include #include #include "iw.h" static int no_seq_check(struct nl_msg *msg, void *arg) { return NL_OK; } struct ieee80211_beacon_channel { __u16 center_freq; bool passive_scan; bool no_ibss; }; static int parse_beacon_hint_chan(struct nlattr *tb, struct ieee80211_beacon_channel *chan) { struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; static struct nla_policy beacon_freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, }; if (nla_parse_nested(tb_freq, NL80211_FREQUENCY_ATTR_MAX, tb, beacon_freq_policy)) return -EINVAL; chan->center_freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) chan->passive_scan = true; if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) chan->no_ibss = true; return 0; } static void print_frame(struct print_event_args *args, struct nlattr *attr) { uint8_t *frame; size_t len; int i; char macbuf[6*3]; uint16_t tmp; if (!attr) printf(" [no frame]"); frame = nla_data(attr); len = nla_len(attr); if (len < 26) { printf(" [invalid frame: "); goto print_frame; } mac_addr_n2a(macbuf, frame + 10); printf(" %s -> ", macbuf); mac_addr_n2a(macbuf, frame + 4); printf("%s", macbuf); switch (frame[0] & 0xfc) { case 0x10: /* assoc resp */ case 0x30: /* reassoc resp */ /* status */ tmp = (frame[27] << 8) + frame[26]; printf(" status: %d: %s", tmp, get_status_str(tmp)); break; case 0x00: /* assoc req */ case 0x20: /* reassoc req */ break; case 0xb0: /* auth */ /* status */ tmp = (frame[29] << 8) + frame[28]; printf(" status: %d: %s", tmp, get_status_str(tmp)); break; break; case 0xa0: /* disassoc */ case 0xc0: /* deauth */ /* reason */ tmp = (frame[25] << 8) + frame[24]; printf(" reason %d: %s", tmp, get_reason_str(tmp)); break; } if (!args->frame) return; printf(" [frame:"); print_frame: for (i = 0; i < len; i++) printf(" %.02x", frame[i]); printf("]"); } static void parse_cqm_event(struct nlattr **attrs) { static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = { [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, }; struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1]; struct nlattr *cqm_attr = attrs[NL80211_ATTR_CQM]; printf("CQM event: "); if (!cqm_attr || nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, cqm_attr, cqm_policy)) { printf("missing data!\n"); return; } if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]) { enum nl80211_cqm_rssi_threshold_event rssi_event; bool found_one = false; rssi_event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]); switch (rssi_event) { case NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: printf("RSSI went above threshold\n"); found_one = true; break; case NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW: printf("RSSI went below threshold\n"); found_one = true; break; case NL80211_CQM_RSSI_BEACON_LOSS_EVENT: printf("Beacon loss detected\n"); found_one = true; break; } if (!found_one) printf("Unknown event type: %i\n", rssi_event); } else if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT] && attrs[NL80211_ATTR_MAC]) { uint32_t frames; char buf[3*6]; frames = nla_get_u32(cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]); mac_addr_n2a(buf, nla_data(attrs[NL80211_ATTR_MAC])); printf("peer %s didn't ACK %d packets\n", buf, frames); } else printf("unknown event\n"); } static const char * key_type_str(enum nl80211_key_type key_type) { static char buf[30]; switch (key_type) { case NL80211_KEYTYPE_GROUP: return "Group"; case NL80211_KEYTYPE_PAIRWISE: return "Pairwise"; case NL80211_KEYTYPE_PEERKEY: return "PeerKey"; default: snprintf(buf, sizeof(buf), "unknown(%d)", key_type); return buf; } } static void parse_mic_failure(struct nlattr **attrs) { printf("Michael MIC failure event:"); if (attrs[NL80211_ATTR_MAC]) { char addr[3 * ETH_ALEN]; mac_addr_n2a(addr, nla_data(attrs[NL80211_ATTR_MAC])); printf(" source MAC address %s", addr); } if (attrs[NL80211_ATTR_KEY_SEQ] && nla_len(attrs[NL80211_ATTR_KEY_SEQ]) == 6) { unsigned char *seq = nla_data(attrs[NL80211_ATTR_KEY_SEQ]); printf(" seq=%02x%02x%02x%02x%02x%02x", seq[0], seq[1], seq[2], seq[3], seq[4], seq[5]); } if (attrs[NL80211_ATTR_KEY_TYPE]) { enum nl80211_key_type key_type = nla_get_u32(attrs[NL80211_ATTR_KEY_TYPE]); printf(" Key Type %s", key_type_str(key_type)); } if (attrs[NL80211_ATTR_KEY_IDX]) { __u8 key_id = nla_get_u8(attrs[NL80211_ATTR_KEY_IDX]); printf(" Key Id %d", key_id); } printf("\n"); } static void parse_wowlan_wake_event(struct nlattr **attrs) { struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG]; printf("WoWLAN wakeup\n"); if (!attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { printf("\twakeup not due to WoWLAN\n"); return; } nla_parse(tb, MAX_NL80211_WOWLAN_TRIG, nla_data(attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), nla_len(attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), NULL); if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) printf("\t* was disconnected\n"); if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) printf("\t* magic packet received\n"); if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) printf("\t* pattern index: %u\n", nla_get_u32(tb[NL80211_WOWLAN_TRIG_PKT_PATTERN])); if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) printf("\t* GTK rekey failure\n"); if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) printf("\t* EAP identity request\n"); if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) printf("\t* 4-way handshake\n"); if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) printf("\t* RF-kill released\n"); if (tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211]) { uint8_t *d = nla_data(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211]); int l = nla_len(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211]); int i; printf("\t* packet (might be truncated): "); for (i = 0; i < l; i++) { if (i > 0) printf(":"); printf("%.2x", d[i]); } printf("\n"); } if (tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023]) { uint8_t *d = nla_data(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023]); int l = nla_len(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023]); int i; printf("\t* packet (might be truncated): "); for (i = 0; i < l; i++) { if (i > 0) printf(":"); printf("%.2x", d[i]); } printf("\n"); } if (tb[NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH]) printf("\t* TCP connection wakeup received\n"); if (tb[NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST]) printf("\t* TCP connection lost\n"); if (tb[NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS]) printf("\t* TCP connection ran out of tokens\n"); } static int print_event(struct nl_msg *msg, void *arg) { struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *tb[NL80211_ATTR_MAX + 1], *nst; struct print_event_args *args = arg; char ifname[100]; char macbuf[6*3]; __u8 reg_type; struct ieee80211_beacon_channel chan_before_beacon, chan_after_beacon; __u32 wiphy_idx = 0; int rem_nst; __u16 status; if (args->time || args->reltime) { 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; args->have_ts = true; } else usecs -= previous; } 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])); } 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]), nla_get_u32(tb[NL80211_ATTR_WIPHY])); } else if (tb[NL80211_ATTR_IFINDEX]) { if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname); printf("%s: ", ifname); } else if (tb[NL80211_ATTR_WDEV]) { printf("wdev 0x%llx: ", (unsigned long long)nla_get_u64(tb[NL80211_ATTR_WDEV])); } else if (tb[NL80211_ATTR_WIPHY]) { printf("phy #%d: ", nla_get_u32(tb[NL80211_ATTR_WIPHY])); } switch (gnlh->cmd) { case NL80211_CMD_NEW_WIPHY: printf("renamed to %s\n", nla_get_string(tb[NL80211_ATTR_WIPHY_NAME])); break; case NL80211_CMD_TRIGGER_SCAN: printf("scan started\n"); break; case NL80211_CMD_NEW_SCAN_RESULTS: printf("scan finished:"); case NL80211_CMD_SCAN_ABORTED: if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED) printf("scan aborted:"); if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { nla_for_each_nested(nst, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem_nst) printf(" %d", nla_get_u32(nst)); printf(","); } if (tb[NL80211_ATTR_SCAN_SSIDS]) { nla_for_each_nested(nst, tb[NL80211_ATTR_SCAN_SSIDS], rem_nst) { printf(" \""); print_ssid_escaped(nla_len(nst), nla_data(nst)); printf("\""); } } printf("\n"); break; case NL80211_CMD_REG_CHANGE: printf("regulatory domain change: "); reg_type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]); switch (reg_type) { case NL80211_REGDOM_TYPE_COUNTRY: printf("set to %s by %s request", nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]), reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]))); if (tb[NL80211_ATTR_WIPHY]) printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY])); break; case NL80211_REGDOM_TYPE_WORLD: printf("set to world roaming by %s request", reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]))); break; case NL80211_REGDOM_TYPE_CUSTOM_WORLD: printf("custom world roaming rules in place on phy%d by %s request", nla_get_u32(tb[NL80211_ATTR_WIPHY]), reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR]))); break; case NL80211_REGDOM_TYPE_INTERSECTION: printf("intersection used due to a request made by %s", reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR]))); if (tb[NL80211_ATTR_WIPHY]) printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY])); break; default: printf("unknown source (upgrade this utility)"); break; } printf("\n"); break; case NL80211_CMD_REG_BEACON_HINT: wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]); memset(&chan_before_beacon, 0, sizeof(chan_before_beacon)); memset(&chan_after_beacon, 0, sizeof(chan_after_beacon)); if (parse_beacon_hint_chan(tb[NL80211_ATTR_FREQ_BEFORE], &chan_before_beacon)) break; if (parse_beacon_hint_chan(tb[NL80211_ATTR_FREQ_AFTER], &chan_after_beacon)) break; if (chan_before_beacon.center_freq != chan_after_beacon.center_freq) break; /* A beacon hint is sent _only_ if something _did_ change */ printf("beacon hint:\n"); printf("phy%d %d MHz [%d]:\n", wiphy_idx, chan_before_beacon.center_freq, ieee80211_frequency_to_channel(chan_before_beacon.center_freq)); if (chan_before_beacon.passive_scan && !chan_after_beacon.passive_scan) printf("\to active scanning enabled\n"); if (chan_before_beacon.no_ibss && !chan_after_beacon.no_ibss) printf("\to beaconing enabled\n"); break; case NL80211_CMD_NEW_STATION: mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); printf("new station %s\n", macbuf); break; case NL80211_CMD_DEL_STATION: mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); printf("del station %s\n", macbuf); break; case NL80211_CMD_JOIN_IBSS: mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); printf("IBSS %s joined\n", macbuf); break; case NL80211_CMD_AUTHENTICATE: printf("auth"); if (tb[NL80211_ATTR_FRAME]) print_frame(args, tb[NL80211_ATTR_FRAME]); else if (tb[NL80211_ATTR_TIMED_OUT]) printf(": timed out"); else printf(": unknown event"); printf("\n"); break; case NL80211_CMD_ASSOCIATE: printf("assoc"); if (tb[NL80211_ATTR_FRAME]) print_frame(args, tb[NL80211_ATTR_FRAME]); else if (tb[NL80211_ATTR_TIMED_OUT]) printf(": timed out"); else printf(": unknown event"); printf("\n"); break; case NL80211_CMD_DEAUTHENTICATE: printf("deauth"); print_frame(args, tb[NL80211_ATTR_FRAME]); printf("\n"); break; case NL80211_CMD_DISASSOCIATE: printf("disassoc"); print_frame(args, tb[NL80211_ATTR_FRAME]); printf("\n"); break; case NL80211_CMD_UNPROT_DEAUTHENTICATE: printf("unprotected deauth"); print_frame(args, tb[NL80211_ATTR_FRAME]); printf("\n"); break; case NL80211_CMD_UNPROT_DISASSOCIATE: printf("unprotected disassoc"); print_frame(args, tb[NL80211_ATTR_FRAME]); printf("\n"); break; case NL80211_CMD_CONNECT: status = 0; if (!tb[NL80211_ATTR_STATUS_CODE]) printf("unknown connect status"); else if (nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]) == 0) printf("connected"); else { status = nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]); printf("failed to connect"); } if (tb[NL80211_ATTR_MAC]) { mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); printf(" to %s", macbuf); } if (status) printf(", status: %d: %s", status, get_status_str(status)); printf("\n"); break; case NL80211_CMD_ROAM: printf("roamed"); if (tb[NL80211_ATTR_MAC]) { mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); printf(" to %s", macbuf); } printf("\n"); break; case NL80211_CMD_DISCONNECT: printf("disconnected"); if (tb[NL80211_ATTR_DISCONNECTED_BY_AP]) printf(" (by AP)"); else printf(" (local request)"); if (tb[NL80211_ATTR_REASON_CODE]) printf(" reason: %d: %s", nla_get_u16(tb[NL80211_ATTR_REASON_CODE]), get_reason_str(nla_get_u16(tb[NL80211_ATTR_REASON_CODE]))); printf("\n"); break; case NL80211_CMD_REMAIN_ON_CHANNEL: printf("remain on freq %d (%dms, cookie %llx)\n", nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]), nla_get_u32(tb[NL80211_ATTR_DURATION]), (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE])); break; case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: printf("done with remain 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; case NL80211_CMD_MICHAEL_MIC_FAILURE: parse_mic_failure(tb); break; case NL80211_CMD_FRAME_TX_STATUS: printf("mgmt 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; case NL80211_CMD_SET_WOWLAN: parse_wowlan_wake_event(tb); break; case NL80211_CMD_PROBE_CLIENT: if (tb[NL80211_ATTR_MAC]) mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); else strcpy(macbuf, "??"); printf("probe client %s (cookie %llx): %s\n", macbuf, (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]), tb[NL80211_ATTR_ACK] ? "acked" : "no ack"); break; default: printf("unknown event %d\n", gnlh->cmd); break; } fflush(stdout); return NL_SKIP; } struct wait_event { int n_cmds; const __u32 *cmds; __u32 cmd; struct print_event_args *pargs; }; static int wait_event(struct nl_msg *msg, void *arg) { struct wait_event *wait = 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) print_event(msg, wait->pargs); } } return NL_SKIP; } int __prepare_listen_events(struct nl80211_state *state) { int mcid, ret; /* Configuration multicast group */ mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "config"); if (mcid < 0) return mcid; ret = nl_socket_add_membership(state->nl_sock, mcid); if (ret) return ret; /* Scan multicast group */ mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "scan"); if (mcid >= 0) { ret = nl_socket_add_membership(state->nl_sock, mcid); if (ret) return ret; } /* Regulatory multicast group */ mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "regulatory"); if (mcid >= 0) { ret = nl_socket_add_membership(state->nl_sock, mcid); if (ret) return ret; } /* MLME multicast group */ mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "mlme"); 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, struct print_event_args *args) { struct nl_cb *cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); struct wait_event wait_ev; if (!cb) { fprintf(stderr, "failed to allocate netlink callbacks\n"); return -ENOMEM; } /* no sequence checking for multicast messages */ nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); if (n_waits && waits) { wait_ev.cmds = waits; wait_ev.n_cmds = n_waits; wait_ev.pargs = args; nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, wait_event, &wait_ev); } else nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_event, args); wait_ev.cmd = 0; while (!wait_ev.cmd) nl_recvmsgs(state->nl_sock, cb); nl_cb_put(cb); return wait_ev.cmd; } __u32 listen_events(struct nl80211_state *state, const int n_waits, const __u32 *waits) { int ret; ret = __prepare_listen_events(state); if (ret) return ret; return __do_listen_events(state, n_waits, waits, 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 ret; memset(&args, 0, sizeof(args)); argc--; argv++; while (argc > 0) { if (strcmp(argv[0], "-f") == 0) args.frame = true; else if (strcmp(argv[0], "-t") == 0) args.time = true; else if (strcmp(argv[0], "-r") == 0) args.reltime = true; else return 1; argc--; argv++; } if (args.time && args.reltime) return 1; if (argc) return 1; ret = __prepare_listen_events(state); if (ret) return ret; return __do_listen_events(state, 0, NULL, &args); } TOPLEVEL(event, "[-t] [-r] [-f]", 0, 0, CIB_NONE, print_events, "Monitor events from the kernel.\n" "-t - print timestamp\n" "-r - print relative timstamp\n" "-f - print full frame for auth/assoc etc."); iw-3.10/genl.c000066400000000000000000000046151214041270600131500ustar00rootroot00000000000000/* * This ought to be provided by libnl */ #include #include #include #include #include #include #include #include "iw.h" static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) { int *ret = arg; *ret = err->error; return NL_STOP; } static int ack_handler(struct nl_msg *msg, void *arg) { int *ret = arg; *ret = 0; return NL_STOP; } struct handler_args { const char *group; int id; }; static int family_handler(struct nl_msg *msg, void *arg) { struct handler_args *grp = arg; struct nlattr *tb[CTRL_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *mcgrp; int rem_mcgrp; nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb[CTRL_ATTR_MCAST_GROUPS]) return NL_SKIP; nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp) { struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1]; nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp), nla_len(mcgrp), NULL); if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] || !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]) continue; if (strncmp(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]), grp->group, nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]))) continue; grp->id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]); break; } return NL_SKIP; } int nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group) { struct nl_msg *msg; struct nl_cb *cb; int ret, ctrlid; struct handler_args grp = { .group = group, .id = -ENOENT, }; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; cb = nl_cb_alloc(NL_CB_DEFAULT); if (!cb) { ret = -ENOMEM; goto out_fail_cb; } ctrlid = genl_ctrl_resolve(sock, "nlctrl"); genlmsg_put(msg, 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0); ret = -ENOBUFS; NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family); ret = nl_send_auto_complete(sock, msg); if (ret < 0) goto out; ret = 1; nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret); nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, family_handler, &grp); while (ret > 0) nl_recvmsgs(sock, cb); if (ret == 0) ret = grp.id; nla_put_failure: out: nl_cb_put(cb); out_fail_cb: nlmsg_free(msg); return ret; } iw-3.10/hwsim.c000066400000000000000000000071071214041270600133510ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include "nl80211.h" #include "iw.h" /* These enums need to be kept in sync with the kernel */ enum hwsim_testmode_attr { __HWSIM_TM_ATTR_INVALID = 0, HWSIM_TM_ATTR_CMD = 1, HWSIM_TM_ATTR_PS = 2, /* keep last */ __HWSIM_TM_ATTR_AFTER_LAST, HWSIM_TM_ATTR_MAX = __HWSIM_TM_ATTR_AFTER_LAST - 1 }; enum hwsim_testmode_cmd { HWSIM_TM_CMD_SET_PS = 0, HWSIM_TM_CMD_GET_PS = 1, HWSIM_TM_CMD_STOP_QUEUES = 2, HWSIM_TM_CMD_WAKE_QUEUES = 3, }; SECTION(hwsim); static int print_hwsim_ps_handler(struct nl_msg *msg, void *arg) { struct nlattr *attrs[NL80211_ATTR_MAX + 1]; struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!attrs[NL80211_ATTR_TESTDATA]) return NL_SKIP; nla_parse(tb, HWSIM_TM_ATTR_MAX, nla_data(attrs[NL80211_ATTR_TESTDATA]), nla_len(attrs[NL80211_ATTR_TESTDATA]), NULL); printf("HWSIM PS: %d\n", nla_get_u32(tb[HWSIM_TM_ATTR_PS])); return NL_SKIP; } static int handle_hwsim_getps(struct nl80211_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { struct nlattr *tmdata; tmdata = nla_nest_start(msg, NL80211_ATTR_TESTDATA); if (!tmdata) goto nla_put_failure; NLA_PUT_U32(msg, HWSIM_TM_ATTR_CMD, HWSIM_TM_CMD_GET_PS); nla_nest_end(msg, tmdata); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, 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, struct nl_msg *msg, int argc, char **argv, enum id_input id) { struct nlattr *tmdata; __u32 ps; char *end; if (argc != 1) return 1; ps = strtoul(argv[0], &end, 0); if (*end) return 1; tmdata = nla_nest_start(msg, NL80211_ATTR_TESTDATA); if (!tmdata) goto nla_put_failure; NLA_PUT_U32(msg, HWSIM_TM_ATTR_CMD, HWSIM_TM_CMD_SET_PS); NLA_PUT_U32(msg, HWSIM_TM_ATTR_PS, ps); nla_nest_end(msg, tmdata); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_hwsim_ps_handler, NULL); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(hwsim, setps, "", NL80211_CMD_TESTMODE, 0, CIB_PHY, handle_hwsim_setps, ""); static int handle_hwsim_stop_queues(struct nl80211_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { struct nlattr *tmdata; if (argc != 0) return 1; tmdata = nla_nest_start(msg, NL80211_ATTR_TESTDATA); if (!tmdata) goto nla_put_failure; NLA_PUT_U32(msg, HWSIM_TM_ATTR_CMD, HWSIM_TM_CMD_STOP_QUEUES); nla_nest_end(msg, tmdata); return 0; nla_put_failure: return -ENOBUFS; } 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, struct nl_msg *msg, int argc, char **argv, enum id_input id) { struct nlattr *tmdata; if (argc != 0) return 1; tmdata = nla_nest_start(msg, NL80211_ATTR_TESTDATA); if (!tmdata) goto nla_put_failure; NLA_PUT_U32(msg, HWSIM_TM_ATTR_CMD, HWSIM_TM_CMD_WAKE_QUEUES); nla_nest_end(msg, tmdata); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(hwsim, wakequeues, "", NL80211_CMD_TESTMODE, 0, CIB_PHY, handle_hwsim_wake_queues, ""); iw-3.10/ibss.c000066400000000000000000000075641214041270600131710ustar00rootroot00000000000000#ifndef _POSIX_SOURCE #define _POSIX_SOURCE #endif #include #include #include #include #include #include #include #include #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; 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; 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, }, { .name = "NOHT", .val = NL80211_CHAN_NO_HT, }, }; unsigned int htval; if (argc < 2) return 1; /* SSID */ NLA_PUT(msg, NL80211_ATTR_SSID, strlen(argv[0]), argv[0]); argv++; argc--; /* freq */ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, strtoul(argv[0], &end, 10)); if (*end != '\0') return 1; argv++; argc--; if (argc) { for (i = 0; i < ARRAY_SIZE(htmap); i++) { if (strcasecmp(htmap[i].name, argv[0]) == 0) { htval = htmap[i].val; break; } } if (i != ARRAY_SIZE(htmap)) { NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, htval); argv++; argc--; } } if (argc && strcmp(argv[0], "fixed-freq") == 0) { NLA_PUT_FLAG(msg, NL80211_ATTR_FREQ_FIXED); argv++; argc--; } if (argc) { if (mac_addr_a2n(abssid, argv[0]) == 0) { NLA_PUT(msg, NL80211_ATTR_MAC, 6, abssid); argv++; argc--; } } if (argc > 1 && strcmp(argv[0], "beacon-interval") == 0) { argv++; argc--; bintval = strtoul(argv[0], &end, 10); if (*end != '\0') return 1; NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, bintval); argv++; argc--; } /* basic rates */ if (argc > 1 && strcmp(argv[0], "basic-rates") == 0) { argv++; argc--; value = strtok_r(argv[0], ",", &sptr); while (value && n_rates < NL80211_MAX_SUPP_RATES) { rate = strtod(value, &end); rates[n_rates] = rate * 2; /* filter out suspicious values */ if (*end != '\0' || !rates[n_rates] || rate*2 != rates[n_rates]) return 1; n_rates++; value = strtok_r(NULL, ",", &sptr); } NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, n_rates, rates); argv++; argc--; } /* multicast rate */ if (argc > 1 && strcmp(argv[0], "mcast-rate") == 0) { argv++; argc--; rate = strtod(argv[0], &end); if (*end != '\0') return 1; NLA_PUT_U32(msg, NL80211_ATTR_MCAST_RATE, (int)(rate * 10)); 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; } static int leave_ibss(struct nl80211_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { return 0; } COMMAND(ibss, leave, NULL, NL80211_CMD_LEAVE_IBSS, 0, CIB_NETDEV, leave_ibss, "Leave the current IBSS cell."); COMMAND(ibss, join, " [HT20|HT40+|HT40-|NOHT] [fixed-freq] [] [beacon-interval ]" " [basic-rates ] [mcast-rate ] " "[key d:0:abcde]", NL80211_CMD_JOIN_IBSS, 0, CIB_NETDEV, join_ibss, "Join the IBSS cell with the given SSID, if it doesn't exist create\n" "it on the given frequency. When fixed frequency is requested, don't\n" "join/create a cell on a different frequency. When a fixed BSSID is\n" "requested use that BSSID and do not adopt another cell's BSSID even\n" "if it has higher TSF and the same SSID. If an IBSS is created, create\n" "it with the specified basic-rates, multicast-rate and beacon-interval."); iw-3.10/ieee80211.h000066400000000000000000000030721214041270600135270ustar00rootroot00000000000000#ifndef __IEEE80211 #define __IEEE80211 /* 802.11n HT capability AMPDU settings (for ampdu_params_info) */ #define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03 #define IEEE80211_HT_AMPDU_PARM_DENSITY 0x1C #define IEEE80211_HT_CAP_SUP_WIDTH_20_40 0x0002 #define IEEE80211_HT_CAP_SGI_40 0x0040 #define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 #define IEEE80211_HT_MCS_MASK_LEN 10 /** * struct ieee80211_mcs_info - MCS information * @rx_mask: RX mask * @rx_highest: highest supported RX rate. If set represents * the highest supported RX data rate in units of 1 Mbps. * If this field is 0 this value should not be used to * consider the highest RX data rate supported. * @tx_params: TX parameters */ struct ieee80211_mcs_info { __u8 rx_mask[IEEE80211_HT_MCS_MASK_LEN]; __u16 rx_highest; __u8 tx_params; __u8 reserved[3]; } __attribute__ ((packed)); /** * struct ieee80211_ht_cap - HT capabilities * * This structure is the "HT capabilities element" as * described in 802.11n D5.0 7.3.2.57 */ struct ieee80211_ht_cap { __u16 cap_info; __u8 ampdu_params_info; /* 16 bytes MCS information */ struct ieee80211_mcs_info mcs; __u16 extended_ht_cap_info; __u32 tx_BF_cap_info; __u8 antenna_selection_info; } __attribute__ ((packed)); struct ieee80211_vht_mcs_info { __u16 rx_vht_mcs; __u16 rx_highest; __u16 tx_vht_mcs; __u16 tx_highest; } __attribute__ ((packed)); struct ieee80211_vht_cap { __u32 cap_info; struct ieee80211_vht_mcs_info mcs; } __attribute__ ((packed)); #endif /* __IEEE80211 */ iw-3.10/info.c000066400000000000000000000505611214041270600131570ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include "nl80211.h" #include "iw.h" static void print_flag(const char *name, int *open) { if (!*open) printf(" ("); else printf(", "); printf("%s", name); *open = 1; } static char *cipher_name(__u32 c) { static char buf[20]; switch (c) { case 0x000fac01: return "WEP40 (00-0f-ac:1)"; case 0x000fac05: return "WEP104 (00-0f-ac:5)"; case 0x000fac02: return "TKIP (00-0f-ac:2)"; case 0x000fac04: return "CCMP (00-0f-ac:4)"; case 0x000fac06: return "CMAC (00-0f-ac:6)"; case 0x000fac08: return "GCMP (00-0f-ac:8)"; case 0x00147201: return "WPI-SMS4 (00-14-72:1)"; default: sprintf(buf, "%.2x-%.2x-%.2x:%d", c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff); return buf; } } 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_phy_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, }; struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = { [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 }, [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG }, }; 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 open; /* * static variables only work here, other applications need to use the * callback pointer and store them there so they can be multithreaded * and/or have multiple netlink sockets, etc. */ static int64_t phy_id = -1; static int last_band = -1; static bool band_had_freq = false; bool print_name = true; nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb_msg[NL80211_ATTR_WIPHY]) { if (nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]) == phy_id) print_name = false; else last_band = -1; phy_id = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]); } if (print_name && tb_msg[NL80211_ATTR_WIPHY_NAME]) printf("Wiphy %s\n", nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME])); /* 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) { if (last_band != nl_band->nla_type) { printf("\tBand %d:\n", nl_band->nla_type + 1); band_had_freq = false; } 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]); print_ht_capability(cap); } if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) { __u8 exponent = nla_get_u8(tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]); print_ampdu_length(exponent); } if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) { __u8 spacing = nla_get_u8(tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]); print_ampdu_spacing(spacing); } if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] && nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]) == 16) print_ht_mcs(nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])); if (tb_band[NL80211_BAND_ATTR_VHT_CAPA] && 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_FREQS]) { if (!band_had_freq) { printf("\t\tFrequencies:\n"); band_had_freq = true; } 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), freq_policy); if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); printf("\t\t\t* %d MHz [%d]", freq, ieee80211_frequency_to_channel(freq)); if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] && !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) printf(" (%.1f dBm)", 0.01 * nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER])); open = 0; if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) { print_flag("disabled", &open); goto next; } if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) print_flag("passive scanning", &open); if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) print_flag("no IBSS", &open); if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) print_flag("radar detection", &open); 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_band[NL80211_BAND_ATTR_RATES]) { printf("\t\tBitrates (non-HT):\n"); nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), nla_len(nl_rate), rate_policy); if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) continue; printf("\t\t\t* %2.1f Mbps", 0.1 * nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE])); open = 0; if (tb_rate[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE]) print_flag("short preamble supported", &open); if (open) printf(")"); printf("\n"); } } } } if (tb_msg[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) printf("\tmax # scan SSIDs: %d\n", nla_get_u8(tb_msg[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])); if (tb_msg[NL80211_ATTR_MAX_SCAN_IE_LEN]) printf("\tmax scan IEs length: %d bytes\n", nla_get_u16(tb_msg[NL80211_ATTR_MAX_SCAN_IE_LEN])); if (tb_msg[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) { unsigned int frag; frag = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]); if (frag != (unsigned int)-1) printf("\tFragmentation threshold: %d\n", frag); } if (tb_msg[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) { unsigned int rts; rts = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_RTS_THRESHOLD]); if (rts != (unsigned int)-1) printf("\tRTS threshold: %d\n", rts); } if (tb_msg[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) { unsigned char coverage; coverage = nla_get_u8(tb_msg[NL80211_ATTR_WIPHY_COVERAGE_CLASS]); /* See handle_distance() for an explanation where the '450' comes from */ printf("\tCoverage class: %d (up to %dm)\n", coverage, 450 * coverage); } if (tb_msg[NL80211_ATTR_CIPHER_SUITES]) { int num = nla_len(tb_msg[NL80211_ATTR_CIPHER_SUITES]) / sizeof(__u32); int i; __u32 *ciphers = nla_data(tb_msg[NL80211_ATTR_CIPHER_SUITES]); if (num > 0) { printf("\tSupported Ciphers:\n"); for (i = 0; i < num; i++) printf("\t\t* %s\n", cipher_name(ciphers[i])); } } if (tb_msg[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX] && tb_msg[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX]) printf("\tAvailable Antennas: TX %#x RX %#x\n", nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX]), nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX])); if (tb_msg[NL80211_ATTR_WIPHY_ANTENNA_TX] && tb_msg[NL80211_ATTR_WIPHY_ANTENNA_RX]) printf("\tConfigured Antennas: TX %#x RX %#x\n", 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_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_INTERFACE_COMBINATIONS]) { struct nlattr *nl_combi; int rem_combi; bool have_combinations = false; nla_for_each_nested(nl_combi, tb_msg[NL80211_ATTR_INTERFACE_COMBINATIONS], rem_combi) { static struct nla_policy iface_combination_policy[NUM_NL80211_IFACE_COMB] = { [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED }, [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 }, [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG }, [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 }, [NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS] = { .type = NLA_U32 }, }; struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB]; static struct nla_policy iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = { [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED }, [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 }, }; struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT]; struct nlattr *nl_limit; int err, rem_limit; bool comma = false; if (!have_combinations) { printf("\tvalid interface combinations:\n"); have_combinations = true; } printf("\t\t * "); err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB, nl_combi, iface_combination_policy); if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] || !tb_comb[NL80211_IFACE_COMB_MAXNUM] || !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) { printf(" \n"); goto broken_combination; } 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]) { printf("\n"); goto broken_combination; } 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(" } <= %u", nla_get_u32(tb_limit[NL80211_IFACE_LIMIT_MAX])); } printf(",\n\t\t "); printf("total <= %d, #channels <= %d%s", nla_get_u32(tb_comb[NL80211_IFACE_COMB_MAXNUM]), nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]), tb_comb[NL80211_IFACE_COMB_STA_AP_BI_MATCH] ? ", STA/AP BI must match" : ""); if (tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS]) { unsigned long widths = nla_get_u32(tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS]); if (widths) { int width; bool first = true; printf(", radar detect widths: {"); for (width = 0; width < 32; width++) if (widths & (1 << width)) { printf("%s %s", first ? "":",", channel_width_name(width)); first = false; } printf(" }\n"); } } printf("\n"); broken_combination: ; } if (!have_combinations) printf("\tinterface combinations are not supported\n"); } if (tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]) { printf("\tSupported commands:\n"); nla_for_each_nested(nl_cmd, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS], rem_cmd) printf("\t\t * %s\n", command_name(nla_get_u32(nl_cmd))); } if (tb_msg[NL80211_ATTR_TX_FRAME_TYPES]) { printf("\tSupported TX frame types:\n"); nla_for_each_nested(nl_if, tb_msg[NL80211_ATTR_TX_FRAME_TYPES], rem_if) { bool printed = false; nla_for_each_nested(nl_ftype, nl_if, rem_ftype) { if (!printed) printf("\t\t * %s:", iftype_name(nla_type(nl_if))); printed = true; printf(" 0x%.2x", nla_get_u16(nl_ftype)); } if (printed) printf("\n"); } } if (tb_msg[NL80211_ATTR_RX_FRAME_TYPES]) { printf("\tSupported RX frame types:\n"); nla_for_each_nested(nl_if, tb_msg[NL80211_ATTR_RX_FRAME_TYPES], rem_if) { bool printed = false; nla_for_each_nested(nl_ftype, nl_if, rem_ftype) { if (!printed) printf("\t\t * %s:", iftype_name(nla_type(nl_if))); printed = true; printf(" 0x%.2x", nla_get_u16(nl_ftype)); } if (printed) printf("\n"); } } if (tb_msg[NL80211_ATTR_SUPPORT_IBSS_RSN]) printf("\tDevice supports RSN-IBSS.\n"); if (tb_msg[NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED]) { struct nlattr *tb_wowlan[NUM_NL80211_WOWLAN_TRIG]; static struct nla_policy wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { [NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG }, [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG }, [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG }, [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .minlen = 12 }, [NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED] = { .type = NLA_FLAG }, [NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE] = { .type = NLA_FLAG }, [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG }, [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED }, }; struct nl80211_wowlan_pattern_support *pat; int err; err = nla_parse_nested(tb_wowlan, MAX_NL80211_WOWLAN_TRIG, tb_msg[NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED], wowlan_policy); printf("\tWoWLAN support:"); if (err) { printf(" \n"); } else { printf("\n"); if (tb_wowlan[NL80211_WOWLAN_TRIG_ANY]) printf("\t\t * wake up on anything (device continues operating normally)\n"); if (tb_wowlan[NL80211_WOWLAN_TRIG_DISCONNECT]) printf("\t\t * wake up on disconnect\n"); 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]) { 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); } if (tb_wowlan[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED]) printf("\t\t * can do GTK rekeying\n"); if (tb_wowlan[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) printf("\t\t * wake up on GTK rekey failure\n"); if (tb_wowlan[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) printf("\t\t * wake up on EAP identity request\n"); if (tb_wowlan[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) printf("\t\t * wake up on 4-way handshake\n"); if (tb_wowlan[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) printf("\t\t * wake up on rfkill release\n"); if (tb_wowlan[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) printf("\t\t * wake up on TCP connection\n"); } } if (tb_msg[NL80211_ATTR_ROAM_SUPPORT]) printf("\tDevice supports roaming.\n"); if (tb_msg[NL80211_ATTR_SUPPORT_AP_UAPSD]) printf("\tDevice supports AP-side u-APSD.\n"); if (tb_msg[NL80211_ATTR_HT_CAPABILITY_MASK]) { struct ieee80211_ht_cap *cm; printf("\tHT Capability overrides:\n"); if (nla_len(tb_msg[NL80211_ATTR_HT_CAPABILITY_MASK]) >= 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", cm->mcs.rx_mask[0], cm->mcs.rx_mask[1], cm->mcs.rx_mask[2], cm->mcs.rx_mask[3], cm->mcs.rx_mask[4], cm->mcs.rx_mask[5], cm->mcs.rx_mask[6], cm->mcs.rx_mask[7], cm->mcs.rx_mask[8], cm->mcs.rx_mask[9]); if (cm->cap_info & htole16(IEEE80211_HT_CAP_MAX_AMSDU)) printf("\t\t * maximum A-MSDU length\n"); if (cm->cap_info & htole16(IEEE80211_HT_CAP_SUP_WIDTH_20_40)) printf("\t\t * supported channel width\n"); if (cm->cap_info & htole16(IEEE80211_HT_CAP_SGI_40)) printf("\t\t * short GI for 40 MHz\n"); if (cm->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_FACTOR) printf("\t\t * max A-MPDU length exponent\n"); if (cm->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_DENSITY) printf("\t\t * min MPDU start spacing\n"); } else { printf("\tERROR: capabilities mask is too short, expected: %d, received: %d\n", (int)(sizeof(*cm)), (int)(nla_len(tb_msg[NL80211_ATTR_HT_CAPABILITY_MASK]))); } } if (tb_msg[NL80211_ATTR_FEATURE_FLAGS]) { unsigned int features = nla_get_u32(tb_msg[NL80211_ATTR_FEATURE_FLAGS]); if (features & NL80211_FEATURE_SK_TX_STATUS) printf("\tDevice supports TX status socket option.\n"); if (features & NL80211_FEATURE_HT_IBSS) printf("\tDevice supports HT-IBSS.\n"); if (features & NL80211_FEATURE_INACTIVITY_TIMER) printf("\tDevice has client inactivity timer.\n"); if (features & NL80211_FEATURE_CELL_BASE_REG_HINTS) printf("\tDevice accepts cell base station regulatory hints.\n"); if (features & NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL) printf("\tP2P Device uses a channel (of the concurrent ones)\n"); if (features & NL80211_FEATURE_LOW_PRIORITY_SCAN) printf("\tDevice supports low priority scan.\n"); if (features & NL80211_FEATURE_SCAN_FLUSH) printf("\tDevice supports scan flush.\n"); if (features & NL80211_FEATURE_AP_SCAN) printf("\tDevice supports AP scan.\n"); } 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) { char *feat_args[] = { "features", "-q" }; int err; err = handle_cmd(state, CIB_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); return 0; } __COMMAND(NULL, info, "info", NULL, NL80211_CMD_GET_WIPHY, 0, 0, CIB_PHY, handle_info, "Show capabilities for the specified wireless device.", NULL); 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, int argc, char **argv, enum id_input id) { int 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; } TOPLEVEL(commands, NULL, NL80211_CMD_GET_WIPHY, 0, CIB_NONE, handle_commands, "list all known commands and their decimal & hex value"); static int print_feature_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); bool print = (unsigned long)arg; #define maybe_printf(...) do { if (print) printf(__VA_ARGS__); } while (0) nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]) { uint32_t feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]); maybe_printf("nl80211 features: 0x%x\n", feat); if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP) { maybe_printf("\t* split wiphy dump\n"); nl80211_has_split_wiphy = true; } } return NL_SKIP; } static int handle_features(struct nl80211_state *state, struct nl_cb *cb, 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); return 0; } TOPLEVEL(features, "", NL80211_CMD_GET_PROTOCOL_FEATURES, 0, CIB_NONE, handle_features, ""); iw-3.10/interface.c000066400000000000000000000327251214041270600141660ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include "nl80211.h" #include "iw.h" #define VALID_FLAGS "none: no special flags\n"\ "fcsfail: show frames with FCS errors\n"\ "control: show control frames\n"\ "otherbss: show frames from other BSSes\n"\ "cook: use cooked mode" SECTION(interface); static char *mntr_flags[NL80211_MNTR_FLAG_MAX + 1] = { "none", "fcsfail", "plcpfail", "control", "otherbss", "cook", }; static int parse_mntr_flags(int *_argc, char ***_argv, struct nl_msg *msg) { struct nl_msg *flags; int err = -ENOBUFS; enum nl80211_mntr_flags flag; int argc = *_argc; char **argv = *_argv; flags = nlmsg_alloc(); if (!flags) return -ENOMEM; while (argc) { int ok = 0; for (flag = __NL80211_MNTR_FLAG_INVALID; flag <= NL80211_MNTR_FLAG_MAX; flag++) { if (strcmp(*argv, mntr_flags[flag]) == 0) { ok = 1; /* * This shouldn't be adding "flag" if that is * zero, but due to a problem in the kernel's * nl80211 code (using NLA_NESTED policy) it * will reject an empty nested attribute but * not one that contains an invalid attribute */ NLA_PUT_FLAG(flags, flag); break; } } if (!ok) { err = -EINVAL; goto out; } argc--; argv++; } nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags); err = 0; nla_put_failure: out: nlmsg_free(flags); *_argc = argc; *_argv = argv; return err; } /* for help */ #define IFACE_TYPES "Valid interface types are: managed, ibss, monitor, mesh, wds." /* return 0 if ok, internal error otherwise */ static int get_if_type(int *argc, char ***argv, enum nl80211_iftype *type, bool need_type) { char *tpstr; if (*argc < 1 + !!need_type) return 1; if (need_type && strcmp((*argv)[0], "type")) return 1; tpstr = (*argv)[!!need_type]; *argc -= 1 + !!need_type; *argv += 1 + !!need_type; if (strcmp(tpstr, "adhoc") == 0 || strcmp(tpstr, "ibss") == 0) { *type = NL80211_IFTYPE_ADHOC; return 0; } else if (strcmp(tpstr, "monitor") == 0) { *type = NL80211_IFTYPE_MONITOR; return 0; } else if (strcmp(tpstr, "master") == 0 || strcmp(tpstr, "ap") == 0) { *type = NL80211_IFTYPE_UNSPECIFIED; fprintf(stderr, "You need to run a management daemon, e.g. hostapd,\n"); fprintf(stderr, "see http://wireless.kernel.org/en/users/Documentation/hostapd\n"); fprintf(stderr, "for more information on how to do that.\n"); return 2; } else if (strcmp(tpstr, "__ap") == 0) { *type = NL80211_IFTYPE_AP; return 0; } else if (strcmp(tpstr, "__ap_vlan") == 0) { *type = NL80211_IFTYPE_AP_VLAN; return 0; } else if (strcmp(tpstr, "wds") == 0) { *type = NL80211_IFTYPE_WDS; return 0; } else if (strcmp(tpstr, "managed") == 0 || strcmp(tpstr, "mgd") == 0 || strcmp(tpstr, "station") == 0) { *type = NL80211_IFTYPE_STATION; return 0; } else if (strcmp(tpstr, "mp") == 0 || strcmp(tpstr, "mesh") == 0) { *type = NL80211_IFTYPE_MESH_POINT; return 0; } else if (strcmp(tpstr, "__p2pcl") == 0) { *type = NL80211_IFTYPE_P2P_CLIENT; return 0; } else if (strcmp(tpstr, "__p2pdev") == 0) { *type = NL80211_IFTYPE_P2P_DEVICE; return 0; } else if (strcmp(tpstr, "__p2pgo") == 0) { *type = NL80211_IFTYPE_P2P_GO; return 0; } fprintf(stderr, "invalid interface type %s\n", tpstr); return 2; } static int parse_4addr_flag(const char *value, struct nl_msg *msg) { if (strcmp(value, "on") == 0) NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, 1); else if (strcmp(value, "off") == 0) NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, 0); else return 1; return 0; nla_put_failure: return 1; } 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) { char *name; char *mesh_id = NULL; enum nl80211_iftype type; int tpset; if (argc < 1) return 1; name = argv[0]; argc--; argv++; tpset = get_if_type(&argc, &argv, &type, true); if (tpset) return tpset; if (argc) { if (strcmp(argv[0], "mesh_id") == 0) { argc--; argv++; if (!argc) return 1; mesh_id = argv[0]; argc--; argv++; } else if (strcmp(argv[0], "4addr") == 0) { argc--; argv++; if (parse_4addr_flag(argv[0], msg)) { fprintf(stderr, "4addr error\n"); return 2; } argc--; argv++; } else if (strcmp(argv[0], "flags") == 0) { argc--; argv++; if (parse_mntr_flags(&argc, &argv, msg)) { fprintf(stderr, "flags error\n"); return 2; } } else { return 1; } } if (argc) return 1; NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, type); if (mesh_id) NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(mesh_id), mesh_id); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(interface, add, " type [mesh_id ] [4addr on|off] [flags *]", NL80211_CMD_NEW_INTERFACE, 0, CIB_PHY, handle_interface_add, "Add a new virtual interface with the given configuration.\n" IFACE_TYPES "\n\n" "The flags are only used for monitor interfaces, valid flags are:\n" VALID_FLAGS "\n\n" "The mesh_id is used only for mesh mode."); COMMAND(interface, add, " type [mesh_id ] [4addr on|off] [flags *]", 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) { return 0; } TOPLEVEL(del, NULL, NL80211_CMD_DEL_INTERFACE, 0, CIB_NETDEV, handle_interface_del, "Remove this virtual interface"); HIDDEN(interface, del, NULL, NL80211_CMD_DEL_INTERFACE, 0, CIB_NETDEV, handle_interface_del); static char *channel_type_name(enum nl80211_channel_type channel_type) { switch (channel_type) { case NL80211_CHAN_NO_HT: return "NO HT"; case NL80211_CHAN_HT20: return "HT20"; case NL80211_CHAN_HT40MINUS: return "HT40-"; case NL80211_CHAN_HT40PLUS: return "HT40+"; default: return "unknown"; } } char *channel_width_name(enum nl80211_chan_width width) { switch (width) { case NL80211_CHAN_WIDTH_20_NOHT: return "20 MHz (no HT)"; case NL80211_CHAN_WIDTH_20: return "20 MHz"; case NL80211_CHAN_WIDTH_40: return "40 MHz"; case NL80211_CHAN_WIDTH_80: return "80 MHz"; case NL80211_CHAN_WIDTH_80P80: return "80+80 MHz"; case NL80211_CHAN_WIDTH_160: return "160 MHz"; default: return "unknown"; } } static int print_iface_handler(struct nl_msg *msg, void *arg) { struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; unsigned int *wiphy = arg; const char *indent = ""; nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (wiphy && tb_msg[NL80211_ATTR_WIPHY]) { unsigned int thiswiphy = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]); indent = "\t"; if (*wiphy != thiswiphy) printf("phy#%d\n", thiswiphy); *wiphy = thiswiphy; } if (tb_msg[NL80211_ATTR_IFNAME]) printf("%sInterface %s\n", indent, nla_get_string(tb_msg[NL80211_ATTR_IFNAME])); else printf("%sUnnamed/non-netdev interface\n", indent); if (tb_msg[NL80211_ATTR_IFINDEX]) printf("%s\tifindex %d\n", indent, nla_get_u32(tb_msg[NL80211_ATTR_IFINDEX])); if (tb_msg[NL80211_ATTR_WDEV]) printf("%s\twdev 0x%llx\n", indent, (unsigned long long)nla_get_u64(tb_msg[NL80211_ATTR_WDEV])); if (tb_msg[NL80211_ATTR_MAC]) { char mac_addr[20]; mac_addr_n2a(mac_addr, nla_data(tb_msg[NL80211_ATTR_MAC])); printf("%s\taddr %s\n", indent, mac_addr); } if (tb_msg[NL80211_ATTR_SSID]) { printf("%s\tssid ", indent); print_ssid_escaped(nla_len(tb_msg[NL80211_ATTR_SSID]), nla_data(tb_msg[NL80211_ATTR_SSID])); printf("\n"); } if (tb_msg[NL80211_ATTR_IFTYPE]) printf("%s\ttype %s\n", indent, iftype_name(nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]))); if (!wiphy && tb_msg[NL80211_ATTR_WIPHY]) printf("%s\twiphy %d\n", indent, nla_get_u32(tb_msg[NL80211_ATTR_WIPHY])); if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) { uint32_t freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]); printf("%s\tchannel %d (%d MHz)", indent, ieee80211_frequency_to_channel(freq), freq); if (tb_msg[NL80211_ATTR_CHANNEL_WIDTH]) { printf(", width: %s", channel_width_name(nla_get_u32(tb_msg[NL80211_ATTR_CHANNEL_WIDTH]))); if (tb_msg[NL80211_ATTR_CENTER_FREQ1]) printf(", center1: %d MHz", nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ1])); if (tb_msg[NL80211_ATTR_CENTER_FREQ2]) printf(", center2: %d MHz", nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ2])); } else if (tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { enum nl80211_channel_type channel_type; channel_type = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); printf(" %s", channel_type_name(channel_type)); } printf("\n"); } 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); 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) { if (!argc) return 1; NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR); switch (parse_mntr_flags(&argc, &argv, msg)) { case 0: return 0; case -ENOMEM: fprintf(stderr, "failed to allocate flags\n"); return 2; case -EINVAL: fprintf(stderr, "unknown flag %s\n", *argv); return 2; default: return 2; } nla_put_failure: return -ENOBUFS; } COMMAND(set, monitor, "*", NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_set, "Set monitor flags. Valid flags are:\n" 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) { char *mesh_id = NULL; if (argc != 1) return 1; mesh_id = argv[0]; NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(mesh_id), mesh_id); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(set, meshid, "", NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_meshid, NULL); 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); 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) { enum nl80211_iftype type; int tpset; tpset = get_if_type(&argc, &argv, &type, false); if (tpset) return tpset; if (argc) return 1; NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, type); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(set, type, "", NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_type, "Set interface type/mode.\n" 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) { if (argc != 1) return 1; return parse_4addr_flag(argv[0], msg); } COMMAND(set, 4addr, "", NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_4addr, "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) { uint16_t noack_map; char *end; if (argc != 1) return 1; noack_map = strtoul(argv[0], &end, 16); if (*end) return 1; NLA_PUT_U16(msg, NL80211_ATTR_NOACK_MAP, noack_map); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(set, noack_map, "", NL80211_CMD_SET_NOACK_MAP, 0, CIB_NETDEV, handle_interface_noack_map, "Set the NoAck map for the TIDs. (0x0009 = BE, 0x0006 = BK, 0x0030 = VI, 0x00C0 = VO)"); 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) { unsigned char mac_addr[ETH_ALEN]; if (argc < 1) return 1; if (mac_addr_a2n(mac_addr, argv[0])) { fprintf(stderr, "Invalid MAC address\n"); return 2; } argc--; argv++; if (argc) return 1; NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(set, peer, "", NL80211_CMD_SET_WDS_PEER, 0, CIB_NETDEV, handle_interface_wds_peer, "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) { float rate; char *end; if (argc != 1) { printf("Invalid parameters!\n"); return 2; } rate = strtod(argv[0], &end); if (*end != '\0') return 1; NLA_PUT_U32(msg, NL80211_ATTR_MCAST_RATE, (int)(rate * 10)); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(set, mcast_rate, "", NL80211_CMD_SET_MCAST_RATE, 0, CIB_NETDEV, set_mcast_rate, "Set the multicast bitrate."); iw-3.10/iw.8000066400000000000000000000021351214041270600125620ustar00rootroot00000000000000.TH IW 8 "7 June 2012" "iw" "Linux" .SH NAME iw \- show / manipulate wireless devices and their configuration .SH SYNOPSIS .ad l .in +8 .ti -8 .B iw .RI [ " OPTIONS " ] " " { " .BR help " [ " .RI ""command " ]" .BR "|" .RI ""OBJECT " " COMMAND " }" .sp .ti -8 .IR OBJECT " := { " .BR dev " | " phy " | " reg " }" .sp .ti -8 .IR OPTIONS " := { --version | --debug }" .SH OPTIONS .TP .BR " --version" print version information and exit. .TP .BR " --debug" enable netlink message debugging. .SH IW - COMMAND SYNTAX .SS .I OBJECT .TP .B dev - network interface. .TP .B phy - wireless hardware device (by name). .TP .B phy# - wireless hardware device (by index). .TP .B reg - regulatory agent. .SS .I COMMAND Specifies the action to perform on the object. The set of possible actions depends on the object type. .B iw help will print all supported commands, while .B iw help command will print the help for all matching commands. .SH SEE ALSO .BR ip (8), .BR crda (8), .BR regdbdump (8), .BR regulatory.bin (5) .BR http://wireless.kernel.org/en/users/Documentation/iw iw-3.10/iw.c000066400000000000000000000265371214041270600126510ustar00rootroot00000000000000/* * nl80211 userspace tool * * Copyright 2007, 2008 Johannes Berg */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nl80211.h" #include "iw.h" /* libnl 1.x compatibility code */ #if !defined(CONFIG_LIBNL20) && !defined(CONFIG_LIBNL30) static inline struct nl_handle *nl_socket_alloc(void) { return nl_handle_alloc(); } static inline void nl_socket_free(struct nl_sock *h) { nl_handle_destroy(h); } static inline int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf) { return nl_set_buffer_size(sk, rxbuf, txbuf); } #endif /* CONFIG_LIBNL20 && CONFIG_LIBNL30 */ int iw_debug = 0; static int nl80211_init(struct nl80211_state *state) { int err; state->nl_sock = nl_socket_alloc(); if (!state->nl_sock) { fprintf(stderr, "Failed to allocate netlink socket.\n"); 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; } state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211"); if (state->nl80211_id < 0) { fprintf(stderr, "nl80211 not found.\n"); err = -ENOENT; goto out_handle_destroy; } return 0; out_handle_destroy: nl_socket_free(state->nl_sock); return err; } static void nl80211_cleanup(struct nl80211_state *state) { nl_socket_free(state->nl_sock); } static int cmd_size; 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)) static void __usage_cmd(const struct cmd *cmd, char *indent, bool full) { const char *start, *lend, *end; printf("%s", indent); switch (cmd->idby) { case CIB_NONE: break; case CIB_PHY: printf("phy "); break; case CIB_NETDEV: printf("dev "); break; case CIB_WDEV: printf("wdev "); break; } if (cmd->parent && cmd->parent->name) printf("%s ", cmd->parent->name); printf("%s", cmd->name); if (cmd->args) { /* print line by line */ start = cmd->args; end = strchr(start, '\0'); printf(" "); do { lend = strchr(start, '\n'); if (!lend) lend = end; if (start != cmd->args) { printf("\t"); switch (cmd->idby) { case CIB_NONE: break; case CIB_PHY: printf("phy "); break; case CIB_NETDEV: printf("dev "); break; case CIB_WDEV: printf("wdev "); break; } if (cmd->parent && cmd->parent->name) printf("%s ", cmd->parent->name); printf("%s ", cmd->name); } printf("%.*s\n", (int)(lend - start), start); start = lend + 1; } while (end != lend); } else printf("\n"); if (!full || !cmd->help) return; /* hack */ if (strlen(indent)) indent = "\t\t"; else printf("\n"); /* print line by line */ start = cmd->help; end = strchr(start, '\0'); do { lend = strchr(start, '\n'); if (!lend) lend = end; printf("%s", indent); printf("%.*s\n", (int)(lend - start), start); start = lend + 1; } while (end != lend); printf("\n"); } static void usage_options(void) { printf("Options:\n"); printf("\t--debug\t\tenable netlink debugging\n"); } static const char *argv0; static void usage(int argc, char **argv) { const struct cmd *section, *cmd; bool full = argc >= 0; const char *sect_filt = NULL; const char *cmd_filt = NULL; if (argc > 0) sect_filt = argv[0]; if (argc > 1) cmd_filt = argv[1]; printf("Usage:\t%s [options] command\n", argv0); usage_options(); printf("\t--version\tshow version (%s)\n", iw_version); printf("Commands:\n"); for_each_cmd(section) { if (section->parent) continue; if (sect_filt && strcmp(section->name, sect_filt)) continue; if (section->handler && !section->hidden) __usage_cmd(section, "\t", full); for_each_cmd(cmd) { if (section != cmd->parent) continue; if (!cmd->handler || cmd->hidden) continue; if (cmd_filt && strcmp(cmd->name, cmd_filt)) continue; __usage_cmd(cmd, "\t", full); } } printf("\nCommands that use the netdev ('dev') can also be given the\n" "'wdev' instead to identify the device.\n"); printf("\nYou can omit the 'phy' or 'dev' if " "the identification is unique,\n" "e.g. \"iw wlan0 info\" or \"iw phy0 info\". " "(Don't when scripting.)\n\n" "Do NOT screenscrape this tool, we don't " "consider its output stable.\n\n"); } static int print_help(struct nl80211_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { exit(3); } TOPLEVEL(help, "[command]", 0, 0, CIB_NONE, print_help, "Print usage for all or a specific command, e.g.\n" "\"help wowlan\" or \"help wowlan enable\"."); static void usage_cmd(const struct cmd *cmd) { printf("Usage:\t%s [options] ", argv0); __usage_cmd(cmd, "", true); usage_options(); } static void version(void) { printf("iw version %s\n", iw_version); } static int phy_lookup(char *name) { char buf[200]; int fd, pos; snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name); fd = open(buf, O_RDONLY); if (fd < 0) return -1; pos = read(fd, buf, sizeof(buf) - 1); if (pos < 0) { close(fd); return -1; } buf[pos] = '\0'; close(fd); return atoi(buf); } static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) { int *ret = arg; *ret = err->error; return NL_STOP; } static int finish_handler(struct nl_msg *msg, void *arg) { int *ret = arg; *ret = 0; return NL_SKIP; } static int ack_handler(struct nl_msg *msg, void *arg) { int *ret = arg; *ret = 0; return NL_STOP; } static int __handle_cmd(struct nl80211_state *state, enum id_input idby, int argc, char **argv, const struct cmd **cmdout) { const struct cmd *cmd, *match = NULL, *sectcmd; struct nl_cb *cb; struct nl_cb *s_cb; struct nl_msg *msg; signed long long devidx = 0; int err, o_argc; const char *command, *section; char *tmp, **o_argv; enum command_identify_by command_idby = CIB_NONE; if (argc <= 1 && idby != II_NONE) return 1; o_argc = argc; o_argv = argv; switch (idby) { case II_PHY_IDX: command_idby = CIB_PHY; devidx = strtoul(*argv + 4, &tmp, 0); if (*tmp != '\0') return 1; argc--; argv++; break; case II_PHY_NAME: command_idby = CIB_PHY; devidx = phy_lookup(*argv); argc--; argv++; break; case II_NETDEV: command_idby = CIB_NETDEV; devidx = if_nametoindex(*argv); if (devidx == 0) devidx = -1; argc--; argv++; break; case II_WDEV: command_idby = CIB_WDEV; devidx = strtoll(*argv, &tmp, 0); if (*tmp != '\0') return 1; argc--; argv++; default: break; } if (devidx < 0) return -errno; section = *argv; argc--; argv++; for_each_cmd(sectcmd) { if (sectcmd->parent) continue; /* ok ... bit of a hack for the dupe 'info' section */ if (match && sectcmd->idby != command_idby) continue; if (strcmp(sectcmd->name, section) == 0) match = sectcmd; } sectcmd = match; match = NULL; if (!sectcmd) return 1; if (argc > 0) { command = *argv; for_each_cmd(cmd) { if (!cmd->handler) continue; if (cmd->parent != sectcmd) continue; /* * ignore mismatch id by, but allow WDEV * in place of NETDEV */ if (cmd->idby != command_idby && !(cmd->idby == CIB_NETDEV && command_idby == CIB_WDEV)) continue; if (strcmp(cmd->name, command)) continue; if (argc > 1 && !cmd->args) continue; match = cmd; break; } if (match) { argc--; argv++; } } if (match) cmd = match; else { /* Use the section itself, if possible. */ cmd = sectcmd; if (argc && !cmd->args) return 1; if (cmd->idby != command_idby && !(cmd->idby == CIB_NETDEV && command_idby == CIB_WDEV)) return 1; if (!cmd->handler) return 1; } if (cmd->selector) { cmd = cmd->selector(argc, argv); if (!cmd) return 1; } if (cmdout) *cmdout = cmd; if (!cmd->cmd) { argc = o_argc; argv = o_argv; return cmd->handler(state, NULL, NULL, argc, argv, idby); } msg = nlmsg_alloc(); if (!msg) { fprintf(stderr, "failed to allocate netlink message\n"); return 2; } cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); s_cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); if (!cb || !s_cb) { fprintf(stderr, "failed to allocate netlink callbacks\n"); err = 2; goto out_free_msg; } genlmsg_put(msg, 0, 0, state->nl80211_id, 0, cmd->nl_msg_flags, cmd->cmd, 0); switch (command_idby) { case CIB_PHY: NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx); break; case CIB_NETDEV: NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx); break; case CIB_WDEV: NLA_PUT_U64(msg, NL80211_ATTR_WDEV, devidx); break; default: break; } err = cmd->handler(state, cb, msg, argc, argv, idby); if (err) goto out; nl_socket_set_cb(state->nl_sock, s_cb); err = nl_send_auto_complete(state->nl_sock, msg); if (err < 0) goto out; err = 1; 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); while (err > 0) nl_recvmsgs(state->nl_sock, cb); out: nl_cb_put(cb); out_free_msg: nlmsg_free(msg); return err; nla_put_failure: fprintf(stderr, "building message failed\n"); return 2; } int handle_cmd(struct nl80211_state *state, enum id_input idby, int argc, char **argv) { return __handle_cmd(state, idby, argc, argv, NULL); } int main(int argc, char **argv) { struct nl80211_state nlstate; int err; const struct cmd *cmd = NULL; /* calculate command size including padding */ cmd_size = abs((long)&__section_set - (long)&__section_get); /* strip off self */ argc--; argv0 = *argv++; if (argc > 0 && strcmp(*argv, "--debug") == 0) { iw_debug = 1; argc--; argv++; } if (argc > 0 && strcmp(*argv, "--version") == 0) { version(); return 0; } /* need to treat "help" command specially so it works w/o nl80211 */ if (argc == 0 || strcmp(*argv, "help") == 0) { usage(argc - 1, argv + 1); return 0; } err = nl80211_init(&nlstate); if (err) return 1; if (strcmp(*argv, "dev") == 0 && argc > 1) { argc--; argv++; err = __handle_cmd(&nlstate, II_NETDEV, argc, argv, &cmd); } else if (strncmp(*argv, "phy", 3) == 0 && argc > 1) { if (strlen(*argv) == 3) { argc--; argv++; err = __handle_cmd(&nlstate, II_PHY_NAME, argc, argv, &cmd); } else if (*(*argv + 3) == '#') err = __handle_cmd(&nlstate, II_PHY_IDX, argc, argv, &cmd); else goto detect; } else if (strcmp(*argv, "wdev") == 0 && argc > 1) { argc--; argv++; err = __handle_cmd(&nlstate, II_WDEV, argc, argv, &cmd); } else { int idx; enum id_input idby = II_NONE; detect: if ((idx = if_nametoindex(argv[0])) != 0) idby = II_NETDEV; else if ((idx = phy_lookup(argv[0])) >= 0) idby = II_PHY_NAME; err = __handle_cmd(&nlstate, idby, argc, argv, &cmd); } if (err == 1) { if (cmd) usage_cmd(cmd); else usage(0, NULL); } else if (err < 0) fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err); nl80211_cleanup(&nlstate); return err; } iw-3.10/iw.h000066400000000000000000000123651214041270600126500ustar00rootroot00000000000000#ifndef __IW_H #define __IW_H #include #include #include #include #include #include #include "nl80211.h" #include "ieee80211.h" #define ETH_ALEN 6 /* libnl 1.x compatibility code */ #if !defined(CONFIG_LIBNL20) && !defined(CONFIG_LIBNL30) # define nl_sock nl_handle #endif struct nl80211_state { struct nl_sock *nl_sock; int nl80211_id; }; enum command_identify_by { CIB_NONE, CIB_PHY, CIB_NETDEV, CIB_WDEV, }; enum id_input { II_NONE, II_NETDEV, II_PHY_NAME, II_PHY_IDX, II_WDEV, }; struct cmd { const char *name; const char *args; const char *help; const enum nl80211_commands cmd; int nl_msg_flags; int hidden; 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. */ int (*handler)(struct nl80211_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id); const struct cmd *(*selector)(int argc, char **argv); const struct cmd *parent; }; #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"))) = { \ .name = (_name), \ .args = (_args), \ .cmd = (_nlcmd), \ .nl_msg_flags = (_flags), \ .hidden = (_hidden), \ .idby = (_idby), \ .handler = (_handler), \ .help = (_help), \ .parent = _section, \ .selector = (_sel), \ } #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 #define COMMAND(section, name, args, cmd, flags, idby, handler, help) \ __COMMAND(&(__section ## _ ## section), name, #name, args, cmd, flags, 0, idby, handler, help, NULL) #define COMMAND_ALIAS(section, name, args, cmd, flags, idby, handler, help, selector, alias)\ __ACMD(&(__section ## _ ## section), name, #name, args, cmd, flags, 0, idby, handler, help, selector, alias) #define HIDDEN(section, name, args, cmd, flags, idby, handler) \ __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"))) = { \ .name = (#_name), \ .args = (_args), \ .cmd = (_nlcmd), \ .nl_msg_flags = (_flags), \ .idby = (_idby), \ .handler = (_handler), \ .help = (_help), \ } #define SECTION(_name) \ struct cmd __section ## _ ## _name \ __attribute__((used)) __attribute__((section("__cmd"))) = { \ .name = (#_name), \ .hidden = 1, \ } #define DECLARE_SECTION(_name) \ extern struct cmd __section ## _ ## _name; extern const char iw_version[]; extern int iw_debug; int handle_cmd(struct nl80211_state *state, enum id_input idby, int argc, char **argv); struct print_event_args { struct timeval ts; /* internal */ bool have_ts; /* must be set false */ bool frame, time, reltime; }; __u32 listen_events(struct nl80211_state *state, const int n_waits, const __u32 *waits); int __prepare_listen_events(struct nl80211_state *state); __u32 __do_listen_events(struct nl80211_state *state, const int n_waits, const __u32 *waits, struct print_event_args *args); int mac_addr_a2n(unsigned char *mac_addr, char *arg); void mac_addr_n2a(char *mac_addr, 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); 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); char *channel_width_name(enum nl80211_chan_width width); const char *iftype_name(enum nl80211_iftype iftype); const char *command_name(enum nl80211_commands cmd); int ieee80211_channel_to_frequency(int chan); int ieee80211_frequency_to_channel(int freq); void print_ssid_escaped(const uint8_t len, const uint8_t *data); int nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group); char *reg_initiator_to_string(__u8 initiator); const char *get_reason_str(uint16_t reason); const char *get_status_str(uint16_t status); enum print_ie_type { PRINT_SCAN, PRINT_LINK, }; #define BIT(x) (1ULL<<(x)) void print_ies(unsigned char *ie, int ielen, bool unknown, enum print_ie_type ptype); void parse_tx_bitrate(struct nlattr *bitrate_attr, char *buf, int buflen); DECLARE_SECTION(set); DECLARE_SECTION(get); #endif /* __IW_H */ iw-3.10/link.c000066400000000000000000000171421214041270600131570ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include "nl80211.h" #include "iw.h" struct link_result { uint8_t bssid[8]; bool link_found; bool anything_found; }; static struct link_result lr = { .link_found = false }; static int link_bss_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *bss[NL80211_BSS_MAX + 1]; static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { [NL80211_BSS_TSF] = { .type = NLA_U64 }, [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, [NL80211_BSS_BSSID] = { }, [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 }, [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 }, [NL80211_BSS_INFORMATION_ELEMENTS] = { }, [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, [NL80211_BSS_STATUS] = { .type = NLA_U32 }, }; struct link_result *result = arg; char mac_addr[20], dev[20]; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb[NL80211_ATTR_BSS]) { fprintf(stderr, "bss info missing!\n"); return NL_SKIP; } if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], bss_policy)) { fprintf(stderr, "failed to parse nested attributes!\n"); return NL_SKIP; } if (!bss[NL80211_BSS_BSSID]) return NL_SKIP; if (!bss[NL80211_BSS_STATUS]) return NL_SKIP; mac_addr_n2a(mac_addr, nla_data(bss[NL80211_BSS_BSSID])); if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev); switch (nla_get_u32(bss[NL80211_BSS_STATUS])) { case NL80211_BSS_STATUS_ASSOCIATED: printf("Connected to %s (on %s)\n", mac_addr, dev); break; case NL80211_BSS_STATUS_AUTHENTICATED: printf("Authenticated with %s (on %s)\n", mac_addr, dev); return NL_SKIP; case NL80211_BSS_STATUS_IBSS_JOINED: printf("Joined IBSS %s (on %s)\n", mac_addr, dev); break; default: return NL_SKIP; } result->anything_found = true; if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) print_ies(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]), nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), false, PRINT_LINK); if (bss[NL80211_BSS_FREQUENCY]) printf("\tfreq: %d\n", nla_get_u32(bss[NL80211_BSS_FREQUENCY])); if (nla_get_u32(bss[NL80211_BSS_STATUS]) != NL80211_BSS_STATUS_ASSOCIATED) return NL_SKIP; /* only in the assoc case do we want more info from station get */ result->link_found = true; memcpy(result->bssid, nla_data(bss[NL80211_BSS_BSSID]), 6); return NL_SKIP; } 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) { if (argc > 0) return 1; nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, link_bss_handler, &lr); return 0; } static int print_link_sta(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1]; struct nlattr *binfo[NL80211_STA_BSS_PARAM_MAX + 1]; static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = { [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_PACKETS] = { .type = NLA_U32 }, [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED }, [NL80211_STA_INFO_LLID] = { .type = NLA_U16 }, [NL80211_STA_INFO_PLID] = { .type = NLA_U16 }, [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 }, }; static struct nla_policy bss_policy[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 }, }; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb[NL80211_ATTR_STA_INFO]) { fprintf(stderr, "sta stats missing!\n"); return NL_SKIP; } if (nla_parse_nested(sinfo, NL80211_STA_INFO_MAX, tb[NL80211_ATTR_STA_INFO], stats_policy)) { fprintf(stderr, "failed to parse nested attributes!\n"); return NL_SKIP; } if (sinfo[NL80211_STA_INFO_RX_BYTES] && sinfo[NL80211_STA_INFO_RX_PACKETS]) printf("\tRX: %u bytes (%u packets)\n", nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES]), nla_get_u32(sinfo[NL80211_STA_INFO_RX_PACKETS])); if (sinfo[NL80211_STA_INFO_TX_BYTES] && sinfo[NL80211_STA_INFO_TX_PACKETS]) printf("\tTX: %u bytes (%u packets)\n", nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES]), nla_get_u32(sinfo[NL80211_STA_INFO_TX_PACKETS])); if (sinfo[NL80211_STA_INFO_SIGNAL]) printf("\tsignal: %d dBm\n", (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL])); if (sinfo[NL80211_STA_INFO_TX_BITRATE]) { char buf[100]; parse_tx_bitrate(sinfo[NL80211_STA_INFO_TX_BITRATE], buf, sizeof(buf)); printf("\ttx bitrate: %s\n", buf); } if (sinfo[NL80211_STA_INFO_BSS_PARAM]) { if (nla_parse_nested(binfo, NL80211_STA_BSS_PARAM_MAX, sinfo[NL80211_STA_INFO_BSS_PARAM], bss_policy)) { fprintf(stderr, "failed to parse nested bss parameters!\n"); } else { char *delim = ""; printf("\n\tbss flags:\t"); if (binfo[NL80211_STA_BSS_PARAM_CTS_PROT]) { printf("CTS-protection"); delim = " "; } if (binfo[NL80211_STA_BSS_PARAM_SHORT_PREAMBLE]) { printf("%sshort-preamble", delim); delim = " "; } if (binfo[NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME]) printf("%sshort-slot-time", delim); printf("\n\tdtim period:\t%d", nla_get_u8(binfo[NL80211_STA_BSS_PARAM_DTIM_PERIOD])); printf("\n\tbeacon int:\t%d", nla_get_u16(binfo[NL80211_STA_BSS_PARAM_BEACON_INTERVAL])); printf("\n"); } } return NL_SKIP; } 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) { unsigned char mac_addr[ETH_ALEN]; if (argc < 1) return 1; if (mac_addr_a2n(mac_addr, argv[0])) { fprintf(stderr, "invalid mac address\n"); return 2; } argc--; argv++; if (argc) return 1; NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_link_sta, NULL); return 0; nla_put_failure: return -ENOBUFS; } static int handle_link(struct nl80211_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { char *link_argv[] = { NULL, "link", "get_bss", NULL, }; char *station_argv[] = { NULL, "link", "get_sta", NULL, NULL, }; char bssid_buf[3*6]; int err; link_argv[0] = argv[0]; err = handle_cmd(state, id, 3, link_argv); if (err) return err; if (!lr.link_found) { if (!lr.anything_found) printf("Not connected.\n"); return 0; } mac_addr_n2a(bssid_buf, lr.bssid); bssid_buf[17] = '\0'; station_argv[0] = argv[0]; station_argv[3] = bssid_buf; return handle_cmd(state, id, 4, station_argv); } 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, CIB_NETDEV, handle_link_sta); HIDDEN(link, get_bss, NULL, NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_for_link); iw-3.10/mesh.c000066400000000000000000000307751214041270600131650ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include "nl80211.h" #include "iw.h" SECTION(mesh); typedef struct _any_t { union { uint32_t as_32; int32_t as_s32; uint16_t as_16; uint8_t as_8; } u; } _any; /* describes a mesh parameter */ struct mesh_param_descr { const char *name; enum nl80211_meshconf_params mesh_param_num; int (*nla_put_fn)(struct nl_msg*, int, _any*); uint32_t (*parse_fn)(const char*, _any*); void (*nla_print_fn)(struct nlattr *); }; /* utility functions for manipulating and printing u8/u16/u32 values and * timesouts. */ static int _my_nla_put_u8(struct nl_msg *n, int mesh_param_num, _any *value) { return nla_put(n, mesh_param_num, sizeof(uint8_t), &value->u.as_8); } static int _my_nla_put_u16(struct nl_msg *n, int mesh_param_num, _any *value) { return nla_put(n, mesh_param_num, sizeof(uint16_t), &value->u.as_16); } static int _my_nla_put_u32(struct nl_msg *n, int mesh_param_num, _any *value) { return nla_put(n, mesh_param_num, sizeof(uint32_t), &value->u.as_32); } static uint32_t _parse_u8(const char *str, _any *ret) { char *endptr = NULL; unsigned long int v = strtoul(str, &endptr, 10); if (*endptr != '\0') return 0xff; if (v > 0xff) return 0xff; ret->u.as_8 = (uint8_t)v; return 0; } static uint32_t _parse_u8_as_bool(const char *str, _any *ret) { char *endptr = NULL; unsigned long int v = strtoul(str, &endptr, 10); if (*endptr != '\0') return 0x1; if (v > 0x1) return 0x1; ret->u.as_8 = (uint8_t)v; return 0; } static uint32_t _parse_u16(const char *str, _any *ret) { char *endptr = NULL; long int v = strtol(str, &endptr, 10); if (*endptr != '\0') return 0xffff; if ((v < 0) || (v > 0xffff)) return 0xffff; ret->u.as_16 = (uint16_t)v; return 0; } static uint32_t _parse_u32(const char *str, _any *ret) { char *endptr = NULL; long long int v = strtoll(str, &endptr, 10); if (*endptr != '\0') return 0xffffffff; if ((v < 0) || (v > 0xffffffff)) return 0xffffffff; ret->u.as_32 = (uint32_t)v; return 0; } static uint32_t _parse_s32(const char *str, _any *ret) { char *endptr = NULL; long int v = strtol(str, &endptr, 10); if (*endptr != '\0') return 0xffffffff; if (v > 0xff) return 0xffffffff; ret->u.as_s32 = (int32_t)v; return 0; } static uint32_t _parse_u32_power_mode(const char *str, _any *ret) { unsigned long int v; /* Parse attribute for the name of power mode */ if (!strcmp(str, "active")) v = NL80211_MESH_POWER_ACTIVE; else if (!strcmp(str, "light")) v = NL80211_MESH_POWER_LIGHT_SLEEP; else if (!strcmp(str, "deep")) v = NL80211_MESH_POWER_DEEP_SLEEP; else return 0xff; ret->u.as_32 = (uint32_t)v; return 0; } static void _print_u8(struct nlattr *a) { printf("%d", nla_get_u8(a)); } static void _print_u16(struct nlattr *a) { printf("%d", nla_get_u16(a)); } static void _print_u16_timeout(struct nlattr *a) { printf("%d milliseconds", nla_get_u16(a)); } static void _print_u16_in_TUs(struct nlattr *a) { printf("%d TUs", nla_get_u16(a)); } static void _print_u32(struct nlattr *a) { printf("%d", nla_get_u32(a)); } static void _print_u32_timeout(struct nlattr *a) { printf("%u milliseconds", nla_get_u32(a)); } static void _print_u32_in_TUs(struct nlattr *a) { printf("%d TUs", nla_get_u32(a)); } static void _print_u32_power_mode(struct nlattr *a) { unsigned long v = nla_get_u32(a); switch (v) { case NL80211_MESH_POWER_ACTIVE: printf("active"); break; case NL80211_MESH_POWER_LIGHT_SLEEP: printf("light"); break; case NL80211_MESH_POWER_DEEP_SLEEP: printf("deep"); break; default: printf("undefined"); break; } } static void _print_s32_in_dBm(struct nlattr *a) { printf("%d dBm", (int32_t) nla_get_u32(a)); } /* The current mesh parameters */ const static struct mesh_param_descr _mesh_param_descrs[] = { {"mesh_retry_timeout", NL80211_MESHCONF_RETRY_TIMEOUT, _my_nla_put_u16, _parse_u16, _print_u16_timeout}, {"mesh_confirm_timeout", NL80211_MESHCONF_CONFIRM_TIMEOUT, _my_nla_put_u16, _parse_u16, _print_u16_timeout}, {"mesh_holding_timeout", NL80211_MESHCONF_HOLDING_TIMEOUT, _my_nla_put_u16, _parse_u16, _print_u16_timeout}, {"mesh_max_peer_links", NL80211_MESHCONF_MAX_PEER_LINKS, _my_nla_put_u16, _parse_u16, _print_u16}, {"mesh_max_retries", NL80211_MESHCONF_MAX_RETRIES, _my_nla_put_u8, _parse_u8, _print_u8}, {"mesh_ttl", NL80211_MESHCONF_TTL, _my_nla_put_u8, _parse_u8, _print_u8}, {"mesh_element_ttl", NL80211_MESHCONF_ELEMENT_TTL, _my_nla_put_u8, _parse_u8, _print_u8}, {"mesh_auto_open_plinks", NL80211_MESHCONF_AUTO_OPEN_PLINKS, _my_nla_put_u8, _parse_u8_as_bool, _print_u8}, {"mesh_hwmp_max_preq_retries", NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, _my_nla_put_u8, _parse_u8, _print_u8}, {"mesh_path_refresh_time", NL80211_MESHCONF_PATH_REFRESH_TIME, _my_nla_put_u32, _parse_u32, _print_u32_timeout}, {"mesh_min_discovery_timeout", NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, _my_nla_put_u16, _parse_u16, _print_u16_timeout}, {"mesh_hwmp_active_path_timeout", NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, _my_nla_put_u32, _parse_u32, _print_u32_in_TUs}, {"mesh_hwmp_preq_min_interval", NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, _my_nla_put_u16, _parse_u16, _print_u16_in_TUs}, {"mesh_hwmp_net_diameter_traversal_time", NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, _my_nla_put_u16, _parse_u16, _print_u16_in_TUs}, {"mesh_hwmp_rootmode", NL80211_MESHCONF_HWMP_ROOTMODE, _my_nla_put_u8, _parse_u8, _print_u8}, {"mesh_hwmp_rann_interval", NL80211_MESHCONF_HWMP_RANN_INTERVAL, _my_nla_put_u16, _parse_u16, _print_u16_in_TUs}, {"mesh_gate_announcements", NL80211_MESHCONF_GATE_ANNOUNCEMENTS, _my_nla_put_u8, _parse_u8, _print_u8}, {"mesh_fwding", NL80211_MESHCONF_FORWARDING, _my_nla_put_u8, _parse_u8_as_bool, _print_u8}, {"mesh_sync_offset_max_neighor", NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, _my_nla_put_u32, _parse_u32, _print_u32}, {"mesh_rssi_threshold", NL80211_MESHCONF_RSSI_THRESHOLD, _my_nla_put_u32, _parse_s32, _print_s32_in_dBm}, {"mesh_hwmp_active_path_to_root_timeout", NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, _my_nla_put_u32, _parse_u32, _print_u32_in_TUs}, {"mesh_hwmp_root_interval", NL80211_MESHCONF_HWMP_ROOT_INTERVAL, _my_nla_put_u16, _parse_u16, _print_u16_in_TUs}, {"mesh_hwmp_confirmation_interval", NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, _my_nla_put_u16, _parse_u16, _print_u16_in_TUs}, {"mesh_power_mode", NL80211_MESHCONF_POWER_MODE, _my_nla_put_u32, _parse_u32_power_mode, _print_u32_power_mode}, {"mesh_awake_window", NL80211_MESHCONF_AWAKE_WINDOW, _my_nla_put_u16, _parse_u16, _print_u16_in_TUs}, }; static void print_all_mesh_param_descr(void) { int i; printf("Possible mesh parameters are:\n"); for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) printf(" - %s\n", _mesh_param_descrs[i].name); } static const struct mesh_param_descr *find_mesh_param(const char *name) { int i; /* Find out what mesh parameter we want to change. */ for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) { if (strcmp(_mesh_param_descrs[i].name, name) == 0) 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) { const struct mesh_param_descr *mdescr; struct nlattr *container; uint32_t ret; int err; container = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS); if (!container) return -ENOBUFS; if (!argc) return 1; while (argc) { const char *name; char *value; _any any; memset(&any, 0, sizeof(_any)); name = argv[0]; value = strchr(name, '='); if (value) { *value = '\0'; value++; argc--; argv++; } else { /* backward compat -- accept w/o '=' */ if (argc < 2) { printf("Must specify a value for %s.\n", name); return 2; } value = argv[1]; argc -= 2; argv += 2; } mdescr = find_mesh_param(name); if (!mdescr) return 2; /* Parse the new value */ ret = mdescr->parse_fn(value, &any); if (ret != 0) { if (mdescr->mesh_param_num == NL80211_MESHCONF_POWER_MODE) printf("%s must be set to active, light or " "deep.\n", mdescr->name); else printf("%s must be set to a number " "between 0 and %u\n", mdescr->name, ret); return 2; } err = mdescr->nla_put_fn(msg, mdescr->mesh_param_num, &any); if (err) return err; } nla_nest_end(msg, container); return err; } COMMAND(set, mesh_param, "= [=]*", NL80211_CMD_SET_MESH_PARAMS, 0, CIB_NETDEV, set_interface_meshparam, "Set mesh parameter (run command without any to see available ones)."); /* Getter */ static int print_mesh_param_handler(struct nl_msg *msg, void *arg) { const struct mesh_param_descr *mdescr = arg; struct nlattr *attrs[NL80211_ATTR_MAX + 1]; struct nlattr *parent_attr; struct nlattr *mesh_params[NL80211_MESHCONF_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); /* locate NL80211_ATTR_MESH_PARAMS */ nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); parent_attr = attrs[NL80211_ATTR_MESH_PARAMS]; if (!parent_attr) return -EINVAL; /* unpack the mesh parameters */ if (nla_parse_nested(mesh_params, NL80211_MESHCONF_ATTR_MAX, parent_attr, NULL)) return -EINVAL; if (!mdescr) { int i; 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"); } return NL_SKIP; } /* print out the mesh parameter */ 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) return 1; if (argc == 1) { mdescr = find_mesh_param(argv[0]); if (!mdescr) return 2; } nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_mesh_param_handler, (void *)mdescr); return 0; } COMMAND(get, mesh_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, struct nl_msg *msg, int argc, char **argv, enum id_input id) { struct nlattr *container; float rate; int bintval, dtim_period; char *end; if (argc < 1) return 1; NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(argv[0]), argv[0]); argc--; argv++; if (argc > 1 && strcmp(argv[0], "mcast-rate") == 0) { argv++; argc--; rate = strtod(argv[0], &end); if (*end != '\0') return 1; NLA_PUT_U32(msg, NL80211_ATTR_MCAST_RATE, (int)(rate * 10)); argv++; argc--; } if (argc > 1 && strcmp(argv[0], "beacon-interval") == 0) { argc--; argv++; bintval = strtoul(argv[0], &end, 10); if (*end != '\0') return 1; NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, bintval); argv++; argc--; } if (argc > 1 && strcmp(argv[0], "dtim-period") == 0) { argc--; argv++; dtim_period = strtoul(argv[0], &end, 10); if (*end != '\0') return 1; NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period); argv++; argc--; } container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP); if (!container) return -ENOBUFS; if (argc > 1 && strcmp(argv[0], "vendor_sync") == 0) { argv++; argc--; if (strcmp(argv[0], "on") == 0) NLA_PUT_U8(msg, NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, 1); else NLA_PUT_U8(msg, NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, 0); argv++; argc--; } /* parse and put other NL80211_ATTR_MESH_SETUP elements here */ nla_nest_end(msg, container); if (!argc) return 0; return set_interface_meshparam(state, cb, msg, argc, argv, id); nla_put_failure: return -ENOBUFS; } COMMAND(mesh, join, " [mcast-rate ]" " [beacon-interval