OSDN Git Service

Minimize amount of Flow Control packets for L2CAP CoC
authorJakub Pawlowski <jpawlowski@google.com>
Thu, 4 Jan 2018 13:06:21 +0000 (05:06 -0800)
committerJakub Pawlowski <jpawlowski@google.com>
Wed, 31 Jan 2018 22:19:54 +0000 (14:19 -0800)
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

stack/gap/gap_conn.cc
stack/l2cap/l2c_api.cc
stack/l2cap/l2c_csm.cc
stack/l2cap/l2c_int.h
stack/l2cap/l2c_main.cc

index 663482f..72183bb 100644 (file)
@@ -210,7 +210,7 @@ uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id,
 
   /* 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();
@@ -219,6 +219,10 @@ uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id,
       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;
index 5ce141e..e280b67 100644 (file)
@@ -555,7 +555,10 @@ uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr,
   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) {
@@ -625,7 +628,10 @@ bool L2CA_ConnectLECocRsp(const RawAddress& p_bd_addr, uint8_t id,
     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);
index 2fe0d0b..97841f2 100644 (file)
@@ -1105,7 +1105,7 @@ static void l2c_csm_open(tL2C_CCB* p_ccb, uint16_t event, void* p_data) {
     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
          */
index 83c5833..421e34d 100644 (file)
 #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).
@@ -327,6 +336,10 @@ typedef struct t_l2c_ccb {
   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;
 
 /***********************************************************************
index 6114702..6861488 100644 (file)
@@ -215,9 +215,18 @@ void l2c_rcv_acl_data(BT_HDR* p_msg) {
 
   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)