mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-11-29 13:59:24 +01:00
frame-xchg: Add facility to keep retransmitting after ACK
In some cases a P2P peer will ACK our frame but not reply on the first attempt, and other implementations seem to handle this by going back to retransmitting the frame at a high rate until it gets ACKed again, at which point they will again give the peer a longer time to tx the response frame. Implement the same logic here by adding a retries_on_ack parameter that takes the number of additional times we want to restart the normal retransmit counter after we received no response frame on the first attempt. So passing 0 maintains the current behaviour, 1 for 1 extra attempt, etc. In effect we may retransmit a frame about 15 * (retry_on_ack + 1) * <in-kernel retransmit limit> times. The kernel/driver retransmits a frame a number of times if there's no ACK (I've seen about 20 normally) at a high frequency, if that fails we retry the whole process 15 times inside frame-xchg.c and if we still get no ACK at any point, we give up. If we do get an ACK, we wait for a response frame and if we don't get that we will optionally reset the retry counter and restart the whole thing retry_on_ack times.
This commit is contained in:
parent
e7a9a43410
commit
e6de4b10ad
@ -107,6 +107,7 @@ struct frame_xchg_data {
|
|||||||
unsigned int retry_cnt;
|
unsigned int retry_cnt;
|
||||||
unsigned int retry_interval;
|
unsigned int retry_interval;
|
||||||
unsigned int resp_timeout;
|
unsigned int resp_timeout;
|
||||||
|
unsigned int retries_on_ack;
|
||||||
bool in_frame_cb : 1;
|
bool in_frame_cb : 1;
|
||||||
bool stale : 1;
|
bool stale : 1;
|
||||||
};
|
};
|
||||||
@ -726,6 +727,9 @@ static bool frame_watch_remove_by_handler(uint64_t wdev_id, uint32_t group_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void frame_xchg_tx_retry(struct frame_xchg_data *fx);
|
static void frame_xchg_tx_retry(struct frame_xchg_data *fx);
|
||||||
|
static bool frame_xchg_resp_handle(const struct mmpdu_header *mpdu,
|
||||||
|
const void *body, size_t body_len,
|
||||||
|
int rssi, void *user_data);
|
||||||
static void frame_xchg_resp_cb(const struct mmpdu_header *mpdu,
|
static void frame_xchg_resp_cb(const struct mmpdu_header *mpdu,
|
||||||
const void *body, size_t body_len,
|
const void *body, size_t body_len,
|
||||||
int rssi, void *user_data);
|
int rssi, void *user_data);
|
||||||
@ -805,12 +809,20 @@ static void frame_xchg_timeout_cb(struct l_timeout *timeout,
|
|||||||
frame_xchg_tx_retry(fx);
|
frame_xchg_tx_retry(fx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void frame_xchg_resp_timeout_cb(struct l_timeout *timeout,
|
static void frame_xchg_listen_end_cb(struct l_timeout *timeout,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct frame_xchg_data *fx = user_data;
|
struct frame_xchg_data *fx = user_data;
|
||||||
|
|
||||||
|
if (!fx->retries_on_ack) {
|
||||||
frame_xchg_done(fx, 0);
|
frame_xchg_done(fx, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
l_timeout_remove(fx->timeout);
|
||||||
|
fx->retries_on_ack--;
|
||||||
|
fx->retry_cnt = 0;
|
||||||
|
frame_xchg_tx_retry(fx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void frame_xchg_tx_status(struct frame_xchg_data *fx, bool acked)
|
static void frame_xchg_tx_status(struct frame_xchg_data *fx, bool acked)
|
||||||
@ -850,17 +862,20 @@ static void frame_xchg_tx_status(struct frame_xchg_data *fx, bool acked)
|
|||||||
fx->have_cookie = false;
|
fx->have_cookie = false;
|
||||||
|
|
||||||
l_debug("Processing an early frame");
|
l_debug("Processing an early frame");
|
||||||
frame_xchg_resp_cb(fx->early_frame.mpdu, fx->early_frame.body,
|
|
||||||
fx->early_frame.body_len,
|
|
||||||
fx->early_frame.rssi, fx);
|
|
||||||
|
|
||||||
frame_xchg_done(fx, 0);
|
if (frame_xchg_resp_handle(fx->early_frame.mpdu,
|
||||||
|
fx->early_frame.body,
|
||||||
|
fx->early_frame.body_len,
|
||||||
|
fx->early_frame.rssi, fx))
|
||||||
|
return;
|
||||||
|
|
||||||
|
frame_xchg_listen_end_cb(NULL, fx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Txed frame ACKed, listen for response frames */
|
/* Txed frame ACKed, listen for response frames */
|
||||||
fx->timeout = l_timeout_create_ms(fx->resp_timeout,
|
fx->timeout = l_timeout_create_ms(fx->resp_timeout,
|
||||||
frame_xchg_resp_timeout_cb, fx,
|
frame_xchg_listen_end_cb, fx,
|
||||||
frame_xchg_timeout_destroy);
|
frame_xchg_timeout_destroy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -946,7 +961,7 @@ static void frame_xchg_tx_retry(struct frame_xchg_data *fx)
|
|||||||
fx->retry_cnt++;
|
fx->retry_cnt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void frame_xchg_resp_cb(const struct mmpdu_header *mpdu,
|
static bool frame_xchg_resp_handle(const struct mmpdu_header *mpdu,
|
||||||
const void *body, size_t body_len,
|
const void *body, size_t body_len,
|
||||||
int rssi, void *user_data)
|
int rssi, void *user_data)
|
||||||
{
|
{
|
||||||
@ -957,10 +972,10 @@ static void frame_xchg_resp_cb(const struct mmpdu_header *mpdu,
|
|||||||
l_debug("");
|
l_debug("");
|
||||||
|
|
||||||
if (memcmp(mpdu->address_1, fx->tx_mpdu->address_2, 6))
|
if (memcmp(mpdu->address_1, fx->tx_mpdu->address_2, 6))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
if (memcmp(mpdu->address_2, fx->tx_mpdu->address_1, 6))
|
if (memcmp(mpdu->address_2, fx->tx_mpdu->address_1, 6))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Is the received frame's BSSID same as the transmitted frame's
|
* Is the received frame's BSSID same as the transmitted frame's
|
||||||
@ -970,7 +985,7 @@ static void frame_xchg_resp_cb(const struct mmpdu_header *mpdu,
|
|||||||
*/
|
*/
|
||||||
if (memcmp(mpdu->address_3, fx->tx_mpdu->address_3, 6) &&
|
if (memcmp(mpdu->address_3, fx->tx_mpdu->address_3, 6) &&
|
||||||
!util_mem_is_zero(mpdu->address_3, 6))
|
!util_mem_is_zero(mpdu->address_3, 6))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
for (entry = l_queue_get_entries(fx->rx_watches);
|
for (entry = l_queue_get_entries(fx->rx_watches);
|
||||||
entry; entry = entry->next) {
|
entry; entry = entry->next) {
|
||||||
@ -994,18 +1009,18 @@ static void frame_xchg_resp_cb(const struct mmpdu_header *mpdu,
|
|||||||
* to just exit without touching anything.
|
* to just exit without touching anything.
|
||||||
*/
|
*/
|
||||||
if (!fx->in_frame_cb)
|
if (!fx->in_frame_cb)
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
fx->in_frame_cb = false;
|
fx->in_frame_cb = false;
|
||||||
|
|
||||||
if (done || fx->stale) {
|
if (done || fx->stale) {
|
||||||
fx->cb = NULL;
|
fx->cb = NULL;
|
||||||
frame_xchg_done(fx, 0);
|
frame_xchg_done(fx, 0);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
early_frame:
|
early_frame:
|
||||||
/*
|
/*
|
||||||
@ -1016,13 +1031,21 @@ early_frame:
|
|||||||
* Save the response frame to be processed in the Tx done callback.
|
* Save the response frame to be processed in the Tx done callback.
|
||||||
*/
|
*/
|
||||||
if (fx->early_frame.mpdu)
|
if (fx->early_frame.mpdu)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
hdr_len = (const uint8_t *) body - (const uint8_t *) mpdu;
|
hdr_len = (const uint8_t *) body - (const uint8_t *) mpdu;
|
||||||
fx->early_frame.mpdu = l_memdup(mpdu, body_len + hdr_len);
|
fx->early_frame.mpdu = l_memdup(mpdu, body_len + hdr_len);
|
||||||
fx->early_frame.body = (const uint8_t *) fx->early_frame.mpdu + hdr_len;
|
fx->early_frame.body = (const uint8_t *) fx->early_frame.mpdu + hdr_len;
|
||||||
fx->early_frame.body_len = body_len;
|
fx->early_frame.body_len = body_len;
|
||||||
fx->early_frame.rssi = rssi;
|
fx->early_frame.rssi = rssi;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void frame_xchg_resp_cb(const struct mmpdu_header *mpdu,
|
||||||
|
const void *body, size_t body_len,
|
||||||
|
int rssi, void *user_data)
|
||||||
|
{
|
||||||
|
frame_xchg_resp_handle(mpdu, body, body_len, rssi, user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool frame_xchg_match(const void *a, const void *b)
|
static bool frame_xchg_match(const void *a, const void *b)
|
||||||
@ -1050,8 +1073,8 @@ static bool frame_xchg_match(const void *a, const void *b)
|
|||||||
*/
|
*/
|
||||||
void frame_xchg_startv(uint64_t wdev_id, struct iovec *frame, uint32_t freq,
|
void frame_xchg_startv(uint64_t wdev_id, struct iovec *frame, uint32_t freq,
|
||||||
unsigned int retry_interval, unsigned int resp_timeout,
|
unsigned int retry_interval, unsigned int resp_timeout,
|
||||||
uint32_t group_id, frame_xchg_cb_t cb, void *user_data,
|
unsigned int retries_on_ack, uint32_t group_id,
|
||||||
va_list resp_args)
|
frame_xchg_cb_t cb, void *user_data, va_list resp_args)
|
||||||
{
|
{
|
||||||
struct frame_xchg_data *fx;
|
struct frame_xchg_data *fx;
|
||||||
size_t frame_len;
|
size_t frame_len;
|
||||||
@ -1095,6 +1118,7 @@ void frame_xchg_startv(uint64_t wdev_id, struct iovec *frame, uint32_t freq,
|
|||||||
fx->freq = freq;
|
fx->freq = freq;
|
||||||
fx->retry_interval = retry_interval;
|
fx->retry_interval = retry_interval;
|
||||||
fx->resp_timeout = resp_timeout;
|
fx->resp_timeout = resp_timeout;
|
||||||
|
fx->retries_on_ack = retries_on_ack;
|
||||||
fx->cb = cb;
|
fx->cb = cb;
|
||||||
fx->user_data = user_data;
|
fx->user_data = user_data;
|
||||||
fx->group_id = group_id;
|
fx->group_id = group_id;
|
||||||
|
@ -45,6 +45,6 @@ bool frame_watch_wdev_remove(uint64_t wdev_id);
|
|||||||
|
|
||||||
void frame_xchg_startv(uint64_t wdev_id, struct iovec *frame, uint32_t freq,
|
void frame_xchg_startv(uint64_t wdev_id, struct iovec *frame, uint32_t freq,
|
||||||
unsigned int retry_interval, unsigned int resp_timeout,
|
unsigned int retry_interval, unsigned int resp_timeout,
|
||||||
uint32_t group_id, frame_xchg_cb_t cb, void *user_data,
|
unsigned int retries_on_ack, uint32_t group_id,
|
||||||
va_list resp_args);
|
frame_xchg_cb_t cb, void *user_data, va_list resp_args);
|
||||||
void frame_xchg_stop(uint64_t wdev_id);
|
void frame_xchg_stop(uint64_t wdev_id);
|
||||||
|
Loading…
Reference in New Issue
Block a user