iwinfo: nl80211: perform split wiphy dump

Perform a split wiphy dump when acquiring the hw modelist of a mac80211
device. Otherwise HE capabilities are missing from the message.

This is necessary since upstream commit f8d504caa ("nl80211: reduce
non-split wiphy dump size")  (Kernel 5.9).

Signed-off-by: David Bauer <mail@david-bauer.net>
This commit is contained in:
David Bauer 2021-04-19 01:38:15 +02:00
parent 50b64a63e3
commit 70d2136069

View file

@ -2941,8 +2941,73 @@ struct nl80211_modes
bool ok; bool ok;
uint32_t hw; uint32_t hw;
uint32_t ht; uint32_t ht;
uint32_t nl_freq;
uint16_t nl_ht;
uint32_t nl_vht;
uint16_t he_phy_cap[6];
}; };
static int nl80211_eval_modelist(struct nl80211_modes *m)
{
/* Treat any nonzero capability as 11n */
if (m->nl_ht > 0)
{
m->hw |= IWINFO_80211_N;
m->ht |= IWINFO_HTMODE_HT20;
if (m->nl_ht & (1 << 1))
m->ht |= IWINFO_HTMODE_HT40;
}
if (m->he_phy_cap[0] != 0) {
m->hw |= IWINFO_80211_AX;
m->ht |= IWINFO_HTMODE_HE20;
if (m->he_phy_cap[0] & BIT(9))
m->ht |= IWINFO_HTMODE_HE40;
if (m->he_phy_cap[0] & BIT(10))
m->ht |= IWINFO_HTMODE_HE40 | IWINFO_HTMODE_HE80;
if (m->he_phy_cap[0] & BIT(11))
m->ht |= IWINFO_HTMODE_HE160;
if (m->he_phy_cap[0] & BIT(12))
m->ht |= IWINFO_HTMODE_HE160 | IWINFO_HTMODE_HE80_80;
}
if (m->nl_freq < 2485)
{
m->hw |= IWINFO_80211_B;
m->hw |= IWINFO_80211_G;
}
else if (m->nl_vht)
{
/* Treat any nonzero capability as 11ac */
if (m->nl_vht > 0)
{
m->hw |= IWINFO_80211_AC;
m->ht |= IWINFO_HTMODE_VHT20 | IWINFO_HTMODE_VHT40 | IWINFO_HTMODE_VHT80;
switch ((m->nl_vht >> 2) & 3)
{
case 2:
m->ht |= IWINFO_HTMODE_VHT80_80;
/* fall through */
case 1:
m->ht |= IWINFO_HTMODE_VHT160;
}
}
}
else if (m->nl_freq >= 56160)
{
m->hw |= IWINFO_80211_AD;
}
else if (!(m->hw & IWINFO_80211_AC))
{
m->hw |= IWINFO_80211_A;
}
}
static int nl80211_get_modelist_cb(struct nl_msg *msg, void *arg) static int nl80211_get_modelist_cb(struct nl_msg *msg, void *arg)
{ {
struct nl80211_modes *m = arg; struct nl80211_modes *m = arg;
@ -2962,52 +3027,33 @@ static int nl80211_get_modelist_cb(struct nl_msg *msg, void *arg)
nla_data(band), nla_len(band), NULL); nla_data(band), nla_len(band), NULL);
if (bands[NL80211_BAND_ATTR_HT_CAPA]) if (bands[NL80211_BAND_ATTR_HT_CAPA])
caps = nla_get_u16(bands[NL80211_BAND_ATTR_HT_CAPA]); m->nl_ht = nla_get_u16(bands[NL80211_BAND_ATTR_HT_CAPA]);
/* Treat any nonzero capability as 11n */ if (bands[NL80211_BAND_ATTR_VHT_CAPA])
if (caps > 0) m->nl_vht = nla_get_u32(bands[NL80211_BAND_ATTR_VHT_CAPA]);
{
m->hw |= IWINFO_80211_N;
m->ht |= IWINFO_HTMODE_HT20;
if (caps & (1 << 1))
m->ht |= IWINFO_HTMODE_HT40;
}
if (bands[NL80211_BAND_ATTR_IFTYPE_DATA]) { if (bands[NL80211_BAND_ATTR_IFTYPE_DATA]) {
struct nlattr *tb[NL80211_BAND_IFTYPE_ATTR_MAX + 1]; struct nlattr *tb[NL80211_BAND_IFTYPE_ATTR_MAX + 1];
uint16_t phy_cap[6] = { 0 };
struct nlattr *nl_iftype; struct nlattr *nl_iftype;
int rem_band; int rem_band;
int len; int len;
m->hw |= IWINFO_80211_AX;
m->ht |= IWINFO_HTMODE_HE20;
nla_for_each_nested(nl_iftype, bands[NL80211_BAND_ATTR_IFTYPE_DATA], rem_band) { nla_for_each_nested(nl_iftype, bands[NL80211_BAND_ATTR_IFTYPE_DATA], rem_band) {
nla_parse(tb, NL80211_BAND_IFTYPE_ATTR_MAX, nla_parse(tb, NL80211_BAND_IFTYPE_ATTR_MAX,
nla_data(nl_iftype), nla_len(nl_iftype), NULL); nla_data(nl_iftype), nla_len(nl_iftype), NULL);
if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]) { if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]) {
len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]); len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]);
if (len > sizeof(phy_cap) - 1) if (len > sizeof(m->he_phy_cap) - 1)
len = sizeof(phy_cap) - 1; len = sizeof(m->he_phy_cap) - 1;
memcpy(&((__u8 *)phy_cap)[1], memcpy(&((__u8 *)m->he_phy_cap)[1],
nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]), nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]),
len); len);
} }
if (phy_cap[0] & BIT(9))
m->ht |= IWINFO_HTMODE_HE40;
if (phy_cap[0] & BIT(10))
m->ht |= IWINFO_HTMODE_HE40 | IWINFO_HTMODE_HE80;
if (phy_cap[0] & BIT(11))
m->ht |= IWINFO_HTMODE_HE160;
if (phy_cap[0] & BIT(12))
m->ht |= IWINFO_HTMODE_HE160 | IWINFO_HTMODE_HE80_80;
} }
} }
if (bands[NL80211_BAND_ATTR_FREQS]) {
nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS], nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS],
freqs_remain) freqs_remain)
{ {
@ -3017,39 +3063,7 @@ static int nl80211_get_modelist_cb(struct nl_msg *msg, void *arg)
if (!freqs[NL80211_FREQUENCY_ATTR_FREQ]) if (!freqs[NL80211_FREQUENCY_ATTR_FREQ])
continue; continue;
if (nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]) < 2485) m->nl_freq = nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]);
{
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 (nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]) >= 56160)
{
m->hw |= IWINFO_80211_AD;
}
else if (!(m->hw & IWINFO_80211_AC))
{
m->hw |= IWINFO_80211_A;
} }
} }
} }
@ -3062,20 +3076,29 @@ static int nl80211_get_modelist_cb(struct nl_msg *msg, void *arg)
static int nl80211_get_hwmodelist(const char *ifname, int *buf) static int nl80211_get_hwmodelist(const char *ifname, int *buf)
{ {
struct nl80211_modes m = { 0 }; struct nl80211_msg_conveyor *cv;
struct nl80211_modes m = {};
uint32_t features = nl80211_get_protocol_features(ifname);
int flags;
if (nl80211_request(ifname, NL80211_CMD_GET_WIPHY, 0, flags = features & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP ? NLM_F_DUMP : 0;
nl80211_get_modelist_cb, &m)) cv = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, flags);
if (!cv)
goto out; goto out;
if (!m.ok) NLA_PUT_FLAG(cv->msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
goto out; if (nl80211_send(cv, nl80211_get_modelist_cb, &m))
goto nla_put_failure;
nl80211_eval_modelist(&m);
*buf = m.hw; *buf = m.hw;
return 0; return 0;
nla_put_failure:
nl80211_free(cv);
out: out:
*buf = 0;
return -1; return -1;
} }
@ -3150,20 +3173,29 @@ static int nl80211_get_htmode(const char *ifname, int *buf)
static int nl80211_get_htmodelist(const char *ifname, int *buf) static int nl80211_get_htmodelist(const char *ifname, int *buf)
{ {
struct nl80211_modes m = { 0 }; struct nl80211_msg_conveyor *cv;
struct nl80211_modes m = {};
uint32_t features = nl80211_get_protocol_features(ifname);
int flags;
if (nl80211_request(ifname, NL80211_CMD_GET_WIPHY, 0, flags = features & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP ? NLM_F_DUMP : 0;
nl80211_get_modelist_cb, &m)) cv = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, flags);
if (!cv)
goto out; goto out;
if (!m.ok) NLA_PUT_FLAG(cv->msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
goto out; if (nl80211_send(cv, nl80211_get_modelist_cb, &m))
goto nla_put_failure;
nl80211_eval_modelist(&m);
*buf = m.ht; *buf = m.ht;
return 0; return 0;
nla_put_failure:
nl80211_free(cv);
out: out:
*buf = 0;
return -1; return -1;
} }