This is an automated email from the ASF dual-hosted git repository.
janc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
The following commit(s) were added to refs/heads/master by this push:
new ec622cee5 nimble/host: Rework locking in L2CAP
ec622cee5 is described below
commit ec622cee58ed6c19b524ecff74a4a868b8b710c4
Author: Szymon Janc <[email protected]>
AuthorDate: Tue Jul 29 18:19:15 2025 +0200
nimble/host: Rework locking in L2CAP
Main goal here to cleanup how locking is being done in L2CAP code:
- avoid double/nested locking
- avoid lock-unlock-lock pattern due to public API calls from
internal code
- provide _nolock variants to be used internally
- public API is locked wrapper around _nolock private API
- avoid locking in FOO and unlocking in BAR function for code clarify
---
nimble/host/src/ble_l2cap.c | 33 ++-
nimble/host/src/ble_l2cap_coc.c | 8 +-
nimble/host/src/ble_l2cap_sig.c | 388 ++++++++++++++++++----------------
nimble/host/src/ble_l2cap_sig_cmd.c | 16 +-
nimble/host/src/ble_l2cap_sig_priv.h | 44 ++--
nimble/host/test/src/ble_l2cap_test.c | 9 +-
6 files changed, 274 insertions(+), 224 deletions(-)
diff --git a/nimble/host/src/ble_l2cap.c b/nimble/host/src/ble_l2cap.c
index 5a4ff9ad4..69e879918 100644
--- a/nimble/host/src/ble_l2cap.c
+++ b/nimble/host/src/ble_l2cap.c
@@ -152,7 +152,13 @@ int
ble_l2cap_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu,
struct os_mbuf *sdu_rx, ble_l2cap_event_fn *cb, void *cb_arg)
{
- return ble_l2cap_sig_coc_connect(conn_handle, psm, mtu, sdu_rx, cb,
cb_arg);
+ int rc;
+
+ ble_hs_lock();
+ rc = ble_l2cap_sig_connect_nolock(conn_handle, psm, mtu, sdu_rx, cb,
cb_arg);
+ ble_hs_unlock();
+
+ return rc;
}
int
@@ -183,8 +189,14 @@ ble_l2cap_enhanced_connect(uint16_t conn_handle,
uint8_t num, struct os_mbuf *sdu_rx[],
ble_l2cap_event_fn *cb, void *cb_arg)
{
- return ble_l2cap_sig_ecoc_connect(conn_handle, psm, mtu,
- num, sdu_rx, cb, cb_arg);
+ int rc;
+
+ ble_hs_lock();
+ rc = ble_l2cap_sig_ecoc_connect_nolock(conn_handle, psm, mtu, num, sdu_rx,
+ cb, cb_arg);
+ ble_hs_unlock();
+
+ return rc;
}
int
@@ -192,6 +204,7 @@ ble_l2cap_reconfig(struct ble_l2cap_chan *chans[], uint8_t
num, uint16_t new_mtu
{
int i;
uint16_t conn_handle;
+ int rc;
if (num == 0 || !chans) {
return BLE_HS_EINVAL;
@@ -206,13 +219,23 @@ ble_l2cap_reconfig(struct ble_l2cap_chan *chans[],
uint8_t num, uint16_t new_mtu
}
}
- return ble_l2cap_sig_coc_reconfig(conn_handle, chans, num, new_mtu);
+ ble_hs_lock();
+ rc = ble_l2cap_sig_coc_reconfig_nolock(conn_handle, chans, num, new_mtu);
+ ble_hs_unlock();
+
+ return rc;
}
int
ble_l2cap_disconnect(struct ble_l2cap_chan *chan)
{
- return ble_l2cap_sig_disconnect(chan);
+ int rc;
+
+ ble_hs_lock();
+ rc = ble_l2cap_sig_disconnect_nolock(chan);
+ ble_hs_unlock();
+
+ return rc;
}
/**
diff --git a/nimble/host/src/ble_l2cap_coc.c b/nimble/host/src/ble_l2cap_coc.c
index cb74e7b70..0c38f6951 100644
--- a/nimble/host/src/ble_l2cap_coc.c
+++ b/nimble/host/src/ble_l2cap_coc.c
@@ -599,8 +599,8 @@ ble_l2cap_coc_le_credits_update(uint16_t conn_handle,
uint16_t dcid,
if (chan->coc_tx.credits + credits > 0xFFFF) {
BLE_HS_LOG(INFO, "LE CoC credits overflow...disconnecting\n");
+ ble_l2cap_sig_disconnect_nolock(chan);
ble_hs_unlock();
- ble_l2cap_sig_disconnect(chan);
return;
}
@@ -648,10 +648,8 @@ ble_l2cap_coc_recv_ready(struct ble_l2cap_chan *chan,
struct os_mbuf *sdu_rx)
* to be able to send complete SDU.
*/
if (chan->coc_rx.credits < c->initial_credits) {
- ble_hs_unlock();
- ble_l2cap_sig_le_credits(chan->conn_handle, chan->scid,
- c->initial_credits - chan->coc_rx.credits);
- ble_hs_lock();
+ ble_l2cap_sig_le_credits_nolock(chan->conn_handle, chan->scid,
+ c->initial_credits -
chan->coc_rx.credits);
chan->coc_rx.credits = c->initial_credits;
}
diff --git a/nimble/host/src/ble_l2cap_sig.c b/nimble/host/src/ble_l2cap_sig.c
index 3b9e452e5..2325909be 100644
--- a/nimble/host/src/ble_l2cap_sig.c
+++ b/nimble/host/src/ble_l2cap_sig.c
@@ -248,16 +248,6 @@ ble_l2cap_sig_proc_free(struct ble_l2cap_sig_proc *proc)
}
}
-static void
-ble_l2cap_sig_proc_insert(struct ble_l2cap_sig_proc *proc)
-{
- ble_l2cap_sig_dbg_assert_proc_not_inserted(proc);
-
- ble_hs_lock();
- STAILQ_INSERT_HEAD(&ble_l2cap_sig_procs, proc, next);
- ble_hs_unlock();
-}
-
/**
* Tests if a proc entry fits the specified criteria.
*
@@ -345,14 +335,20 @@ ble_l2cap_sig_proc_set_timer(struct ble_l2cap_sig_proc
*proc)
}
static void
-ble_l2cap_sig_process_status(struct ble_l2cap_sig_proc *proc, int status)
+ble_l2cap_sig_proc_insert(struct ble_l2cap_sig_proc *proc)
{
- if (status == 0) {
- ble_l2cap_sig_proc_set_timer(proc);
- ble_l2cap_sig_proc_insert(proc);
- } else {
- ble_l2cap_sig_proc_free(proc);
- }
+ BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
+
+ ble_l2cap_sig_dbg_assert_proc_not_inserted(proc);
+
+ STAILQ_INSERT_HEAD(&ble_l2cap_sig_procs, proc, next);
+}
+
+static void
+ble_l2cap_sig_proc_start(struct ble_l2cap_sig_proc *proc)
+{
+ ble_l2cap_sig_proc_set_timer(proc);
+ ble_l2cap_sig_proc_insert(proc);
}
/*****************************************************************************
@@ -564,9 +560,9 @@ done:
}
int
-ble_l2cap_sig_update(uint16_t conn_handle,
- struct ble_l2cap_sig_update_params *params,
- ble_l2cap_sig_update_fn *cb, void *cb_arg)
+ble_l2cap_sig_update_nolock(uint16_t conn_handle,
+ struct ble_l2cap_sig_update_params *params,
+ ble_l2cap_sig_update_fn *cb, void *cb_arg)
{
struct os_mbuf *txom;
struct ble_l2cap_sig_update_req *req;
@@ -580,30 +576,25 @@ ble_l2cap_sig_update(uint16_t conn_handle,
STATS_INC(ble_l2cap_stats, update_init);
- ble_hs_lock();
rc = ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SIG,
&conn, &chan);
if (rc != 0) {
- ble_hs_unlock();
- goto done;
+ return rc;
}
master = conn->bhc_flags & BLE_HS_CONN_F_MASTER;
- ble_hs_unlock();
if (master) {
/* Only the slave can initiate the L2CAP connection update
* procedure.
*/
- rc = BLE_HS_EINVAL;
- goto done;
+ return BLE_HS_EINVAL;
}
proc = ble_l2cap_sig_proc_alloc();
if (proc == NULL) {
STATS_INC(ble_l2cap_stats, update_fail);
- rc = BLE_HS_ENOMEM;
- goto done;
+ return BLE_HS_ENOMEM;
}
proc->op = BLE_L2CAP_SIG_PROC_OP_UPDATE;
@@ -616,8 +607,8 @@ ble_l2cap_sig_update(uint16_t conn_handle,
sizeof(*req), &txom);
if (!req) {
STATS_INC(ble_l2cap_stats, update_fail);
- rc = BLE_HS_ENOMEM;
- goto done;
+ ble_l2cap_sig_proc_free(proc);
+ return BLE_HS_ENOMEM;
}
req->itvl_min = htole16(params->itvl_min);
@@ -625,10 +616,27 @@ ble_l2cap_sig_update(uint16_t conn_handle,
req->slave_latency = htole16(params->slave_latency);
req->timeout_multiplier = htole16(params->timeout_multiplier);
- rc = ble_l2cap_sig_tx(conn_handle, txom);
+ rc = ble_l2cap_sig_tx_nolock(conn_handle, txom);
+ if (rc) {
+ STATS_INC(ble_l2cap_stats, update_fail);
+ ble_l2cap_sig_proc_free(proc);
+ return rc;
+ }
+
+ ble_l2cap_sig_proc_start(proc);
+ return 0;
+}
+
+int
+ble_l2cap_sig_update(uint16_t conn_handle, struct ble_l2cap_sig_update_params
*params,
+ ble_l2cap_sig_update_fn *cb, void *cb_arg)
+{
+ int rc;
+
+ ble_hs_lock();
+ rc = ble_l2cap_sig_update_nolock(conn_handle, params, cb, cb_arg);
+ ble_hs_unlock();
-done:
- ble_l2cap_sig_process_status(proc, rc);
return rc;
}
@@ -858,6 +866,8 @@ ble_l2cap_sig_credit_base_reconfig_req_rx(uint16_t
conn_handle,
goto failed;
}
+ ble_l2cap_sig_tx_nolock(conn_handle, txom);
+
ble_hs_unlock();
for (i = 0; i < cid_cnt; i++) {
@@ -866,12 +876,11 @@ ble_l2cap_sig_credit_base_reconfig_req_rx(uint16_t
conn_handle,
ble_l2cap_event_coc_reconfigured(conn_handle, 0, chan[i], true);
}
- ble_l2cap_sig_tx(conn_handle, txom);
return 0;
failed:
+ ble_l2cap_sig_tx_nolock(conn_handle, txom);
ble_hs_unlock();
- ble_l2cap_sig_tx(conn_handle, txom);
return 0;
}
@@ -945,9 +954,8 @@ ble_l2cap_sig_credit_base_con_req_rx(uint16_t conn_handle,
struct ble_hs_conn *conn;
uint16_t scid;
unsigned int num_of_scids;
- uint8_t chan_created = 0;
- int i;
unsigned int len;
+ unsigned int i;
rc = ble_l2cap_sig_mbuf_pullup_base(om, sizeof(*req), &num_of_scids);
if (rc != 0) {
@@ -965,16 +973,9 @@ ble_l2cap_sig_credit_base_con_req_rx(uint16_t conn_handle,
return 0;
}
- ble_hs_lock();
-
memset(rsp, 0, len);
- /* Initial dummy values in case of error, just to satisfy PTS */
- rsp->credits = htole16(1);
- rsp->mps = htole16(BLE_L2CAP_ECOC_MIN_MTU);
- rsp->mtu = htole16(BLE_L2CAP_ECOC_MIN_MTU);
-
- if (hdr->length <= sizeof(*req)) {
+ if (hdr->length <= sizeof(*req) || num_of_scids > ARRAY_SIZE(chans)) {
rsp->result = htole16(BLE_L2CAP_COC_ERR_INVALID_PARAMETERS);
goto failed;
}
@@ -986,8 +987,6 @@ ble_l2cap_sig_credit_base_con_req_rx(uint16_t conn_handle,
goto failed;
}
- conn = ble_hs_conn_find_assert(conn_handle);
-
/* First verify that provided SCIDs are good */
for (i = 0; i < num_of_scids; i++) {
scid = le16toh(req->scids[i]);
@@ -997,30 +996,40 @@ ble_l2cap_sig_credit_base_con_req_rx(uint16_t conn_handle,
}
}
- /* Let us try to connect channels */
+ ble_hs_lock();
+ /* we should not handle any disconnects in between unlock-lock so this can
+ * be asserted
+ */
+ conn = ble_hs_conn_find_assert(conn_handle);
+
+ /* Note: to simplify implementation stop processing further channels on
+ * error
+ */
+
for (i = 0; i < num_of_scids; i++) {
- /* Verify CID. Note, scid in the request is dcid for out local channel
*/
scid = le16toh(req->scids[i]);
- chans[i] = ble_hs_conn_chan_find_by_dcid(conn, scid);
- if (chans[i]) {
+
+ /* verify for already used CIDs */
+ if (ble_hs_conn_chan_find_by_dcid(conn, scid)) {
rsp->result = htole16(BLE_L2CAP_COC_ERR_SOURCE_CID_ALREADY_USED);
- rsp->dcids[i] = htole16(chans[i]->scid);
continue;
}
rc = ble_l2cap_coc_create_srv_chan(conn, le16toh(req->psm), &chans[i]);
if (rc != 0) {
- if (i == 0) {
- /* In case it is very first channel we cannot create it means
PSM is incorrect
- * or we are out of resources. Just send a response now.
- */
+ if (rc == BLE_HS_ENOTSUP) {
+ /* PSM not supported */
rsp->result = htole16(ble_l2cap_sig_ble_hs_err2coc_err(rc));
+ ble_hs_unlock();
goto failed;
- } else {
- /* We cannot create number of channels req by peer due to
limited resources. */
- rsp->result = htole16(BLE_L2CAP_COC_ERR_NO_RESOURCES);
- goto done;
}
+
+ /* We cannot process more due to limited resources
+ * If we limit further due to eg. authorization result will be
+ * overwritten later on
+ */
+ rsp->result = htole16(BLE_L2CAP_COC_ERR_NO_RESOURCES);
+ break;
}
/* Fill up remote configuration. Note MPS is the L2CAP MTU*/
@@ -1030,64 +1039,78 @@ ble_l2cap_sig_credit_base_con_req_rx(uint16_t
conn_handle,
chans[i]->coc_tx.mtu = le16toh(req->mtu);
ble_hs_conn_chan_insert(conn, chans[i]);
- /* Sending event to the app. Unlock hs */
- ble_hs_unlock();
- rc = ble_l2cap_event_coc_accept(chans[i], le16toh(req->mtu));
- if (rc == 0) {
- rsp->dcids[i] = htole16(chans[i]->scid);
- chan_created++;
- if (chan_created == 1) {
- /* We need to set it once as there are same initial parameters
- * for all the channels
- */
- rsp->credits = htole16(chans[i]->coc_rx.credits);
- rsp->mps = htole16(chans[i]->my_mtu);
- rsp->mtu = htole16(chans[i]->coc_rx.mtu);
+ /* We need to set it once as there are same initial parameters for all
+ * the channels, regardless if were accepted or not
+ */
+ if (rsp->mtu == 0) {
+ rsp->mtu = htole16(chans[i]->coc_rx.mtu);
+ rsp->mps = htole16(chans[i]->my_mtu);
+ rsp->credits = htole16(chans[i]->coc_rx.credits);
+ }
+ }
+
+ /* further process only channels we have resources for */
+ num_of_scids = i;
+
+ /* Sending events to the app. Unlock hs */
+ ble_hs_unlock();
+
+ for (i = 0; i < num_of_scids; i++) {
+ if (chans[i]) {
+ rc = ble_l2cap_event_coc_accept(chans[i], le16toh(req->mtu));
+ if (rc != 0) {
+ chans[i]->cb = NULL;
+ rsp->result = htole16(ble_l2cap_sig_ble_hs_err2coc_err(rc));
+ continue;
}
- } else {
- /* Make sure we do not send disconnect event when removing channel
*/
- chans[i]->cb = NULL;
- ble_hs_lock();
- conn = ble_hs_conn_find_assert(conn_handle);
+ rsp->dcids[i] = htole16(chans[i]->scid);
+ }
+ }
+
+ ble_hs_lock();
+ conn = ble_hs_conn_find_assert(conn_handle);
+
+ /* removed not accepted channels */
+ for (i = 0; i < num_of_scids; i++) {
+ if (chans[i] && chans[i]->cb == NULL) {
ble_hs_conn_delete_chan(conn, chans[i]);
chans[i] = NULL;
- rsp->result = htole16(ble_l2cap_sig_ble_hs_err2coc_err(rc));
- rc = 0;
- ble_hs_unlock();
}
-
- ble_hs_lock();
- conn = ble_hs_conn_find_assert(conn_handle);
}
-done:
- ble_hs_unlock();
- rc = ble_l2cap_sig_tx(conn_handle, txom);
+ /* send response */
+ rc = ble_l2cap_sig_tx_nolock(conn_handle, txom);
if (rc != 0) {
- ble_hs_lock();
- conn = ble_hs_conn_find_assert(conn_handle);
+ /* cleanup if we failed to send response
+ * TODO should we notify app on failure?
+ */
for (i = 0; i < num_of_scids; i++) {
if (chans[i]) {
+ chans[i]->cb = NULL;
ble_hs_conn_delete_chan(conn, chans[i]);
+ chans[i] = NULL;
}
}
- ble_hs_unlock();
- return 0;
}
+ ble_hs_unlock();
+
/* Notify user about connection status */
for (i = 0; i < num_of_scids; i++) {
if (chans[i]) {
- ble_l2cap_event_coc_connected(chans[i], rc);
+ ble_l2cap_event_coc_connected(chans[i], 0);
}
}
return 0;
failed:
- ble_hs_unlock();
+ /* dummy values in case of error, just to satisfy PTS */
+ rsp->credits = htole16(1);
+ rsp->mps = htole16(BLE_L2CAP_ECOC_MIN_MTU);
+ rsp->mtu = htole16(BLE_L2CAP_ECOC_MIN_MTU);
ble_l2cap_sig_tx(conn_handle, txom);
return 0;
}
@@ -1169,19 +1192,16 @@ ble_l2cap_sig_credit_base_con_rsp_rx(uint16_t
conn_handle,
ble_hs_conn_chan_insert(conn, chan);
}
- ble_hs_unlock();
-
-done:
- for (i = 0; i < 5; i++){
- if (duplicated_cids[i] != 0){
- ble_hs_lock();
- conn = ble_hs_conn_find(conn_handle);
+ for (i = 0; i < ARRAY_SIZE(duplicated_cids); i++) {
+ if (duplicated_cids[i] != 0) {
chan = ble_hs_conn_chan_find_by_dcid(conn, duplicated_cids[i]);
- ble_hs_unlock();
- rc = ble_l2cap_sig_disconnect(chan);
+ rc |= ble_l2cap_sig_disconnect_nolock(chan);
}
}
+ ble_hs_unlock();
+
+done:
ble_l2cap_sig_coc_connect_cb(proc, rc);
ble_l2cap_sig_proc_free(proc);
@@ -1355,9 +1375,9 @@ done:
}
int
-ble_l2cap_sig_coc_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu,
- struct os_mbuf *sdu_rx,
- ble_l2cap_event_fn *cb, void *cb_arg)
+ble_l2cap_sig_connect_nolock(uint16_t conn_handle, uint16_t psm, uint16_t mtu,
+ struct os_mbuf *sdu_rx, ble_l2cap_event_fn *cb,
+ void *cb_arg)
{
struct ble_hs_conn *conn;
struct ble_l2cap_sig_proc *proc;
@@ -1370,24 +1390,19 @@ ble_l2cap_sig_coc_connect(uint16_t conn_handle,
uint16_t psm, uint16_t mtu,
return BLE_HS_EINVAL;
}
- ble_hs_lock();
conn = ble_hs_conn_find(conn_handle);
-
if (!conn) {
- ble_hs_unlock();
return BLE_HS_ENOTCONN;
}
chan = ble_l2cap_coc_chan_alloc(conn, psm, mtu, sdu_rx, cb, cb_arg);
if (!chan) {
- ble_hs_unlock();
return BLE_HS_ENOMEM;
}
proc = ble_l2cap_sig_proc_alloc();
if (!proc) {
ble_l2cap_chan_free(conn, chan);
- ble_hs_unlock();
return BLE_HS_ENOMEM;
}
@@ -1401,10 +1416,8 @@ ble_l2cap_sig_coc_connect(uint16_t conn_handle, uint16_t
psm, uint16_t mtu,
sizeof(*req), &txom);
if (!req) {
ble_l2cap_chan_free(conn, chan);
- ble_hs_unlock();
- rc = BLE_HS_ENOMEM;
- /* Goto done to clear proc */
- goto done;
+ ble_l2cap_sig_proc_free(proc);
+ return BLE_HS_ENOMEM;
}
req->psm = htole16(psm);
@@ -1413,52 +1426,42 @@ ble_l2cap_sig_coc_connect(uint16_t conn_handle,
uint16_t psm, uint16_t mtu,
req->mps = htole16(chan->my_coc_mps);
req->credits = htole16(chan->coc_rx.credits);
- ble_hs_unlock();
-
- rc = ble_l2cap_sig_tx(proc->conn_handle, txom);
+ rc = ble_l2cap_sig_tx_nolock(proc->conn_handle, txom);
if (rc != 0) {
- ble_hs_lock();
- conn = ble_hs_conn_find_assert(conn_handle);
ble_l2cap_chan_free(conn, chan);
- ble_hs_unlock();
+ ble_l2cap_sig_proc_free(proc);
+ return rc;
}
-done:
- ble_l2cap_sig_process_status(proc, rc);
+ ble_l2cap_sig_proc_start(proc);
- return rc;
+ return 0;
}
#if MYNEWT_VAL(BLE_L2CAP_ENHANCED_COC)
int
-ble_l2cap_sig_ecoc_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu,
- uint8_t num, struct os_mbuf *sdu_rx[],
- ble_l2cap_event_fn *cb, void *cb_arg)
+ble_l2cap_sig_ecoc_connect_nolock(uint16_t conn_handle, uint16_t psm, uint16_t
mtu,
+ uint8_t num, struct os_mbuf *sdu_rx[],
+ ble_l2cap_event_fn *cb, void *cb_arg)
{
struct ble_hs_conn *conn;
struct ble_l2cap_sig_proc *proc;
- struct ble_l2cap_chan *chan = NULL;
struct os_mbuf *txom;
struct ble_l2cap_sig_credit_base_connect_req *req;
int rc;
int i;
- int j;
if (!sdu_rx || !cb) {
return BLE_HS_EINVAL;
}
- ble_hs_lock();
conn = ble_hs_conn_find(conn_handle);
-
if (!conn) {
- ble_hs_unlock();
return BLE_HS_ENOTCONN;
}
proc = ble_l2cap_sig_proc_alloc();
if (!proc) {
- ble_hs_unlock();
return BLE_HS_ENOMEM;
}
@@ -1469,52 +1472,56 @@ ble_l2cap_sig_ecoc_connect(uint16_t conn_handle,
uint16_t psm, uint16_t mtu,
req = ble_l2cap_sig_cmd_get(BLE_L2CAP_SIG_OP_CREDIT_CONNECT_REQ, proc->id,
sizeof(*req) + num * sizeof(uint16_t), &txom);
if (!req) {
- ble_hs_unlock();
- rc = BLE_HS_ENOMEM;
- /* Goto done to clear proc */
- goto done;
+ ble_l2cap_sig_proc_free(proc);
+ return BLE_HS_ENOMEM;
}
for (i = 0; i < num; i++) {
- chan = ble_l2cap_coc_chan_alloc(conn, psm, mtu, sdu_rx[i], cb, cb_arg);
- if (!chan) {
+ proc->connect.chan[i] =
+ ble_l2cap_coc_chan_alloc(conn, psm, mtu, sdu_rx[i], cb, cb_arg);
+ if (!proc->connect.chan[i]) {
/* Clear request buffer */
os_mbuf_free_chain(txom);
-
- for (j = 0; j < i; j++) {
- /* Clear callback to make sure "Disconnected event" to the
user */
- chan[j].cb = NULL;
- ble_l2cap_chan_free(conn, proc->connect.chan[j]);
- }
- ble_hs_unlock();
rc = BLE_HS_ENOMEM;
- goto done;
+ goto failed;
}
- proc->connect.chan[i] = chan;
}
proc->connect.chan_cnt = num;
+ /* all channels have same params */
req->psm = htole16(psm);
- req->mtu = htole16(chan->coc_rx.mtu);
- req->mps = htole16(chan->my_mtu);
- req->credits = htole16(chan->coc_rx.credits);
+ req->mtu = htole16(proc->connect.chan[0]->coc_rx.mtu);
+ req->mps = htole16(proc->connect.chan[0]->my_mtu);
+ req->credits = htole16(proc->connect.chan[0]->coc_rx.credits);
for (i = 0; i < num; i++) {
req->scids[i] = htole16(proc->connect.chan[i]->scid);
}
- ble_hs_unlock();
+ rc = ble_l2cap_sig_tx_nolock(proc->conn_handle, txom);
+ if (rc) {
+ rc = BLE_HS_ENOMEM;
+ goto failed;
+ }
- rc = ble_l2cap_sig_tx(proc->conn_handle, txom);
+ ble_l2cap_sig_proc_start(proc);
-done:
- ble_l2cap_sig_process_status(proc, rc);
+ return 0;
- return rc;
+failed:
+ /* clean up on failure, ble_l2cap_chan_free() handles NULL as well */
+ for (i = 0; i < num; i++) {
+ proc->connect.chan[i]->cb = NULL;
+ ble_l2cap_chan_free(conn, proc->connect.chan[i]);
+ }
+
+ ble_l2cap_sig_proc_free(proc);
+ return BLE_HS_ENOMEM;
}
int
-ble_l2cap_sig_coc_reconfig(uint16_t conn_handle, struct ble_l2cap_chan
*chans[],
- uint8_t num, uint16_t new_mtu)
+ble_l2cap_sig_coc_reconfig_nolock(uint16_t conn_handle,
+ struct ble_l2cap_chan *chans[], uint8_t num,
+ uint16_t new_mtu)
{
struct ble_hs_conn *conn;
struct ble_l2cap_sig_proc *proc;
@@ -1523,17 +1530,13 @@ ble_l2cap_sig_coc_reconfig(uint16_t conn_handle, struct
ble_l2cap_chan *chans[],
int rc;
int i;
- ble_hs_lock();
conn = ble_hs_conn_find(conn_handle);
-
if (!conn) {
- ble_hs_unlock();
return BLE_HS_ENOTCONN;
}
proc = ble_l2cap_sig_proc_alloc();
if (!proc) {
- ble_hs_unlock();
return BLE_HS_ENOMEM;
}
@@ -1541,9 +1544,8 @@ ble_l2cap_sig_coc_reconfig(uint16_t conn_handle, struct
ble_l2cap_chan *chans[],
if (ble_hs_conn_chan_exist(conn, chans[i])) {
proc->reconfig.cids[i] = chans[i]->scid;
} else {
- ble_hs_unlock();
- rc = BLE_HS_ENOMEM;
- goto done;
+ ble_l2cap_sig_proc_free(proc);
+ return BLE_HS_ENOMEM;
}
}
@@ -1557,9 +1559,8 @@ ble_l2cap_sig_coc_reconfig(uint16_t conn_handle, struct
ble_l2cap_chan *chans[],
req = ble_l2cap_sig_cmd_get(BLE_L2CAP_SIG_OP_CREDIT_RECONFIG_REQ, proc->id,
sizeof(*req) + num * sizeof(uint16_t), &txom);
if (!req) {
- ble_hs_unlock();
- rc = BLE_HS_ENOMEM;
- goto done;
+ ble_l2cap_sig_proc_free(proc);
+ return BLE_HS_ENOMEM;
}
/* For now we allow to change CoC MTU only.*/
@@ -1570,14 +1571,14 @@ ble_l2cap_sig_coc_reconfig(uint16_t conn_handle, struct
ble_l2cap_chan *chans[],
req->dcids[i] = htole16(proc->reconfig.cids[i]);
}
- ble_hs_unlock();
-
- rc = ble_l2cap_sig_tx(proc->conn_handle, txom);
-
-done:
- ble_l2cap_sig_process_status(proc, rc);
+ rc = ble_l2cap_sig_tx_nolock(proc->conn_handle, txom);
+ if (rc) {
+ ble_l2cap_sig_proc_free(proc);
+ return rc;
+ }
- return rc;
+ ble_l2cap_sig_proc_start(proc);
+ return 0;
}
#endif
@@ -1714,7 +1715,7 @@ ble_l2cap_sig_disc_rsp_rx(uint16_t conn_handle, struct
ble_l2cap_sig_hdr *hdr,
rsp = (struct ble_l2cap_sig_disc_rsp *)(*om)->om_data;
if (chan->dcid != le16toh(rsp->dcid) || chan->scid != le16toh(rsp->scid)) {
/* This response is incorrect, lets wait for timeout */
- ble_l2cap_sig_process_status(proc, 0);
+ ble_l2cap_sig_proc_start(proc);
return 0;
}
@@ -1726,7 +1727,7 @@ done:
}
int
-ble_l2cap_sig_disconnect(struct ble_l2cap_chan *chan)
+ble_l2cap_sig_disconnect_nolock(struct ble_l2cap_chan *chan)
{
struct os_mbuf *txom;
struct ble_l2cap_sig_disc_req *req;
@@ -1755,23 +1756,24 @@ ble_l2cap_sig_disconnect(struct ble_l2cap_chan *chan)
req = ble_l2cap_sig_cmd_get(BLE_L2CAP_SIG_OP_DISCONN_REQ, proc->id,
sizeof(*req), &txom);
if (!req) {
- rc = BLE_HS_ENOMEM;
- goto done;
+ ble_l2cap_sig_proc_free(proc);
+ return BLE_HS_ENOMEM;
}
req->dcid = htole16(chan->dcid);
req->scid = htole16(chan->scid);
- rc = ble_l2cap_sig_tx(proc->conn_handle, txom);
- /* Mark channel as disconnecting */
- if (rc == 0) {
- chan->flags |= BLE_L2CAP_CHAN_F_DISCONNECTING;
+ rc = ble_l2cap_sig_tx_nolock(proc->conn_handle, txom);
+ if (rc) {
+ ble_l2cap_sig_proc_free(proc);
+ return rc;
}
-done:
- ble_l2cap_sig_process_status(proc, rc);
+ /* Mark channel as disconnecting */
+ chan->flags |= BLE_L2CAP_CHAN_F_DISCONNECTING;
+ ble_l2cap_sig_proc_start(proc);
- return rc;
+ return 0;
}
static int
@@ -1800,7 +1802,7 @@ ble_l2cap_sig_le_credits_rx(uint16_t conn_handle, struct
ble_l2cap_sig_hdr *hdr,
}
int
-ble_l2cap_sig_le_credits(uint16_t conn_handle, uint16_t scid, uint16_t credits)
+ble_l2cap_sig_le_credits_nolock(uint16_t conn_handle, uint16_t scid, uint16_t
credits)
{
struct ble_l2cap_sig_le_credits *cmd;
struct os_mbuf *txom;
@@ -1815,7 +1817,19 @@ ble_l2cap_sig_le_credits(uint16_t conn_handle, uint16_t
scid, uint16_t credits)
cmd->scid = htole16(scid);
cmd->credits = htole16(credits);
- return ble_l2cap_sig_tx(conn_handle, txom);
+ return ble_l2cap_sig_tx_nolock(conn_handle, txom);
+}
+
+int
+ble_l2cap_sig_le_credits(uint16_t conn_handle, uint16_t scid, uint16_t credits)
+{
+ int rc;
+
+ ble_hs_lock();
+ rc = ble_l2cap_sig_le_credits_nolock(conn_handle, scid, credits);
+ ble_hs_unlock();
+
+ return rc;
}
#endif
diff --git a/nimble/host/src/ble_l2cap_sig_cmd.c
b/nimble/host/src/ble_l2cap_sig_cmd.c
index 48b35249e..381e3a996 100644
--- a/nimble/host/src/ble_l2cap_sig_cmd.c
+++ b/nimble/host/src/ble_l2cap_sig_cmd.c
@@ -23,13 +23,14 @@
#if NIMBLE_BLE_CONNECT
/* this function consumes tx os_mbuf */
int
-ble_l2cap_sig_tx(uint16_t conn_handle, struct os_mbuf *txom)
+ble_l2cap_sig_tx_nolock(uint16_t conn_handle, struct os_mbuf *txom)
{
struct ble_l2cap_chan *chan;
struct ble_hs_conn *conn;
int rc;
- ble_hs_lock();
+ BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
+
rc = ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SIG,
&conn, &chan);
if (rc == 0) {
@@ -37,6 +38,17 @@ ble_l2cap_sig_tx(uint16_t conn_handle, struct os_mbuf *txom)
} else {
os_mbuf_free_chain(txom);
}
+
+ return rc;
+}
+
+int
+ble_l2cap_sig_tx(uint16_t conn_handle, struct os_mbuf *txom)
+{
+ int rc;
+
+ ble_hs_lock();
+ rc = ble_l2cap_sig_tx_nolock(conn_handle, txom);
ble_hs_unlock();
return rc;
diff --git a/nimble/host/src/ble_l2cap_sig_priv.h
b/nimble/host/src/ble_l2cap_sig_priv.h
index a698cd0d8..c7e7b5b46 100644
--- a/nimble/host/src/ble_l2cap_sig_priv.h
+++ b/nimble/host/src/ble_l2cap_sig_priv.h
@@ -123,50 +123,54 @@ int ble_l2cap_sig_reject_tx(uint16_t conn_handle,
int ble_l2cap_sig_reject_invalid_cid_tx(uint16_t conn_handle, uint8_t id,
uint16_t src_cid, uint16_t dst_cid);
int ble_l2cap_sig_tx(uint16_t conn_handle, struct os_mbuf *txom);
+int ble_l2cap_sig_tx_nolock(uint16_t conn_handle, struct os_mbuf *txom);
void *ble_l2cap_sig_cmd_get(uint8_t opcode, uint8_t id, uint16_t len,
struct os_mbuf **txom);
#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) != 0
-int ble_l2cap_sig_coc_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu,
- struct os_mbuf *sdu_rx,
- ble_l2cap_event_fn *cb, void *cb_arg);
-int ble_l2cap_sig_disconnect(struct ble_l2cap_chan *chan);
+int ble_l2cap_sig_connect_nolock(uint16_t conn_handle, uint16_t psm,
+ uint16_t mtu, struct os_mbuf *sdu_rx,
+ ble_l2cap_event_fn *cb, void *cb_arg);
+int ble_l2cap_sig_disconnect_nolock(struct ble_l2cap_chan *chan);
+int ble_l2cap_sig_le_credits_nolock(uint16_t conn_handle, uint16_t scid,
+ uint16_t credits);
int ble_l2cap_sig_le_credits(uint16_t conn_handle, uint16_t scid,
uint16_t credits);
#else
static inline int
-ble_l2cap_sig_coc_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu,
- struct os_mbuf *sdu_rx,
- ble_l2cap_event_fn *cb, void *cb_arg)
+ble_l2cap_sig_connect_nolock(uint16_t conn_handle, uint16_t psm, uint16_t mtu,
+ struct os_mbuf *sdu_rx, ble_l2cap_event_fn *cb,
+ void *cb_arg)
{
return BLE_HS_ENOTSUP;
}
static inline int
-ble_l2cap_sig_disconnect(struct ble_l2cap_chan *chan)
+ble_l2cap_sig_disconnect_nolock(struct ble_l2cap_chan *chan)
{
return BLE_HS_ENOTSUP;
}
#endif
#if MYNEWT_VAL(BLE_L2CAP_ENHANCED_COC)
-int ble_l2cap_sig_ecoc_connect(uint16_t conn_handle,
- uint16_t psm, uint16_t mtu,
- uint8_t num, struct os_mbuf *sdu_rx[],
- ble_l2cap_event_fn *cb, void *cb_arg);
-int ble_l2cap_sig_coc_reconfig(uint16_t conn_handle, struct ble_l2cap_chan
*chans[],
- uint8_t num, uint16_t new_mtu);
+int ble_l2cap_sig_ecoc_connect_nolock(uint16_t conn_handle, uint16_t psm,
uint16_t mtu,
+ uint8_t num, struct os_mbuf *sdu_rx[],
+ ble_l2cap_event_fn *cb, void *cb_arg);
+int ble_l2cap_sig_coc_reconfig_nolock(uint16_t conn_handle,
+ struct ble_l2cap_chan *chans[],
+ uint8_t num, uint16_t new_mtu);
#else
static inline int
-ble_l2cap_sig_ecoc_connect(uint16_t conn_handle,
- uint16_t psm, uint16_t mtu,
- uint8_t num, struct os_mbuf *sdu_rx[],
- ble_l2cap_event_fn *cb, void *cb_arg)
+ble_l2cap_sig_ecoc_connect_nolock(uint16_t conn_handle, uint16_t psm, uint16_t
mtu,
+ uint8_t num, struct os_mbuf *sdu_rx[],
+ ble_l2cap_event_fn *cb, void *cb_arg)
{
return BLE_HS_ENOTSUP;
}
+
static inline int
-ble_l2cap_sig_coc_reconfig(uint16_t conn_handle, struct ble_l2cap_chan
*chans[],
- uint8_t num, uint16_t new_mtu)
+ble_l2cap_sig_coc_reconfig_nolock(uint16_t conn_handle,
+ struct ble_l2cap_chan *chans[], uint8_t num,
+ uint16_t new_mtu)
{
return BLE_HS_ENOTSUP;
}
diff --git a/nimble/host/test/src/ble_l2cap_test.c
b/nimble/host/test/src/ble_l2cap_test.c
index 9ea7f8533..5d7729a86 100644
--- a/nimble/host/test/src/ble_l2cap_test.c
+++ b/nimble/host/test/src/ble_l2cap_test.c
@@ -786,8 +786,8 @@ ble_l2cap_test_coc_connect_multi(struct test_data *t)
assert(sdu_rx[i] != NULL);
}
- rc = ble_l2cap_sig_ecoc_connect(2, t->psm, t->mtu, t->num, sdu_rx,
- ble_l2cap_test_event, t);
+ rc = ble_l2cap_enhanced_connect(2, t->psm, t->mtu, t->num, sdu_rx,
+ ble_l2cap_test_event, t);
TEST_ASSERT_FATAL(rc == ev->early_error);
if (rc != 0) {
@@ -851,8 +851,7 @@ ble_l2cap_test_coc_connect(struct test_data *t)
sdu_rx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0);
assert(sdu_rx != NULL);
- rc = ble_l2cap_sig_coc_connect(2, t->psm, t->mtu, sdu_rx,
- ble_l2cap_test_event, t);
+ rc = ble_l2cap_connect(2, t->psm, t->mtu, sdu_rx, ble_l2cap_test_event, t);
TEST_ASSERT_FATAL(rc == ev->early_error);
if (rc != 0) {
@@ -955,7 +954,7 @@ ble_l2cap_test_coc_disc(struct test_data *t)
uint8_t id;
int rc;
- rc = ble_l2cap_sig_disconnect(t->chan[0]);
+ rc = ble_l2cap_disconnect(t->chan[0]);
TEST_ASSERT_FATAL(rc == 0);
req.dcid = htole16(t->chan[0]->dcid);