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;
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 *);
}
}
+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];
" iwinfo <device> freqlist\n"
" iwinfo <device> assoclist\n"
" iwinfo <device> countrylist\n"
+ " iwinfo <device> htmodelist\n"
" iwinfo <backend> phyname <section>\n"
);
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;
"P2P Go",
};
+const char *IWINFO_HTMODE_NAMES[] = {
+ "HT20",
+ "HT40",
+ "VHT20",
+ "VHT40",
+ "VHT80",
+ "VHT80+80",
+ "VHT160",
+};
+
/*
* ISO3166 country labels
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 *))
{
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)
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)
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)
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)
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),
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),
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),
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),
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 */
.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,
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;
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)
/* 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)
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])
{
/* 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;
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);
.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,
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 */
.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,
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;
.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,