nl80211: Split wiphy_info_handler() into smaller helper functions
Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
4324555222
commit
5f43910727
1 changed files with 205 additions and 150 deletions
|
@ -2546,12 +2546,42 @@ static unsigned int probe_resp_offload_support(int supp_protocols)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int wiphy_info_handler(struct nl_msg *msg, void *arg)
|
static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
|
||||||
|
struct nlattr *tb)
|
||||||
{
|
{
|
||||||
struct nlattr *tb[NL80211_ATTR_MAX + 1];
|
struct nlattr *nl_mode;
|
||||||
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
|
int i;
|
||||||
struct wiphy_info_data *info = arg;
|
|
||||||
struct wpa_driver_capa *capa = info->capa;
|
if (tb == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
nla_for_each_nested(nl_mode, tb, i) {
|
||||||
|
switch (nla_type(nl_mode)) {
|
||||||
|
case NL80211_IFTYPE_AP:
|
||||||
|
info->capa->flags |= WPA_DRIVER_FLAGS_AP;
|
||||||
|
break;
|
||||||
|
case NL80211_IFTYPE_P2P_GO:
|
||||||
|
info->p2p_go_supported = 1;
|
||||||
|
break;
|
||||||
|
case NL80211_IFTYPE_P2P_CLIENT:
|
||||||
|
info->p2p_client_supported = 1;
|
||||||
|
break;
|
||||||
|
case NL80211_IFTYPE_MONITOR:
|
||||||
|
info->monitor_supported = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
|
||||||
|
struct nlattr *nl_combi)
|
||||||
|
{
|
||||||
|
struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
|
||||||
|
struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
|
||||||
|
struct nlattr *nl_limit, *nl_mode;
|
||||||
|
int err, rem_limit, rem_mode;
|
||||||
|
int combination_has_p2p = 0, combination_has_mgd = 0;
|
||||||
static struct nla_policy
|
static struct nla_policy
|
||||||
iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
|
iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
|
||||||
[NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
|
[NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
|
||||||
|
@ -2564,6 +2594,164 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
|
||||||
[NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
|
[NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
|
||||||
|
nl_combi, iface_combination_policy);
|
||||||
|
if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
|
||||||
|
!tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
|
||||||
|
!tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
|
||||||
|
return 0; /* broken combination */
|
||||||
|
|
||||||
|
nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS],
|
||||||
|
rem_limit) {
|
||||||
|
err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT,
|
||||||
|
nl_limit, iface_limit_policy);
|
||||||
|
if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES])
|
||||||
|
return 0; /* broken combination */
|
||||||
|
|
||||||
|
nla_for_each_nested(nl_mode,
|
||||||
|
tb_limit[NL80211_IFACE_LIMIT_TYPES],
|
||||||
|
rem_mode) {
|
||||||
|
int ift = nla_type(nl_mode);
|
||||||
|
if (ift == NL80211_IFTYPE_P2P_GO ||
|
||||||
|
ift == NL80211_IFTYPE_P2P_CLIENT)
|
||||||
|
combination_has_p2p = 1;
|
||||||
|
if (ift == NL80211_IFTYPE_STATION)
|
||||||
|
combination_has_mgd = 1;
|
||||||
|
}
|
||||||
|
if (combination_has_p2p && combination_has_mgd)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (combination_has_p2p && combination_has_mgd) {
|
||||||
|
info->p2p_concurrent = 1;
|
||||||
|
if (nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) > 1)
|
||||||
|
info->p2p_multichan_concurrent = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wiphy_info_iface_comb(struct wiphy_info_data *info,
|
||||||
|
struct nlattr *tb)
|
||||||
|
{
|
||||||
|
struct nlattr *nl_combi;
|
||||||
|
int rem_combi;
|
||||||
|
|
||||||
|
if (tb == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
nla_for_each_nested(nl_combi, tb, rem_combi) {
|
||||||
|
if (wiphy_info_iface_comb_process(info, nl_combi) > 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
|
||||||
|
struct nlattr *tb)
|
||||||
|
{
|
||||||
|
struct nlattr *nl_cmd;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (tb == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
nla_for_each_nested(nl_cmd, tb, i) {
|
||||||
|
switch (nla_get_u32(nl_cmd)) {
|
||||||
|
case NL80211_CMD_AUTHENTICATE:
|
||||||
|
info->auth_supported = 1;
|
||||||
|
break;
|
||||||
|
case NL80211_CMD_CONNECT:
|
||||||
|
info->connect_supported = 1;
|
||||||
|
break;
|
||||||
|
case NL80211_CMD_START_SCHED_SCAN:
|
||||||
|
info->capa->sched_scan_supported = 1;
|
||||||
|
break;
|
||||||
|
case NL80211_CMD_PROBE_CLIENT:
|
||||||
|
info->poll_command_supported = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wiphy_info_max_roc(struct wpa_driver_capa *capa,
|
||||||
|
struct nlattr *tb)
|
||||||
|
{
|
||||||
|
/* default to 5000 since early versions of mac80211 don't set it */
|
||||||
|
capa->max_remain_on_chan = 5000;
|
||||||
|
|
||||||
|
if (tb)
|
||||||
|
capa->max_remain_on_chan = nla_get_u32(tb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls,
|
||||||
|
struct nlattr *ext_setup)
|
||||||
|
{
|
||||||
|
if (tdls == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
|
||||||
|
capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
|
||||||
|
|
||||||
|
if (ext_setup) {
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
|
||||||
|
capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wiphy_info_feature_flags(struct wiphy_info_data *info,
|
||||||
|
struct nlattr *tb)
|
||||||
|
{
|
||||||
|
u32 flags;
|
||||||
|
struct wpa_driver_capa *capa = info->capa;
|
||||||
|
|
||||||
|
if (tb == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
flags = nla_get_u32(tb);
|
||||||
|
|
||||||
|
if (flags & NL80211_FEATURE_SK_TX_STATUS)
|
||||||
|
info->data_tx_status = 1;
|
||||||
|
|
||||||
|
if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
|
||||||
|
capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
|
||||||
|
|
||||||
|
if (flags & NL80211_FEATURE_SAE)
|
||||||
|
capa->flags |= WPA_DRIVER_FLAGS_SAE;
|
||||||
|
|
||||||
|
if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
|
||||||
|
capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa,
|
||||||
|
struct nlattr *tb)
|
||||||
|
{
|
||||||
|
u32 protocols;
|
||||||
|
|
||||||
|
if (tb == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
protocols = nla_get_u32(tb);
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response offload in AP "
|
||||||
|
"mode");
|
||||||
|
capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
|
||||||
|
capa->probe_resp_offloads = probe_resp_offload_support(protocols);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wiphy_info_handler(struct nl_msg *msg, void *arg)
|
||||||
|
{
|
||||||
|
struct nlattr *tb[NL80211_ATTR_MAX + 1];
|
||||||
|
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
|
||||||
|
struct wiphy_info_data *info = arg;
|
||||||
|
struct wpa_driver_capa *capa = info->capa;
|
||||||
|
|
||||||
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
|
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
|
||||||
genlmsg_attrlen(gnlh, 0), NULL);
|
genlmsg_attrlen(gnlh, 0), NULL);
|
||||||
|
|
||||||
|
@ -2579,109 +2767,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
|
||||||
capa->max_match_sets =
|
capa->max_match_sets =
|
||||||
nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
|
nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
|
||||||
|
|
||||||
if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
|
wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]);
|
||||||
struct nlattr *nl_mode;
|
wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]);
|
||||||
int i;
|
wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]);
|
||||||
nla_for_each_nested(nl_mode,
|
|
||||||
tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
|
|
||||||
switch (nla_type(nl_mode)) {
|
|
||||||
case NL80211_IFTYPE_AP:
|
|
||||||
capa->flags |= WPA_DRIVER_FLAGS_AP;
|
|
||||||
break;
|
|
||||||
case NL80211_IFTYPE_P2P_GO:
|
|
||||||
info->p2p_go_supported = 1;
|
|
||||||
break;
|
|
||||||
case NL80211_IFTYPE_P2P_CLIENT:
|
|
||||||
info->p2p_client_supported = 1;
|
|
||||||
break;
|
|
||||||
case NL80211_IFTYPE_MONITOR:
|
|
||||||
info->monitor_supported = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) {
|
|
||||||
struct nlattr *nl_combi;
|
|
||||||
int rem_combi;
|
|
||||||
|
|
||||||
nla_for_each_nested(nl_combi,
|
|
||||||
tb[NL80211_ATTR_INTERFACE_COMBINATIONS],
|
|
||||||
rem_combi) {
|
|
||||||
struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
|
|
||||||
struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
|
|
||||||
struct nlattr *nl_limit, *nl_mode;
|
|
||||||
int err, rem_limit, rem_mode;
|
|
||||||
int combination_has_p2p = 0, combination_has_mgd = 0;
|
|
||||||
|
|
||||||
err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
|
|
||||||
nl_combi,
|
|
||||||
iface_combination_policy);
|
|
||||||
if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
|
|
||||||
!tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
|
|
||||||
!tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
|
|
||||||
goto broken_combination;
|
|
||||||
|
|
||||||
nla_for_each_nested(nl_limit,
|
|
||||||
tb_comb[NL80211_IFACE_COMB_LIMITS],
|
|
||||||
rem_limit) {
|
|
||||||
err = nla_parse_nested(tb_limit,
|
|
||||||
MAX_NL80211_IFACE_LIMIT,
|
|
||||||
nl_limit,
|
|
||||||
iface_limit_policy);
|
|
||||||
if (err ||
|
|
||||||
!tb_limit[NL80211_IFACE_LIMIT_TYPES])
|
|
||||||
goto broken_combination;
|
|
||||||
|
|
||||||
nla_for_each_nested(
|
|
||||||
nl_mode,
|
|
||||||
tb_limit[NL80211_IFACE_LIMIT_TYPES],
|
|
||||||
rem_mode) {
|
|
||||||
int ift = nla_type(nl_mode);
|
|
||||||
if (ift == NL80211_IFTYPE_P2P_GO ||
|
|
||||||
ift == NL80211_IFTYPE_P2P_CLIENT)
|
|
||||||
combination_has_p2p = 1;
|
|
||||||
if (ift == NL80211_IFTYPE_STATION)
|
|
||||||
combination_has_mgd = 1;
|
|
||||||
}
|
|
||||||
if (combination_has_p2p && combination_has_mgd)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (combination_has_p2p && combination_has_mgd) {
|
|
||||||
info->p2p_concurrent = 1;
|
|
||||||
if (nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) > 1)
|
|
||||||
info->p2p_multichan_concurrent = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
broken_combination:
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
|
|
||||||
struct nlattr *nl_cmd;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
nla_for_each_nested(nl_cmd,
|
|
||||||
tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
|
|
||||||
switch (nla_get_u32(nl_cmd)) {
|
|
||||||
case NL80211_CMD_AUTHENTICATE:
|
|
||||||
info->auth_supported = 1;
|
|
||||||
break;
|
|
||||||
case NL80211_CMD_CONNECT:
|
|
||||||
info->connect_supported = 1;
|
|
||||||
break;
|
|
||||||
case NL80211_CMD_START_SCHED_SCAN:
|
|
||||||
capa->sched_scan_supported = 1;
|
|
||||||
break;
|
|
||||||
case NL80211_CMD_PROBE_CLIENT:
|
|
||||||
info->poll_command_supported = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
|
if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
|
||||||
wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
|
wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
|
||||||
|
@ -2694,55 +2782,21 @@ broken_combination:
|
||||||
capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
|
capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* default to 5000 since early versions of mac80211 don't set it */
|
wiphy_info_max_roc(capa,
|
||||||
capa->max_remain_on_chan = 5000;
|
tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
|
||||||
|
|
||||||
if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
|
if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
|
||||||
capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
|
capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
|
||||||
|
|
||||||
if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION])
|
wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT],
|
||||||
capa->max_remain_on_chan =
|
tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]);
|
||||||
nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
|
|
||||||
|
|
||||||
if (tb[NL80211_ATTR_TDLS_SUPPORT]) {
|
|
||||||
wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
|
|
||||||
capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
|
|
||||||
|
|
||||||
if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) {
|
|
||||||
wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
|
|
||||||
capa->flags |=
|
|
||||||
WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[NL80211_ATTR_DEVICE_AP_SME])
|
if (tb[NL80211_ATTR_DEVICE_AP_SME])
|
||||||
info->device_ap_sme = 1;
|
info->device_ap_sme = 1;
|
||||||
|
|
||||||
if (tb[NL80211_ATTR_FEATURE_FLAGS]) {
|
wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
|
||||||
u32 flags = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]);
|
wiphy_info_probe_resp_offload(capa,
|
||||||
|
tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
|
||||||
if (flags & NL80211_FEATURE_SK_TX_STATUS)
|
|
||||||
info->data_tx_status = 1;
|
|
||||||
|
|
||||||
if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
|
|
||||||
capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
|
|
||||||
|
|
||||||
if (flags & NL80211_FEATURE_SAE)
|
|
||||||
capa->flags |= WPA_DRIVER_FLAGS_SAE;
|
|
||||||
|
|
||||||
if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
|
|
||||||
capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) {
|
|
||||||
int protocols =
|
|
||||||
nla_get_u32(tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
|
|
||||||
wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response "
|
|
||||||
"offload in AP mode");
|
|
||||||
capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
|
|
||||||
capa->probe_resp_offloads =
|
|
||||||
probe_resp_offload_support(protocols);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NL_SKIP;
|
return NL_SKIP;
|
||||||
}
|
}
|
||||||
|
@ -5069,7 +5123,8 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
|
||||||
idx = phy_info->last_chan_idx;
|
idx = phy_info->last_chan_idx;
|
||||||
|
|
||||||
nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
|
nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
|
||||||
nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
|
nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
|
||||||
|
nla_data(nl_freq),
|
||||||
nla_len(nl_freq), freq_policy);
|
nla_len(nl_freq), freq_policy);
|
||||||
if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
|
if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
|
||||||
continue;
|
continue;
|
||||||
|
|
Loading…
Reference in a new issue