network: Store Transition Disable info

This indication can come in via EAPoL message 3 or during
FILS Association.  It carries information as to whether certain
transition mode options should be disabled.  See WPA3 Specification,
version 3 for more details.
This commit is contained in:
Denis Kenzior 2021-07-15 17:06:34 -05:00
parent 8cfe038d67
commit 47ba837e98
5 changed files with 95 additions and 18 deletions

View File

@ -54,6 +54,7 @@ enum handshake_event {
HANDSHAKE_EVENT_FAILED,
HANDSHAKE_EVENT_REKEY_FAILED,
HANDSHAKE_EVENT_EAP_NOTIFY,
HANDSHAKE_EVENT_TRANSITION_DISABLE,
};
typedef void (*handshake_event_func_t)(struct handshake_state *hs,

View File

@ -25,6 +25,8 @@
#define NET_AUTOCONNECT SETTINGS, "AutoConnect"
#define NET_ALWAYS_RANDOMIZE_ADDRESS SETTINGS, "AlwaysRandomizeAddress"
#define NET_ADDRESS_OVERRIDE SETTINGS, "AddressOverride"
#define NET_TRANSITION_DISABLE SETTINGS, "TransitionDisable"
#define NET_TRANSITION_DISABLE_MODES SETTINGS, "DisabledTransitionModes"
enum security;
struct scan_freq_set;
@ -67,6 +69,8 @@ struct network_config {
bool override_addr:1;
bool always_random_addr:1;
uint8_t sta_addr[6];
bool have_transition_disable : 1;
uint8_t transition_disable;
};
struct network_info {

View File

@ -83,6 +83,8 @@ struct network {
bool ask_passphrase:1; /* Whether we should force-ask agent */
bool is_hs20:1;
bool anqp_pending:1; /* Set if there is a pending ANQP request */
uint8_t transition_disable; /* Temporary cache until info is set */
bool have_transition_disable:1;
int rank;
/* Holds DBus Connect() message if it comes in before ANQP finishes */
struct l_dbus_message *connect_after_anqp;
@ -353,6 +355,29 @@ bool network_set_psk(struct network *network, const uint8_t *psk)
return true;
}
int network_set_transition_disable(struct network *network,
const uint8_t *td, size_t len)
{
struct network_info *info = network->info;
/* We only recognize bits 0, 2, 3 */
uint8_t supported_bitmask = 0x0d;
if (len < 1)
return -EBADMSG;
network->have_transition_disable = true;
network->transition_disable = td[0] & supported_bitmask;
if (info && info->config.have_transition_disable &&
info->config.transition_disable ==
network->transition_disable)
return 0;
network->sync_settings = true;
return 0;
}
int network_get_signal_strength(const struct network *network)
{
struct scan_bss *best_bss = l_queue_peek_head(network->bss_list);
@ -608,26 +633,35 @@ static void network_settings_save_sae_pt_ecc(struct l_settings *settings,
l_settings_set_bytes(settings, "Security", key, buf, len);
}
void network_sync_settings(struct network *network)
static void network_settings_save(struct network *network,
struct l_settings *settings)
{
struct l_settings *settings = network->settings;
struct l_settings *fs_settings;
const char *ssid = network_get_ssid(network);
if (network->have_transition_disable) {
char *modes[4];
unsigned int i = 0;
if (!network->sync_settings)
l_settings_set_bool(settings, NET_TRANSITION_DISABLE, true);
if (test_bit(&network->transition_disable, 0))
modes[i++] = "personal";
if (test_bit(&network->transition_disable, 2))
modes[i++] = "enterprise";
if (test_bit(&network->transition_disable, 3))
modes[i++] = "open";
modes[i] = NULL;
l_settings_set_string_list(settings,
NET_TRANSITION_DISABLE_MODES,
modes, ' ');
}
if (network->security != SECURITY_PSK)
return;
network->sync_settings = false;
/*
* Re-open the settings from Disk, in case they were updated
* since we last opened them. We only update the [Security]
* bits here
*/
fs_settings = storage_network_open(SECURITY_PSK, ssid);
if (fs_settings)
settings = fs_settings;
/* We only update the [Security] bits here, wipe the group first */
l_settings_remove_group(settings, "Security");
if (network->psk)
@ -643,11 +677,38 @@ void network_sync_settings(struct network *network)
if (network->sae_pt_20)
network_settings_save_sae_pt_ecc(settings, network->sae_pt_20);
}
storage_network_sync(SECURITY_PSK, ssid, settings);
void network_sync_settings(struct network *network)
{
struct network_info *info = network->info;
if (fs_settings)
if (!network->sync_settings)
return;
l_debug("");
network->sync_settings = false;
/*
* Re-open the settings from Disk, in case they were updated
* since we last opened them.
*/
if (network->info) {
struct l_settings *fs_settings = info->ops->open(info);
if (L_WARN_ON(!fs_settings))
return;
network_settings_save(network, fs_settings);
info->ops->sync(info, fs_settings);
l_settings_free(fs_settings);
return;
}
network_settings_save(network, network->settings);
storage_network_sync(network->security, network->ssid,
network->settings);
}
const struct network_info *network_get_info(const struct network *network)

View File

@ -46,6 +46,9 @@ struct l_settings *network_get_settings(const struct network *network);
bool network_set_psk(struct network *network, const uint8_t *psk);
int network_set_transition_disable(struct network *network,
const uint8_t *td, size_t len);
int network_handshake_setup(struct network *network,
struct handshake_state *hs);

View File

@ -714,6 +714,14 @@ static void station_handshake_event(struct handshake_state *hs,
l_warn("Unable to securely rekey on this hw/kernel...");
station_reconnect(station);
break;
case HANDSHAKE_EVENT_TRANSITION_DISABLE:
{
const uint8_t *td = va_arg(args, const uint8_t *);
size_t len = va_arg(args, size_t);
network_set_transition_disable(network, td, len);
break;
}
case HANDSHAKE_EVENT_COMPLETE:
case HANDSHAKE_EVENT_SETTING_KEYS_FAILED:
case HANDSHAKE_EVENT_EAP_NOTIFY: