From 38083ef0e94767e9c4997958d122487a48c359cc Mon Sep 17 00:00:00 2001 From: Sumeet Singh Date: Mon, 26 Aug 2024 15:47:07 +0800 Subject: [PATCH] Fixed incorrect condition when comparing l2cap header length and mps/mtu --- nimble/host/src/ble_l2cap.c | 41 ++++++++++++++++++++++++++-- nimble/host/src/ble_l2cap_priv.h | 2 ++ nimble/host/src/ble_l2cap_sig.c | 4 +-- nimble/host/src/ble_l2cap_sig_priv.h | 4 +-- 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/nimble/host/src/ble_l2cap.c b/nimble/host/src/ble_l2cap.c index 2bc50e0e9..2062007b1 100644 --- a/nimble/host/src/ble_l2cap.c +++ b/nimble/host/src/ble_l2cap.c @@ -207,7 +207,29 @@ 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); + return ble_l2cap_sig_coc_reconfig(conn_handle, chans, num, new_mtu, MYNEWT_VAL(BLE_L2CAP_COC_MPS)); +} + +int +ble_l2cap_reconfig_mtu_mps(struct ble_l2cap_chan *chans[], uint8_t num, uint16_t new_mtu, uint16_t new_mps) +{ + int i; + uint16_t conn_handle; + + if (num == 0 || !chans) { + return BLE_HS_EINVAL; + } + + conn_handle = chans[0]->conn_handle; + + for (i = 1; i < num; i++) { + if (conn_handle != chans[i]->conn_handle) { + BLE_HS_LOG(ERROR, "All channels should have same conn handle\n"); + return BLE_HS_EINVAL; + } + } + + return ble_l2cap_sig_coc_reconfig(conn_handle, chans, num, new_mtu, new_mps); } int @@ -387,14 +409,27 @@ ble_l2cap_rx(struct ble_hs_conn *conn, goto err; } + /* For CIDs from dynamic range we check if SDU size isn't larger than MPS */ + if (chan->dcid >= 0x0040 && chan->dcid <= 0x007F && l2cap_hdr.len > (chan->my_coc_mps + BLE_L2CAP_SDU_SZ)) { + /* Data exceeds MPS */ + BLE_HS_LOG(ERROR, "error: sdu_len > chan->my_coc_mps (%d>%d)\n", + l2cap_hdr.len, chan->my_coc_mps); + ble_l2cap_disconnect(chan); + rc = BLE_HS_EBADDATA; + goto err; + } + if (chan->rx_buf != NULL) { /* Previous data packet never completed. Discard old packet. */ ble_l2cap_remove_rx(conn, chan); } - if (l2cap_hdr.len > ble_l2cap_get_mtu(chan)) { - /* More data then we expected on the channel */ + if (l2cap_hdr.len - BLE_L2CAP_SDU_SZ > ble_l2cap_get_mtu(chan)) { + /* More data than we expected on the channel. + * Disconnect peer with invalid behaviour + */ rc = BLE_HS_EBADDATA; + ble_l2cap_disconnect(chan); goto err; } diff --git a/nimble/host/src/ble_l2cap_priv.h b/nimble/host/src/ble_l2cap_priv.h index 21e6a8bf6..128afeed1 100644 --- a/nimble/host/src/ble_l2cap_priv.h +++ b/nimble/host/src/ble_l2cap_priv.h @@ -55,6 +55,7 @@ extern struct os_mempool ble_l2cap_chan_pool; #define BLE_L2CAP_CID_BLACK_HOLE 0xffff #define BLE_L2CAP_HDR_SZ 4 +#define BLE_L2CAP_SDU_SZ 2 typedef uint8_t ble_l2cap_chan_flags; @@ -137,6 +138,7 @@ int ble_l2cap_enhanced_connect(uint16_t conn_handle, uint8_t num, struct os_mbuf *sdu_rx[], ble_l2cap_event_fn *cb, void *cb_arg); int ble_l2cap_reconfig(struct ble_l2cap_chan *chans[], uint8_t num, uint16_t new_mtu); +int ble_l2cap_reconfig_mtu_mps(struct ble_l2cap_chan *chans[], uint8_t num, uint16_t new_mtu, uint16_t new_mps); #ifdef __cplusplus } diff --git a/nimble/host/src/ble_l2cap_sig.c b/nimble/host/src/ble_l2cap_sig.c index aaf9c642a..9bc90f72c 100644 --- a/nimble/host/src/ble_l2cap_sig.c +++ b/nimble/host/src/ble_l2cap_sig.c @@ -1435,7 +1435,7 @@ done: int ble_l2cap_sig_coc_reconfig(uint16_t conn_handle, struct ble_l2cap_chan *chans[], - uint8_t num, uint16_t new_mtu) + uint8_t num, uint16_t new_mtu, uint16_t new_mps) { struct ble_hs_conn *conn; struct ble_l2cap_sig_proc *proc; @@ -1471,7 +1471,7 @@ ble_l2cap_sig_coc_reconfig(uint16_t conn_handle, struct ble_l2cap_chan *chans[], proc->op = BLE_L2CAP_SIG_PROC_OP_RECONFIG; proc->reconfig.cid_cnt = num; proc->reconfig.new_mtu = new_mtu; - proc->reconfig.new_mps = MYNEWT_VAL(BLE_L2CAP_COC_MPS); + proc->reconfig.new_mps = new_mps; proc->id = ble_l2cap_sig_next_id(); proc->conn_handle = conn_handle; diff --git a/nimble/host/src/ble_l2cap_sig_priv.h b/nimble/host/src/ble_l2cap_sig_priv.h index a698cd0d8..b997ce35e 100644 --- a/nimble/host/src/ble_l2cap_sig_priv.h +++ b/nimble/host/src/ble_l2cap_sig_priv.h @@ -154,7 +154,7 @@ int ble_l2cap_sig_ecoc_connect(uint16_t conn_handle, 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); + uint8_t num, uint16_t new_mtu, uint16_t new_mps); #else static inline int ble_l2cap_sig_ecoc_connect(uint16_t conn_handle, @@ -166,7 +166,7 @@ ble_l2cap_sig_ecoc_connect(uint16_t conn_handle, } static inline int ble_l2cap_sig_coc_reconfig(uint16_t conn_handle, struct ble_l2cap_chan *chans[], - uint8_t num, uint16_t new_mtu) + uint8_t num, uint16_t new_mtu, uint16_t new_mps) { return BLE_HS_ENOTSUP; }