iwinfo: add support for querying available HT modes
[project/iwinfo.git] / iwinfo_nl80211.c
index 3facba953702ddd02b28eb5a12f74815c8bd5275..efc58e6be489c289e47c337a41fe1ba47ae2d06c 100644 (file)
@@ -2274,9 +2274,8 @@ static int nl80211_get_freqlist_cb(struct nl_msg *msg, void *arg)
                        e->channel = nl80211_freq2channel(e->mhz);
 
                        e->restricted = (
-                               freqs[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] ||
-                               freqs[NL80211_FREQUENCY_ATTR_NO_IBSS]      ||
-                               freqs[NL80211_FREQUENCY_ATTR_RADAR]
+                               freqs[NL80211_FREQUENCY_ATTR_NO_IR] &&
+                               !freqs[NL80211_FREQUENCY_ATTR_RADAR]
                        ) ? 1 : 0;
 
                        e++;
@@ -2356,9 +2355,17 @@ static int nl80211_get_countrylist(const char *ifname, char *buf, int *len)
        return 0;
 }
 
-static int nl80211_get_hwmodelist_cb(struct nl_msg *msg, void *arg)
+
+struct nl80211_modes
+{
+       bool ok;
+       uint32_t hw;
+       uint32_t ht;
+};
+
+static int nl80211_get_modelist_cb(struct nl_msg *msg, void *arg)
 {
-       int *modes = arg;
+       struct nl80211_modes *m = arg;
        int bands_remain, freqs_remain;
        uint16_t caps = 0;
        uint32_t vht_caps = 0;
@@ -2367,8 +2374,6 @@ static int nl80211_get_hwmodelist_cb(struct nl_msg *msg, void *arg)
        struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1];
        struct nlattr *band, *freq;
 
-       *modes = 0;
-
        if (attr[NL80211_ATTR_WIPHY_BANDS])
        {
                nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain)
@@ -2381,14 +2386,13 @@ static int nl80211_get_hwmodelist_cb(struct nl_msg *msg, void *arg)
 
                        /* Treat any nonzero capability as 11n */
                        if (caps > 0)
-                               *modes |= IWINFO_80211_N;
-
-                       if (bands[NL80211_BAND_ATTR_VHT_CAPA])
-                               vht_caps = nla_get_u32(bands[NL80211_BAND_ATTR_VHT_CAPA]);
+                       {
+                               m->hw |= IWINFO_80211_N;
+                               m->ht |= IWINFO_HTMODE_HT20;
 
-                       /* Treat any nonzero capability as 11ac */
-                       if (vht_caps > 0)
-                               *modes |= IWINFO_80211_AC;
+                               if (caps & (1 << 1))
+                                       m->ht |= IWINFO_HTMODE_HT40;
+                       }
 
                        nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS],
                                            freqs_remain)
@@ -2401,15 +2405,38 @@ static int nl80211_get_hwmodelist_cb(struct nl_msg *msg, void *arg)
 
                                if (nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]) < 2485)
                                {
-                                       *modes |= IWINFO_80211_B;
-                                       *modes |= IWINFO_80211_G;
+                                       m->hw |= IWINFO_80211_B;
+                                       m->hw |= IWINFO_80211_G;
+                               }
+                               else if (bands[NL80211_BAND_ATTR_VHT_CAPA])
+                               {
+                                       vht_caps = nla_get_u32(bands[NL80211_BAND_ATTR_VHT_CAPA]);
+
+                                       /* Treat any nonzero capability as 11ac */
+                                       if (vht_caps > 0)
+                                       {
+                                               m->hw |= IWINFO_80211_AC;
+                                               m->ht |= IWINFO_HTMODE_VHT20 | IWINFO_HTMODE_VHT40 | IWINFO_HTMODE_VHT80;
+
+                                               switch ((vht_caps >> 2) & 3)
+                                               {
+                                               case 2:
+                                                       m->ht |= IWINFO_HTMODE_VHT80_80;
+                                                       /* fall through */
+
+                                               case 1:
+                                                       m->ht |= IWINFO_HTMODE_VHT160;
+                                               }
+                                       }
                                }
-                               else if (!(*modes & IWINFO_80211_AC))
+                               else if (!(m->hw & IWINFO_80211_AC))
                                {
-                                       *modes |= IWINFO_80211_A;
+                                       m->hw |= IWINFO_80211_A;
                                }
                        }
                }
+
+               m->ok = 1;
        }
 
        return NL_SKIP;
@@ -2418,17 +2445,46 @@ static int nl80211_get_hwmodelist_cb(struct nl_msg *msg, void *arg)
 static int nl80211_get_hwmodelist(const char *ifname, int *buf)
 {
        struct nl80211_msg_conveyor *req;
+       struct nl80211_modes m = { };
 
        req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
        if (req)
        {
-               nl80211_send(req, nl80211_get_hwmodelist_cb, buf);
+               nl80211_send(req, nl80211_get_modelist_cb, &m);
                nl80211_free(req);
        }
 
-       return *buf ? 0 : -1;
+       if (m.ok)
+       {
+               *buf = m.hw;
+               return 0;
+       }
+
+       return -1;
 }
 
+static int nl80211_get_htmodelist(const char *ifname, int *buf)
+{
+       struct nl80211_msg_conveyor *req;
+       struct nl80211_modes m = { };
+
+       req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
+       if (req)
+       {
+               nl80211_send(req, nl80211_get_modelist_cb, &m);
+               nl80211_free(req);
+       }
+
+       if (m.ok)
+       {
+               *buf = m.ht;
+               return 0;
+       }
+
+       return -1;
+}
+
+
 static int nl80211_get_ifcomb_cb(struct nl_msg *msg, void *arg)
 {
        struct nlattr **attr = nl80211_parse(msg);
@@ -2446,15 +2502,15 @@ static int nl80211_get_ifcomb_cb(struct nl_msg *msg, void *arg)
                        [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
                        [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
                };
-               struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
+               struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB+1];
                static struct nla_policy iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
                        [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
                        [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
                };
-               struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
+               struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT+1];
                struct nlattr *limit;
 
-               nla_parse_nested(tb_comb, NL80211_BAND_ATTR_MAX, comb, iface_combination_policy);
+               nla_parse_nested(tb_comb, NUM_NL80211_IFACE_COMB, comb, iface_combination_policy);
 
                if (!tb_comb[NL80211_IFACE_COMB_LIMITS])
                        continue;
@@ -2575,6 +2631,17 @@ static int nl80211_get_frequency_offset(const char *ifname, int *buf)
        return 0;
 }
 
+static int nl80211_lookup_phyname(const char *section, char *buf)
+{
+       int idx;
+
+       if ((idx = nl80211_phy_idx_from_uci(section)) < 0)
+               return -1;
+
+       sprintf(buf, "phy%d", idx);
+       return 0;
+}
+
 const struct iwinfo_ops nl80211_ops = {
        .name             = "nl80211",
        .probe            = nl80211_probe,
@@ -2590,6 +2657,7 @@ const struct iwinfo_ops nl80211_ops = {
        .quality_max      = nl80211_get_quality_max,
        .mbssid_support   = nl80211_get_mbssid_support,
        .hwmodelist       = nl80211_get_hwmodelist,
+       .htmodelist       = nl80211_get_htmodelist,
        .mode             = nl80211_get_mode,
        .ssid             = nl80211_get_ssid,
        .bssid            = nl80211_get_bssid,
@@ -2603,5 +2671,6 @@ const struct iwinfo_ops nl80211_ops = {
        .scanlist         = nl80211_get_scanlist,
        .freqlist         = nl80211_get_freqlist,
        .countrylist      = nl80211_get_countrylist,
+       .lookup_phy       = nl80211_lookup_phyname,
        .close            = nl80211_close
 };