@@ -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;
+ 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();