summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <dirbaio@dirbaio.net>2022-05-12 03:42:56 +0200
committerGitHub <noreply@github.com>2022-05-12 03:42:56 +0200
commit08d6d12b4c4a561b900d6d1d98b95345d26558a7 (patch)
treee62dbf051dc74d62ba47885b24fa8c45188de94d
parente1271e1dc9e9ba865a6e5aed46379cd803154588 (diff)
parentd3a5e8bf29441a32aaa6537f6f84ff998c106a9e (diff)
downloadnrf-softdevice-08d6d12b4c4a561b900d6d1d98b95345d26558a7.zip
Merge pull request #89 from embassy-rs/l2cap-credit-bug-workaround
wip: Workaround l2cap credit flow control bug
-rw-r--r--nrf-softdevice/Cargo.toml5
-rw-r--r--nrf-softdevice/src/ble/l2cap.rs42
2 files changed, 47 insertions, 0 deletions
diff --git a/nrf-softdevice/Cargo.toml b/nrf-softdevice/Cargo.toml
index 99dde0b..33ee0f0 100644
--- a/nrf-softdevice/Cargo.toml
+++ b/nrf-softdevice/Cargo.toml
@@ -29,6 +29,11 @@ ble-gatt-client = ["ble-gatt"]
critical-section-impl = ["critical-section/custom-impl"]
+# Workaround l2cap credit bug. If set, infinite credits are issued
+# to the peer in batches. The `credits` config when establishing the channel is ignored.
+# https://devzone.nordicsemi.com/f/nordic-q-a/81894/s140-7-3-0-softdevice-assertion-failed-at-pc-0xa806-using-l2cap
+ble-l2cap-credit-wrokaround = []
+
[dependencies]
defmt = { version = "0.3", optional = true }
log = { version = "0.4.11", optional = true }
diff --git a/nrf-softdevice/src/ble/l2cap.rs b/nrf-softdevice/src/ble/l2cap.rs
index ab366e1..7154c1f 100644
--- a/nrf-softdevice/src/ble/l2cap.rs
+++ b/nrf-softdevice/src/ble/l2cap.rs
@@ -11,6 +11,41 @@ use crate::raw;
use crate::util::{get_union_field, Portal};
use crate::{RawError, Softdevice};
+#[cfg(feature = "ble-l2cap-credit-wrokaround")]
+fn credit_hack_refill(conn: u16, cid: u16) {
+ const CREDITS_MAX: u16 = 0xFFFF;
+ const CREDITS_MIN: u16 = 1024;
+
+ let mut credits = 0;
+ let ret = unsafe { raw::sd_ble_l2cap_ch_flow_control(conn, cid, 0, &mut credits) };
+ if let Err(err) = RawError::convert(ret) {
+ warn!("sd_ble_l2cap_ch_flow_control credits query err {:?}", err);
+ return;
+ }
+ info!("sd_ble_l2cap_ch_flow_control credits={=u16:x}", credits);
+
+ if credits > CREDITS_MIN {
+ // Still enough credits, no need to refill.
+ return;
+ }
+
+ info!("refilling credits");
+
+ let ret = unsafe { raw::sd_ble_l2cap_ch_flow_control(conn, cid, CREDITS_MAX, ptr::null_mut()) };
+ if let Err(err) = RawError::convert(ret) {
+ warn!(
+ "sd_ble_l2cap_ch_flow_control credits=CREDITS_MAX err {:?}",
+ err
+ );
+ return;
+ }
+
+ let ret = unsafe { raw::sd_ble_l2cap_ch_flow_control(conn, cid, 0, ptr::null_mut()) };
+ if let Err(err) = RawError::convert(ret) {
+ warn!("sd_ble_l2cap_ch_flow_control credits=0 err {:?}", err);
+ }
+}
+
pub(crate) unsafe fn on_evt(ble_evt: *const raw::ble_evt_t) {
let l2cap_evt = get_union_field(ble_evt, &(*ble_evt).evt.l2cap_evt);
match (*ble_evt).header.evt_id as u32 {
@@ -178,6 +213,8 @@ impl<P: Packet> L2cap<P> {
let _evt = &l2cap_evt.params.ch_setup;
// default is 1
+ let _ = config.credits;
+ #[cfg(not(feature = "ble-l2cap-credit-wrokaround"))]
if config.credits != 1 {
let ret = raw::sd_ble_l2cap_ch_flow_control(
conn_handle,
@@ -260,6 +297,8 @@ impl<P: Packet> L2cap<P> {
}
// default is 1
+ let _ = config.credits;
+ #[cfg(not(feature = "ble-l2cap-credit-wrokaround"))]
if config.credits != 1 {
let ret = raw::sd_ble_l2cap_ch_flow_control(
conn_handle,
@@ -400,6 +439,9 @@ impl<P: Packet> Channel<P> {
return Err(err.into());
}
+ #[cfg(feature = "ble-l2cap-credit-wrokaround")]
+ credit_hack_refill(conn_handle, self.cid);
+
portal(conn_handle)
.wait_many(|ble_evt| unsafe {
match (*ble_evt).header.evt_id as u32 {