iwinfo: add support for querying available HT modes
authorJo-Philipp Wich <jow@openwrt.org>
Fri, 8 May 2015 11:14:36 +0000 (13:14 +0200)
committerJo-Philipp Wich <jow@openwrt.org>
Fri, 8 May 2015 11:29:10 +0000 (13:29 +0200)
Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
include/iwinfo.h
iwinfo_cli.c
iwinfo_lib.c
iwinfo_lua.c
iwinfo_madwifi.c
iwinfo_nl80211.c
iwinfo_wext.c
iwinfo_wl.c

index 57a88e2..95020a4 100644 (file)
@@ -66,6 +66,21 @@ enum iwinfo_opmode {
 extern const char *IWINFO_OPMODE_NAMES[];
 
 
+enum iwinfo_htmode {
+       IWINFO_HTMODE_HT20       = (1 << 0),
+       IWINFO_HTMODE_HT40       = (1 << 1),
+       IWINFO_HTMODE_VHT20      = (1 << 2),
+       IWINFO_HTMODE_VHT40      = (1 << 3),
+       IWINFO_HTMODE_VHT80      = (1 << 4),
+       IWINFO_HTMODE_VHT80_80   = (1 << 5),
+       IWINFO_HTMODE_VHT160     = (1 << 6),
+
+       IWINFO_HTMODE_COUNT      = 7
+};
+
+extern const char *IWINFO_HTMODE_NAMES[IWINFO_HTMODE_COUNT];
+
+
 struct iwinfo_rate_entry {
        uint32_t rate;
        int8_t mcs;
@@ -165,6 +180,7 @@ struct iwinfo_ops {
        int (*quality_max)(const char *, int *);
        int (*mbssid_support)(const char *, int *);
        int (*hwmodelist)(const char *, int *);
+       int (*htmodelist)(const char *, int *);
        int (*ssid)(const char *, char *);
        int (*bssid)(const char *, char *);
        int (*country)(const char *, char *);
index d9a59e2..ed6be54 100644 (file)
@@ -744,6 +744,23 @@ static void print_countrylist(const struct iwinfo_ops *iw, const char *ifname)
        }
 }
 
+static void print_htmodelist(const struct iwinfo_ops *iw, const char *ifname)
+{
+       int i, htmodes = 0;
+
+       if (iw->htmodelist(ifname, &htmodes))
+       {
+               printf("No HT mode information available\n");
+               return;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(IWINFO_HTMODE_NAMES); i++)
+               if (htmodes & (1 << i))
+                       printf("%s ", IWINFO_HTMODE_NAMES[i]);
+
+       printf("\n");
+}
+
 static void lookup_phy(const struct iwinfo_ops *iw, const char *section)
 {
        char buf[IWINFO_BUFSIZE];
@@ -781,6 +798,7 @@ int main(int argc, char **argv)
                        "       iwinfo <device> freqlist\n"
                        "       iwinfo <device> assoclist\n"
                        "       iwinfo <device> countrylist\n"
+                       "       iwinfo <device> htmodelist\n"
                        "       iwinfo <backend> phyname <section>\n"
                );
 
@@ -873,6 +891,10 @@ int main(int argc, char **argv)
                                        print_countrylist(iw, argv[1]);
                                        break;
 
+                               case 'h':
+                                       print_htmodelist(iw, argv[1]);
+                                       break;
+
                                default:
                                        fprintf(stderr, "Unknown command: %s\n", argv[i]);
                                        rv = 1;
index 0ab7be0..fa9bb9f 100644 (file)
@@ -57,6 +57,16 @@ const char *IWINFO_OPMODE_NAMES[] = {
        "P2P Go",
 };
 
+const char *IWINFO_HTMODE_NAMES[] = {
+       "HT20",
+       "HT40",
+       "VHT20",
+       "VHT40",
+       "VHT80",
+       "VHT80+80",
+       "VHT160",
+};
+
 
 /*
  * ISO3166 country labels
index 3201af4..21d6bbc 100644 (file)
@@ -509,6 +509,29 @@ static int iwinfo_L_hwmodelist(lua_State *L, int (*func)(const char *, int *))
        return 1;
 }
 
+/* Wrapper for htmode list */
+static int iwinfo_L_htmodelist(lua_State *L, int (*func)(const char *, int *))
+{
+       const char *ifname = luaL_checkstring(L, 1);
+       int i, htmodes = 0;
+
+       if (!(*func)(ifname, &htmodes))
+       {
+               lua_newtable(L);
+
+               for (i = 0; i < ARRAY_SIZE(IWINFO_HTMODE_NAMES); i++)
+               {
+                       lua_pushboolean(L, htmodes & (1 << i));
+                       lua_setfield(L, -2, IWINFO_HTMODE_NAMES[i]);
+               }
+
+               return 1;
+       }
+
+       lua_pushnil(L);
+       return 1;
+}
+
 /* Wrapper for mbssid_support */
 static int iwinfo_L_mbssid_support(lua_State *L, int (*func)(const char *, int *))
 {
@@ -636,6 +659,7 @@ LUA_WRAP_STRUCT_OP(wl,scanlist)
 LUA_WRAP_STRUCT_OP(wl,freqlist)
 LUA_WRAP_STRUCT_OP(wl,countrylist)
 LUA_WRAP_STRUCT_OP(wl,hwmodelist)
+LUA_WRAP_STRUCT_OP(wl,htmodelist)
 LUA_WRAP_STRUCT_OP(wl,encryption)
 LUA_WRAP_STRUCT_OP(wl,mbssid_support)
 LUA_WRAP_STRUCT_OP(wl,hardware_id)
@@ -665,6 +689,7 @@ LUA_WRAP_STRUCT_OP(madwifi,scanlist)
 LUA_WRAP_STRUCT_OP(madwifi,freqlist)
 LUA_WRAP_STRUCT_OP(madwifi,countrylist)
 LUA_WRAP_STRUCT_OP(madwifi,hwmodelist)
+LUA_WRAP_STRUCT_OP(madwifi,htmodelist)
 LUA_WRAP_STRUCT_OP(madwifi,encryption)
 LUA_WRAP_STRUCT_OP(madwifi,mbssid_support)
 LUA_WRAP_STRUCT_OP(madwifi,hardware_id)
@@ -694,6 +719,7 @@ LUA_WRAP_STRUCT_OP(nl80211,scanlist)
 LUA_WRAP_STRUCT_OP(nl80211,freqlist)
 LUA_WRAP_STRUCT_OP(nl80211,countrylist)
 LUA_WRAP_STRUCT_OP(nl80211,hwmodelist)
+LUA_WRAP_STRUCT_OP(nl80211,htmodelist)
 LUA_WRAP_STRUCT_OP(nl80211,encryption)
 LUA_WRAP_STRUCT_OP(nl80211,mbssid_support)
 LUA_WRAP_STRUCT_OP(nl80211,hardware_id)
@@ -722,6 +748,7 @@ LUA_WRAP_STRUCT_OP(wext,scanlist)
 LUA_WRAP_STRUCT_OP(wext,freqlist)
 LUA_WRAP_STRUCT_OP(wext,countrylist)
 LUA_WRAP_STRUCT_OP(wext,hwmodelist)
+LUA_WRAP_STRUCT_OP(wext,htmodelist)
 LUA_WRAP_STRUCT_OP(wext,encryption)
 LUA_WRAP_STRUCT_OP(wext,mbssid_support)
 LUA_WRAP_STRUCT_OP(wext,hardware_id)
@@ -749,6 +776,7 @@ static const luaL_reg R_wl[] = {
        LUA_REG(wl,freqlist),
        LUA_REG(wl,countrylist),
        LUA_REG(wl,hwmodelist),
+       LUA_REG(wl,htmodelist),
        LUA_REG(wl,encryption),
        LUA_REG(wl,mbssid_support),
        LUA_REG(wl,hardware_id),
@@ -781,6 +809,7 @@ static const luaL_reg R_madwifi[] = {
        LUA_REG(madwifi,freqlist),
        LUA_REG(madwifi,countrylist),
        LUA_REG(madwifi,hwmodelist),
+       LUA_REG(madwifi,htmodelist),
        LUA_REG(madwifi,encryption),
        LUA_REG(madwifi,mbssid_support),
        LUA_REG(madwifi,hardware_id),
@@ -813,6 +842,7 @@ static const luaL_reg R_nl80211[] = {
        LUA_REG(nl80211,freqlist),
        LUA_REG(nl80211,countrylist),
        LUA_REG(nl80211,hwmodelist),
+       LUA_REG(nl80211,htmodelist),
        LUA_REG(nl80211,encryption),
        LUA_REG(nl80211,mbssid_support),
        LUA_REG(nl80211,hardware_id),
@@ -844,6 +874,7 @@ static const luaL_reg R_wext[] = {
        LUA_REG(wext,freqlist),
        LUA_REG(wext,countrylist),
        LUA_REG(wext,hwmodelist),
+       LUA_REG(wext,htmodelist),
        LUA_REG(wext,encryption),
        LUA_REG(wext,mbssid_support),
        LUA_REG(wext,hardware_id),
index bb7fc63..f28bca1 100644 (file)
@@ -1024,6 +1024,12 @@ static int madwifi_get_hwmodelist(const char *ifname, int *buf)
        return -1;
 }
 
+static int madwifi_get_htmodelist(const char *ifname, int *buf)
+{
+       /* OpenWrt's madwifi did never support any HT rates */
+       return -1;
+}
+
 static int madwifi_get_mbssid_support(const char *ifname, int *buf)
 {
        /* Test whether we can create another interface */
@@ -1116,6 +1122,7 @@ const struct iwinfo_ops madwifi_ops = {
        .quality_max      = madwifi_get_quality_max,
        .mbssid_support   = madwifi_get_mbssid_support,
        .hwmodelist       = madwifi_get_hwmodelist,
+       .htmodelist       = madwifi_get_htmodelist,
        .mode             = madwifi_get_mode,
        .ssid             = madwifi_get_ssid,
        .bssid            = madwifi_get_bssid,
index 2562492..efc58e6 100644 (file)
@@ -2355,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
 {
-       int *modes = arg;
+       bool ok;
+       uint32_t hw;
+       uint32_t ht;
+};
+
+static int nl80211_get_modelist_cb(struct nl_msg *msg, void *arg)
+{
+       struct nl80211_modes *m = arg;
        int bands_remain, freqs_remain;
        uint16_t caps = 0;
        uint32_t vht_caps = 0;
@@ -2366,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)
@@ -2380,7 +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;
+                       {
+                               m->hw |= IWINFO_80211_N;
+                               m->ht |= IWINFO_HTMODE_HT20;
+
+                               if (caps & (1 << 1))
+                                       m->ht |= IWINFO_HTMODE_HT40;
+                       }
 
                        nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS],
                                            freqs_remain)
@@ -2393,8 +2405,8 @@ 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])
                                {
@@ -2402,14 +2414,29 @@ static int nl80211_get_hwmodelist_cb(struct nl_msg *msg, void *arg)
 
                                        /* Treat any nonzero capability as 11ac */
                                        if (vht_caps > 0)
-                                               *modes |= IWINFO_80211_AC;
+                                       {
+                                               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);
@@ -2601,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,
index a6cc516..73ba650 100644 (file)
@@ -440,6 +440,12 @@ static int wext_get_hwmodelist(const char *ifname, int *buf)
        return -1;
 }
 
+static int wext_get_htmodelist(const char *ifname, int *buf)
+{
+       /* Stub */
+       return -1;
+}
+
 static int wext_get_encryption(const char *ifname, char *buf)
 {
        /* No reliable crypto info in wext */
@@ -541,6 +547,7 @@ const struct iwinfo_ops wext_ops = {
        .quality_max      = wext_get_quality_max,
        .mbssid_support   = wext_get_mbssid_support,
        .hwmodelist       = wext_get_hwmodelist,
+       .htmodelist       = wext_get_htmodelist,
        .mode             = wext_get_mode,
        .ssid             = wext_get_ssid,
        .bssid            = wext_get_bssid,
index 7cbda96..c7517ec 100644 (file)
@@ -630,6 +630,29 @@ static int wl_get_hwmodelist(const char *ifname, int *buf)
        return -1;
 }
 
+static int wl_get_htmodelist(const char *ifname, int *buf)
+{
+       int modes;
+
+       if (!wl_get_hwmodelist(ifname, &modes))
+       {
+               *buf = 0;
+
+               /* FIXME: determine real capabilities */
+
+               if (modes & IWINFO_80211_N)
+                       *buf |= IWINFO_HTMODE_HT20 | IWINFO_HTMODE_HT40;
+
+               if (modes & IWINFO_80211_AC)
+                       *buf |= IWINFO_HTMODE_VHT20 | IWINFO_HTMODE_VHT40 |
+                               IWINFO_HTMODE_VHT80;
+
+               return 0;
+       }
+
+       return -1;
+}
+
 static int wl_get_mbssid_support(const char *ifname, int *buf)
 {
        wlc_rev_info_t revinfo;
@@ -715,6 +738,7 @@ const struct iwinfo_ops wl_ops = {
        .quality_max      = wl_get_quality_max,
        .mbssid_support   = wl_get_mbssid_support,
        .hwmodelist       = wl_get_hwmodelist,
+       .htmodelist       = wl_get_htmodelist,
        .mode             = wl_get_mode,
        .ssid             = wl_get_ssid,
        .bssid            = wl_get_bssid,