]> git.ipfire.org Git - thirdparty/iw.git/commitdiff
iw: support split wiphy dump
authorJohannes Berg <johannes.berg@intel.com>
Thu, 14 Feb 2013 15:32:53 +0000 (16:32 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 25 Mar 2013 15:32:50 +0000 (16:32 +0100)
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

diff --git a/info.c b/info.c
index 390ef6dbd7e6faa54f979633cebe6a7449095f54..3d4eaebe590fb3426c1491a64f47e29c4d865aee 100644 (file)
--- a/info.c
+++ b/info.c
@@ -92,104 +92,127 @@ 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++;
-
-               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;
+       /* 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;
                        }
-                       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");
+                       last_band = nl_band->nla_type;
 
-                       if (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;
+                       nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
+                                 nla_len(nl_band), NULL);
 
-                               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);
+                       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_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");
+                               }
                                }
-                               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");
+                       }
+                       }
                }
        }
 
@@ -514,10 +537,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.");
@@ -535,3 +560,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, "");