nl80211: Split wiphy_info_handler() into smaller helper functions

Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2013-03-10 16:05:55 +02:00
parent 4324555222
commit 5f43910727

View file

@ -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;