mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-11-26 10:39:23 +01:00
dpp: handle sending a frame after ROC ends
There is a potential corner case of an offchannel frame callback being called after ROC has ended. This could happen in theory if a received frame is queued right as the ROC session expires. If the ROC cancel event makes it to user space before the frame IWD will schedule another ROC then receive the frame. This doesn't prevent IWD from sending out another frame since OFFCHANNEL_TX_OK is used, but it will prevent IWD from receiving a response frame since no dwell duration is used with DPP. To handle this an roc_started bool was added to the dpp_sm which tracks the ROC state. If dpp_send_frame is called when roc_started is false the frame will be saved and sent out once the ROC session is started again.
This commit is contained in:
parent
8a877d8692
commit
07197e24fc
67
src/dpp.c
67
src/dpp.c
@ -138,12 +138,39 @@ struct dpp_sm {
|
|||||||
uint32_t connect_scan_id;
|
uint32_t connect_scan_id;
|
||||||
uint64_t frame_cookie;
|
uint64_t frame_cookie;
|
||||||
uint8_t frame_retry;
|
uint8_t frame_retry;
|
||||||
|
void *frame_pending;
|
||||||
|
size_t frame_size;
|
||||||
|
|
||||||
struct l_dbus_message *pending;
|
struct l_dbus_message *pending;
|
||||||
|
|
||||||
bool mcast_support : 1;
|
bool mcast_support : 1;
|
||||||
|
bool roc_started : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void *dpp_serialize_iovec(struct iovec *iov, size_t iov_len,
|
||||||
|
size_t *out_len)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
size_t size = 0;
|
||||||
|
uint8_t *ret;
|
||||||
|
|
||||||
|
for (i = 0; i < iov_len; i++)
|
||||||
|
size += iov[i].iov_len;
|
||||||
|
|
||||||
|
ret = l_malloc(size);
|
||||||
|
size = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < iov_len; i++) {
|
||||||
|
memcpy(ret + size, iov[i].iov_base, iov[i].iov_len);
|
||||||
|
size += iov[i].iov_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_len)
|
||||||
|
*out_len = size;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void dpp_free_auth_data(struct dpp_sm *dpp)
|
static void dpp_free_auth_data(struct dpp_sm *dpp)
|
||||||
{
|
{
|
||||||
if (dpp->own_proto_public) {
|
if (dpp->own_proto_public) {
|
||||||
@ -209,6 +236,11 @@ static void dpp_reset(struct dpp_sm *dpp)
|
|||||||
dpp->peer_asn1 = NULL;
|
dpp->peer_asn1 = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dpp->frame_pending) {
|
||||||
|
l_free(dpp->frame_pending);
|
||||||
|
dpp->frame_pending = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
dpp->state = DPP_STATE_NOTHING;
|
dpp->state = DPP_STATE_NOTHING;
|
||||||
dpp->new_freq = 0;
|
dpp->new_freq = 0;
|
||||||
dpp->frame_retry = 0;
|
dpp->frame_retry = 0;
|
||||||
@ -267,6 +299,19 @@ static void dpp_send_frame(struct dpp_sm *dpp,
|
|||||||
{
|
{
|
||||||
struct l_genl_msg *msg;
|
struct l_genl_msg *msg;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A received frame could potentially come in after the ROC session has
|
||||||
|
* ended. In this case the frame needs to be stored until ROC is started
|
||||||
|
* and sent at that time. The offchannel_id is also checked since
|
||||||
|
* this is not applicable when DPP is in a responder role waiting
|
||||||
|
* on the currently connected channel i.e. offchannel is never used.
|
||||||
|
*/
|
||||||
|
if (!dpp->roc_started && dpp->offchannel_id) {
|
||||||
|
dpp->frame_pending = dpp_serialize_iovec(iov, iov_len,
|
||||||
|
&dpp->frame_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
msg = l_genl_msg_new_sized(NL80211_CMD_FRAME, 512);
|
msg = l_genl_msg_new_sized(NL80211_CMD_FRAME, 512);
|
||||||
l_genl_msg_append_attr(msg, NL80211_ATTR_WDEV, 8, &dpp->wdev_id);
|
l_genl_msg_append_attr(msg, NL80211_ATTR_WDEV, 8, &dpp->wdev_id);
|
||||||
l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY_FREQ, 4, &freq);
|
l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY_FREQ, 4, &freq);
|
||||||
@ -281,6 +326,20 @@ static void dpp_send_frame(struct dpp_sm *dpp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dpp_frame_retry(struct dpp_sm *dpp)
|
||||||
|
{
|
||||||
|
struct iovec iov;
|
||||||
|
|
||||||
|
iov.iov_base = dpp->frame_pending;
|
||||||
|
iov.iov_len = dpp->frame_size;
|
||||||
|
|
||||||
|
dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
|
||||||
|
|
||||||
|
l_free(dpp->frame_pending);
|
||||||
|
dpp->frame_pending = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t dpp_build_header(const uint8_t *src, const uint8_t *dest,
|
static size_t dpp_build_header(const uint8_t *src, const uint8_t *dest,
|
||||||
enum dpp_frame_type type,
|
enum dpp_frame_type type,
|
||||||
uint8_t buf[static 32])
|
uint8_t buf[static 32])
|
||||||
@ -1360,6 +1419,13 @@ static void dpp_roc_started(void *user_data)
|
|||||||
* the authenticate response now.
|
* the authenticate response now.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
dpp->roc_started = true;
|
||||||
|
|
||||||
|
if (dpp->frame_pending) {
|
||||||
|
dpp_frame_retry(dpp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (dpp->state) {
|
switch (dpp->state) {
|
||||||
case DPP_STATE_PRESENCE:
|
case DPP_STATE_PRESENCE:
|
||||||
if (dpp->role == DPP_CAPABILITY_CONFIGURATOR)
|
if (dpp->role == DPP_CAPABILITY_CONFIGURATOR)
|
||||||
@ -1409,6 +1475,7 @@ static void dpp_presence_timeout(int error, void *user_data)
|
|||||||
struct dpp_sm *dpp = user_data;
|
struct dpp_sm *dpp = user_data;
|
||||||
|
|
||||||
dpp->offchannel_id = 0;
|
dpp->offchannel_id = 0;
|
||||||
|
dpp->roc_started = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If cancelled this is likely due to netdev going down or from Stop().
|
* If cancelled this is likely due to netdev going down or from Stop().
|
||||||
|
Loading…
Reference in New Issue
Block a user