From 7b39bee1c62dc68c84938cda43115e4d30724d1e Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Fri, 8 May 2015 13:14:36 +0200 Subject: [PATCH] iwinfo: add support for querying available HT modes Signed-off-by: Jo-Philipp Wich --- include/iwinfo.h | 16 ++++++++++ iwinfo_cli.c | 22 +++++++++++++ iwinfo_lib.c | 10 ++++++ iwinfo_lua.c | 31 ++++++++++++++++++ iwinfo_madwifi.c | 7 +++++ iwinfo_nl80211.c | 81 +++++++++++++++++++++++++++++++++++++++++------- iwinfo_wext.c | 7 +++++ iwinfo_wl.c | 24 ++++++++++++++ 8 files changed, 186 insertions(+), 12 deletions(-) diff --git a/include/iwinfo.h b/include/iwinfo.h index 57a88e2..95020a4 100644 --- a/include/iwinfo.h +++ b/include/iwinfo.h @@ -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 *); diff --git a/iwinfo_cli.c b/iwinfo_cli.c index d9a59e2..ed6be54 100644 --- a/iwinfo_cli.c +++ b/iwinfo_cli.c @@ -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 freqlist\n" " iwinfo assoclist\n" " iwinfo countrylist\n" + " iwinfo htmodelist\n" " iwinfo phyname
\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; diff --git a/iwinfo_lib.c b/iwinfo_lib.c index 0ab7be0..fa9bb9f 100644 --- a/iwinfo_lib.c +++ b/iwinfo_lib.c @@ -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 diff --git a/iwinfo_lua.c b/iwinfo_lua.c index 3201af4..21d6bbc 100644 --- a/iwinfo_lua.c +++ b/iwinfo_lua.c @@ -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), diff --git a/iwinfo_madwifi.c b/iwinfo_madwifi.c index bb7fc63..f28bca1 100644 --- a/iwinfo_madwifi.c +++ b/iwinfo_madwifi.c @@ -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, diff --git a/iwinfo_nl80211.c b/iwinfo_nl80211.c index 2562492..efc58e6 100644 --- a/iwinfo_nl80211.c +++ b/iwinfo_nl80211.c @@ -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, diff --git a/iwinfo_wext.c b/iwinfo_wext.c index a6cc516..73ba650 100644 --- a/iwinfo_wext.c +++ b/iwinfo_wext.c @@ -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, diff --git a/iwinfo_wl.c b/iwinfo_wl.c index 7cbda96..c7517ec 100644 --- a/iwinfo_wl.c +++ b/iwinfo_wl.c @@ -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,