In order to not waste bandwidth on Flow Control packets with credits:
1. Set Initial Credits in the connect request/response to the maximum value
2. Send credits only when the remote has less than 64 of them left,
increasing the value back to maximum.
Bug:
68359837
Test: observe data flow in btsnoop log
Change-Id: I34e1fecc55422b34df0b1e82bb2b402eb06620bd
/* Configure L2CAP COC, if transport is LE */
if (transport == BT_TRANSPORT_LE) {
- p_ccb->local_coc_cfg.credits = L2CAP_LE_DEFAULT_CREDIT;
+ p_ccb->local_coc_cfg.credits = L2CAP_LE_CREDIT_DEFAULT;
p_ccb->local_coc_cfg.mtu = p_cfg->mtu;
uint16_t max_mps = controller_get_interface()->get_acl_data_size_ble();
le_mps = max_mps;
}
p_ccb->local_coc_cfg.mps = le_mps;
+
+ VLOG(2) << __func__ << ": credits=" << p_ccb->local_coc_cfg.credits
+ << ", mps=" << p_ccb->local_coc_cfg.mps
+ << ", mtu=" << p_ccb->local_coc_cfg.mtu;
}
p_ccb->p_callback = p_cb;
p_ccb->p_rcb = p_rcb;
/* Save the configuration */
- if (p_cfg) memcpy(&p_ccb->local_conn_cfg, p_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+ if (p_cfg) {
+ memcpy(&p_ccb->local_conn_cfg, p_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+ p_ccb->remote_credit_count = p_cfg->credits;
+ }
/* If link is up, start the L2CAP connection */
if (p_lcb->link_state == LST_CONNECTED) {
return false;
}
- if (p_cfg) memcpy(&p_ccb->local_conn_cfg, p_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+ if (p_cfg) {
+ memcpy(&p_ccb->local_conn_cfg, p_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+ p_ccb->remote_credit_count = p_cfg->credits;
+ }
if (result == L2CAP_CONN_OK)
l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_RSP, NULL);
case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
credit = (uint16_t*)p_data;
L2CAP_TRACE_DEBUG("%s Credits received %d", __func__, *credit);
- if ((p_ccb->peer_conn_cfg.credits + *credit) > L2CAP_LE_MAX_CREDIT) {
+ if ((p_ccb->peer_conn_cfg.credits + *credit) > L2CAP_LE_CREDIT_MAX) {
/* we have received credits more than max coc credits,
* so disconnecting the Le Coc Channel
*/
#define L2CAP_MIN_MTU 48 /* Minimum acceptable MTU is 48 bytes */
/* LE credit based L2CAP connection parameters */
-#define L2CAP_LE_MIN_MTU 23
-#define L2CAP_LE_MIN_MPS 23
-#define L2CAP_LE_MAX_MPS 65533
-#define L2CAP_LE_MIN_CREDIT 0
-#define L2CAP_LE_MAX_CREDIT 65535
-#define L2CAP_LE_DEFAULT_CREDIT 1
+constexpr uint16_t L2CAP_LE_MIN_MTU = 23; // Minimum SDU size
+constexpr uint16_t L2CAP_LE_MIN_MPS = 23;
+constexpr uint16_t L2CAP_LE_MAX_MPS = 65533;
+constexpr uint16_t L2CAP_LE_CREDIT_MAX = 65535;
+
+// This is initial amout of credits we send, and amount to which we increase
+// credits once they fall below threshold
+constexpr uint16_t L2CAP_LE_CREDIT_DEFAULT = 0xffff;
+
+// If credit count on remote fall below this value, we send back credits to
+// reach default value.
+constexpr uint16_t L2CAP_LE_CREDIT_THRESHOLD = 0x0040;
+
+static_assert(L2CAP_LE_CREDIT_THRESHOLD < L2CAP_LE_CREDIT_DEFAULT,
+ "Threshold must be smaller then default credits");
/*
* Timeout values (in milliseconds).
uint16_t fixed_chnl_idle_tout; /* Idle timeout to use for the fixed channel */
#endif
uint16_t tx_data_len;
+
+ /* Number of LE frames that the remote can send to us (credit count in
+ * remote). Valid only for LE CoC */
+ uint16_t remote_credit_count;
} tL2C_CCB;
/***********************************************************************
if (p_lcb->transport == BT_TRANSPORT_LE) {
l2c_lcc_proc_pdu(p_ccb, p_msg);
- // Got a pkt, valid send out credits to the peer device
- uint16_t credit = L2CAP_LE_DEFAULT_CREDIT;
- l2c_csm_execute(p_ccb, L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT, &credit);
+
+ /* The remote device has one less credit left */
+ --p_ccb->remote_credit_count;
+
+ /* If the credits left on the remote device are getting low, send some */
+ if (p_ccb->remote_credit_count <= L2CAP_LE_CREDIT_THRESHOLD) {
+ uint16_t credits = L2CAP_LE_CREDIT_DEFAULT - p_ccb->remote_credit_count;
+ p_ccb->remote_credit_count = L2CAP_LE_CREDIT_DEFAULT;
+
+ /* Return back credits */
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT, &credits);
+ }
} else {
/* Basic mode packets go straight to the state machine */
if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)