3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-11-29 22:19:23 +01:00

wiphy: Add initial preference management

This patch saves off the PSK generated based on the passphrase provided
by the agent/user.  The PSK is saved only if the connection is
successful.

Subsequent connection attempts to the known AP use the PSK saved on the
filesystem (default /var/lib/iwd/<ssid>.psk).  If the connection fails,
the agent will again be asked for the passphrase on the next attempt.
This commit is contained in:
Denis Kenzior 2015-04-27 07:51:28 -05:00
parent bd3856e178
commit 93aaf21459

View File

@ -46,6 +46,7 @@
#include "src/crypto.h" #include "src/crypto.h"
#include "src/netdev.h" #include "src/netdev.h"
#include "src/mpdu.h" #include "src/mpdu.h"
#include "src/storage.h"
static struct l_genl *genl = NULL; static struct l_genl *genl = NULL;
static struct l_genl_family *nl80211 = NULL; static struct l_genl_family *nl80211 = NULL;
@ -59,6 +60,9 @@ struct network {
unsigned int agent_request; unsigned int agent_request;
enum scan_ssid_security ssid_security; enum scan_ssid_security ssid_security;
struct l_queue *bss_list; struct l_queue *bss_list;
struct l_settings *settings;
bool update_psk:1; /* Whether PSK should be written to storage */
bool ask_psk:1; /* Whether we should force-ask agent for PSK */
}; };
struct bss { struct bss {
@ -199,13 +203,27 @@ static struct l_dbus_message *network_get_properties(struct l_dbus *dbus,
return reply; return reply;
} }
static void netdev_disassociated(struct netdev *netdev)
{
struct network *network = netdev->connected_bss->network;
l_settings_free(network->settings);
network->settings = NULL;
netdev->connected_bss = NULL;
}
static void genl_connect_cb(struct l_genl_msg *msg, void *user_data) static void genl_connect_cb(struct l_genl_msg *msg, void *user_data)
{ {
struct netdev *netdev = user_data; struct netdev *netdev = user_data;
if (l_genl_msg_get_error(msg) < 0 && netdev->connect_pending) if (l_genl_msg_get_error(msg) < 0) {
dbus_pending_reply(&netdev->connect_pending, if (netdev->connect_pending)
dbus_pending_reply(&netdev->connect_pending,
dbus_error_failed(netdev->connect_pending)); dbus_error_failed(netdev->connect_pending));
netdev_disassociated(netdev);
}
} }
static int mlme_authenticate_cmd(struct network *network) static int mlme_authenticate_cmd(struct network *network)
@ -242,10 +260,12 @@ static void passphrase_callback(enum agent_result result,
if (result != AGENT_RESULT_OK) { if (result != AGENT_RESULT_OK) {
dbus_pending_reply(&netdev->connect_pending, dbus_pending_reply(&netdev->connect_pending,
dbus_error_aborted(netdev->connect_pending)); dbus_error_aborted(netdev->connect_pending));
l_settings_free(network->settings);
network->settings = NULL;
return; return;
} }
l_free(network->psk);
network->psk = l_malloc(32); network->psk = l_malloc(32);
if (crypto_psk_from_passphrase(passphrase, (uint8_t *) network->ssid, if (crypto_psk_from_passphrase(passphrase, (uint8_t *) network->ssid,
@ -255,6 +275,8 @@ static void passphrase_callback(enum agent_result result,
"Ensure Crypto Engine is properly configured"); "Ensure Crypto Engine is properly configured");
dbus_pending_reply(&netdev->connect_pending, dbus_pending_reply(&netdev->connect_pending,
dbus_error_failed(netdev->connect_pending)); dbus_error_failed(netdev->connect_pending));
l_settings_free(network->settings);
network->settings = NULL;
l_free(network->psk); l_free(network->psk);
network->psk = NULL; network->psk = NULL;
@ -262,9 +284,62 @@ static void passphrase_callback(enum agent_result result,
return; return;
} }
/*
* We need to store the PSK in our permanent store. However, before
* we do that, make sure the PSK works. We write to the store only
* when we are connected
*/
network->update_psk = true;
mlme_authenticate_cmd(network); mlme_authenticate_cmd(network);
} }
static struct l_dbus_message *network_connect_psk(struct network *network,
struct l_dbus_message *message)
{
struct netdev *netdev = network->netdev;
const char *psk;
l_debug("");
network->settings = storage_network_open("psk", network->ssid);
psk = l_settings_get_value(network->settings, "Security",
"PreSharedKey");
if (psk) {
size_t len;
l_debug("psk: %s", psk);
network->psk = l_util_from_hexstring(psk, &len);
l_debug("len: %zd", len);
if (network->psk && len != 32) {
l_debug("Can't parse PSK");
l_free(network->psk);
network->psk = NULL;
}
}
l_debug("ask_psk: %s", network->ask_psk ? "true" : "false");
if (network->ask_psk || !network->psk) {
network->ask_psk = false;
network->agent_request =
agent_request_passphrase(network->object_path,
passphrase_callback,
network);
if (!network->agent_request)
return dbus_error_no_agent(message);
} else
mlme_authenticate_cmd(network);
netdev->connect_pending = l_dbus_message_ref(message);
return NULL;
}
static struct l_dbus_message *network_connect(struct l_dbus *dbus, static struct l_dbus_message *network_connect(struct l_dbus *dbus,
struct l_dbus_message *message, struct l_dbus_message *message,
void *user_data) void *user_data)
@ -279,31 +354,14 @@ static struct l_dbus_message *network_connect(struct l_dbus *dbus,
switch (network->ssid_security) { switch (network->ssid_security) {
case SCAN_SSID_SECURITY_PSK: case SCAN_SSID_SECURITY_PSK:
if (!network->psk) { return network_connect_psk(network, message);
network->agent_request =
agent_request_passphrase(
network->object_path,
passphrase_callback,
network);
if (!network->agent_request)
return dbus_error_no_agent(message);
break;
}
/* fall through */
case SCAN_SSID_SECURITY_NONE: case SCAN_SSID_SECURITY_NONE:
mlme_authenticate_cmd(network); mlme_authenticate_cmd(network);
break; netdev->connect_pending = l_dbus_message_ref(message);
return NULL;
default: default:
return dbus_error_not_supported(message); return dbus_error_not_supported(message);
} }
netdev->connect_pending = l_dbus_message_ref(message);
return NULL;
} }
static void setup_network_interface(struct l_dbus_interface *interface) static void setup_network_interface(struct l_dbus_interface *interface)
@ -751,7 +809,8 @@ static void connect_failed_cb(struct l_genl_msg *msg,
dbus_pending_reply(&netdev->connect_pending, dbus_pending_reply(&netdev->connect_pending,
dbus_error_failed(netdev->connect_pending)); dbus_error_failed(netdev->connect_pending));
netdev->connected_bss = NULL;
netdev_disassociated(netdev);
} }
static void setting_keys_failed(struct netdev *netdev, uint16_t reason_code) static void setting_keys_failed(struct netdev *netdev, uint16_t reason_code)
@ -887,6 +946,7 @@ static void wiphy_set_tk(uint32_t ifindex, const uint8_t *aa,
void *user_data) void *user_data)
{ {
struct netdev *netdev = user_data; struct netdev *netdev = user_data;
struct network *network = netdev->connected_bss->network;
struct ie_rsn_info info; struct ie_rsn_info info;
enum crypto_cipher cipher; enum crypto_cipher cipher;
@ -905,6 +965,18 @@ static void wiphy_set_tk(uint32_t ifindex, const uint8_t *aa,
return; return;
} }
/* If we got here, then our PSK works. Save if required */
if (network->update_psk) {
char *hex;
network->update_psk = false;
hex = l_util_hexstring(network->psk, 32);
l_settings_set_value(network->settings, "Security",
"PreSharedKey", hex);
l_free(hex);
storage_network_sync("psk", network->ssid, network->settings);
}
netdev->pairwise_new_key_cmd_id = netdev->pairwise_new_key_cmd_id =
mlme_new_pairwise_key(netdev, cipher, aa, mlme_new_pairwise_key(netdev, cipher, aa,
tk, crypto_cipher_key_len(cipher)); tk, crypto_cipher_key_len(cipher));
@ -1061,7 +1133,7 @@ static void mlme_associate_event(struct l_genl_msg *msg, struct netdev *netdev)
l_error("association failed %s (%d)", strerror(-err), err); l_error("association failed %s (%d)", strerror(-err), err);
dbus_pending_reply(&netdev->connect_pending, dbus_pending_reply(&netdev->connect_pending,
dbus_error_failed(netdev->connect_pending)); dbus_error_failed(netdev->connect_pending));
netdev->connected_bss = NULL; netdev_disassociated(netdev);
return; return;
} }
@ -1097,6 +1169,8 @@ static void mlme_associate_cmd(struct netdev *netdev)
if (!bss) { if (!bss) {
error = dbus_error_not_available(netdev->connect_pending); error = dbus_error_not_available(netdev->connect_pending);
dbus_pending_reply(&netdev->connect_pending, error); dbus_pending_reply(&netdev->connect_pending, error);
netdev_disassociated(netdev);
return; return;
} }
@ -1177,7 +1251,7 @@ static void mlme_authenticate_event(struct l_genl_msg *msg,
error: error:
dbus_pending_reply(&netdev->connect_pending, dbus_pending_reply(&netdev->connect_pending,
dbus_error_failed(netdev->connect_pending)); dbus_error_failed(netdev->connect_pending));
netdev->connected_bss = NULL; netdev_disassociated(netdev);
} }
static void mlme_deauthenticate_event(struct l_genl_msg *msg, static void mlme_deauthenticate_event(struct l_genl_msg *msg,
@ -1235,12 +1309,12 @@ static void mlme_disconnect_event(struct l_genl_msg *msg,
* once more * once more
*/ */
if (network->ssid_security == SCAN_SSID_SECURITY_PSK) { if (network->ssid_security == SCAN_SSID_SECURITY_PSK) {
l_free(network->psk); network->update_psk = false;
network->psk = NULL; network->ask_psk = true;
} }
} }
netdev->connected_bss = NULL; netdev_disassociated(netdev);
} }
static bool parse_ie(struct bss *bss, const uint8_t **ssid, int *ssid_len, static bool parse_ie(struct bss *bss, const uint8_t **ssid, int *ssid_len,