ap: add profile settings PairwiseCiphers/GroupCipher

These can now be optionally provided in an AP profile and provide a
way to limit what ciphers can be chosen. This still is dependent on
what the hardware supports.
This commit is contained in:
James Prestwood 2022-11-02 15:51:08 -07:00 committed by Denis Kenzior
parent 5f84a78638
commit 262685e818
1 changed files with 83 additions and 6 deletions

View File

@ -3132,12 +3132,38 @@ static bool ap_load_psk(struct ap_state *ap, const struct l_settings *config)
return true;
}
/*
* Note: only PTK/GTK ciphers are supported here since this is all these are
* used for.
*/
static enum ie_rsn_cipher_suite ap_string_to_cipher(const char *str)
{
if (!strcmp(str, "UseGroupCipher"))
return IE_RSN_CIPHER_SUITE_USE_GROUP_CIPHER;
else if (!strcmp(str, "TKIP"))
return IE_RSN_CIPHER_SUITE_TKIP;
else if (!strcmp(str, "CCMP-128") || !strcmp(str, "CCMP"))
return IE_RSN_CIPHER_SUITE_CCMP;
else if (!strcmp(str, "GCMP-128") || !strcmp(str, "GCMP"))
return IE_RSN_CIPHER_SUITE_GCMP;
else if (!strcmp(str, "GCMP-256"))
return IE_RSN_CIPHER_SUITE_GCMP_256;
else if (!strcmp(str, "CCMP-256"))
return IE_RSN_CIPHER_SUITE_CCMP_256;
else
return 0;
}
static int ap_load_config(struct ap_state *ap, const struct l_settings *config,
bool *out_cck_rates)
{
struct wiphy *wiphy = netdev_get_wiphy(ap->netdev);
size_t len;
L_AUTO_FREE_VAR(char *, strval) = NULL;
_auto_(l_strv_free) char **ciphers_str = NULL;
uint16_t cipher_mask;
int err;
int i;
strval = l_settings_get_string(config, "General", "SSID");
if (L_WARN_ON(!strval))
@ -3212,6 +3238,8 @@ static int ap_load_config(struct ap_state *ap, const struct l_settings *config,
l_error("AP [WSC].PrimaryDeviceType format unknown");
return -EINVAL;
}
l_free(l_steal_ptr(strval));
} else {
/* Make ourselves a WFA standard PC by default */
ap->wsc_primary_device_type.category = 1;
@ -3260,6 +3288,61 @@ static int ap_load_config(struct ap_state *ap, const struct l_settings *config,
} else
*out_cck_rates = true;
cipher_mask = wiphy_get_supported_ciphers(wiphy, IE_GROUP_CIPHERS);
/* If the config sets a group cipher use that directly */
strval = l_settings_get_string(config, "Security", "GroupCipher");
if (strval) {
enum ie_rsn_cipher_suite cipher = ap_string_to_cipher(strval);
if (!cipher || !(cipher & cipher_mask)) {
l_error("Unsupported or unknown group cipher %s",
strval);
return -ENOTSUP;
}
ap->group_cipher = cipher;
l_free(l_steal_ptr(strval));
} else {
/* No config override, use CCMP (or TKIP if not supported) */
if (cipher_mask & IE_RSN_CIPHER_SUITE_CCMP)
ap->group_cipher = IE_RSN_CIPHER_SUITE_CCMP;
else
ap->group_cipher = IE_RSN_CIPHER_SUITE_TKIP;
}
cipher_mask = wiphy_get_supported_ciphers(wiphy, IE_PAIRWISE_CIPHERS);
ciphers_str = l_settings_get_string_list(config, "Security",
"PairwiseCiphers", ',');
for (i = 0; ciphers_str && ciphers_str[i]; i++) {
enum ie_rsn_cipher_suite cipher =
ap_string_to_cipher(ciphers_str[i]);
/*
* Constrain list to only values in both supported ciphers and
* the cipher list provided.
*/
if (!cipher || !(cipher & cipher_mask)) {
l_error("Unsupported or unknown pairwise cipher %s",
ciphers_str[i]);
return -ENOTSUP;
}
ap->ciphers |= cipher;
}
if (!ap->ciphers) {
/*
* Default behavior if no ciphers are specified, disable TKIP
* for security if CCMP is available
*/
if (cipher_mask & IE_RSN_CIPHER_SUITE_CCMP)
cipher_mask &= ~IE_RSN_CIPHER_SUITE_TKIP;
ap->ciphers = cipher_mask;
}
return 0;
}
@ -3302,12 +3385,6 @@ struct ap_state *ap_start(struct netdev *netdev, struct l_settings *config,
err = -EINVAL;
/* TODO: Add all ciphers supported by wiphy */
ap->ciphers = wiphy_select_cipher(wiphy, IE_RSN_CIPHER_SUITE_TKIP |
IE_RSN_CIPHER_SUITE_CCMP);
ap->group_cipher = wiphy_select_cipher(wiphy,
IE_RSN_CIPHER_SUITE_TKIP |
IE_RSN_CIPHER_SUITE_CCMP);
ap->beacon_interval = 100;
ap->networks = l_queue_new();