Add HT40 flags into driver channel list
This can be used to figure out whether the driver would allow HT40-/HT40+ on any specific channel.
This commit is contained in:
parent
148bb37f2e
commit
d8e66e80b9
|
@ -31,6 +31,9 @@
|
||||||
#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
|
#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
|
||||||
#define HOSTAPD_CHAN_NO_IBSS 0x00000004
|
#define HOSTAPD_CHAN_NO_IBSS 0x00000004
|
||||||
#define HOSTAPD_CHAN_RADAR 0x00000008
|
#define HOSTAPD_CHAN_RADAR 0x00000008
|
||||||
|
#define HOSTAPD_CHAN_HT40PLUS 0x00000010
|
||||||
|
#define HOSTAPD_CHAN_HT40MINUS 0x00000020
|
||||||
|
#define HOSTAPD_CHAN_HT40 0x00000040
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct hostapd_channel_data - Channel information
|
* struct hostapd_channel_data - Channel information
|
||||||
|
|
|
@ -3093,6 +3093,154 @@ wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start,
|
||||||
|
int end)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
for (c = 0; c < mode->num_channels; c++) {
|
||||||
|
struct hostapd_channel_data *chan = &mode->channels[c];
|
||||||
|
if (chan->freq - 10 >= start && chan->freq + 10 <= end)
|
||||||
|
chan->flag |= HOSTAPD_CHAN_HT40;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
|
||||||
|
int end)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
for (c = 0; c < mode->num_channels; c++) {
|
||||||
|
struct hostapd_channel_data *chan = &mode->channels[c];
|
||||||
|
if (!(chan->flag & HOSTAPD_CHAN_HT40))
|
||||||
|
continue;
|
||||||
|
if (chan->freq - 30 >= start && chan->freq - 10 <= end)
|
||||||
|
chan->flag |= HOSTAPD_CHAN_HT40MINUS;
|
||||||
|
if (chan->freq + 10 >= start && chan->freq + 30 <= end)
|
||||||
|
chan->flag |= HOSTAPD_CHAN_HT40PLUS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void nl80211_reg_rule_ht40(struct nlattr *tb[],
|
||||||
|
struct phy_info_arg *results)
|
||||||
|
{
|
||||||
|
u32 start, end, max_bw;
|
||||||
|
u16 m;
|
||||||
|
|
||||||
|
if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
|
||||||
|
tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
|
||||||
|
tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
|
||||||
|
end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
|
||||||
|
max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz",
|
||||||
|
start, end, max_bw);
|
||||||
|
if (max_bw < 40)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (m = 0; m < *results->num_modes; m++) {
|
||||||
|
if (!(results->modes[m].ht_capab &
|
||||||
|
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
|
||||||
|
continue;
|
||||||
|
nl80211_set_ht40_mode(&results->modes[m], start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void nl80211_reg_rule_sec(struct nlattr *tb[],
|
||||||
|
struct phy_info_arg *results)
|
||||||
|
{
|
||||||
|
u32 start, end, max_bw;
|
||||||
|
u16 m;
|
||||||
|
|
||||||
|
if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
|
||||||
|
tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
|
||||||
|
tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
|
||||||
|
end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
|
||||||
|
max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
|
||||||
|
|
||||||
|
if (max_bw < 20)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (m = 0; m < *results->num_modes; m++) {
|
||||||
|
if (!(results->modes[m].ht_capab &
|
||||||
|
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
|
||||||
|
continue;
|
||||||
|
nl80211_set_ht40_mode_sec(&results->modes[m], start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int nl80211_get_reg(struct nl_msg *msg, void *arg)
|
||||||
|
{
|
||||||
|
struct phy_info_arg *results = arg;
|
||||||
|
struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
|
||||||
|
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
|
||||||
|
struct nlattr *nl_rule;
|
||||||
|
struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1];
|
||||||
|
int rem_rule;
|
||||||
|
static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
|
||||||
|
[NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
|
||||||
|
[NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
|
||||||
|
[NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
|
||||||
|
[NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
|
||||||
|
[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
|
||||||
|
[NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
|
||||||
|
};
|
||||||
|
|
||||||
|
nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
|
||||||
|
genlmsg_attrlen(gnlh, 0), NULL);
|
||||||
|
if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
|
||||||
|
!tb_msg[NL80211_ATTR_REG_RULES]) {
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: No regulatory information "
|
||||||
|
"available");
|
||||||
|
return NL_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
|
||||||
|
(char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
|
||||||
|
|
||||||
|
nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
|
||||||
|
{
|
||||||
|
nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
|
||||||
|
nla_data(nl_rule), nla_len(nl_rule), reg_policy);
|
||||||
|
nl80211_reg_rule_ht40(tb_rule, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
|
||||||
|
{
|
||||||
|
nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
|
||||||
|
nla_data(nl_rule), nla_len(nl_rule), reg_policy);
|
||||||
|
nl80211_reg_rule_sec(tb_rule, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NL_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv,
|
||||||
|
struct phy_info_arg *results)
|
||||||
|
{
|
||||||
|
struct nl_msg *msg;
|
||||||
|
|
||||||
|
msg = nlmsg_alloc();
|
||||||
|
if (!msg)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
|
||||||
|
0, NL80211_CMD_GET_REG, 0);
|
||||||
|
return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct hostapd_hw_modes *
|
static struct hostapd_hw_modes *
|
||||||
wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
|
wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
|
||||||
{
|
{
|
||||||
|
@ -3116,8 +3264,10 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
|
||||||
|
|
||||||
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
|
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
|
||||||
|
|
||||||
if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0)
|
if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
|
||||||
|
nl80211_set_ht40_flags(drv, &result);
|
||||||
return wpa_driver_nl80211_add_11b(result.modes, num_modes);
|
return wpa_driver_nl80211_add_11b(result.modes, num_modes);
|
||||||
|
}
|
||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue