Bluetooth: controller: Fix deferred Conn Update offset population
Fix deferred Connection Update offset population by introduction of explicit states waiting for the offset calculation to complete in the ULL_LOW context. Fixes #29636. The problem was, in an encrypted connection the enqueued PDU to be transmitted is encrypt in the prepare callback by the hardware and swapped to a different buffer for transmission; the deferred offset population did not reflect in the transmitted PDU as it was filled in the cleartext buffer while encryption completed into the encrypted buffer. Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
parent
c1b2f21f12
commit
383e688e3f
3 changed files with 81 additions and 37 deletions
|
@ -2197,12 +2197,6 @@ static inline void event_conn_upd_init(struct ll_conn *conn,
|
||||||
struct mayfly *mfy_sched_offset,
|
struct mayfly *mfy_sched_offset,
|
||||||
void (*fp_mfy_select_or_use)(void *))
|
void (*fp_mfy_select_or_use)(void *))
|
||||||
{
|
{
|
||||||
/* move to in progress */
|
|
||||||
conn->llcp_cu.state = LLCP_CUI_STATE_INPROG;
|
|
||||||
|
|
||||||
/* set instant */
|
|
||||||
conn->llcp.conn_upd.instant = event_counter + conn->lll.latency + 6;
|
|
||||||
|
|
||||||
/* place the conn update req packet as next in tx queue */
|
/* place the conn update req packet as next in tx queue */
|
||||||
pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
|
pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
|
||||||
pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, conn_update_ind) +
|
pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, conn_update_ind) +
|
||||||
|
@ -2218,10 +2212,11 @@ static inline void event_conn_upd_init(struct ll_conn *conn,
|
||||||
sys_cpu_to_le16(conn->llcp_cu.latency);
|
sys_cpu_to_le16(conn->llcp_cu.latency);
|
||||||
pdu_ctrl_tx->llctrl.conn_update_ind.timeout =
|
pdu_ctrl_tx->llctrl.conn_update_ind.timeout =
|
||||||
sys_cpu_to_le16(conn->llcp_cu.timeout);
|
sys_cpu_to_le16(conn->llcp_cu.timeout);
|
||||||
pdu_ctrl_tx->llctrl.conn_update_ind.instant =
|
|
||||||
sys_cpu_to_le16(conn->llcp.conn_upd.instant);
|
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
|
#if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
|
||||||
|
/* move to offset calculation requested state */
|
||||||
|
conn->llcp_cu.state = LLCP_CUI_STATE_OFFS_REQ;
|
||||||
|
|
||||||
{
|
{
|
||||||
uint32_t retval;
|
uint32_t retval;
|
||||||
|
|
||||||
|
@ -2257,6 +2252,9 @@ static inline void event_conn_upd_init(struct ll_conn *conn,
|
||||||
ARG_UNUSED(ticks_at_expire);
|
ARG_UNUSED(ticks_at_expire);
|
||||||
ARG_UNUSED(mfy_sched_offset);
|
ARG_UNUSED(mfy_sched_offset);
|
||||||
ARG_UNUSED(fp_mfy_select_or_use);
|
ARG_UNUSED(fp_mfy_select_or_use);
|
||||||
|
|
||||||
|
/* move to in progress */
|
||||||
|
conn->llcp_cu.state = LLCP_CUI_STATE_INPROG;
|
||||||
#endif /* !CONFIG_BT_CTLR_SCHED_ADVANCED */
|
#endif /* !CONFIG_BT_CTLR_SCHED_ADVANCED */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2281,15 +2279,62 @@ static inline int event_conn_upd_prep(struct ll_conn *conn, uint16_t lazy,
|
||||||
instant_latency = (event_counter - conn->llcp.conn_upd.instant) &
|
instant_latency = (event_counter - conn->llcp.conn_upd.instant) &
|
||||||
0xffff;
|
0xffff;
|
||||||
if (conn->llcp_cu.state != LLCP_CUI_STATE_INPROG) {
|
if (conn->llcp_cu.state != LLCP_CUI_STATE_INPROG) {
|
||||||
|
struct pdu_data *pdu_ctrl_tx;
|
||||||
|
struct node_rx_pdu *rx;
|
||||||
|
struct node_tx *tx;
|
||||||
#if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
|
#if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
|
||||||
static memq_link_t s_link;
|
static memq_link_t s_link;
|
||||||
static struct mayfly s_mfy_sched_offset = {0, 0,
|
static struct mayfly s_mfy_sched_offset = {0, 0,
|
||||||
&s_link, 0, 0 };
|
&s_link, 0, 0 };
|
||||||
void (*fp_mfy_select_or_use)(void *) = NULL;
|
void (*fp_mfy_select_or_use)(void *) = NULL;
|
||||||
#endif /* CONFIG_BT_CTLR_SCHED_ADVANCED */
|
|
||||||
struct pdu_data *pdu_ctrl_tx;
|
switch (conn->llcp_cu.state) {
|
||||||
struct node_rx_pdu *rx;
|
case LLCP_CUI_STATE_USE:
|
||||||
struct node_tx *tx;
|
fp_mfy_select_or_use = ull_sched_mfy_win_offset_use;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
|
||||||
|
case LLCP_CUI_STATE_SELECT:
|
||||||
|
fp_mfy_select_or_use = ull_sched_mfy_win_offset_select;
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
|
||||||
|
|
||||||
|
case LLCP_CUI_STATE_OFFS_REQ:
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
case LLCP_CUI_STATE_OFFS_RDY:
|
||||||
|
/* set instant */
|
||||||
|
conn->llcp.conn_upd.instant = event_counter +
|
||||||
|
conn->lll.latency + 6;
|
||||||
|
pdu_ctrl_tx =
|
||||||
|
CONTAINER_OF(conn->llcp.conn_upd.pdu_win_offset,
|
||||||
|
struct pdu_data,
|
||||||
|
llctrl.conn_update_ind.win_offset);
|
||||||
|
pdu_ctrl_tx->llctrl.conn_update_ind.instant =
|
||||||
|
sys_cpu_to_le16(conn->llcp.conn_upd.instant);
|
||||||
|
/* move to in progress */
|
||||||
|
conn->llcp_cu.state = LLCP_CUI_STATE_INPROG;
|
||||||
|
/* enqueue control PDU */
|
||||||
|
tx = CONTAINER_OF(pdu_ctrl_tx, struct node_tx, pdu);
|
||||||
|
ctrl_tx_enqueue(conn, tx);
|
||||||
|
return -EINPROGRESS;
|
||||||
|
|
||||||
|
case LLCP_CUI_STATE_REJECT:
|
||||||
|
/* move to in progress */
|
||||||
|
conn->llcp_cu.state = LLCP_CUI_STATE_INPROG;
|
||||||
|
/* enqueue control PDU */
|
||||||
|
pdu_ctrl_tx =
|
||||||
|
CONTAINER_OF(conn->llcp.conn_upd.pdu_win_offset,
|
||||||
|
struct pdu_data,
|
||||||
|
llctrl.conn_update_ind.win_offset);
|
||||||
|
tx = CONTAINER_OF(pdu_ctrl_tx, struct node_tx, pdu);
|
||||||
|
ctrl_tx_enqueue(conn, tx);
|
||||||
|
return -EINPROGRESS;
|
||||||
|
default:
|
||||||
|
LL_ASSERT(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif /* !CONFIG_BT_CTLR_SCHED_ADVANCED */
|
||||||
|
|
||||||
rx = ll_pdu_rx_alloc_peek(1);
|
rx = ll_pdu_rx_alloc_peek(1);
|
||||||
if (!rx) {
|
if (!rx) {
|
||||||
|
@ -2308,32 +2353,20 @@ static inline int event_conn_upd_prep(struct ll_conn *conn, uint16_t lazy,
|
||||||
pdu_ctrl_tx = (void *)tx->pdu;
|
pdu_ctrl_tx = (void *)tx->pdu;
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
|
#if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
|
||||||
switch (conn->llcp_cu.state) {
|
|
||||||
case LLCP_CUI_STATE_USE:
|
|
||||||
fp_mfy_select_or_use = ull_sched_mfy_win_offset_use;
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
|
|
||||||
case LLCP_CUI_STATE_SELECT:
|
|
||||||
fp_mfy_select_or_use = ull_sched_mfy_win_offset_select;
|
|
||||||
break;
|
|
||||||
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
|
|
||||||
|
|
||||||
default:
|
|
||||||
LL_ASSERT(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
event_conn_upd_init(conn, event_counter, ticks_at_expire,
|
event_conn_upd_init(conn, event_counter, ticks_at_expire,
|
||||||
pdu_ctrl_tx, &s_mfy_sched_offset,
|
pdu_ctrl_tx, &s_mfy_sched_offset,
|
||||||
fp_mfy_select_or_use);
|
fp_mfy_select_or_use);
|
||||||
#else /* !CONFIG_BT_CTLR_SCHED_ADVANCED */
|
#else /* !CONFIG_BT_CTLR_SCHED_ADVANCED */
|
||||||
event_conn_upd_init(conn, event_counter, ticks_at_expire,
|
event_conn_upd_init(conn, event_counter, ticks_at_expire,
|
||||||
pdu_ctrl_tx, NULL, NULL);
|
pdu_ctrl_tx, NULL, NULL);
|
||||||
#endif /* !CONFIG_BT_CTLR_SCHED_ADVANCED */
|
/* set instant */
|
||||||
|
conn->llcp.conn_upd.instant = event_counter +
|
||||||
|
conn->lll.latency + 6;
|
||||||
|
pdu_ctrl_tx->llctrl.conn_update_ind.instant =
|
||||||
|
sys_cpu_to_le16(conn->llcp.conn_upd.instant);
|
||||||
|
/* enqueue control PDU */
|
||||||
ctrl_tx_enqueue(conn, tx);
|
ctrl_tx_enqueue(conn, tx);
|
||||||
|
#endif /* !CONFIG_BT_CTLR_SCHED_ADVANCED */
|
||||||
} else if (instant_latency <= 0x7FFF) {
|
} else if (instant_latency <= 0x7FFF) {
|
||||||
uint32_t ticks_win_offset = 0;
|
uint32_t ticks_win_offset = 0;
|
||||||
uint32_t ticks_slot_overhead;
|
uint32_t ticks_slot_overhead;
|
||||||
|
|
|
@ -146,8 +146,11 @@ struct ll_conn {
|
||||||
enum {
|
enum {
|
||||||
LLCP_CUI_STATE_INPROG,
|
LLCP_CUI_STATE_INPROG,
|
||||||
LLCP_CUI_STATE_USE,
|
LLCP_CUI_STATE_USE,
|
||||||
LLCP_CUI_STATE_SELECT
|
LLCP_CUI_STATE_SELECT,
|
||||||
} state:2 __packed;
|
LLCP_CUI_STATE_OFFS_REQ,
|
||||||
|
LLCP_CUI_STATE_OFFS_RDY,
|
||||||
|
LLCP_CUI_STATE_REJECT,
|
||||||
|
} state:3 __packed;
|
||||||
uint8_t cmd:1;
|
uint8_t cmd:1;
|
||||||
uint16_t interval;
|
uint16_t interval;
|
||||||
uint16_t latency;
|
uint16_t latency;
|
||||||
|
|
|
@ -182,6 +182,9 @@ void ull_sched_mfy_win_offset_use(void *param)
|
||||||
win_offset = conn->llcp_cu.win_offset_us / CONN_INT_UNIT_US;
|
win_offset = conn->llcp_cu.win_offset_us / CONN_INT_UNIT_US;
|
||||||
|
|
||||||
sys_put_le16(win_offset, (void *)conn->llcp.conn_upd.pdu_win_offset);
|
sys_put_le16(win_offset, (void *)conn->llcp.conn_upd.pdu_win_offset);
|
||||||
|
|
||||||
|
/* move to offset calculated state */
|
||||||
|
conn->llcp_cu.state = LLCP_CUI_STATE_OFFS_RDY;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
|
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
|
||||||
|
@ -260,11 +263,15 @@ void ull_sched_mfy_win_offset_select(void *param)
|
||||||
CONN_INT_UNIT_US;
|
CONN_INT_UNIT_US;
|
||||||
sys_put_le16(win_offset_s,
|
sys_put_le16(win_offset_s,
|
||||||
(void *)conn->llcp.conn_upd.pdu_win_offset);
|
(void *)conn->llcp.conn_upd.pdu_win_offset);
|
||||||
|
/* move to offset calculated state */
|
||||||
|
conn->llcp_cu.state = LLCP_CUI_STATE_OFFS_RDY;
|
||||||
} else if (!has_offset_s) {
|
} else if (!has_offset_s) {
|
||||||
conn->llcp_cu.win_offset_us = win_offset_m[0] *
|
conn->llcp_cu.win_offset_us = win_offset_m[0] *
|
||||||
CONN_INT_UNIT_US;
|
CONN_INT_UNIT_US;
|
||||||
sys_put_le16(win_offset_m[0],
|
sys_put_le16(win_offset_m[0],
|
||||||
(void *)conn->llcp.conn_upd.pdu_win_offset);
|
(void *)conn->llcp.conn_upd.pdu_win_offset);
|
||||||
|
/* move to offset calculated state */
|
||||||
|
conn->llcp_cu.state = LLCP_CUI_STATE_OFFS_RDY;
|
||||||
} else {
|
} else {
|
||||||
struct pdu_data *pdu_ctrl_tx;
|
struct pdu_data *pdu_ctrl_tx;
|
||||||
|
|
||||||
|
@ -278,10 +285,9 @@ void ull_sched_mfy_win_offset_select(void *param)
|
||||||
ull_conn_upd_curr_reset();
|
ull_conn_upd_curr_reset();
|
||||||
|
|
||||||
/* send reject_ind_ext */
|
/* send reject_ind_ext */
|
||||||
pdu_ctrl_tx = (void *)
|
pdu_ctrl_tx = CONTAINER_OF(conn->llcp.conn_upd.pdu_win_offset,
|
||||||
((uint8_t *)conn->llcp.conn_upd.pdu_win_offset -
|
struct pdu_data,
|
||||||
offsetof(struct pdu_data,
|
llctrl.conn_update_ind.win_offset);
|
||||||
llctrl.conn_update_ind.win_offset));
|
|
||||||
pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
|
pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
|
||||||
pdu_ctrl_tx->len =
|
pdu_ctrl_tx->len =
|
||||||
offsetof(struct pdu_data_llctrl, reject_ext_ind) +
|
offsetof(struct pdu_data_llctrl, reject_ext_ind) +
|
||||||
|
@ -292,6 +298,8 @@ void ull_sched_mfy_win_offset_select(void *param)
|
||||||
PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ;
|
PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ;
|
||||||
pdu_ctrl_tx->llctrl.reject_ext_ind.error_code =
|
pdu_ctrl_tx->llctrl.reject_ext_ind.error_code =
|
||||||
BT_HCI_ERR_UNSUPP_LL_PARAM_VAL;
|
BT_HCI_ERR_UNSUPP_LL_PARAM_VAL;
|
||||||
|
/* move to conn param reject */
|
||||||
|
conn->llcp_cu.state = LLCP_CUI_STATE_REJECT;
|
||||||
}
|
}
|
||||||
#undef OFFSET_S_MAX
|
#undef OFFSET_S_MAX
|
||||||
#undef OFFSET_M_MAX
|
#undef OFFSET_M_MAX
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue