diff mbox

[RFC] iw: support split wiphy dump

Message ID 1360856049-2546-1-git-send-email-johannes@sipsolutions.net (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Johannes Berg Feb. 14, 2013, 3:34 p.m. UTC
From: Johannes Berg <johannes.berg@intel.com>

This adds support for the new split wiphy dump,
it only uses it for "iw list", not for "info"
though, so far. Using it for "info" would mean
querying the kernel capability first and then
using get/dump (with filter) depending on that.
---
 info.c | 206 +++++++++++++++++++++++++++++++++++++++++------------------------
 1 file changed, 131 insertions(+), 75 deletions(-)

Comments

Johannes Berg Feb. 14, 2013, 3:40 p.m. UTC | #1
On Thu, 2013-02-14 at 16:34 +0100, Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
> 
> This adds support for the new split wiphy dump,
> it only uses it for "iw list", not for "info"
> though, so far. Using it for "info" would mean
> querying the kernel capability first and then
> using get/dump (with filter) depending on that.

Dennis, are you up for implementing this in wpa_supplicant?

johannes

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Dennis H Jensen Feb. 15, 2013, 8:56 a.m. UTC | #2
On Thu, 2013-02-14 at 16:40 +0100, Johannes Berg wrote:
> On Thu, 2013-02-14 at 16:34 +0100, Johannes Berg wrote:
> > From: Johannes Berg <johannes.berg@intel.com>
> > 
> > This adds support for the new split wiphy dump,
> > it only uses it for "iw list", not for "info"
> > though, so far. Using it for "info" would mean
> > querying the kernel capability first and then
> > using get/dump (with filter) depending on that.
> 
> Dennis, are you up for implementing this in wpa_supplicant?

Great, this will solve it. I can handle the wpa_supplicant; give me a
couple of days to get it sorted.

What's the procedure, do I post to both lists or just the hostap?

//Dennis

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Johannes Berg Feb. 15, 2013, 9:21 a.m. UTC | #3
On Fri, 2013-02-15 at 09:56 +0100, Dennis H Jensen wrote:
> On Thu, 2013-02-14 at 16:40 +0100, Johannes Berg wrote:
> > On Thu, 2013-02-14 at 16:34 +0100, Johannes Berg wrote:
> > > From: Johannes Berg <johannes.berg@intel.com>
> > > 
> > > This adds support for the new split wiphy dump,
> > > it only uses it for "iw list", not for "info"
> > > though, so far. Using it for "info" would mean
> > > querying the kernel capability first and then
> > > using get/dump (with filter) depending on that.
> > 
> > Dennis, are you up for implementing this in wpa_supplicant?
> 
> Great, this will solve it. I can handle the wpa_supplicant; give me a
> couple of days to get it sorted.

FWIW, I think for wpa_s there are two possibilities:
 1) simply always use NL_F_DUMP with NL80211_CMD_GET_WIPHY, and include
    the filter & split attributes; this will mean on old kernels it will
    retrieve information for all devices so you have to filter it
 2) query the nl80211 global features first when initialising the
    nl80211 sockets, and then use NL_F_DUMP with the filter only if the
    feature is supported in the kernel

Both are about the same difficulty because for 2) you need the extra
feature command (once at init) while for 1) you need an extra command to
get the wiphy index for the device you care about for filtering. For 1)
that command would be NL80211_CMD_GET_INTERFACE.

> What's the procedure, do I post to both lists or just the hostap?

Just hostap is fine.

johannes

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/info.c b/info.c
index 08dbfc0..5f0d535 100644
--- a/info.c
+++ b/info.c
@@ -78,92 +78,116 @@  static int print_phy_handler(struct nl_msg *msg, void *arg)
 	struct nlattr *nl_mode;
 	struct nlattr *nl_cmd;
 	struct nlattr *nl_if, *nl_ftype;
-	int bandidx = 1;
 	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_BANDS])
-		return NL_SKIP;
-
-	if (tb_msg[NL80211_ATTR_WIPHY_NAME])
+	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]));
 
-	nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
-		printf("\tBand %d:\n", bandidx);
-		bandidx++;
+	/* 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);
+			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]));
-
-		printf("\t\tFrequencies:\n");
-
-		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_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_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");
-		}
 
-		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_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");
+			}
+			}
 		}
 	}
 
@@ -464,10 +488,12 @@  static int handle_info(struct nl80211_state *state,
 		       enum id_input id)
 {
 	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_phy_handler, NULL);
+	/* kernels not supporting it will ignore this */
+	nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
 
 	return 0;
 }
-__COMMAND(NULL, info, "info", NULL, NL80211_CMD_GET_WIPHY, 0, 0, CIB_PHY, handle_info,
+__COMMAND(NULL, info, "info", NULL, NL80211_CMD_GET_WIPHY, NLM_F_DUMP, 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.");
@@ -485,3 +511,33 @@  static int handle_commands(struct nl80211_state *state,
 }
 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));
+
+	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]);
+
+		printf("nl80211 features: 0x%x\n", feat);
+		if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+			printf("\t* split wiphy dump\n");
+	}
+
+	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)
+{
+	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_feature_handler, NULL);
+	return 0;
+}
+
+TOPLEVEL(features, NULL, NL80211_CMD_GET_PROTOCOL_FEATURES, 0, CIB_NONE,
+	 handle_features, "");