Bluetooth: controller: split: Fix advertising for multiple peripherals

When multiple simultaneous peripheral connections are
supported, restarting connectable advertising by host on
peripheral connection establishment failed in controller.
This prevented establishing new connections while first
connection was active.

The failure was caused by a bug in the way controller was
using quota for Rx PDU buffers. As the quota count was
release before the connection complete event rx PDU buffer
being released, the Rx PDUs needed to reserve for
connection complete event for new connectable advertising
was not available. This caused the connectable advertising
enable to fail.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2019-09-27 12:04:22 +05:30 committed by Carles Cufí
commit 9d6c170e22

View file

@ -479,10 +479,6 @@ void ll_rx_dequeue(void)
struct node_rx_hdr *rx = NULL;
memq_link_t *link;
#if defined(CONFIG_BT_CONN)
struct node_rx_cc *cc = NULL;
#endif /* CONFIG_BT_CONN */
link = memq_dequeue(memq_ll_rx.tail, &memq_ll_rx.head,
(void **)&rx);
LL_ASSERT(link);
@ -491,24 +487,73 @@ void ll_rx_dequeue(void)
/* handle object specific clean up */
switch (rx->type) {
#if defined(CONFIG_BT_OBSERVER) || \
defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY) || \
defined(CONFIG_BT_CTLR_PROFILE_ISR) || \
defined(CONFIG_BT_CTLR_ADV_INDICATION) || \
defined(CONFIG_BT_CTLR_SCAN_INDICATION) || \
defined(CONFIG_BT_CTLR_USER_EXT) || \
defined(CONFIG_BT_CONN)
#if defined(CONFIG_BT_CONN)
/* fallthrough */
case NODE_RX_TYPE_CONNECTION:
{
cc = (void *)((struct node_rx_pdu *)rx)->pdu;
if (cc->status) {
break;
struct node_rx_cc *cc = (void *)((struct node_rx_pdu *)rx)->pdu;
struct node_rx_ftr *ftr = &(rx->rx_ftr);
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) &&
((cc->status == BT_HCI_ERR_ADV_TIMEOUT) || cc->role)) {
struct lll_adv *lll = ftr->param;
struct ll_adv_set *adv = (void *)HDR_LLL2EVT(lll);
if (cc->status == BT_HCI_ERR_ADV_TIMEOUT) {
struct lll_conn *conn_lll;
struct ll_conn *conn;
memq_link_t *link;
conn_lll = lll->conn;
LL_ASSERT(conn_lll);
LL_ASSERT(!conn_lll->link_tx_free);
link = memq_deinit(&conn_lll->memq_tx.head,
&conn_lll->memq_tx.tail);
LL_ASSERT(link);
conn_lll->link_tx_free = link;
conn = (void *)HDR_LLL2EVT(conn_lll);
ll_conn_release(conn);
lll->conn = NULL;
} else {
/* Release un-utilized node rx */
if (adv->node_rx_cc_free) {
void *rx_free;
rx_free = adv->node_rx_cc_free;
adv->node_rx_cc_free = NULL;
ll_rx_release(rx_free);
}
}
adv->is_enabled = 0U;
} else if (IS_ENABLED(CONFIG_BT_CENTRAL)) {
struct lll_scan *lll = ftr->param;
struct ll_scan_set *scan = (void *)HDR_LLL2EVT(lll);
scan->is_enabled = 0U;
} else {
LL_ASSERT(0);
}
if (IS_ENABLED(CONFIG_BT_CTLR_PRIVACY)) {
u8_t bm;
bm = (IS_ENABLED(CONFIG_BT_OBSERVER) &&
ull_scan_is_enabled(0) << 1) |
(IS_ENABLED(CONFIG_BT_BROADCASTER) &&
ull_adv_is_enabled(0));
if (!bm) {
ull_filter_adv_scan_state_cb(0);
}
}
}
break;
case NODE_RX_TYPE_TERMINATE:
case NODE_RX_TYPE_DC_PDU:
#endif /* CONFIG_BT_CONN */
@ -545,7 +590,6 @@ void ll_rx_dequeue(void)
#endif /* CONFIG_BT_CONN */
#if defined(CONFIG_BT_CTLR_PROFILE_ISR)
/* fallthrough */
case NODE_RX_TYPE_PROFILE:
#endif /* CONFIG_BT_CTLR_PROFILE_ISR */
@ -565,104 +609,23 @@ void ll_rx_dequeue(void)
#if defined(CONFIG_BT_CTLR_USER_EXT)
case NODE_RX_TYPE_USER_START ... NODE_RX_TYPE_USER_END:
#endif /* CONFIG_BT_CTLR_USER_EXT */
/*
* We have just dequeued from memq_ll_rx; that frees up some
* quota for Link Layer. Note that we threw away the rx node
* we have just dequeued from memq_ll_rx. But, this is OK,
* since prio_recv_thread() peeked in memq_ll_rx via
* ll_rx_get() before.
*/
ll_rx_link_inc_quota(1);
break;
#endif /* CONFIG_BT_OBSERVER ||
* CONFIG_BT_CTLR_SCAN_REQ_NOTIFY ||
* CONFIG_BT_CTLR_PROFILE_ISR ||
* CONFIG_BT_CTLR_ADV_INDICATION ||
* CONFIG_BT_CTLR_SCAN_INDICATION ||
* CONFIG_BT_CTLR_USER_EXT ||
* CONFIG_BT_CONN
*/
#if defined(CONFIG_BT_CONN)
/* fall through */
case NODE_RX_TYPE_TERMINATE:
/* Did not use data link quota */
/* Ensure that at least one 'case' statement is present for this
* code block.
*/
case NODE_RX_TYPE_NONE:
LL_ASSERT(rx->type != NODE_RX_TYPE_NONE);
break;
#endif /* CONFIG_BT_CONN */
default:
LL_ASSERT(0);
break;
}
/* FIXME: clean up when porting Mesh Ext. */
if (0) {
#if defined(CONFIG_BT_CONN)
} else if (rx->type == NODE_RX_TYPE_CONNECTION) {
struct node_rx_ftr *ftr;
ftr = &(rx->rx_ftr);
if (0) {
#if defined(CONFIG_BT_PERIPHERAL)
} else if ((cc->status == 0x3c) || cc->role) {
struct lll_adv *lll = ftr->param;
struct ll_adv_set *adv = (void *)HDR_LLL2EVT(lll);
if (cc->status == 0x3c) {
struct lll_conn *conn_lll;
struct ll_conn *conn;
memq_link_t *link;
conn_lll = lll->conn;
LL_ASSERT(conn_lll);
LL_ASSERT(!conn_lll->link_tx_free);
link = memq_deinit(&conn_lll->memq_tx.head,
&conn_lll->memq_tx.tail);
LL_ASSERT(link);
conn_lll->link_tx_free = link;
conn = (void *)HDR_LLL2EVT(conn_lll);
ll_conn_release(conn);
lll->conn = NULL;
} else {
/* Release un-utilized node rx */
if (adv->node_rx_cc_free) {
void *rx_free;
rx_free = adv->node_rx_cc_free;
adv->node_rx_cc_free = NULL;
ll_rx_release(rx_free);
}
}
adv->is_enabled = 0U;
#endif /* CONFIG_BT_PERIPHERAL */
#if defined(CONFIG_BT_CENTRAL)
} else {
struct lll_scan *lll = ftr->param;
struct ll_scan_set *scan = (void *)HDR_LLL2EVT(lll);
scan->is_enabled = 0U;
#endif /* CONFIG_BT_CENTRAL */
}
if (IS_ENABLED(CONFIG_BT_CTLR_PRIVACY)) {
u8_t bm;
bm = (IS_ENABLED(CONFIG_BT_OBSERVER) &&
ull_scan_is_enabled(0) << 1) |
(IS_ENABLED(CONFIG_BT_BROADCASTER) &&
ull_adv_is_enabled(0));
if (!bm) {
ull_filter_adv_scan_state_cb(0);
}
}
#endif /* CONFIG_BT_CONN */
#if defined(CONFIG_BT_HCI_MESH_EXT)
} else if (rx->type == NODE_RX_TYPE_MESH_ADV_CPLT) {
struct ll_adv_set *adv;
@ -800,6 +763,7 @@ void ll_rx_mem_release(void **node_rx)
*/
case NODE_RX_TYPE_NONE:
LL_ASSERT(rx_free->type != NODE_RX_TYPE_NONE);
ll_rx_link_inc_quota(1);
mem_release(rx_free, &mem_pdu_rx.free);
break;