diff --git a/src/dpp.c b/src/dpp.c index 5bf004d8..35807a8c 100644 --- a/src/dpp.c +++ b/src/dpp.c @@ -91,6 +91,7 @@ struct dpp_sm { size_t freqs_idx; uint32_t dwell; uint32_t current_freq; + uint32_t new_freq; struct scan_freq_set *presence_list; uint32_t offchannel_id; @@ -169,6 +170,7 @@ static void dpp_reset(struct dpp_sm *dpp) } dpp->state = DPP_STATE_NOTHING; + dpp->new_freq = 0; explicit_bzero(dpp->r_nonce, dpp->nonce_len); explicit_bzero(dpp->i_nonce, dpp->nonce_len); @@ -1238,14 +1240,29 @@ static void dpp_roc_started(void *user_data) struct dpp_sm *dpp = user_data; /* - * If not in presence procedure or in a configurator role, just stay - * on channel. + * - If a configurator, nothing to do but wait for a request + * - If in the presence state continue sending announcements. + * - If authenticating, and this is a result of a channel switch send + * the authenticate response now. */ - if (dpp->state != DPP_STATE_PRESENCE || - dpp->role == DPP_CAPABILITY_CONFIGURATOR) + if (dpp->role == DPP_CAPABILITY_CONFIGURATOR) return; - dpp_presence_announce(dpp); + switch (dpp->state) { + case DPP_STATE_PRESENCE: + dpp_presence_announce(dpp); + break; + case DPP_STATE_AUTHENTICATING: + if (dpp->new_freq) { + dpp->current_freq = dpp->new_freq; + dpp->new_freq = 0; + send_authenticate_response(dpp); + } + + break; + default: + break; + } } static void dpp_start_offchannel(struct dpp_sm *dpp, uint32_t freq); @@ -1332,6 +1349,7 @@ static void authenticate_request(struct dpp_sm *dpp, const uint8_t *from, uint64_t k1[L_ECC_MAX_DIGITS]; const void *ad0 = body + 2; const void *ad1 = body + 8; + uint32_t freq; if (dpp->state != DPP_STATE_PRESENCE) return; @@ -1371,20 +1389,39 @@ static void authenticate_request(struct dpp_sm *dpp, const uint8_t *from, } break; - /* - * TODO: Go on this channel for remainder of auth protocol. - * - * "the Responder determines whether it can use the requested - * channel for the following exchanges. If so, it sends the DPP - * Authentication Response frame on that channel. If not, it - * discards the DPP Authentication Request frame without - * replying to it." - * - * For the time being this feature is not being implemented and - * the frame will be dropped. - */ + case DPP_ATTR_CHANNEL: - return; + if (len != 2) + return; + + freq = oci_to_frequency(l_get_u8(data), + l_get_u8(data + 1)); + + if (freq == dpp->current_freq) + break; + + /* + * Configurators are already connected to a network, so + * to preserve wireless performance the enrollee will + * be required to be on this channel, not a channel it + * requests. + */ + if (dpp->role == DPP_CAPABILITY_CONFIGURATOR) + return; + + /* + * Otherwise, as an enrollee, we can jump to whatever + * channel the configurator requests + */ + dpp->new_freq = freq; + + l_debug("Configurator requested a new frequency %u", + dpp->new_freq); + + offchannel_cancel(dpp->wdev_id, dpp->offchannel_id); + dpp_start_offchannel(dpp, dpp->new_freq); + + break; default: break; } @@ -1478,7 +1515,9 @@ static void authenticate_request(struct dpp_sm *dpp, const uint8_t *from, dpp->state = DPP_STATE_AUTHENTICATING; dpp_reset_protocol_timer(dpp); - send_authenticate_response(dpp); + /* Don't send if the frequency is changing */ + if (!dpp->new_freq) + send_authenticate_response(dpp); return;