@@ -54,6 +54,7 @@
#include "src/handshake.h"
#include "src/nl80211util.h"
#include "src/knownnetworks.h"
+#include "src/dpp-common.h"
#define DPP_FRAME_MAX_RETRIES 5
#define DPP_FRAME_RETRY_TIMEOUT 1
@@ -67,20 +68,6 @@ static uint32_t unicast_watch;
static uint8_t dpp_prefix[] = { 0x04, 0x09, 0x50, 0x6f, 0x9a, 0x1a, 0x01 };
-enum dpp_state {
- DPP_STATE_NOTHING,
- DPP_STATE_PRESENCE,
- DPP_STATE_PKEX_EXCHANGE,
- DPP_STATE_PKEX_COMMIT_REVEAL,
- DPP_STATE_AUTHENTICATING,
- DPP_STATE_CONFIGURING,
-};
-
-enum dpp_capability {
- DPP_CAPABILITY_ENROLLEE = 0x01,
- DPP_CAPABILITY_CONFIGURATOR = 0x02,
-};
-
enum dpp_interface {
DPP_INTERFACE_UNBOUND,
DPP_INTERFACE_DPP,
@@ -95,6 +82,7 @@ struct pkex_agent {
};
struct dpp {
+ struct dpp_sm *sm;
struct netdev *netdev;
char *uri;
uint8_t role;
@@ -104,10 +92,10 @@ struct dpp {
uint64_t wdev_id;
+ /* Could probably do away with storing these here */
struct l_ecc_scalar *boot_private;
struct l_ecc_point *boot_public;
- enum dpp_state state;
enum dpp_interface interface;
struct pkex_agent *agent;
@@ -121,18 +109,17 @@ struct dpp {
size_t freqs_idx;
uint32_t dwell;
uint32_t current_freq;
- uint32_t new_freq;
struct scan_freq_set *presence_list;
uint32_t max_roc;
uint32_t offchannel_id;
uint8_t peer_addr[6];
+ bool peer_accepted;
/* Timeout of either auth/config protocol */
struct l_timeout *timeout;
- struct dpp_configuration *config;
uint32_t connect_scan_id;
uint64_t frame_cookie;
uint8_t frame_retry;
@@ -140,19 +127,12 @@ struct dpp {
size_t frame_size;
struct l_timeout *retry_timeout;
- struct l_dbus_message *pending;
-
struct l_idle *connect_idle;
- /* PKEX-specific values */
- char *pkex_id;
- char *pkex_key;
-
uint32_t pkex_scan_id;
bool mcast_support : 1;
bool roc_started : 1;
- bool channel_switch : 1;
};
static const char *dpp_role_to_string(enum dpp_capability role)
@@ -173,8 +153,7 @@ static bool dpp_pkex_get_started(struct l_dbus *dbus,
void *user_data)
{
struct dpp *dpp = user_data;
- bool started = (dpp->state != DPP_STATE_NOTHING &&
- dpp->interface == DPP_INTERFACE_PKEX);
+ bool started = (dpp->sm && dpp->interface == DPP_INTERFACE_PKEX);
l_dbus_message_builder_append_basic(builder, 'b', &started);
@@ -189,8 +168,7 @@ static bool dpp_pkex_get_role(struct l_dbus *dbus,
struct dpp *dpp = user_data;
const char *role;
- if (dpp->state == DPP_STATE_NOTHING ||
- dpp->interface != DPP_INTERFACE_PKEX)
+ if (!dpp->sm || dpp->interface != DPP_INTERFACE_PKEX)
return false;
role = dpp_role_to_string(dpp->role);
@@ -207,8 +185,7 @@ static bool dpp_get_started(struct l_dbus *dbus,
void *user_data)
{
struct dpp *dpp = user_data;
- bool started = (dpp->state != DPP_STATE_NOTHING &&
- dpp->interface == DPP_INTERFACE_DPP);
+ bool started = (dpp->sm && dpp->interface == DPP_INTERFACE_DPP);
l_dbus_message_builder_append_basic(builder, 'b', &started);
@@ -223,8 +200,7 @@ static bool dpp_get_role(struct l_dbus *dbus,
struct dpp *dpp = user_data;
const char *role;
- if (dpp->state == DPP_STATE_NOTHING ||
- dpp->interface != DPP_INTERFACE_DPP)
+ if (!dpp->sm || dpp->interface != DPP_INTERFACE_DPP)
return false;
role = dpp_role_to_string(dpp->role);
@@ -242,8 +218,7 @@ static bool dpp_get_uri(struct l_dbus *dbus,
{
struct dpp *dpp = user_data;
- if (dpp->state == DPP_STATE_NOTHING ||
- dpp->interface != DPP_INTERFACE_DPP)
+ if (!dpp->sm || dpp->interface != DPP_INTERFACE_DPP)
return false;
l_dbus_message_builder_append_basic(builder, 's', dpp->uri);
@@ -380,11 +355,6 @@ static void dpp_reset(struct dpp *dpp)
dpp->timeout = NULL;
}
- if (dpp->config) {
- dpp_configuration_free(dpp->config);
- dpp->config = NULL;
- }
-
if (dpp->connect_scan_id) {
scan_cancel(dpp->wdev_id, dpp->connect_scan_id);
dpp->connect_scan_id = 0;
@@ -410,7 +380,6 @@ static void dpp_reset(struct dpp *dpp)
dpp->connect_idle = NULL;
}
- dpp->new_freq = 0;
dpp->frame_retry = 0;
dpp->frame_cookie = 0;
@@ -419,6 +388,11 @@ static void dpp_reset(struct dpp *dpp)
dpp_property_changed_notify(dpp);
dpp->interface = DPP_INTERFACE_UNBOUND;
+
+ if (dpp->sm) {
+ dpp_sm_free(dpp->sm);
+ dpp->sm = NULL;
+ }
}
static void dpp_free(struct dpp *dpp)
@@ -510,7 +484,27 @@ static void dpp_frame_retry(struct dpp *dpp)
dpp->frame_pending = NULL;
}
-static void dpp_write_config(struct dpp_configuration *config,
+static size_t dpp_build_mpdu_header(const uint8_t *src,
+ const uint8_t *dest, uint8_t *buf)
+{
+ struct mmpdu_header *hdr = (struct mmpdu_header *)buf;
+ uint8_t *body;
+
+ hdr->fc.protocol_version = 0;
+ hdr->fc.type = MPDU_TYPE_MANAGEMENT;
+ hdr->fc.subtype = MPDU_MANAGEMENT_SUBTYPE_ACTION;
+ memcpy(hdr->address_1, dest, 6);
+ memcpy(hdr->address_2, src, 6);
+ memcpy(hdr->address_3, broadcast, 6);
+
+ body = buf + mmpdu_header_len(hdr);
+ /* Category: Public */
+ *body++ = 0x04;
+
+ return body - buf;
+}
+
+static void dpp_write_config(const struct dpp_configuration *config,
struct network *network)
{
_auto_(l_settings_free) struct l_settings *settings = l_settings_new();
@@ -555,9 +549,13 @@ static void dpp_start_connect(struct l_idle *idle, void *user_data)
struct scan_bss *bss;
struct network *network;
int ret;
+ const struct dpp_configuration *config;
- network = station_network_find(station, dpp->config->ssid,
- SECURITY_PSK);
+ config = dpp_sm_get_configuration(dpp->sm);
+ if (L_WARN_ON(!config))
+ return;
+
+ network = station_network_find(station, config->ssid, SECURITY_PSK);
dpp_reset(dpp);
@@ -618,7 +616,8 @@ static void dpp_known_network_watch(enum known_networks_event event,
void *user_data)
{
struct dpp *dpp = user_data;
-
+ struct station *station = station_find(netdev_get_ifindex(dpp->netdev));
+ const struct dpp_configuration *config;
/*
* Check the following
* - DPP is enrolling
@@ -628,16 +627,23 @@ static void dpp_known_network_watch(enum known_networks_event event,
* immediately modified after DPP synced it).
* - DPP didn't start a scan for the network.
*/
+ if (!dpp->sm)
+ return;
+
+ config = dpp_sm_get_configuration(dpp->sm);
+
if (dpp->role != DPP_CAPABILITY_ENROLLEE)
return;
- if (!dpp->config)
+ if (!config)
return;
- if (strcmp(info->ssid, dpp->config->ssid))
+ if (strcmp(info->ssid, config->ssid))
return;
if (dpp->connect_idle)
return;
if (dpp->connect_scan_id)
return;
+ if (!station || station_get_connected_network(station))
+ return;
switch (event) {
case KNOWN_NETWORKS_EVENT_ADDED:
@@ -663,54 +669,40 @@ static void dpp_handle_config_frame(const struct mmpdu_header *frame,
int rssi, void *user_data)
{
struct dpp *dpp = user_data;
- struct dpp_configuration *config = NULL;
- struct station *station = station_find(netdev_get_ifindex(dpp->netdev));
- struct network *network = NULL;
- struct scan_bss *bss = NULL;
- dpp_write_config(config, network);
+ if (!dpp->sm)
+ return;
- offchannel_cancel(dpp->wdev_id, dpp->offchannel_id);
+ dpp_handle_rx(dpp->sm, body + 1, body_len - 1);
+}
- if (network && bss) {
- l_debug("delaying connect until settings are synced");
- dpp->config = config;
- return;
- } else if (station) {
- struct scan_parameters params = {0};
+static void dpp_tx_frame(const uint8_t *data, size_t len,
+ void *user_data)
+{
+ struct dpp *dpp = user_data;
+ struct iovec iov[2];
+ uint8_t hdr[36];
- params.ssid = (void *) config->ssid;
- params.ssid_len = config->ssid_len;
+ memset(hdr, 0, sizeof(hdr));
- l_debug("Scanning for %s", config->ssid);
+ iov[0].iov_len = dpp_build_mpdu_header(netdev_get_address(dpp->netdev),
+ dpp->peer_addr, hdr);
+ iov[0].iov_base = hdr;
- dpp->connect_scan_id = scan_active_full(dpp->wdev_id, ¶ms,
- dpp_scan_triggered,
- dpp_scan_results, dpp,
- dpp_scan_destroy);
- if (dpp->connect_scan_id) {
- dpp->config = config;
- return;
- }
- }
+ iov[1].iov_base = (void *)data;
+ iov[1].iov_len = len;
+ dpp_send_frame(dpp, iov, 2, dpp->current_freq);
}
static void dpp_roc_started(void *user_data)
{
struct dpp *dpp = user_data;
- /*
- * - If a configurator, nothing to do but wait for a request
- * (unless multicast frame registration is unsupported in which case
- * send an authenticate request now)
- * - If in the presence state continue sending announcements.
- * - If authenticating, and this is a result of a channel switch send
- * the authenticate response now.
- */
-
dpp->roc_started = true;
+ dpp_sm_set_write_handler(dpp->sm, dpp_tx_frame);
+
/*
* The retry timer indicates a frame was not acked in which case we
* should not change any state or send any frames until that expires.
@@ -733,6 +725,8 @@ static void dpp_offchannel_timeout(int error, void *user_data)
dpp->offchannel_id = 0;
dpp->roc_started = false;
+ dpp_sm_set_write_handler(dpp->sm, NULL);
+
/*
* If cancelled this is likely due to netdev going down or from Stop().
* Otherwise there was some other problem which is probably not
@@ -790,6 +784,8 @@ static void dpp_start_offchannel(struct dpp *dpp, uint32_t freq)
if (dpp->offchannel_id)
offchannel_cancel(dpp->wdev_id, dpp->offchannel_id);
+ l_debug("starting offchannel on frequency %u, dwell=%u", freq, dpp->dwell);
+
dpp->offchannel_id = id;
}
@@ -797,23 +793,16 @@ static void dpp_handle_frame(struct dpp *dpp,
const struct mmpdu_header *frame,
const void *body, size_t body_len)
{
- const uint8_t *ptr;
+ if (!dpp->sm)
+ return;
- /*
- * Both handlers offset by 8 bytes to reach the beginning of the DPP
- * attributes. Easier checking this in one place, which also covers the
- * frame type byte.
- */
- if (body_len < 8)
+ /* Frame from a different device after DPP has already started */
+ if (dpp->peer_accepted && memcmp(dpp->peer_addr, frame->address_2, 6))
return;
- ptr = body + 7;
+ memcpy(dpp->peer_addr, frame->address_2, 6);
- switch (*ptr) {
- default:
- l_debug("Unhandled DPP frame %u", *ptr);
- break;
- }
+ dpp_handle_rx(dpp->sm, body + 1, body_len - 1);
}
static bool match_wdev(const void *a, const void *b)
@@ -851,6 +840,7 @@ static void dpp_mlme_notify(struct l_genl_msg *msg, void *user_data)
bool ack = false;
struct iovec iov;
uint8_t cmd = l_genl_msg_get_command(msg);
+ enum dpp_state state;
if (cmd != NL80211_CMD_FRAME_TX_STATUS)
return;
@@ -863,16 +853,17 @@ static void dpp_mlme_notify(struct l_genl_msg *msg, void *user_data)
return;
dpp = l_queue_find(dpp_list, match_wdev, &wdev_id);
- if (!dpp)
+ if (!dpp || !dpp->sm)
return;
+ state = dpp_sm_get_state(dpp->sm);
+
/*
* Don't retransmit for presence or PKEX exchange if an enrollee, both
* are broadcast frames which don't expect an ack.
*/
- if (dpp->state == DPP_STATE_NOTHING ||
- dpp->state == DPP_STATE_PRESENCE ||
- (dpp->state == DPP_STATE_PKEX_EXCHANGE &&
+ if (state == DPP_STATE_PRESENCE ||
+ (state == DPP_STATE_PKEX_EXCHANGE &&
dpp->role == DPP_CAPABILITY_ENROLLEE))
return;
@@ -886,20 +877,6 @@ static void dpp_mlme_notify(struct l_genl_msg *msg, void *user_data)
if (!ack)
goto retransmit;
- /*
- * Special handling for a channel transition when acting as a
- * configurator. The auth request was sent offchannel so we need to
- * wait for the ACK before going back to the connected channel.
- */
- if (dpp->channel_switch) {
- if (dpp->offchannel_id) {
- offchannel_cancel(dpp->wdev_id, dpp->offchannel_id);
- dpp->offchannel_id = 0;
- }
-
- dpp->channel_switch = false;
- }
-
return;
retransmit:
@@ -1035,7 +1012,7 @@ static void dpp_station_state_watch(enum station_state state, void *user_data)
{
struct dpp *dpp = user_data;
- if (dpp->state == DPP_STATE_NOTHING)
+ if (!dpp->sm)
return;
switch (state) {
@@ -1089,17 +1066,20 @@ static void dpp_create(struct netdev *netdev)
uint8_t dpp_conf_request_prefix[] = { 0x04, 0x0a };
uint64_t wdev_id = netdev_get_wdev_id(netdev);
struct station *station = station_find(netdev_get_ifindex(netdev));
+ const struct l_ecc_curve *curve = l_ecc_curve_from_ike_group(19);
dpp->netdev = netdev;
- dpp->state = DPP_STATE_NOTHING;
dpp->interface = DPP_INTERFACE_UNBOUND;
dpp->wdev_id = wdev_id;
-
dpp->max_roc = wiphy_get_max_roc_duration(wiphy_find_by_wdev(wdev_id));
dpp->mcast_support = wiphy_has_ext_feature(
wiphy_find_by_wdev(dpp->wdev_id),
NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS);
+ /* TODO: Support a user-provided key pair */
+ l_ecdh_generate_key_pair(curve, &dpp->boot_private,
+ &dpp->boot_public);
+
l_dbus_object_add_interface(dbus, netdev_get_path(netdev),
IWD_DPP_INTERFACE, dpp);
l_dbus_object_add_interface(dbus, netdev_get_path(netdev),
@@ -1212,6 +1192,175 @@ static void dpp_start_presence(struct dpp *dpp, uint32_t *limit_freqs,
dpp_start_offchannel(dpp, dpp->current_freq);
}
+static void dpp_event_success(struct dpp *dpp)
+{
+ struct station *station = station_find(netdev_get_ifindex(dpp->netdev));
+ struct network *network = NULL;
+ struct scan_bss *bss = NULL;
+ const struct dpp_configuration *config;
+
+ config = dpp_sm_get_configuration(dpp->sm);
+ if (L_WARN_ON(!config))
+ goto reset;
+
+ /*
+ * We should have a station device, but if not DPP can write the
+ * credentials out and be done
+ */
+ if (station) {
+ network = station_network_find(station, config->ssid,
+ SECURITY_PSK);
+ if (network)
+ bss = network_bss_select(network, true);
+ }
+
+ dpp_write_config(config, network);
+
+ offchannel_cancel(dpp->wdev_id, dpp->offchannel_id);
+ dpp->offchannel_id = 0;
+
+ if (network && bss) {
+ l_debug("delaying connect until settings are synced");
+ return;
+ } else if (station) {
+ struct scan_parameters params = {0};
+
+ params.ssid = (void *) config->ssid;
+ params.ssid_len = config->ssid_len;
+
+ l_debug("Scanning for %s", config->ssid);
+
+ dpp->connect_scan_id = scan_active_full(dpp->wdev_id, ¶ms,
+ dpp_scan_triggered,
+ dpp_scan_results, dpp,
+ dpp_scan_destroy);
+ if (dpp->connect_scan_id)
+ return;
+ }
+
+reset:
+ dpp_reset(dpp);
+}
+
+static void dpp_event_channel_switch(struct dpp *dpp,
+ const uint8_t *attr)
+{
+ uint32_t freq;
+
+ freq = oci_to_frequency(attr[0], attr[1]);
+
+ if (freq == dpp->current_freq)
+ return;
+
+ dpp->current_freq = freq;
+
+ dpp_start_offchannel(dpp, dpp->current_freq);
+
+ /*
+ * The common code will attempt to write after this, so ensure that
+ * gets delayed until we are on the right channel
+ */
+ dpp_sm_set_write_handler(dpp->sm, NULL);
+}
+
+static void dpp_pkex_agent_reply(struct l_dbus_message *message,
+ void *user_data)
+{
+ struct dpp *dpp = user_data;
+ const char *error, *text;
+ const char *code;
+
+ dpp->agent->pending_id = 0;
+
+ l_debug("SharedCodeAgent %s path %s replied", dpp->agent->owner,
+ dpp->agent->path);
+
+ if (l_dbus_message_get_error(message, &error, &text)) {
+ l_error("RequestSharedCode() returned %s(\"%s\")",
+ error, text);
+ return;
+ }
+
+ if (!l_dbus_message_get_arguments(message, "s", &code)) {
+ l_debug("Invalid arguments, check SharedCodeAgent!");
+ return;
+ }
+
+ dpp_sm_set_pkex_key(dpp->sm, code);
+}
+
+static bool dpp_event_pkex_key_requested(struct dpp *dpp,
+ const char *identifier)
+{
+ struct l_dbus_message *msg;
+
+ if (!dpp->agent)
+ return false;
+
+ if (L_WARN_ON(dpp->agent->pending_id))
+ return false;
+
+ msg = l_dbus_message_new_method_call(dbus_get_bus(),
+ dpp->agent->owner,
+ dpp->agent->path,
+ IWD_SHARED_CODE_AGENT_INTERFACE,
+ "RequestSharedCode");
+ l_dbus_message_set_arguments(msg, "s", identifier);
+
+ dpp->agent->pending_id = l_dbus_send_with_reply(dbus_get_bus(),
+ msg,
+ dpp_pkex_agent_reply,
+ dpp, NULL);
+ return dpp->agent->pending_id != 0;
+}
+
+static void dpp_event_peer_accepted(struct dpp *dpp)
+{
+ dpp->peer_accepted = true;
+
+ if (dpp_sm_get_state(dpp->sm) != DPP_STATE_PKEX_EXCHANGE)
+ return;
+
+ dpp_sm_set_pkex_peer_mac(dpp->sm, dpp->peer_addr);
+
+ /*
+ * PKEX dictates a 200ms timeout waiting for the exchange
+ * response. After this there is no time requirement for the
+ * remainder of the protocol. Increase the dwell time so we
+ * have the best chance of receiving frames since we will now
+ * remain on a single frequency.
+ */
+ if (dpp->role == DPP_CAPABILITY_ENROLLEE)
+ dpp->dwell = (dpp->max_roc < 2000) ? dpp->max_roc : 2000;
+}
+
+static void dpp_event(enum dpp_event event, const void *event_data,
+ void *user_data)
+{
+ struct dpp *dpp = user_data;
+
+ switch (event) {
+ case DPP_EVENT_PEER_ACCEPTED:
+ dpp_event_peer_accepted(dpp);
+ break;
+ case DPP_EVENT_CHANNEL_SWITCH:
+ dpp_event_channel_switch(dpp, event_data);
+ break;
+ case DPP_EVENT_PKEX_KEY_REQUESTED:
+ dpp_event_pkex_key_requested(dpp, event_data);
+ break;
+ case DPP_EVENT_FAILED:
+ dpp_reset(dpp);
+ break;
+ case DPP_EVENT_SUCCESS:
+ if (dpp->role == DPP_CAPABILITY_ENROLLEE)
+ dpp_event_success(dpp);
+ else
+ dpp_reset(dpp);
+ break;
+ }
+}
+
static struct l_dbus_message *dpp_dbus_start_enrollee(struct l_dbus *dbus,
struct l_dbus_message *message,
void *user_data)
@@ -1219,9 +1368,11 @@ static struct l_dbus_message *dpp_dbus_start_enrollee(struct l_dbus *dbus,
struct dpp *dpp = user_data;
uint32_t freq = band_channel_to_freq(6, BAND_FREQ_2_4_GHZ);
struct station *station = station_find(netdev_get_ifindex(dpp->netdev));
+ struct l_dbus_message *reply;
+ const uint8_t *own_asn1;
+ size_t own_asn1_len;
- if (dpp->state != DPP_STATE_NOTHING ||
- dpp->interface != DPP_INTERFACE_UNBOUND)
+ if (dpp->sm || dpp->interface != DPP_INTERFACE_UNBOUND)
return dbus_error_busy(message);
/*
@@ -1234,14 +1385,23 @@ static struct l_dbus_message *dpp_dbus_start_enrollee(struct l_dbus *dbus,
} else if (!station)
l_debug("No station device, continuing anyways...");
- dpp->state = DPP_STATE_PRESENCE;
+ dpp->sm = dpp_sm_new(dpp_event, dpp->boot_public,
+ dpp->boot_private, dpp);
+
+ dpp_sm_set_role(dpp->sm, DPP_CAPABILITY_ENROLLEE);
+ dpp_sm_start_responder(dpp->sm);
+
+ own_asn1 = dpp_sm_get_own_asn1(dpp->sm, &own_asn1_len);
+
+ dpp->uri = dpp_generate_uri(own_asn1, own_asn1_len, 2,
+ netdev_get_address(dpp->netdev), &freq,
+ 1, NULL, NULL);
+
dpp->role = DPP_CAPABILITY_ENROLLEE;
dpp->interface = DPP_INTERFACE_DPP;
l_debug("DPP Start Enrollee: %s", dpp->uri);
- dpp->pending = l_dbus_message_ref(message);
-
/*
* Going off spec here. Select a single channel to send presence
* announcements on. This will be advertised in the URI. The full
@@ -1251,7 +1411,13 @@ static struct l_dbus_message *dpp_dbus_start_enrollee(struct l_dbus *dbus,
dpp_property_changed_notify(dpp);
- return NULL;
+ memcpy(dpp->peer_addr, broadcast, 6);
+
+ reply = l_dbus_message_new_method_return(message);
+
+ l_dbus_message_set_arguments(reply, "s", dpp->uri);
+
+ return reply;
}
/*
@@ -1284,12 +1450,16 @@ static bool dpp_configurator_start_presence(struct dpp *dpp, const char *uri)
return false;
}
- if (!l_memeqzero(info->mac, 6))
+ if (!l_memeqzero(info->mac, 6)) {
memcpy(dpp->peer_addr, info->mac, 6);
+ /* Set now so we restrict to only frames from this MAC */
+ dpp->peer_accepted = true;
+ }
if (info->freqs)
freqs = scan_freq_set_to_fixed_array(info->freqs, &freqs_len);
+ dpp_sm_set_peer_bootstrap(dpp->sm, info->boot_public);
dpp_free_uri_info(info);
dpp_start_presence(dpp, freqs, freqs_len);
@@ -1311,6 +1481,9 @@ static struct l_dbus_message *dpp_start_configurator_common(
struct l_settings *settings;
struct handshake_state *hs = netdev_get_handshake(dpp->netdev);
const char *uri;
+ struct dpp_configuration *config;
+ const uint8_t *own_asn1;
+ size_t own_asn1_len;
/*
* For now limit the configurator to only configuring enrollees to the
@@ -1331,11 +1504,11 @@ static struct l_dbus_message *dpp_start_configurator_common(
if (network_get_security(network) != SECURITY_PSK)
return dbus_error_not_supported(message);
- if (dpp->state != DPP_STATE_NOTHING ||
- dpp->interface != DPP_INTERFACE_UNBOUND)
+ if (dpp->sm || dpp->interface != DPP_INTERFACE_UNBOUND)
return dbus_error_busy(message);
- dpp->state = DPP_STATE_PRESENCE;
+ dpp->sm = dpp_sm_new(dpp_event, dpp->boot_public,
+ dpp->boot_private, dpp);
if (!responder) {
if (!l_dbus_message_get_arguments(message, "s", &uri))
@@ -1345,26 +1518,47 @@ static struct l_dbus_message *dpp_start_configurator_common(
return dbus_error_invalid_args(message);
if (!dpp->mcast_support)
- dpp->state = DPP_STATE_AUTHENTICATING;
-
- dpp->new_freq = bss->frequency;
+ dpp_sm_set_skip_presence(dpp->sm, true);
} else
dpp->current_freq = bss->frequency;
- dpp->role = DPP_CAPABILITY_CONFIGURATOR;
- dpp->interface = DPP_INTERFACE_DPP;
- dpp->config = dpp_configuration_new(settings,
- network_get_ssid(network),
+ config = dpp_configuration_new(settings, network_get_ssid(network),
hs->akm_suite);
+ dpp_sm_set_configuration(dpp->sm, config);
+ dpp_sm_set_role(dpp->sm, DPP_CAPABILITY_CONFIGURATOR);
+
+ own_asn1 = dpp_sm_get_own_asn1(dpp->sm, &own_asn1_len);
+
+ dpp->uri = dpp_generate_uri(own_asn1, own_asn1_len, 2,
+ netdev_get_address(dpp->netdev),
+ &bss->frequency, 1, NULL, NULL);
+ dpp->interface = DPP_INTERFACE_DPP;
+
+ dpp->dwell = (dpp->max_roc < 2000) ? dpp->max_roc : 2000;
+
dpp_property_changed_notify(dpp);
+ dpp->role = DPP_CAPABILITY_CONFIGURATOR;
+
+ memcpy(dpp->peer_addr, broadcast, 6);
+
l_debug("DPP Start Configurator: %s", dpp->uri);
reply = l_dbus_message_new_method_return(message);
l_dbus_message_set_arguments(reply, "s", dpp->uri);
+ /*
+ * Configurators acting as responders are always on channel so
+ * the writes can be done at any point.
+ */
+ if (responder) {
+ dpp_sm_set_write_handler(dpp->sm, dpp_tx_frame);
+ dpp_sm_start_responder(dpp->sm);
+ } else
+ dpp_sm_start_initiator(dpp->sm);
+
return reply;
}
@@ -1480,10 +1674,12 @@ static bool dpp_pkex_scan_notify(int err, struct l_queue *bss_list,
start:
dpp->current_freq = dpp->freqs[0];
- l_debug("PKEX start enrollee (id=%s)", dpp->pkex_id ?: "unset");
+ l_debug("PKEX start enrollee");
dpp_start_offchannel(dpp, dpp->current_freq);
+ dpp_sm_pkex_start_initiator(dpp->sm);
+
return false;
failed:
@@ -1503,14 +1699,20 @@ static bool dpp_start_pkex_enrollee(struct dpp *dpp, const char *key,
{
_auto_(l_ecc_point_free) struct l_ecc_point *qi = NULL;
+ dpp->sm = dpp_sm_new(dpp_event, dpp->boot_public,
+ dpp->boot_private, dpp);
+
if (identifier)
- dpp->pkex_id = l_strdup(identifier);
+ dpp_sm_set_pkex_identifier(dpp->sm, identifier);
+
+ dpp_sm_set_pkex_key(dpp->sm, key);
+ dpp_sm_set_pkex_own_mac(dpp->sm, netdev_get_address(dpp->netdev));
+ dpp_sm_set_role(dpp->sm, DPP_CAPABILITY_ENROLLEE);
- dpp->pkex_key = l_strdup(key);
memcpy(dpp->peer_addr, broadcast, 6);
dpp->role = DPP_CAPABILITY_ENROLLEE;
- dpp->state = DPP_STATE_PKEX_EXCHANGE;
dpp->interface = DPP_INTERFACE_PKEX;
+
/*
* In theory a driver could support a lesser duration than 200ms. This
* complicates things since we would need to tack on additional
@@ -1596,8 +1798,7 @@ static struct l_dbus_message *dpp_dbus_pkex_start_enrollee(struct l_dbus *dbus,
l_debug("");
- if (dpp->state != DPP_STATE_NOTHING ||
- dpp->interface != DPP_INTERFACE_UNBOUND)
+ if (dpp->sm || dpp->interface != DPP_INTERFACE_UNBOUND)
return dbus_error_busy(message);
if (station && station_get_connected_network(station))
@@ -1651,9 +1852,9 @@ static struct l_dbus_message *dpp_start_pkex_configurator(struct dpp *dpp,
struct network *network = station_get_connected_network(station);
struct scan_bss *bss = station_get_connected_bss(station);
const struct l_settings *settings;
+ struct dpp_configuration *config;
- if (dpp->state != DPP_STATE_NOTHING ||
- dpp->interface != DPP_INTERFACE_UNBOUND)
+ if (dpp->sm || dpp->interface != DPP_INTERFACE_UNBOUND)
return dbus_error_busy(message);
if (!dpp->mcast_support) {
@@ -1671,30 +1872,39 @@ static struct l_dbus_message *dpp_start_pkex_configurator(struct dpp *dpp,
return dbus_error_not_configured(message);
}
+ dpp->sm = dpp_sm_new(dpp_event, dpp->boot_public,
+ dpp->boot_private, dpp);
+
if (identifier)
- dpp->pkex_id = l_strdup(identifier);
+ dpp_sm_set_pkex_identifier(dpp->sm, identifier);
if (key)
- dpp->pkex_key = l_strdup(key);
+ dpp_sm_set_pkex_key(dpp->sm, key);
if (agent_path)
dpp_create_agent(dpp, agent_path, message);
dpp->role = DPP_CAPABILITY_CONFIGURATOR;
- dpp->state = DPP_STATE_PKEX_EXCHANGE;
dpp->interface = DPP_INTERFACE_PKEX;
dpp->current_freq = bss->frequency;
- dpp->config = dpp_configuration_new(network_get_settings(network),
+ config = dpp_configuration_new(network_get_settings(network),
network_get_ssid(network),
hs->akm_suite);
+ dpp_sm_set_role(dpp->sm, DPP_CAPABILITY_CONFIGURATOR);
+ dpp_sm_set_configuration(dpp->sm, config);
+ dpp_sm_set_pkex_own_mac(dpp->sm, netdev_get_address(dpp->netdev));
+ dpp_sm_set_write_handler(dpp->sm, dpp_tx_frame);
+
dpp_property_changed_notify(dpp);
- if (dpp->pkex_key)
+ if (key)
l_debug("Starting PKEX configurator for single enrollee");
else
l_debug("Starting PKEX configurator with agent");
+ dpp_sm_pkex_start_responder(dpp->sm);
+
return l_dbus_message_new_method_return(message);
}