[pkg-wpa-devel] r1375 - in /iw/branches/upstream/current: Makefile event.c ibss.c info.c interface.c iw.c iw.h mesh.c mpath.c phy.c reason.c reg.c scan.c station.c status.c version.sh

kelmo-guest at users.alioth.debian.org kelmo-guest at users.alioth.debian.org
Wed May 13 18:50:00 UTC 2009


Author: kelmo-guest
Date: Wed May 13 18:49:59 2009
New Revision: 1375

URL: http://svn.debian.org/wsvn/?sc=1&rev=1375
Log:
[svn-upgrade] Integrating new upstream version, iw (0.9.14)

Added:
    iw/branches/upstream/current/event.c
    iw/branches/upstream/current/reason.c
    iw/branches/upstream/current/status.c
Modified:
    iw/branches/upstream/current/Makefile
    iw/branches/upstream/current/ibss.c
    iw/branches/upstream/current/info.c
    iw/branches/upstream/current/interface.c
    iw/branches/upstream/current/iw.c
    iw/branches/upstream/current/iw.h
    iw/branches/upstream/current/mesh.c
    iw/branches/upstream/current/mpath.c
    iw/branches/upstream/current/phy.c
    iw/branches/upstream/current/reg.c
    iw/branches/upstream/current/scan.c
    iw/branches/upstream/current/station.c
    iw/branches/upstream/current/version.sh

Modified: iw/branches/upstream/current/Makefile
URL: http://svn.debian.org/wsvn/iw/branches/upstream/current/Makefile?rev=1375&op=diff
==============================================================================
--- iw/branches/upstream/current/Makefile (original)
+++ iw/branches/upstream/current/Makefile Wed May 13 18:49:59 2009
@@ -13,7 +13,7 @@
 CFLAGS ?= -O2 -g
 CFLAGS += -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration
 
-OBJS = iw.o genl.o info.o phy.o interface.o ibss.o station.o util.o mesh.o mpath.o scan.o reg.o version.o
+OBJS = iw.o genl.o event.o info.o phy.o interface.o ibss.o station.o util.o mesh.o mpath.o scan.o reg.o version.o reason.o status.o
 ALL = iw
 
 NL1FOUND := $(shell pkg-config --atleast-version=1 libnl-1 && echo Y)

Added: iw/branches/upstream/current/event.c
URL: http://svn.debian.org/wsvn/iw/branches/upstream/current/event.c?rev=1375&op=file
==============================================================================
--- iw/branches/upstream/current/event.c (added)
+++ iw/branches/upstream/current/event.c Wed May 13 18:49:59 2009
@@ -1,0 +1,305 @@
+#include <stdint.h>
+#include <stdbool.h>
+#include <net/if.h>
+#include <errno.h>
+#include "iw.h"
+
+static int no_seq_check(struct nl_msg *msg, void *arg)
+{
+	return NL_OK;
+}
+
+struct print_event_args {
+	bool frame, time;
+};
+
+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 int print_event(struct nl_msg *msg, void *arg)
+{
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct print_event_args *args = arg;
+	char ifname[100];
+	char macbuf[6*3];
+	__u8 reg_type;
+
+	if (args->time) {
+		struct timeval tv;
+		gettimeofday(&tv, NULL);
+		printf("%ld.%06u: ", (long) tv.tv_sec, (unsigned int) tv.tv_usec);
+	}
+
+	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_IFINDEX]) {
+		if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
+		printf("%s: ", ifname);
+	} 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_NEW_SCAN_RESULTS:
+		printf("scan finished\n");
+		break;
+	case NL80211_CMD_SCAN_ABORTED:
+		printf("scan aborted\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_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");
+		print_frame(args, tb[NL80211_ATTR_FRAME]);
+		printf("\n");
+		break;
+	case NL80211_CMD_ASSOCIATE:
+		printf("assoc");
+		print_frame(args, tb[NL80211_ATTR_FRAME]);
+		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;
+	default:
+		printf("unknown event %d\n", gnlh->cmd);
+		break;
+	}
+
+	return NL_SKIP;
+}
+
+struct wait_event {
+	int n_cmds;
+	const __u32 *cmds;
+	__u32 cmd;
+};
+
+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;
+		}
+	}
+
+	return NL_SKIP;
+}
+
+static __u32 __listen_events(struct nl80211_state *state,
+			     const int n_waits, const __u32 *waits,
+			     struct print_event_args *args)
+{
+	int mcid, ret;
+	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;
+	}
+
+	/* 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;
+	}
+
+	/* 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;
+		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)
+{
+	return __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)
+{
+	struct print_event_args args;
+
+	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
+			return 1;
+		argc--;
+		argv++;
+	}
+
+	if (argc)
+		return 1;
+
+	return __listen_events(state, 0, NULL, &args);
+}
+TOPLEVEL(event, "[-t] [-f]", 0, 0, CIB_NONE, print_events,
+	"Monitor events from the kernel.\n"
+	"-t - print timestamp\n"
+	"-f - print full frame for auth/assoc etc.");

Modified: iw/branches/upstream/current/ibss.c
URL: http://svn.debian.org/wsvn/iw/branches/upstream/current/ibss.c?rev=1375&op=diff
==============================================================================
--- iw/branches/upstream/current/ibss.c (original)
+++ iw/branches/upstream/current/ibss.c Wed May 13 18:49:59 2009
@@ -63,6 +63,12 @@
 	return 0;
 }
 COMMAND(ibss, leave, NULL,
-	NL80211_CMD_LEAVE_IBSS, 0, CIB_NETDEV, leave_ibss);
+	NL80211_CMD_LEAVE_IBSS, 0, CIB_NETDEV, leave_ibss,
+	"Leave the current IBSS cell.");
 COMMAND(ibss, join, "<SSID> <freq in MHz> [fixed-freq] [<fixed bssid>]",
-	NL80211_CMD_JOIN_IBSS, 0, CIB_NETDEV, join_ibss);
+	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.");

Modified: iw/branches/upstream/current/info.c
URL: http://svn.debian.org/wsvn/iw/branches/upstream/current/info.c?rev=1375&op=diff
==============================================================================
--- iw/branches/upstream/current/info.c (original)
+++ iw/branches/upstream/current/info.c Wed May 13 18:49:59 2009
@@ -266,6 +266,8 @@
 
 	return 0;
 }
-TOPLEVEL(info, NULL, NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_info);
-TOPLEVEL(list, NULL, NL80211_CMD_GET_WIPHY, NLM_F_DUMP, CIB_NONE, handle_info);
-TOPLEVEL(phy, NULL, NL80211_CMD_GET_WIPHY, NLM_F_DUMP, CIB_NONE, handle_info);
+TOPLEVEL(info, NULL, NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_info,
+	 "Show capabilities for the specified wireless device.");
+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);

Modified: iw/branches/upstream/current/interface.c
URL: http://svn.debian.org/wsvn/iw/branches/upstream/current/interface.c?rev=1375&op=diff
==============================================================================
--- iw/branches/upstream/current/interface.c (original)
+++ iw/branches/upstream/current/interface.c Wed May 13 18:49:59 2009
@@ -11,6 +11,12 @@
 
 #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"
 
 static char *mntr_flags[NL80211_MNTR_FLAG_MAX + 1] = {
 	"none",
@@ -71,6 +77,9 @@
 	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)
@@ -181,10 +190,15 @@
  nla_put_failure:
 	return -ENOBUFS;
 }
-COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [flags ...]",
-	NL80211_CMD_NEW_INTERFACE, 0, CIB_PHY, handle_interface_add);
-COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [flags ...]",
-	NL80211_CMD_NEW_INTERFACE, 0, CIB_NETDEV, handle_interface_add);
+COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [flags <flag>*]",
+	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, "<name> type <type> [mesh_id <meshid>] [flags <flag>*]",
+	NL80211_CMD_NEW_INTERFACE, 0, CIB_NETDEV, handle_interface_add, NULL);
 
 static int handle_interface_del(struct nl80211_state *state,
 				struct nl_cb *cb,
@@ -193,7 +207,8 @@
 {
 	return 0;
 }
-TOPLEVEL(del, NULL, NL80211_CMD_DEL_INTERFACE, 0, CIB_NETDEV, handle_interface_del);
+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 int print_iface_handler(struct nl_msg *msg, void *arg)
@@ -232,7 +247,8 @@
 	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);
+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,
@@ -259,8 +275,10 @@
  nla_put_failure:
 	return -ENOBUFS;
 }
-COMMAND(set, monitor, "<flag> [...]",
-	NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_set);
+COMMAND(set, monitor, "<flag>*",
+	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,
@@ -281,7 +299,7 @@
 	return -ENOBUFS;
 }
 COMMAND(set, meshid, "<meshid>",
-	NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_meshid);
+	NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_meshid, NULL);
 
 static unsigned int dev_dump_wiphy;
 
@@ -294,7 +312,8 @@
 	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);
+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,
@@ -318,4 +337,6 @@
 	return -ENOBUFS;
 }
 COMMAND(set, type, "<type>",
-	NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_type);
+	NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_type,
+	"Set interface type/mode.\n"
+	IFACE_TYPES);

Modified: iw/branches/upstream/current/iw.c
URL: http://svn.debian.org/wsvn/iw/branches/upstream/current/iw.c?rev=1375&op=diff
==============================================================================
--- iw/branches/upstream/current/iw.c (original)
+++ iw/branches/upstream/current/iw.c Wed May 13 18:49:59 2009
@@ -12,6 +12,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <stdbool.h>
                      
 #include <netlink/genl/genl.h>
 #include <netlink/genl/family.h>
@@ -46,7 +47,7 @@
 #define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache
 #endif /* CONFIG_LIBNL20 */
 
-static int debug = 0;
+int iw_debug = 0;
 
 static int nl80211_init(struct nl80211_state *state)
 {
@@ -93,44 +94,97 @@
 	nl_socket_free(state->nl_sock);
 }
 
-__COMMAND(NULL, NULL, "", NULL, 0, 0, 0, CIB_NONE, NULL);
-__COMMAND(NULL, NULL, "", NULL, 1, 0, 0, CIB_NONE, NULL);
+__COMMAND(NULL, NULL, "", NULL, 0, 0, 0, CIB_NONE, NULL, NULL);
+__COMMAND(NULL, NULL, "", NULL, 1, 0, 0, CIB_NONE, NULL, NULL);
 
 static int cmd_size;
 
-static void usage(const char *argv0)
-{
-	struct cmd *cmd;
-
-	fprintf(stderr, "Usage:\t%s [options] command\n", argv0);
+static void __usage_cmd(struct cmd *cmd, char *indent, bool full)
+{
+	const char *start, *lend, *end;
+
+	fprintf(stderr, "%s", indent);
+
+	switch (cmd->idby) {
+	case CIB_NONE:
+		break;
+	case CIB_PHY:
+		fprintf(stderr, "phy <phyname> ");
+		break;
+	case CIB_NETDEV:
+		fprintf(stderr, "dev <devname> ");
+		break;
+	}
+	if (cmd->section)
+		fprintf(stderr, "%s ", cmd->section);
+	fprintf(stderr, "%s", cmd->name);
+	if (cmd->args)
+		fprintf(stderr, " %s", cmd->args);
+	fprintf(stderr, "\n");
+
+	if (!full || !cmd->help)
+		return;
+
+	/* hack */
+	if (strlen(indent))
+		indent = "\t\t";
+	else
+		fprintf(stderr, "\n");
+
+	/* print line by line */
+	start = cmd->help;
+	end = strchr(start, '\0');
+	do {
+		lend = strchr(start, '\n');
+		if (!lend)
+			lend = end;
+		fprintf(stderr, "%s", indent);
+		fprintf(stderr, "%.*s\n", (int)(lend - start), start);
+		start = lend + 1;
+	} while (end != lend);
+
+	fprintf(stderr, "\n");
+}
+
+static void usage_options(void)
+{
 	fprintf(stderr, "Options:\n");
 	fprintf(stderr, "\t--debug\t\tenable netlink debugging\n");
-	fprintf(stderr, "\t--version\tshow version\n");
+}
+
+static const char *argv0;
+
+static void usage(bool full)
+{
+	struct cmd *cmd;
+
+	fprintf(stderr, "Usage:\t%s [options] command\n", argv0);
+	usage_options();
+	fprintf(stderr, "\t--version\tshow version (%s)\n", iw_version);
 	fprintf(stderr, "Commands:\n");
-	fprintf(stderr, "\thelp\n");
-	fprintf(stderr, "\tevent\n");
 	for (cmd = &__start___cmd; cmd < &__stop___cmd;
 	     cmd = (struct cmd *)((char *)cmd + cmd_size)) {
 		if (!cmd->handler || cmd->hidden)
 			continue;
-		switch (cmd->idby) {
-		case CIB_NONE:
-			fprintf(stderr, "\t");
-			break;
-		case CIB_PHY:
-			fprintf(stderr, "\tphy <phyname> ");
-			break;
-		case CIB_NETDEV:
-			fprintf(stderr, "\tdev <devname> ");
-			break;
-		}
-		if (cmd->section)
-			fprintf(stderr, "%s ", cmd->section);
-		fprintf(stderr, "%s", cmd->name);
-		if (cmd->args)
-			fprintf(stderr, " %s", cmd->args);
-		fprintf(stderr, "\n");
-	}
+		__usage_cmd(cmd, "\t", full);
+	}
+}
+
+static int print_help(struct nl80211_state *state,
+		      struct nl_cb *cb,
+		      struct nl_msg *msg,
+		      int argc, char **argv)
+{
+	exit(3);
+}
+TOPLEVEL(help, NULL, 0, 0, CIB_NONE, print_help,
+	 "Print usage for each command.");
+
+static void usage_cmd(struct cmd *cmd)
+{
+	fprintf(stderr, "Usage:\t%s [options] ", argv0);
+	__usage_cmd(cmd, "", true);
+	usage_options();
 }
 
 static void version(void)
@@ -177,8 +231,8 @@
 	return NL_STOP;
 }
 
-int handle_cmd(struct nl80211_state *state, enum id_input idby,
-	       int argc, char **argv)
+static int __handle_cmd(struct nl80211_state *state, enum id_input idby,
+			int argc, char **argv, struct cmd **cmdout)
 {
 	struct cmd *cmd, *match = NULL;
 	struct nl_cb *cb;
@@ -264,6 +318,9 @@
 	if (!cmd)
 		return 1;
 
+	if (cmdout)
+		*cmdout = cmd;
+
 	if (!cmd->cmd) {
 		argc = o_argc;
 		argv = o_argv;
@@ -276,7 +333,7 @@
 		return 2;
 	}
 
-	cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
+	cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
 	if (!cb) {
 		fprintf(stderr, "failed to allocate netlink callbacks\n");
 		err = 2;
@@ -323,180 +380,17 @@
 	return 2;
 }
 
-static int no_seq_check(struct nl_msg *msg, void *arg)
-{
-	return NL_OK;
-}
-
-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];
-	char ifname[100];
-	char macbuf[6*3];
-	__u8 reg_type;
-
-	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-                          
-	switch (gnlh->cmd) {
-	case NL80211_CMD_NEW_WIPHY:
-		printf("wiphy rename: phy #%d to %s\n",
-		       nla_get_u32(tb[NL80211_ATTR_WIPHY]),
-		       nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]));
-		break;
-	case NL80211_CMD_NEW_SCAN_RESULTS:
-		if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
-		printf("scan finished on %s (phy #%d)\n",
-		       ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY]));
-		break;
-	case NL80211_CMD_SCAN_ABORTED:
-		if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
-		printf("scan aborted on %s (phy #%d)\n",
-		       ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY]));
-		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_JOIN_IBSS:
-		if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
-		mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
-		printf("IBSS %s joined on %s (phy #%d)\n",
-		       macbuf, ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY]));
-		break;
-	default:
-		printf("unknown event: %d\n", gnlh->cmd);
-		break;
-	}
-
-	return NL_SKIP;
-}
-
-struct wait_event {
-	int n_cmds;
-	const __u32 *cmds;
-	__u32 cmd;
-};
-
-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;
-		}
-	}
-
-	return NL_SKIP;
-}
-
-__u32 listen_events(struct nl80211_state *state,
-		    const int n_waits, const __u32 *waits)
-{
-	int mcid, ret;
-	struct nl_cb *cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
-	struct wait_event wait_ev;
-
-	if (!cb) {
-		fprintf(stderr, "failed to allocate netlink callbacks\n");
-		return -ENOMEM;
-	}
-
-	/* 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;
-	}
-
-	/* 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;
-		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, NULL);
-	}
-
-	wait_ev.cmd = 0;
-
-	while (!wait_ev.cmd)
-		nl_recvmsgs(state->nl_sock, cb);
-
-	nl_cb_put(cb);
-
-	return wait_ev.cmd;
+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 char *argv0;
+	struct cmd *cmd = NULL;
 
 	/* calculate command size including padding */
 	cmd_size = abs((long)&__cmd_NULL_NULL_1_CIB_NONE_0
@@ -506,7 +400,7 @@
 	argv0 = *argv++;
 
 	if (argc > 0 && strcmp(*argv, "--debug") == 0) {
-		debug = 1;
+		iw_debug = 1;
 		argc--;
 		argv++;
 	}
@@ -516,8 +410,9 @@
 		return 0;
 	}
 
+	/* need to treat "help" command specially so it works w/o nl80211 */
 	if (argc == 0 || strcmp(*argv, "help") == 0) {
-		usage(argv0);
+		usage(argc != 0);
 		return 0;
 	}
 
@@ -525,30 +420,28 @@
 	if (err)
 		return 1;
 
-	if (strcmp(*argv, "event") == 0) {
-		if (argc != 1)
-			err = 1;
-		else
-			err = listen_events(&nlstate, 0, NULL);
-	} else if (strcmp(*argv, "dev") == 0 && argc > 1) {
+	if (strcmp(*argv, "dev") == 0 && argc > 1) {
 		argc--;
 		argv++;
-		err = handle_cmd(&nlstate, II_NETDEV, 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);
+			err = __handle_cmd(&nlstate, II_PHY_NAME, argc, argv, &cmd);
 		} else if (*(*argv + 3) == '#')
-			err = handle_cmd(&nlstate, II_PHY_IDX, argc, argv);
+			err = __handle_cmd(&nlstate, II_PHY_IDX, argc, argv, &cmd);
 		else
 			err = 1;
 	} else
-		err = handle_cmd(&nlstate, II_NONE, argc, argv);
-
-	if (err == 1)
-		usage(argv0);
-	if (err < 0)
+		err = __handle_cmd(&nlstate, II_NONE, argc, argv, &cmd);
+
+	if (err == 1) {
+		if (cmd)
+			usage_cmd(cmd);
+		else
+			usage(false);
+	} else if (err < 0)
 		fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err);
 
 	nl80211_cleanup(&nlstate);

Modified: iw/branches/upstream/current/iw.h
URL: http://svn.debian.org/wsvn/iw/branches/upstream/current/iw.h?rev=1375&op=diff
==============================================================================
--- iw/branches/upstream/current/iw.h (original)
+++ iw/branches/upstream/current/iw.h Wed May 13 18:49:59 2009
@@ -37,6 +37,7 @@
 	const char *section;
 	const char *name;
 	const char *args;
+	const char *help;
 	const enum nl80211_commands cmd;
 	int nl_msg_flags;
 	int hidden;
@@ -54,21 +55,32 @@
 
 #define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(ar[0]))
 
-#define __COMMAND(sect, symname, name, args, nlcmd, flags, hidden, idby, handler)\
+#define __COMMAND(_section, _symname, _name, _args, _nlcmd, _flags, _hidden, _idby, _handler, _help)\
 	static const struct cmd						\
-	__cmd ## _ ## symname ## _ ## handler ## _ ## nlcmd ## _ ## idby ## _ ## hidden\
-	__attribute__((used)) __attribute__((section("__cmd")))		\
-	= { sect, name, args, nlcmd, flags, hidden, idby, handler }
-#define COMMAND(section, name, args, cmd, flags, idby, handler)	\
-	__COMMAND(#section, name, #name, args, cmd, flags, 0, idby, handler)
-#define HIDDEN(section, name, args, cmd, flags, idby, handler)	\
-	__COMMAND(#section, name, #name, args, cmd, flags, 1, idby, handler)
-#define TOPLEVEL(name, args, cmd, flags, idby, handler)		\
-	__COMMAND(NULL, name, #name, args, cmd, flags, 0, idby, handler)
+	__cmd ## _ ## _symname ## _ ## _handler ## _ ## _nlcmd ## _ ## _idby ## _ ## _hidden\
+	__attribute__((used)) __attribute__((section("__cmd")))	= {	\
+		.section = (_section),					\
+		.name = (_name),					\
+		.args = (_args),					\
+		.cmd = (_nlcmd),					\
+		.nl_msg_flags = (_flags),				\
+		.hidden = (_hidden),					\
+		.idby = (_idby),					\
+		.handler = (_handler),					\
+		.help = (_help),					\
+	 }
+#define COMMAND(section, name, args, cmd, flags, idby, handler, help)	\
+	__COMMAND(#section, name, #name, args, cmd, flags, 0, idby, handler, help)
+#define HIDDEN(section, name, args, cmd, flags, idby, handler)		\
+	__COMMAND(#section, name, #name, args, cmd, flags, 1, idby, handler, NULL)
+#define TOPLEVEL(name, args, cmd, flags, idby, handler, help)		\
+	__COMMAND(NULL, name, #name, args, cmd, flags, 0, idby, handler, help)
 extern struct cmd __start___cmd;
 extern struct cmd __stop___cmd;
 
 extern const char iw_version[];
+
+extern int iw_debug;
 
 int handle_cmd(struct nl80211_state *state, enum id_input idby,
 	       int argc, char **argv);
@@ -87,4 +99,7 @@
 
 char *reg_initiator_to_string(__u8 initiator);
 
+const char *get_reason_str(uint16_t reason);
+const char *get_status_str(uint16_t status);
+
 #endif /* __IW_H */

Modified: iw/branches/upstream/current/mesh.c
URL: http://svn.debian.org/wsvn/iw/branches/upstream/current/mesh.c?rev=1375&op=diff
==============================================================================
--- iw/branches/upstream/current/mesh.c (original)
+++ iw/branches/upstream/current/mesh.c Wed May 13 18:49:59 2009
@@ -244,7 +244,8 @@
 }
 
 COMMAND(set, mesh_param, "<param> <value>",
-	NL80211_CMD_SET_MESH_PARAMS, 0, CIB_NETDEV, set_interface_meshparam);
+	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)
@@ -290,4 +291,5 @@
 }
 
 COMMAND(get, mesh_param, "<param>",
-	NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, get_interface_meshparam);
+	NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, get_interface_meshparam,
+	"Retrieve mesh parameter (run command without any to see available ones).");

Modified: iw/branches/upstream/current/mpath.c
URL: http://svn.debian.org/wsvn/iw/branches/upstream/current/mpath.c?rev=1375&op=diff
==============================================================================
--- iw/branches/upstream/current/mpath.c (original)
+++ iw/branches/upstream/current/mpath.c Wed May 13 18:49:59 2009
@@ -123,9 +123,11 @@
 	return -ENOBUFS;
 }
 COMMAND(mpath, get, "<MAC address>",
-	NL80211_CMD_GET_MPATH, 0, CIB_NETDEV, handle_mpath_get);
+	NL80211_CMD_GET_MPATH, 0, CIB_NETDEV, handle_mpath_get,
+	"Get information on mesh path to the given node.");
 COMMAND(mpath, del, "<MAC address>",
-	NL80211_CMD_DEL_MPATH, 0, CIB_NETDEV, handle_mpath_get);
+	NL80211_CMD_DEL_MPATH, 0, CIB_NETDEV, handle_mpath_get,
+	"Remove the mesh path to the given node.");
 
 static int handle_mpath_set(struct nl80211_state *state,
 			    struct nl_cb *cb,
@@ -169,9 +171,11 @@
 	return -ENOBUFS;
 }
 COMMAND(mpath, new, "<destination MAC address> next_hop <next hop MAC address>",
-	NL80211_CMD_NEW_MPATH, 0, CIB_NETDEV, handle_mpath_set);
+	NL80211_CMD_NEW_MPATH, 0, CIB_NETDEV, handle_mpath_set,
+	"Create a new mesh path (instead of relying on automatic discovery).");
 COMMAND(mpath, set, "<destination MAC address> next_hop <next hop MAC address>",
-	NL80211_CMD_SET_MPATH, 0, CIB_NETDEV, handle_mpath_set);
+	NL80211_CMD_SET_MPATH, 0, CIB_NETDEV, handle_mpath_set,
+	"Set an existing mesh path's next hop.");
 
 static int handle_mpath_dump(struct nl80211_state *state,
 			     struct nl_cb *cb,
@@ -182,4 +186,5 @@
 	return 0;
 }
 COMMAND(mpath, dump, NULL,
-	NL80211_CMD_GET_MPATH, NLM_F_DUMP, CIB_NETDEV, handle_mpath_dump);
+	NL80211_CMD_GET_MPATH, NLM_F_DUMP, CIB_NETDEV, handle_mpath_dump,
+	"List known mesh paths.");

Modified: iw/branches/upstream/current/phy.c
URL: http://svn.debian.org/wsvn/iw/branches/upstream/current/phy.c?rev=1375&op=diff
==============================================================================
--- iw/branches/upstream/current/phy.c (original)
+++ iw/branches/upstream/current/phy.c Wed May 13 18:49:59 2009
@@ -25,7 +25,8 @@
  nla_put_failure:
 	return -ENOBUFS;
 }
-COMMAND(set, name, "<new name>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_name);
+COMMAND(set, name, "<new name>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_name,
+	"Rename this wireless device.");
 
 static int handle_freqchan(struct nl_msg *msg, bool chan,
 			   int argc, char **argv)
@@ -75,9 +76,11 @@
 	return handle_freqchan(msg, false, argc, argv);
 }
 COMMAND(set, freq, "<freq> [HT20|HT40+|HT40-]",
-	NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq);
+	NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq,
+	"Set frequency/channel the hardware is using, including HT\n"
+	"configuration.");
 COMMAND(set, freq, "<freq> [HT20|HT40+|HT40-]",
-	NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq);
+	NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL);
 
 static int handle_chan(struct nl80211_state *state,
 		       struct nl_cb *cb, struct nl_msg *msg,
@@ -86,6 +89,6 @@
 	return handle_freqchan(msg, true, argc, argv);
 }
 COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]",
-	NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan);
+	NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL);
 COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]",
-	NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan);
+	NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);

Added: iw/branches/upstream/current/reason.c
URL: http://svn.debian.org/wsvn/iw/branches/upstream/current/reason.c?rev=1375&op=file
==============================================================================
--- iw/branches/upstream/current/reason.c (added)
+++ iw/branches/upstream/current/reason.c Wed May 13 18:49:59 2009
@@ -1,0 +1,50 @@
+#include <stdint.h>
+#include "iw.h"
+
+static const char *reason_table[] = {
+	[1] = "Unspecified",
+	[2] = "Previous authentication no longer valid",
+	[3] = "Deauthenticated because sending station is leaving (or has left) the IBSS or ESS",
+	[4] = "Disassociated due to inactivity",
+	[5] = "Disassociated because AP is unable to handle all currently associated STA",
+	[6] = "Class 2 frame received from non-authenticated station",
+	[7] = "Class 3 frame received from non-authenticated station",
+	[8] = "Disassociated because sending station is leaving (or has left) the BSS",
+	[9] = "Station requesting (re)association is not authenticated with responding station",
+	[10] = "Disassociated because the information in the Power Capability element is unacceptable",
+	[11] = "Disassociated because the information in the Supported Channels element is unacceptable",
+	[13] = "Invalid information element",
+	[14] = "MIC failure",
+	[15] = "4-way handshake timeout",
+	[16] = "Group key update timeout",
+	[17] = "Information element in 4-way handshake different from (Re-)associate request/Probe response/Beacon",
+	[18] = "Multicast cipher is not valid",
+	[19] = "Unicast cipher is not valid",
+	[20] = "AKMP is not valid",
+	[21] = "Unsupported RSNE version",
+	[22] = "Invalid RSNE capabilities",
+	[23] = "IEEE 802.1X authentication failed",
+	[24] = "Cipher Suite rejected per security policy",
+	[31] = "TS deleted because QoS AP lacks sufficient bandwidth for this QoS STA due to a change in BSS service characteristics or operational mode",
+	[32] = "Disassociated for unspecified] =  QoS-related reason",
+	[33] = "Disassociated because QAP lacks sufficient bandwidth for this STA",
+	[34] = "Disassociated because of excessive frame losses and/or poor channel conditions",
+	[35] = "Disassociated because QSTA is transmitting outside the limits of its polled TXOPs",
+	[36] = "Requested from peer QSTA as the QSTA is leaving the QBSS (or resetting)",
+	[37] = "Requested from peer QSTA as it does not want to use Traffic Stream",
+	[38] = "Requested from peer QSTA as the QSTA received frames indicated Traffic Stream for which it has not set up",
+	[39] = "Requested from peer QSTA due to time out",
+	[40] = "Requested from peer QSTA as the QSTA is leaving the QBSS (or resetting)",
+	[41] = "Requested from peer QSTA as it does not want to receive frames directly from the QSTA",
+	[42] = "Requested from peer QSTA as the QSTA received DLP frames for which it has not set up",
+	[43] = "Requested from peer QSTA as it does not want to use Block Ack",
+	[44] = "Requested from peer QSTA as the QSTA received frames indicated Block Acknowledgement policy for which it has not set up",
+	[45] = "Peer QSTA does not support the requested cipher suite",
+};
+
+const char *get_reason_str(uint16_t reason)
+{
+	if (reason < ARRAY_SIZE(reason_table) && reason_table[reason])
+		return reason_table[reason];
+	return "<unknown>";
+}

Modified: iw/branches/upstream/current/reg.c
URL: http://svn.debian.org/wsvn/iw/branches/upstream/current/reg.c?rev=1375&op=diff
==============================================================================
--- iw/branches/upstream/current/reg.c (original)
+++ iw/branches/upstream/current/reg.c Wed May 13 18:49:59 2009
@@ -91,7 +91,8 @@
 	return -ENOBUFS;
 }
 COMMAND(reg, set, "<ISO/IEC 3166-1 alpha2>",
-	NL80211_CMD_REQ_SET_REG, 0, CIB_NONE, handle_reg_set);
+	NL80211_CMD_REQ_SET_REG, 0, CIB_NONE, handle_reg_set,
+	"Notify the kernel about the current regulatory domain.");
 
 static int print_reg_handler(struct nl_msg *msg, void *arg)
 
@@ -184,4 +185,5 @@
 	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_reg_handler, NULL);
 	return 0;
 }
-COMMAND(reg, get, NULL, NL80211_CMD_GET_REG, 0, CIB_NONE, handle_reg_get);
+COMMAND(reg, get, NULL, NL80211_CMD_GET_REG, 0, CIB_NONE, handle_reg_get,
+	"Print out the kernel's current regulatory domain information.");

Modified: iw/branches/upstream/current/scan.c
URL: http://svn.debian.org/wsvn/iw/branches/upstream/current/scan.c?rev=1375&op=diff
==============================================================================
--- iw/branches/upstream/current/scan.c (original)
+++ iw/branches/upstream/current/scan.c Wed May 13 18:49:59 2009
@@ -13,6 +13,23 @@
 #include "nl80211.h"
 #include "iw.h"
 
+#define WLAN_CAPABILITY_ESS		(1<<0)
+#define WLAN_CAPABILITY_IBSS		(1<<1)
+#define WLAN_CAPABILITY_CF_POLLABLE	(1<<2)
+#define WLAN_CAPABILITY_CF_POLL_REQUEST	(1<<3)
+#define WLAN_CAPABILITY_PRIVACY		(1<<4)
+#define WLAN_CAPABILITY_SHORT_PREAMBLE	(1<<5)
+#define WLAN_CAPABILITY_PBCC		(1<<6)
+#define WLAN_CAPABILITY_CHANNEL_AGILITY	(1<<7)
+#define WLAN_CAPABILITY_SPECTRUM_MGMT	(1<<8)
+#define WLAN_CAPABILITY_QOS		(1<<9)
+#define WLAN_CAPABILITY_SHORT_SLOT_TIME	(1<<10)
+#define WLAN_CAPABILITY_APSD		(1<<11)
+#define WLAN_CAPABILITY_DSSS_OFDM	(1<<13)
+
+static unsigned char wifi_oui[3]      = { 0x00, 0x50, 0xf2 };
+static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
+
 struct scan_params {
 	bool unknown;
 };
@@ -22,30 +39,94 @@
 		       struct nl_msg *msg,
 		       int argc, char **argv)
 {
-	struct nl_msg *ssids = NULL;
+	struct nl_msg *ssids = NULL, *freqs = NULL;
+	char *eptr;
 	int err = -ENOBUFS;
+	int i;
+	enum {
+		NONE,
+		FREQ,
+		SSID,
+		DONE,
+	} parse = NONE;
+	int freq;
+	bool passive = false, have_ssids = false, have_freqs = false;
 
 	ssids = nlmsg_alloc();
 	if (!ssids)
 		return -ENOMEM;
-	NLA_PUT(ssids, 1, 0, "");
-	nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
+
+	freqs = nlmsg_alloc();
+	if (!freqs) {
+		nlmsg_free(ssids);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < argc; i++) {
+		if (parse == NONE && strcmp(argv[i], "freq") == 0) {
+			parse = FREQ;
+			have_freqs = true;
+			continue;
+		} else if (parse < SSID && strcmp(argv[i], "ssid") == 0) {
+			parse = SSID;
+			have_ssids = true;
+			continue;
+		} else if (parse < SSID && strcmp(argv[i], "passive") == 0) {
+			parse = DONE;
+			passive = true;
+			continue;
+		}
+
+		switch (parse) {
+		case NONE:
+		case DONE:
+			return 1;
+		case FREQ:
+			freq = strtoul(argv[i], &eptr, 10);
+			if (eptr != argv[i] + strlen(argv[i]))
+				return 1;
+			NLA_PUT_U32(freqs, i, freq);
+			break;
+		case SSID:
+			NLA_PUT(ssids, i, strlen(argv[i]), argv[i]);
+			break;
+		}
+	}
+
+	if (!have_ssids)
+		NLA_PUT(ssids, 1, 0, "");
+	if (!passive)
+		nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
+
+	if (have_freqs)
+		nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
 
 	err = 0;
  nla_put_failure:
 	nlmsg_free(ssids);
+	nlmsg_free(freqs);
 	return err;
 }
-COMMAND(scan, trigger, NULL,
-	NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan);
-
-typedef void (*printfn)(unsigned char type, unsigned char len, unsigned char *data);
-
-static void print_ssid(unsigned char type, unsigned char len, unsigned char *data)
+COMMAND(scan, trigger, "[freq <freq>*] [ssid <ssid>*|passive]",
+	NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan,
+	 "Trigger a scan on the given frequencies with probing for the given\n"
+	 "SSIDs (or wildcard if not given) unless passive scanning is requested.");
+
+static void tab_on_first(bool *first)
+{
+	if (!*first)
+		printf("\t");
+	else
+		*first = false;
+}
+
+static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data)
 {
 	int i;
-	printf("\tSSID: ");
-	for (i=0; i<len; i++) {
+
+	printf(" ");
+
+	for (i = 0; i < len; i++) {
 		if (isprint(data[i]))
 			printf("%c", data[i]);
 		else
@@ -54,38 +135,512 @@
 	printf("\n");
 }
 
-static void print_supprates(unsigned char type, unsigned char len, unsigned char *data)
+static void print_supprates(const uint8_t type, uint8_t len, const uint8_t *data)
 {
 	int i;
 
-	if (type == 1)
-		printf("\tSupported rates: ");
-	else
-		printf("\tExtended supported rates: ");
-
-	for (i=0; i<len; i++) {
+	printf(" ");
+
+	for (i = 0; i < len; i++) {
 		int r = data[i] & 0x7f;
 		printf("%d.%d%s ", r/2, 5*(r&1), data[i] & 0x80 ? "*":"");
 	}
 	printf("\n");
 }
 
-static void print_ds(unsigned char type, unsigned char len, unsigned char *data)
-{
-	printf("\tDS Parameter set: channel %d\n", data[0]);
-}
-
-static void print_ign(unsigned char type, unsigned char len, unsigned char *data)
-{
-	/* ignore for now, not too useful */
-}
-
-static const printfn ieprinters[] = {
-	[0] = print_ssid,
-	[1] = print_supprates,
-	[3] = print_ds,
-	[5] = print_ign,
-	[50] = print_supprates,
+static void print_ds(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+	printf(" channel %d\n", data[0]);
+}
+
+static void print_country(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+	int i;
+
+	printf(" %.*s", 2, data);
+	switch (data[2]) {
+	case 'I':
+		printf(" (indoor)");
+		break;
+	case 'O':
+		printf(" (outdoor)");
+		break;
+	case ' ':
+		printf(" (in/outdoor)");
+		break;
+	default:
+		printf(" (invalid environment)");
+		break;
+	}
+	printf(", data:");
+	for(i=0; i<len-3; i++)
+		printf(" %.02x", data[i + 3]);
+	printf("\n");
+}
+
+static void print_powerconstraint(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+	printf(" %d dB\n", data[0]);
+}
+
+static void print_erp(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+	if (data[0] == 0x00)
+		printf(" <no flags>");
+	if (data[0] & 0x01)
+		printf(" NonERP_Present");
+	if (data[0] & 0x02)
+		printf(" Use_Protection");
+	if (data[0] & 0x04)
+		printf(" Barker_Preamble_Mode");
+	printf("\n");
+}
+
+static void print_cipher(const uint8_t *data)
+{
+	if (memcmp(data, wifi_oui, 3) == 0) {
+		switch (data[3]) {
+		case 0:
+			printf("Use group cipher suite");
+			break;
+		case 1:
+			printf("WEP-40");
+			break;
+		case 2:
+			printf("TKIP");
+			break;
+		case 4:
+			printf("CCMP");
+			break;
+		case 5:
+			printf("WEP-104");
+			break;
+		default:
+			printf("%.02x-%.02x-%.02x:%d",
+				data[0], data[1] ,data[2], data[3]);
+			break;
+		}
+	} else if (memcmp(data, ieee80211_oui, 3) == 0) {
+		switch (data[3]) {
+		case 0:
+			printf("Use group cipher suite");
+			break;
+		case 1:
+			printf("WEP-40");
+			break;
+		case 2:
+			printf("TKIP");
+			break;
+		case 4:
+			printf("CCMP");
+			break;
+		case 5:
+			printf("WEP-104");
+			break;
+		case 6:
+			printf("AES-128-CMAC");
+			break;
+		default:
+			printf("%.02x-%.02x-%.02x:%d",
+				data[0], data[1] ,data[2], data[3]);
+			break;
+		}
+	} else
+		printf("%.02x-%.02x-%.02x:%d",
+			data[0], data[1] ,data[2], data[3]);
+}
+
+static void print_auth(const uint8_t *data)
+{
+	if (memcmp(data, wifi_oui, 3) == 0) {
+		switch (data[3]) {
+		case 1:
+			printf("IEEE 802.1X");
+			break;
+		case 2:
+			printf("PSK");
+			break;
+		default:
+			printf("%.02x-%.02x-%.02x:%d",
+				data[0], data[1] ,data[2], data[3]);
+			break;
+		}
+	} else if (memcmp(data, ieee80211_oui, 3) == 0) {
+		switch (data[3]) {
+		case 1:
+			printf("IEEE 802.1X");
+			break;
+		case 2:
+			printf("PSK");
+			break;
+		case 3:
+			printf("FT/IEEE 802.1X");
+			break;
+		case 4:
+			printf("FT/PSK");
+			break;
+		case 5:
+			printf("IEEE 802.1X/SHA-256");
+			break;
+		case 6:
+			printf("PSK/SHA-256");
+			break;
+		default:
+			printf("%.02x-%.02x-%.02x:%d",
+				data[0], data[1] ,data[2], data[3]);
+			break;
+		}
+	} else
+		printf("%.02x-%.02x-%.02x:%d",
+			data[0], data[1] ,data[2], data[3]);
+}
+
+static void print_rsn_ie(const char *defcipher, const char *defauth,
+			 uint8_t len, const uint8_t *data)
+{
+	bool first = true;
+	__u16 version, count, capa;
+	int i;
+
+	version = data[0] + (data[1] << 8);
+	tab_on_first(&first);
+	printf("\t * Version: %d\n", version);
+
+	data += 2;
+	len -= 2;
+
+	if (len < 4) {
+		tab_on_first(&first);
+		printf("\t * Group cipher: %s\n", defcipher);
+		printf("\t * Pairwise ciphers: %s\n", defcipher);
+		return;
+	}
+
+	tab_on_first(&first);
+	printf("\t * Group cipher: ");
+	print_cipher(data);
+	printf("\n");
+
+	data += 4;
+	len -= 4;
+
+	if (len < 2) {
+		tab_on_first(&first);
+		printf("\t * Pairwise ciphers: %s\n", defcipher);
+		return;
+	}
+
+	count = data[0] | (data[1] << 8);
+	if (2 + (count * 4) > len)
+		goto invalid;
+
+	tab_on_first(&first);
+	printf("\t * Pairwise ciphers:");
+	for (i = 0; i < count; i++) {
+		printf(" ");
+		print_cipher(data + 2 + (i * 4));
+	}
+	printf("\n");
+
+	data += 2 + (count * 4);
+	len -= 2 + (count * 4);
+
+	if (len < 2) {
+		tab_on_first(&first);
+		printf("\t * Authentication suites: %s\n", defauth);
+		return;
+	}
+
+	count = data[0] | (data[1] << 8);
+	if (2 + (count * 4) > len)
+		goto invalid;
+
+	tab_on_first(&first);
+	printf("\t * Authentication suites:");
+	for (i = 0; i < count; i++) {
+		printf(" ");
+		print_auth(data + 2 + (i * 4));
+	}
+	printf("\n");
+
+	data += 2 + (count * 4);
+	len -= 2 + (count * 4);
+
+	if (len >= 2) {
+		capa = data[0] | (data[1] << 8);
+		tab_on_first(&first);
+		printf("\t * Capabilities:");
+		if (capa & 0x0001)
+			printf(" PreAuth");
+		if (capa & 0x0002)
+			printf(" NoPairwise");
+		switch ((capa & 0x000c) >> 2) {
+		case 0:
+			break;
+		case 1:
+			printf(" 2-PTKSA-RC");
+			break;
+		case 2:
+			printf(" 4-PTKSA-RC");
+			break;
+		case 3:
+			printf(" 16-PTKSA-RC");
+			break;
+		}
+		switch ((capa & 0x0030) >> 4) {
+		case 0:
+			break;
+		case 1:
+			printf(" 2-GTKSA-RC");
+			break;
+		case 2:
+			printf(" 4-GTKSA-RC");
+			break;
+		case 3:
+			printf(" 16-GTKSA-RC");
+			break;
+		}
+		if (capa & 0x0040)
+			printf(" MFP-required");
+		if (capa & 0x0080)
+			printf(" MFP-capable");
+		if (capa & 0x0200)
+			printf(" Peerkey-enabled");
+		if (capa & 0x0400)
+			printf(" SPP-AMSDU-capable");
+		if (capa & 0x0800)
+			printf(" SPP-AMSDU-required");
+		printf(" (0x%.4x)\n", capa);
+		data += 2;
+		len -= 2;
+	}
+
+ invalid:
+	if (len != 0) {
+		printf("\t\t * bogus tail data (%d):", len);
+		while (len) {
+			printf(" %.2x", *data);
+			data++;
+			len--;
+		}
+		printf("\n");
+	}
+}
+
+static void print_rsn(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+	print_rsn_ie("CCMP", "IEEE 802.1X", len, data);
+}
+
+static void print_capabilities(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+	int i, base, bit;
+	bool first = true;
+
+
+	for (i = 0; i < len; i++) {
+		base = i * 8;
+
+		for (bit = 0; bit < 8; bit++) {
+			if (!(data[i] & (1 << bit)))
+				continue;
+
+			if (!first)
+				printf(",");
+			else
+				first = false;
+
+			switch (bit + base) {
+			case 0:
+				printf(" HT Information Exchange Supported");
+				break;
+			case 1:
+				printf(" On-demand Beacon");
+				break;
+			case 2:
+				printf(" Extended Channel Switching");
+				break;
+			case 3:
+				printf(" Wave Indication");
+				break;
+			case 4:
+				printf(" PSMP Capability");
+				break;
+			case 5:
+				printf(" Service Interval Granularity");
+				break;
+			case 6:
+				printf(" S-PSMP Capability");
+				break;
+			default:
+				printf(" %d", bit);
+				break;
+			}
+		}
+	}
+
+	printf("\n");
+}
+
+struct ie_print {
+	const char *name;
+	void (*print)(const uint8_t type, uint8_t len, const uint8_t *data);
+	uint8_t minlen, maxlen;
+};
+
+static void print_ie(const struct ie_print *p, const uint8_t type,
+		     uint8_t len, const uint8_t *data)
+{
+	int i;
+
+	if (!p->print)
+		return;
+
+	printf("\t%s:", p->name);
+	if (len < p->minlen || len > p->maxlen) {
+		if (len > 1) {
+			printf(" <invalid: %d bytes:", len);
+			for (i = 0; i < len; i++)
+				printf(" %.02x", data[i]);
+			printf(">\n");
+		} else if (len)
+			printf(" <invalid: 1 byte: %.02x>\n", data[0]);
+		else
+			printf(" <invalid: no data>\n");
+		return;
+	}
+
+	p->print(type, len, data);
+}
+
+#define PRINT_IGN {		\
+	.name = "IGNORE",	\
+	.print = NULL,		\
+	.minlen = 0,		\
+	.maxlen = 255,		\
+}
+
+static const struct ie_print ieprinters[] = {
+	[0] = { "SSID", print_ssid, 0, 32, },
+	[1] = { "Supported rates", print_supprates, 0, 255, },
+	[3] = { "DS Paramater set", print_ds, 1, 1, },
+	[5] = PRINT_IGN,
+	[7] = { "Country", print_country, 3, 255, },
+	[32] = { "Power constraint", print_powerconstraint, 1, 1, },
+	[42] = { "ERP", print_erp, 1, 255, },
+	[48] = { "RSN", print_rsn, 2, 255, },
+	[50] = { "Extended supported rates", print_supprates, 0, 255, },
+	[127] = { "Extended capabilities", print_capabilities, 0, 255, },
+};
+
+static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+	print_rsn_ie("TKIP", "IEEE 802.1X", len, data);
+}
+
+static void print_wifi_wmm(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+	int i;
+
+	switch (data[0]) {
+	case 0x00:
+		printf(" information:");
+		break;
+	case 0x01:
+		printf(" parameter:");
+		break;
+	default:
+		printf(" type %d:", data[0]);
+		break;
+	}
+
+	for(i = 0; i < len - 1; i++)
+		printf(" %.02x", data[i + 1]);
+	printf("\n");
+}
+
+static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+	bool first = true;
+	__u16 subtype, sublen;
+
+	while (len >= 4) {
+		subtype = (data[0] << 8) + data[1];
+		sublen = (data[2] << 8) + data[3];
+		if (sublen > len)
+			break;
+
+		switch (subtype) {
+		case 0x104a:
+			tab_on_first(&first);
+			printf("\t * Version: %d.%d\n", data[4] >> 4, data[4] & 0xF);
+			break;
+		case 0x1011:
+			tab_on_first(&first);
+			printf("\t * Device name: %.*s\n", sublen, data + 4);
+			break;
+		case 0x1021:
+			tab_on_first(&first);
+			printf("\t * Manufacturer: %.*s\n", sublen, data + 4);
+			break;
+		case 0x1023:
+			tab_on_first(&first);
+			printf("\t * Model: %.*s\n", sublen, data + 4);
+			break;
+		case 0x1057: {
+			__u16 val = (data[4] << 8) | data[5];
+			tab_on_first(&first);
+			printf("\t * AP setup locked: 0x%.4x\n", val);
+			break;
+		}
+		case 0x1008: {
+			__u16 meth = (data[4] << 8) + data[5];
+			bool comma = false;
+			tab_on_first(&first);
+			printf("\t * Config methods:");
+#define T(bit, name) do {		\
+	if (meth & (1<<bit)) {		\
+		if (comma)		\
+			printf(",");	\
+		comma = true;		\
+		printf(" " name);	\
+	} } while (0)
+			T(0, "USB");
+			T(1, "Ethernet");
+			T(2, "Label");
+			T(3, "Display");
+			T(4, "Ext. NFC");
+			T(5, "Int. NFC");
+			T(6, "NFC Intf.");
+			T(7, "PBC");
+			T(8, "Keypad");
+			printf("\n");
+			break;
+#undef T
+		}
+		default:
+			break;
+		}
+
+		data += sublen + 4;
+		len -= sublen + 4;
+	}
+
+	if (len != 0) {
+		printf("\t\t * bogus tail data (%d):", len);
+		while (len) {
+			printf(" %.2x", *data);
+			data++;
+			len--;
+		}
+		printf("\n");
+	}
+}
+
+static const struct ie_print wifiprinters[] = {
+	[1] = { "WPA", print_wifi_wpa, 2, 255, },
+	[2] = { "WMM", print_wifi_wmm, 1, 255, },
+	[4] = { "WPS", print_wifi_wps, 0, 255, },
 };
 
 static void print_vendor(unsigned char len, unsigned char *data,
@@ -93,30 +648,51 @@
 {
 	int i;
 
-	/* currently _all_ vendor IEs are unknown (not parsed) */
+	if (len < 3) {
+		printf("\tVendor specific: <too short> data:");
+		for(i = 0; i < len; i++)
+			printf(" %.02x", data[i]);
+		printf("\n");
+		return;
+	}
+
+	if (len >= 4 && memcmp(data, wifi_oui, 3) == 0) {
+		if (data[3] < ARRAY_SIZE(wifiprinters) && wifiprinters[data[3]].name) {
+			print_ie(&wifiprinters[data[3]], data[3], len - 4, data + 4);
+			return;
+		}
+		if (!params->unknown)
+			return;
+		printf("\tWiFi OUI %#.2x, data:", data[3]);
+		for(i = 0; i < len - 4; i++)
+			printf(" %.02x", data[i + 4]);
+		printf("\n");
+		return;
+	}
+
 	if (!params->unknown)
 		return;
 
-	printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data: ",
+	printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
 		data[0], data[1], data[2]);
-	for (i=3; i<len; i++)
-		printf("\\x%.2x", data[i]);
+	for (i = 3; i < len; i++)
+		printf(" %.2x", data[i]);
 	printf("\n");
 }
 
 static void print_ies(unsigned char *ie, int ielen, struct scan_params *params)
 {
 	while (ielen >= 2 && ielen >= ie[1]) {
-		if (ie[0] < ARRAY_SIZE(ieprinters) && ieprinters[ie[0]]) {
-			ieprinters[ie[0]](ie[0], ie[1], ie + 2);
+		if (ie[0] < ARRAY_SIZE(ieprinters) && ieprinters[ie[0]].name) {
+			print_ie(&ieprinters[ie[0]], ie[0], ie[1], ie + 2);
 		} else if (ie[0] == 221 /* vendor */) {
 			print_vendor(ie[1], ie + 2, params);
 		} else if (params->unknown) {
 			int i;
 
-			printf("\tUnknown IE (%d): ", ie[0]);
+			printf("\tUnknown IE (%d):", ie[0]);
 			for (i=0; i<ie[1]; i++)
-				printf("\\x%.2x", ie[2+i]);
+				printf(" %.2x", ie[2+i]);
 			printf("\n");
 		}
 		ielen -= ie[1] + 2;
@@ -175,9 +751,33 @@
 	if (bss[NL80211_BSS_BEACON_INTERVAL])
 		printf("\tbeacon interval: %d\n",
 			nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]));
-	if (bss[NL80211_BSS_CAPABILITY])
-		printf("\tcapability: 0x%.4x\n",
-			nla_get_u16(bss[NL80211_BSS_CAPABILITY]));
+	if (bss[NL80211_BSS_CAPABILITY]) {
+		__u16 capa = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
+		printf("\tcapability:");
+		if (capa & WLAN_CAPABILITY_ESS)
+			printf(" ESS");
+		if (capa & WLAN_CAPABILITY_IBSS)
+			printf(" IBSS");
+		if (capa & WLAN_CAPABILITY_PRIVACY)
+			printf(" Privacy");
+		if (capa & WLAN_CAPABILITY_SHORT_PREAMBLE)
+			printf(" ShortPreamble");
+		if (capa & WLAN_CAPABILITY_PBCC)
+			printf(" PBCC");
+		if (capa & WLAN_CAPABILITY_CHANNEL_AGILITY)
+			printf(" ChannelAgility");
+		if (capa & WLAN_CAPABILITY_SPECTRUM_MGMT)
+			printf(" SpectrumMgmt");
+		if (capa & WLAN_CAPABILITY_QOS)
+			printf(" QoS");
+		if (capa & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+			printf(" ShortSlotTime");
+		if (capa & WLAN_CAPABILITY_APSD)
+			printf(" APSD");
+		if (capa & WLAN_CAPABILITY_DSSS_OFDM)
+			printf(" DSSS-OFDM");
+		printf(" (0x%.4x)\n", capa);
+	}
 	if (bss[NL80211_BSS_SIGNAL_MBM]) {
 		int s = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
 		printf("\tsignal: %d.%.2d dBm\n", s/100, s%100);
@@ -213,33 +813,72 @@
 	return 0;
 }
 COMMAND(scan, dump, "[-u]",
-	NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump);
+	NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump,
+	"Dump the current scan results. If -u is specified, print unknown\n"
+	"data in scan results.");
 
 static int handle_scan_combined(struct nl80211_state *state,
 				struct nl_cb *cb,
 				struct nl_msg *msg,
 				int argc, char **argv)
 {
-	static char *trig_argv[] = {
-		NULL,
-		"scan",
-		"trigger",
-	};
+	char **trig_argv;
 	static char *dump_argv[] = {
 		NULL,
 		"scan",
 		"dump",
+		NULL,
 	};
 	static const __u32 cmds[] = {
 		NL80211_CMD_NEW_SCAN_RESULTS,
 		NL80211_CMD_SCAN_ABORTED,
 	};
-	int err;
-
+	int trig_argc, dump_argc, err;
+
+	if (argc >= 3 && !strcmp(argv[2], "-u")) {
+		dump_argc = 4;
+		dump_argv[3] = "-u";
+	} else
+		dump_argc = 3;
+
+	trig_argc = 3 + (argc - 2) + (3 - dump_argc);
+	trig_argv = calloc(trig_argc, sizeof(*trig_argv));
+	if (!trig_argv)
+		return -ENOMEM;
 	trig_argv[0] = argv[0];
-	err = handle_cmd(state, II_NETDEV, ARRAY_SIZE(trig_argv), trig_argv);
+	trig_argv[1] = "scan";
+	trig_argv[2] = "trigger";
+	int i;
+	for (i = 0; i < argc - 2 - (dump_argc - 3); i++)
+		trig_argv[i + 3] = argv[i + 2 + (dump_argc - 3)];
+	err = handle_cmd(state, II_NETDEV, trig_argc, trig_argv);
+	free(trig_argv);
 	if (err)
 		return err;
+
+	/*
+	 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
+	 *
+	 * This code has a bug, which requires creating a separate
+	 * nl80211 socket to fix:
+	 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
+	 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
+	 * before (!) we listen to it, because we only start listening
+	 * after we send our scan request.
+	 *
+	 * Doing it the other way around has a race condition as well,
+	 * if you first open the events socket you may get a notification
+	 * for a previous scan.
+	 *
+	 * The only proper way to fix this would be to listen to events
+	 * before sending the command, and for the kernel to send the
+	 * scan request along with the event, so that you can match up
+	 * whether the scan you requested was finished or aborted (this
+	 * may result in processing a scan that another application
+	 * requested, but that doesn't seem to be a problem).
+	 *
+	 * Alas, the kernel doesn't do that (yet).
+	 */
 
 	if (listen_events(state, ARRAY_SIZE(cmds), cmds) ==
 					NL80211_CMD_SCAN_ABORTED) {
@@ -248,6 +887,10 @@
 	}
 
 	dump_argv[0] = argv[0];
-	return handle_cmd(state, II_NETDEV, ARRAY_SIZE(dump_argv), dump_argv);
-}
-TOPLEVEL(scan, NULL, 0, 0, CIB_NETDEV, handle_scan_combined);
+	return handle_cmd(state, II_NETDEV, dump_argc, dump_argv);
+}
+TOPLEVEL(scan, "[-u] [freq <freq>*] [ssid <ssid>*|passive]", 0, 0,
+	 CIB_NETDEV, handle_scan_combined,
+	 "Scan on the given frequencies and probe for the given SSIDs\n"
+	 "(or wildcard if not given) unless passive scanning is requested.\n"
+	 "If -u is specified print unknown data in the scan results.");

Modified: iw/branches/upstream/current/station.c
URL: http://svn.debian.org/wsvn/iw/branches/upstream/current/station.c?rev=1375&op=diff
==============================================================================
--- iw/branches/upstream/current/station.c (original)
+++ iw/branches/upstream/current/station.c Wed May 13 18:49:59 2009
@@ -188,9 +188,11 @@
 	return -ENOBUFS;
 }
 COMMAND(station, get, "<MAC address>",
-	NL80211_CMD_GET_STATION, 0, CIB_NETDEV, handle_station_get);
+	NL80211_CMD_GET_STATION, 0, CIB_NETDEV, handle_station_get,
+	"Get information for a specific station.");
 COMMAND(station, del, "<MAC address>",
-	NL80211_CMD_DEL_STATION, 0, CIB_NETDEV, handle_station_get);
+	NL80211_CMD_DEL_STATION, 0, CIB_NETDEV, handle_station_get,
+	"Remove the given station entry (use with caution!)");
 
 static int handle_station_set(struct nl80211_state *state,
 			      struct nl_cb *cb,
@@ -237,7 +239,8 @@
 	return -ENOBUFS;
 }
 COMMAND(station, set, "<MAC address> plink_action <open|block>",
-	NL80211_CMD_SET_STATION, 0, CIB_NETDEV, handle_station_set);
+	NL80211_CMD_SET_STATION, 0, CIB_NETDEV, handle_station_set,
+	"Set mesh peer link action for this station (peer).");
 
 static int handle_station_dump(struct nl80211_state *state,
 			       struct nl_cb *cb,
@@ -248,4 +251,5 @@
 	return 0;
 }
 COMMAND(station, dump, NULL,
-	NL80211_CMD_GET_STATION, NLM_F_DUMP, CIB_NETDEV, handle_station_dump);
+	NL80211_CMD_GET_STATION, NLM_F_DUMP, CIB_NETDEV, handle_station_dump,
+	"List all stations known, e.g. the AP on managed interfaces");

Added: iw/branches/upstream/current/status.c
URL: http://svn.debian.org/wsvn/iw/branches/upstream/current/status.c?rev=1375&op=file
==============================================================================
--- iw/branches/upstream/current/status.c (added)
+++ iw/branches/upstream/current/status.c Wed May 13 18:49:59 2009
@@ -1,0 +1,59 @@
+#include <stdint.h>
+#include "iw.h"
+
+static const char *status_table[] = {
+	[0] = "Successful",
+	[1] = "Unspecified failure",
+	[10] = "Cannot support all requested capabilities in the capability information field",
+	[11] = "Reassociation denied due to inability to confirm that association exists",
+	[12] = "Association denied due to reason outside the scope of this standard",
+	[13] = "Responding station does not support the specified authentication algorithm",
+	[14] = "Received an authentication frame with authentication transaction sequence number out of expected sequence",
+	[15] = "Authentication rejected because of challenge failure",
+	[16] = "Authentication rejected due to timeout waiting for next frame in sequence",
+	[17] = "Association denied because AP is unable to handle additional associated STA",
+	[18] = "Association denied due to requesting station not supporting all of the data rates in the BSSBasicRateSet parameter",
+	[19] = "Association denied due to requesting station not supporting the short preamble option",
+	[20] = "Association denied due to requesting station not supporting the PBCC modulation option",
+	[21] = "Association denied due to requesting station not supporting the channel agility option",
+	[22] = "Association request rejected because Spectrum Management capability is required",
+	[23] = "Association request rejected because the information in the Power Capability element is unacceptable",
+	[24] = "Association request rejected because the information in the Supported Channels element is unacceptable",
+	[25] = "Association request rejected due to requesting station not supporting the short slot time option",
+	[26] = "Association request rejected due to requesting station not supporting the ER-PBCC modulation option",
+	[27] = "Association denied due to requesting STA not supporting HT features",
+	[28] = "R0KH Unreachable",
+	[29] = "Association denied because the requesting STA does not support the PCO transition required by the AP",
+	[30] = "Association request rejected temporarily; try again later",
+	[31] = "Robust Management frame policy violation",
+	[32] = "Unspecified, QoS related failure",
+	[33] = "Association denied due to QAP having insufficient bandwidth to handle another QSTA",
+	[34] = "Association denied due to poor channel conditions",
+	[35] = "Association (with QBSS) denied due to requesting station not supporting the QoS facility",
+	[37] = "The request has been declined",
+	[38] = "The request has not been successful as one or more parameters have invalid values",
+	[39] = "The TS has not been created because the request cannot be honored. However, a suggested Tspec is provided so that the initiating QSTA may attempt to send another TS with the suggested changes to the TSpec",
+	[40] = "Invalid Information Element",
+	[41] = "Group Cipher is not valid",
+	[42] = "Pairwise Cipher is not valid",
+	[43] = "AKMP is not valid",
+	[44] = "Unsupported RSN IE version",
+	[45] = "Invalid RSN IE Capabilities",
+	[46] = "Cipher suite is rejected per security policy",
+	[47] = "The TS has not been created. However, the HC may be capable of creating a TS, in response to a request, after the time indicated in the TS Delay element",
+	[48] = "Direct link is not allowed in the BSS by policy",
+	[49] = "Destination STA is not present within this QBSS",
+	[50] = "The destination STA is not a QSTA",
+	[51] = "Association denied because Listen Interval is too large",
+	[52] = "Invalid Fast BSS Transition Action Frame Count",
+	[53] = "Invalid PMKID",
+	[54] = "Invalid MDIE",
+	[55] = "Invalid FTIE",
+};
+
+const char *get_status_str(uint16_t status)
+{
+	if (status < ARRAY_SIZE(status_table) && status_table[status])
+		return status_table[status];
+	return "<unknown>";
+}

Modified: iw/branches/upstream/current/version.sh
URL: http://svn.debian.org/wsvn/iw/branches/upstream/current/version.sh?rev=1375&op=diff
==============================================================================
--- iw/branches/upstream/current/version.sh (original)
+++ iw/branches/upstream/current/version.sh Wed May 13 18:49:59 2009
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-VERSION="0.9.13"
+VERSION="0.9.14"
 OUT="$1"
 
 if head=`git rev-parse --verify HEAD 2>/dev/null`; then




More information about the Pkg-wpa-devel mailing list