diff --git a/src/core/supplicant/nm-supplicant-config.c b/src/core/supplicant/nm-supplicant-config.c index 7db614a213..4433e809e9 100644 --- a/src/core/supplicant/nm-supplicant-config.c +++ b/src/core/supplicant/nm-supplicant-config.c @@ -499,6 +499,52 @@ nm_supplicant_config_add_setting_macsec(NMSupplicantConfig *self, return TRUE; } +static void +get_ap_params(guint freq, + NMSettingWirelessChannelWidth width, + guint *out_ht40, + int *out_max_oper_chwidth, + guint *out_center_freq) +{ + *out_ht40 = 0; + *out_max_oper_chwidth = -1; + *out_center_freq = 0; + + switch (width) { + case NM_SETTING_WIRELESS_CHANNEL_WIDTH_40MHZ: + *out_ht40 = 1; + *out_max_oper_chwidth = 0; + return; + case NM_SETTING_WIRELESS_CHANNEL_WIDTH_80MHZ: + { + guint channel; + + if (freq < 5000) { + /* the setting is not valid */ + nm_assert_not_reached(); + return; + } + + /* Determine the center channel according to the table at + * https://en.wikipedia.org/wiki/List_of_WLAN_channels */ + channel = (freq - 5000) / 5; + channel = ((channel / 4 - 1) / 4) * 16 + 10; + + *out_ht40 = 1; + *out_max_oper_chwidth = 1; + *out_center_freq = 5000 + 5 * channel; + + return; + } + + case NM_SETTING_WIRELESS_CHANNEL_WIDTH_AUTO: + case NM_SETTING_WIRELESS_CHANNEL_WIDTH_20MHZ: + default: + /* in case of unknown enum value, fall back to the safest parameters */ + return; + } +} + gboolean nm_supplicant_config_add_setting_wireless(NMSupplicantConfig *self, NMSettingWireless *setting, @@ -562,10 +608,48 @@ nm_supplicant_config_add_setting_wireless(NMSupplicantConfig *self, if ((is_adhoc || is_ap || is_mesh) && fixed_freq) { gs_free char *str_freq = NULL; + guint ht40; + int max_oper_chwidth; + guint center_freq; str_freq = g_strdup_printf("%u", fixed_freq); if (!nm_supplicant_config_add_option(self, "frequency", str_freq, -1, NULL, error)) return FALSE; + + if (is_ap) { + get_ap_params(fixed_freq, + nm_setting_wireless_get_channel_width(setting), + &ht40, + &max_oper_chwidth, + ¢er_freq); + + if (!nm_supplicant_config_add_option(self, "ht40", ht40 ? "1" : "0", -1, NULL, error)) + return FALSE; + + if (center_freq != 0) { + g_free(str_freq); + str_freq = g_strdup_printf("%u", center_freq); + if (!nm_supplicant_config_add_option(self, + "vht_center_freq1", + str_freq, + -1, + NULL, + error)) + return FALSE; + } + + if (max_oper_chwidth >= 0) { + g_free(str_freq); + str_freq = g_strdup_printf("%u", max_oper_chwidth); + if (!nm_supplicant_config_add_option(self, + "max_oper_chwidth", + str_freq, + -1, + NULL, + error)) + return FALSE; + } + } } /* Except for Ad-Hoc, Hotspot and Mesh, request that the driver probe for the diff --git a/src/core/supplicant/nm-supplicant-settings-verify.c b/src/core/supplicant/nm-supplicant-settings-verify.c index 7632854153..6e5e44d2f8 100644 --- a/src/core/supplicant/nm-supplicant-settings-verify.c +++ b/src/core/supplicant/nm-supplicant-settings-verify.c @@ -73,6 +73,7 @@ static const struct Opt opt_table[] = { OPT_KEYWORD("freq_list", NULL), OPT_INT("frequency", 2412, 5825), OPT_KEYWORD("group", NM_MAKE_STRV("CCMP", "TKIP", "WEP104", "WEP40", "GCMP-256", )), + OPT_INT("ht40", 0, 1), OPT_BYTES("identity", 0), OPT_INT("ieee80211w", 0, 2), OPT_INT("ignore_broadcast_ssid", 0, 2), @@ -99,6 +100,7 @@ static const struct Opt opt_table[] = { OPT_INT("macsec_offload", 0, 2), OPT_INT("macsec_policy", 0, 1), OPT_INT("macsec_port", 1, 65534), + OPT_INT("max_oper_chwidth", 0, 9), OPT_BYTES("mka_cak", 65536), OPT_BYTES("mka_ckn", 65536), OPT_BYTES("nai", 0), @@ -155,6 +157,7 @@ static const struct Opt opt_table[] = { OPT_BYTES("ssid", 32), OPT_BYTES("subject_match", 0), OPT_BYTES("subject_match2", 0), + OPT_INT("vht_center_freq1", 0, 100000), OPT_BYTES("wep_key0", 0), OPT_BYTES("wep_key1", 0), OPT_BYTES("wep_key2", 0),