diff --git a/src/ap.c b/src/ap.c index ba827728..44440191 100644 --- a/src/ap.c +++ b/src/ap.c @@ -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();