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
commit 4d967a34b7367195cadc797eff14fc422854574e Author: Szymon Janc <[email protected]> AuthorDate: Wed Feb 26 11:53:30 2025 +0100 nimble/host: Allow L2CAP disconnect request only on COC channels Disconnecting fixed CID channel (like SMP, ATT or control) could lead to hard to debug issues. It is also invalid (at least for ATT CID behavior is clarified in spec) to use this to disconnect fixed channel. --- nimble/host/include/host/ble_l2cap.h | 2 +- nimble/host/src/ble_l2cap_sig.c | 33 ++++++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/nimble/host/include/host/ble_l2cap.h b/nimble/host/include/host/ble_l2cap.h index d6532cf3e..32bd41bc8 100644 --- a/nimble/host/include/host/ble_l2cap.h +++ b/nimble/host/include/host/ble_l2cap.h @@ -571,7 +571,7 @@ int ble_l2cap_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu, /** * @brief Disconnect an L2CAP channel. * - * This function disconnects the specified L2CAP channel by sending a disconnect signal. + * This function disconnects the specified L2CAP connection oriented channel by sending a disconnect signal. * * @param chan Pointer to the L2CAP channel structure representing the channel to disconnect. * diff --git a/nimble/host/src/ble_l2cap_sig.c b/nimble/host/src/ble_l2cap_sig.c index 029e85538..8cb5e0782 100644 --- a/nimble/host/src/ble_l2cap_sig.c +++ b/nimble/host/src/ble_l2cap_sig.c @@ -1574,6 +1574,8 @@ ble_l2cap_sig_disc_req_rx(uint16_t conn_handle, struct ble_l2cap_sig_hdr *hdr, struct ble_l2cap_chan *chan; struct ble_hs_conn *conn; int rc; + uint16_t scid; + uint16_t dcid; rc = ble_hs_mbuf_pullup_base(om, sizeof(*req)); if (rc != 0) { @@ -1593,18 +1595,34 @@ ble_l2cap_sig_disc_req_rx(uint16_t conn_handle, struct ble_l2cap_sig_hdr *hdr, conn = ble_hs_conn_find_assert(conn_handle); req = (struct ble_l2cap_sig_disc_req *) (*om)->om_data; + scid = le16toh(req->scid); + dcid = le16toh(req->dcid); + + if (scid < BLE_L2CAP_COC_CID_START || scid > BLE_L2CAP_COC_CID_END || + dcid < BLE_L2CAP_COC_CID_START || dcid > BLE_L2CAP_COC_CID_END) { + /* Don't bother with look-up if it is not for connection oriented + * channel + */ + chan = NULL; + } else { + /* Let's find matching channel. Note that destination CID in the request + * is from peer perspective. It is source CID from nimble perspective + */ + chan = ble_hs_conn_chan_find_by_scid(conn, dcid); + } - /* Let's find matching channel. Note that destination CID in the request - * is from peer perspective. It is source CID from nimble perspective - */ - chan = ble_hs_conn_chan_find_by_scid(conn, le16toh(req->dcid)); if (!chan) { os_mbuf_free_chain(txom); ble_hs_unlock(); ble_l2cap_sig_reject_invalid_cid_tx(conn_handle, hdr->identifier, req->dcid, req->scid); return 0; } - if (le16toh(req->scid) != chan->dcid) { + + /* Core Spec 6.0 Vol3 PartA 4.6 + * If the receiver finds a DCID match but the SCID fails to find the same + * match, the request should be silently discarded. + */ + if (scid != chan->dcid) { os_mbuf_free_chain(txom); ble_hs_unlock(); return 0; @@ -1704,6 +1722,11 @@ ble_l2cap_sig_disconnect(struct ble_l2cap_chan *chan) struct ble_l2cap_sig_proc *proc; int rc; + /* this is allowed only for connection oriented channels */ + if (chan->scid < BLE_L2CAP_COC_CID_START || chan->scid > BLE_L2CAP_COC_CID_END) { + return BLE_HS_EREJECT; + } + if (chan->flags & BLE_L2CAP_CHAN_F_DISCONNECTING) { return 0; }
