OSDN Git Service

Added support for new Android API for LE CoC
authorStanley Tng <stng@google.com>
Wed, 20 Dec 2017 17:38:30 +0000 (09:38 -0800)
committerStanley Tng <stng@google.com>
Thu, 18 Jan 2018 16:40:43 +0000 (16:40 +0000)
Added support for the new Android API including the management of the
LE_PSM values.
Also fixed a bug when de-registering the L2CAP CoC, the RCB is not
freed correctly.

Test: Ran the new ACTS Tests for LE CoC and existing ACTS for RfComm
Bug: 70683224
Change-Id: I5a545656bece667e7ba942d7b2334e3f5b49b283

bta/jv/bta_jv_act.cc
bta/jv/bta_jv_api.cc
btif/src/btif_sock.cc
btif/src/btif_sock_l2cap.cc
include/hardware/bt_sock.h
stack/include/l2c_api.h
stack/l2cap/l2c_api.cc
stack/l2cap/l2c_int.h
stack/l2cap/l2c_main.cc
stack/l2cap/l2c_utils.cc

index 502ff4e..51e9f41 100644 (file)
@@ -46,6 +46,7 @@
 #include "port_api.h"
 #include "rfcdefs.h"
 #include "sdp_api.h"
+#include "stack/l2cap/l2c_int.h"
 #include "utl.h"
 
 #include "osi/include/osi.h"
@@ -687,6 +688,10 @@ void bta_jv_get_channel_id(
       }
       break;
     case BTA_JV_CONN_TYPE_L2CAP_LE:
+      psm = L2CA_AllocateLePSM();
+      if (psm == 0) {
+        LOG(ERROR) << __func__ << ": Error: No free LE PSM available";
+      }
       break;
     default:
       break;
@@ -715,7 +720,8 @@ void bta_jv_free_scn(int32_t type /* One of BTA_JV_CONN_TYPE_ */,
       bta_jv_set_free_psm(scn);
       break;
     case BTA_JV_CONN_TYPE_L2CAP_LE:
-      // TODO: Not yet implemented...
+      VLOG(2) << __func__ << ": type=BTA_JV_CONN_TYPE_L2CAP_LE. psm=" << scn;
+      L2CA_FreeLePSM(scn);
       break;
     default:
       break;
index 4f9c4d6..893a82e 100644 (file)
@@ -133,7 +133,7 @@ bool BTA_JvIsEncrypted(const RawAddress& bd_addr) {
  *
  ******************************************************************************/
 tBTA_JV_STATUS BTA_JvGetChannelId(int conn_type, uint32_t id, int32_t channel) {
-  VLOG(2) << __func__;
+  VLOG(2) << __func__ << ": conn_type=" << conn_type;
 
   if (conn_type != BTA_JV_CONN_TYPE_RFCOMM &&
       conn_type != BTA_JV_CONN_TYPE_L2CAP &&
index 46bf7ec..c5ba4a6 100644 (file)
@@ -130,6 +130,7 @@ static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
 
   *sock_fd = INVALID_FD;
   bt_status_t status = BT_STATUS_FAIL;
+  int original_channel = channel;
 
   switch (type) {
     case BTSOCK_RFCOMM:
@@ -140,7 +141,22 @@ static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
       status =
           btsock_l2cap_listen(service_name, channel, sock_fd, flags, app_uid);
       break;
-
+    case BTSOCK_L2CAP_LE:
+      if (flags & BTSOCK_FLAG_NO_SDP) {
+        channel = L2CAP_MASK_LE_COC_CHANNEL;
+      } else if (channel > 0) {
+        channel |= L2CAP_MASK_LE_COC_CHANNEL;
+      } else {
+        LOG_ERROR(LOG_TAG, "%s: type BTSOCK_L2CAP_LE: invalid channel=%d",
+                  __func__, channel);
+        break;
+      }
+      LOG_DEBUG(LOG_TAG,
+                "%s: type=BTSOCK_L2CAP_LE, channel=0x%x, original=0x%x",
+                __func__, channel, original_channel);
+      status =
+          btsock_l2cap_listen(service_name, channel, sock_fd, flags, app_uid);
+      break;
     case BTSOCK_SCO:
       status = btsock_sco_listen(sock_fd, flags);
       break;
@@ -173,6 +189,13 @@ static bt_status_t btsock_connect(const RawAddress* bd_addr, btsock_type_t type,
       status = btsock_l2cap_connect(bd_addr, channel, sock_fd, flags, app_uid);
       break;
 
+    case BTSOCK_L2CAP_LE:
+      channel |= L2CAP_MASK_LE_COC_CHANNEL;
+      LOG_DEBUG(LOG_TAG, "%s: type=BTSOCK_L2CAP_LE, channel=0x%x", __func__,
+                channel);
+      status = btsock_l2cap_connect(bd_addr, channel, sock_fd, flags, app_uid);
+      break;
+
     case BTSOCK_SCO:
       status = btsock_sco_connect(bd_addr, sock_fd, flags);
       break;
@@ -192,6 +215,9 @@ static void btsock_signaled(int fd, int type, int flags, uint32_t user_id) {
       btsock_rfc_signaled(fd, flags, user_id);
       break;
     case BTSOCK_L2CAP:
+    case BTSOCK_L2CAP_LE:
+      /* Note: The caller may not distinguish between BTSOCK_L2CAP and
+       * BTSOCK_L2CAP_LE correctly */
       btsock_l2cap_signaled(fd, flags, user_id);
       break;
     default:
index 9e35db4..6ec6a33 100644 (file)
@@ -245,7 +245,7 @@ static void btsock_l2cap_free_l(l2cap_socket* sock) {
       BTA_JvL2capClose(sock->handle);
     }
     if ((sock->channel >= 0) && (sock->server)) {
-      BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP);
+      BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP_LE);
     }
   } else {
     // Only call if we are non server connections
@@ -339,7 +339,7 @@ fail_sockpair:
 }
 
 bt_status_t btsock_l2cap_init(int handle, uid_set_t* set) {
-  APPL_TRACE_DEBUG("%s handle = %d", __func__);
+  APPL_TRACE_DEBUG("%s: handle = %d", __func__, handle);
   std::unique_lock<std::mutex> lock(state_lock);
   pth = handle;
   socks = NULL;
@@ -355,6 +355,7 @@ bt_status_t btsock_l2cap_cleanup() {
 }
 
 static inline bool send_app_psm_or_chan_l(l2cap_socket* sock) {
+  APPL_TRACE_DEBUG("%s: channel=%d", __func__, sock->channel);
   return sock_send_all(sock->our_fd, (const uint8_t*)&sock->channel,
                        sizeof(sock->channel)) == sizeof(sock->channel);
 }
@@ -799,6 +800,9 @@ static bt_status_t btSock_start_l2cap_server_l(l2cap_socket* sock) {
   cfg.fcr_present = true;
   cfg.fcr = obex_l2c_fcr_opts_def;
 
+  APPL_TRACE_DEBUG("%s: fixed_chan=%d, channel=%d, is_le_coc=%d", __func__,
+                   sock->fixed_chan, sock->channel, sock->is_le_coc);
+
   if (sock->fixed_chan) {
     if (BTA_JvL2capStartServerLE(sock->security, 0, NULL, sock->channel,
                                  L2CAP_DEFAULT_MTU, NULL, btsock_l2cap_cbk,
@@ -808,7 +812,7 @@ static bt_status_t btSock_start_l2cap_server_l(l2cap_socket* sock) {
   } else {
     /* If we have a channel specified in the request, just start the server,
      * else we request a PSM and start the server after we receive a PSM. */
-    if (sock->channel < 0) {
+    if (sock->channel <= 0) {
       if (sock->is_le_coc) {
         if (BTA_JvGetChannelId(BTA_JV_CONN_TYPE_L2CAP_LE, sock->id, 0) !=
             BTA_JV_SUCCESS)
index db234eb..f051147 100644 (file)
@@ -27,7 +27,8 @@ __BEGIN_DECLS
 typedef enum {
   BTSOCK_RFCOMM = 1,
   BTSOCK_SCO = 2,
-  BTSOCK_L2CAP = 3
+  BTSOCK_L2CAP = 3,
+  BTSOCK_L2CAP_LE = 4
 } btsock_type_t;
 
 /** Represents the standard BT SOCKET interface. */
index 530e101..a21c4e8 100644 (file)
@@ -379,6 +379,29 @@ extern uint16_t L2CA_AllocatePSM(void);
 
 /*******************************************************************************
  *
+ * Function         L2CA_AllocateLePSM
+ *
+ * Description      Other layers call this function to find an unused LE PSM for
+ *                  L2CAP services.
+ *
+ * Returns          LE_PSM to use if success. Otherwise returns 0.
+ *
+ ******************************************************************************/
+extern uint16_t L2CA_AllocateLePSM(void);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_FreeLePSM
+ *
+ * Description      Free an assigned LE PSM.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void L2CA_FreeLePSM(uint16_t psm);
+
+/*******************************************************************************
+ *
  * Function         L2CA_ConnectReq
  *
  * Description      Higher layers call this function to create an L2CAP
index 6269af3..5ce141e 100644 (file)
@@ -194,6 +194,75 @@ uint16_t L2CA_AllocatePSM(void) {
 
 /*******************************************************************************
  *
+ * Function         L2CA_AllocateLePSM
+ *
+ * Description      To find an unused LE PSM for L2CAP services.
+ *
+ * Returns          LE_PSM to use if success. Otherwise returns 0.
+ *
+ ******************************************************************************/
+uint16_t L2CA_AllocateLePSM(void) {
+  bool done = false;
+  uint16_t psm = l2cb.le_dyn_psm;
+  uint16_t count = 0;
+
+  L2CAP_TRACE_API("%s: last psm=%d", __func__, psm);
+  while (!done) {
+    count++;
+    if (count > LE_DYNAMIC_PSM_RANGE) {
+      L2CAP_TRACE_ERROR("%s: Out of free BLE PSM", __func__);
+      return 0;
+    }
+
+    psm++;
+    if (psm > LE_DYNAMIC_PSM_END) {
+      psm = LE_DYNAMIC_PSM_START;
+    }
+
+    if (!l2cb.le_dyn_psm_assigned[psm - LE_DYNAMIC_PSM_START]) {
+      /* make sure the newly allocated psm is not used right now */
+      if (l2cu_find_ble_rcb_by_psm(psm)) {
+        L2CAP_TRACE_WARNING("%s: supposedly-free PSM=%d have allocated rcb!",
+                            __func__, psm);
+        continue;
+      }
+
+      l2cb.le_dyn_psm_assigned[psm - LE_DYNAMIC_PSM_START] = true;
+      L2CAP_TRACE_DEBUG("%s: assigned PSM=%d", __func__, psm);
+      done = true;
+      break;
+    }
+  }
+  l2cb.le_dyn_psm = psm;
+
+  return (psm);
+}
+
+/*******************************************************************************
+ *
+ * Function         L2CA_FreeLePSM
+ *
+ * Description      Free an assigned LE PSM.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void L2CA_FreeLePSM(uint16_t psm) {
+  L2CAP_TRACE_API("%s: to free psm=%d", __func__, psm);
+
+  if ((psm < LE_DYNAMIC_PSM_START) || (psm > LE_DYNAMIC_PSM_END)) {
+    L2CAP_TRACE_ERROR("%s: Invalid PSM=%d value!", __func__, psm);
+    return;
+  }
+
+  if (!l2cb.le_dyn_psm_assigned[psm - LE_DYNAMIC_PSM_START]) {
+    L2CAP_TRACE_WARNING("%s: PSM=%d was not allocated!", __func__, psm);
+  }
+  l2cb.le_dyn_psm_assigned[psm - LE_DYNAMIC_PSM_START] = false;
+}
+
+/*******************************************************************************
+ *
  * Function         L2CA_ConnectReq
  *
  * Description      Higher layers call this function to create an L2CAP
@@ -358,10 +427,12 @@ uint16_t L2CA_RegisterLECoc(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info) {
 
   /* Check if this is a registration for an outgoing-only connection to */
   /* a dynamic PSM. If so, allocate a "virtual" PSM for the app to use. */
-  if ((psm >= 0x0080) && (p_cb_info->pL2CA_ConnectInd_Cb == NULL)) {
-    for (vpsm = 0x0080; vpsm < 0x0100; vpsm++) {
-      p_rcb = l2cu_find_ble_rcb_by_psm(vpsm);
-      if (p_rcb == NULL) break;
+  if ((psm >= LE_DYNAMIC_PSM_START) &&
+      (p_cb_info->pL2CA_ConnectInd_Cb == NULL)) {
+    vpsm = L2CA_AllocateLePSM();
+    if (vpsm == 0) {
+      L2CAP_TRACE_ERROR("%s: Out of free BLE PSM", __func__);
+      return 0;
     }
 
     L2CAP_TRACE_API("%s Real PSM: 0x%04x  Virtual PSM: 0x%04x", __func__, psm,
@@ -371,6 +442,7 @@ uint16_t L2CA_RegisterLECoc(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info) {
   /* If registration block already there, just overwrite it */
   p_rcb = l2cu_find_ble_rcb_by_psm(vpsm);
   if (p_rcb == NULL) {
+    L2CAP_TRACE_API("%s Allocate rcp for Virtual PSM: 0x%04x", __func__, vpsm);
     p_rcb = l2cu_allocate_ble_rcb(vpsm);
     if (p_rcb == NULL) {
       L2CAP_TRACE_WARNING("%s No BLE RCB available, PSM: 0x%04x  vPSM: 0x%04x",
@@ -400,7 +472,8 @@ void L2CA_DeregisterLECoc(uint16_t psm) {
 
   tL2C_RCB* p_rcb = l2cu_find_ble_rcb_by_psm(psm);
   if (p_rcb == NULL) {
-    L2CAP_TRACE_WARNING("%s PSM: 0x%04x not found for deregistration", psm);
+    L2CAP_TRACE_WARNING("%s PSM: 0x%04x not found for deregistration", __func__,
+                        psm);
     return;
   }
 
@@ -419,7 +492,7 @@ void L2CA_DeregisterLECoc(uint16_t psm) {
       l2c_csm_execute(p_ccb, L2CEVT_L2CA_DISCONNECT_REQ, NULL);
   }
 
-  l2cu_release_rcb(p_rcb);
+  l2cu_release_ble_rcb(p_rcb);
 }
 
 /*******************************************************************************
index a6e111e..83af84f 100644 (file)
@@ -145,6 +145,11 @@ typedef enum {
                                                     */
 #define L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT 36 /* Peer credit packet */
 
+/* Constants for LE Dynamic PSM values */
+#define LE_DYNAMIC_PSM_START 0x0080
+#define LE_DYNAMIC_PSM_END 0x00FF
+#define LE_DYNAMIC_PSM_RANGE (LE_DYNAMIC_PSM_END - LE_DYNAMIC_PSM_START + 1)
+
 /* Bitmask to skip over Broadcom feature reserved (ID) to avoid sending two
    successive ID values, '0' id only or both */
 #define L2CAP_ADJ_BRCM_ID 0x1
@@ -501,6 +506,10 @@ typedef struct {
 #endif /* (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == TRUE) */
 
   uint16_t dyn_psm;
+
+  uint16_t le_dyn_psm; /* Next LE dynamic PSM value to try to assign */
+  bool le_dyn_psm_assigned[LE_DYNAMIC_PSM_RANGE]; /* Table of assigned LE PSM */
+
 } tL2C_CB;
 
 /* Define a structure that contains the information about a connection.
@@ -650,6 +659,7 @@ extern void l2cu_send_feature_req(tL2C_CCB* p_ccb);
 extern tL2C_RCB* l2cu_allocate_rcb(uint16_t psm);
 extern tL2C_RCB* l2cu_find_rcb_by_psm(uint16_t psm);
 extern void l2cu_release_rcb(tL2C_RCB* p_rcb);
+extern void l2cu_release_ble_rcb(tL2C_RCB* p_rcb);
 extern tL2C_RCB* l2cu_allocate_ble_rcb(uint16_t psm);
 extern tL2C_RCB* l2cu_find_ble_rcb_by_psm(uint16_t psm);
 
index 6275965..6114702 100644 (file)
@@ -763,6 +763,9 @@ void l2c_init(void) {
   /* the psm is increased by 2 before being used */
   l2cb.dyn_psm = 0xFFF;
 
+  /* the LE PSM is increased by 1 before being used */
+  l2cb.le_dyn_psm = LE_DYNAMIC_PSM_START - 1;
+
   /* Put all the channel control blocks on the free queue */
   for (xx = 0; xx < MAX_L2CAP_CHANNELS - 1; xx++) {
     l2cb.ccb_pool[xx].p_next_ccb = &l2cb.ccb_pool[xx + 1];
index efe2188..4b17f14 100644 (file)
@@ -1729,6 +1729,21 @@ void l2cu_release_rcb(tL2C_RCB* p_rcb) {
 
 /*******************************************************************************
  *
+ * Function         l2cu_release_ble_rcb
+ *
+ * Description      Mark an LE RCB as no longer in use
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void l2cu_release_ble_rcb(tL2C_RCB* p_rcb) {
+  L2CA_FreeLePSM(p_rcb->psm);
+  p_rcb->in_use = false;
+  p_rcb->psm = 0;
+}
+
+/*******************************************************************************
+ *
  * Function         l2cu_disconnect_chnl
  *
  * Description      Disconnect a channel. Typically, this is due to either