Merge changes from topics "bt-hfp-fix-connection-collision-handling", "bt-rfcomm-improve-logging-and-readability", "bt-rfcomm-add-end-to-end-unit-tests"

* changes:
  HFP: Fix connection colision handling
  RFCOMM: Improve logging and readability
  RFCOMM: Add unit tests for connection scenarios
diff --git a/bta/ag/bta_ag_act.cc b/bta/ag/bta_ag_act.cc
index 75063ac..f0ccef2 100644
--- a/bta/ag/bta_ag_act.cc
+++ b/bta/ag/bta_ag_act.cc
@@ -174,17 +174,13 @@
  *
  ******************************************************************************/
 void bta_ag_start_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
-  RawAddress pending_bd_addr = {};
-
-  /* store parameters */
-  if (!data.IsEmpty()) {
-    p_scb->peer_addr = data.api_open.bd_addr;
-    p_scb->open_services = data.api_open.services;
-    p_scb->cli_sec_mask = data.api_open.sec_mask;
-  }
+  p_scb->peer_addr = data.api_open.bd_addr;
+  p_scb->open_services = data.api_open.services;
+  p_scb->cli_sec_mask = data.api_open.sec_mask;
 
   /* Check if RFCOMM has any incoming connection to avoid collision. */
-  if (PORT_IsOpening(pending_bd_addr)) {
+  RawAddress pending_bd_addr = RawAddress::kEmpty;
+  if (PORT_IsOpening(&pending_bd_addr)) {
     /* Let the incoming connection goes through.                        */
     /* Issue collision for this scb for now.                            */
     /* We will decide what to do when we find incoming connetion later. */
@@ -330,6 +326,7 @@
  *
  ******************************************************************************/
 void bta_ag_rfc_fail(tBTA_AG_SCB* p_scb, UNUSED_ATTR const tBTA_AG_DATA& data) {
+  RawAddress peer_addr = p_scb->peer_addr;
   /* reinitialize stuff */
   p_scb->conn_handle = 0;
   p_scb->conn_service = 0;
@@ -346,7 +343,7 @@
   bta_ag_start_servers(p_scb, p_scb->reg_services);
 
   /* call open cback w. failure */
-  bta_ag_cback_open(p_scb, RawAddress::kEmpty, BTA_AG_FAIL_RFCOMM);
+  bta_ag_cback_open(p_scb, peer_addr, BTA_AG_FAIL_RFCOMM);
 }
 
 /*******************************************************************************
@@ -502,56 +499,51 @@
  *
  ******************************************************************************/
 void bta_ag_rfc_acp_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
-  uint16_t lcid;
-  int i;
-  tBTA_AG_SCB *ag_scb, *other_scb;
-  RawAddress dev_addr = {};
-  int status;
-
+  APPL_TRACE_DEBUG("%s: serv_handle0 = %d serv_handle1 = %d", __func__,
+                   p_scb->serv_handle[0], p_scb->serv_handle[1]);
   /* set role */
   p_scb->role = BTA_AG_ACP;
 
-  APPL_TRACE_DEBUG("bta_ag_rfc_acp_open: serv_handle0 = %d serv_handle1 = %d",
-                   p_scb->serv_handle[0], p_scb->serv_handle[1]);
-
   /* get bd addr of peer */
-  if (PORT_SUCCESS !=
-      (status = PORT_CheckConnection(data.rfc.port_handle, dev_addr, &lcid))) {
-    APPL_TRACE_DEBUG(
-        "bta_ag_rfc_acp_open error PORT_CheckConnection returned status %d",
-        status);
+  uint16_t lcid = 0;
+  RawAddress dev_addr = RawAddress::kEmpty;
+  int status = PORT_CheckConnection(data.rfc.port_handle, &dev_addr, &lcid);
+  if (status != PORT_SUCCESS) {
+    LOG(ERROR) << __func__ << ", PORT_CheckConnection returned " << status;
+    return;
   }
 
   /* Collision Handling */
-  for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_MAX_NUM_CLIENTS;
-       i++, ag_scb++) {
-    if (ag_scb->in_use && alarm_is_scheduled(ag_scb->collision_timer)) {
-      alarm_cancel(ag_scb->collision_timer);
-
-      if (dev_addr == ag_scb->peer_addr) {
-        /* If incoming and outgoing device are same, nothing more to do. */
-        /* Outgoing conn will be aborted because we have successful incoming
-         * conn.  */
-      } else {
-        /* Resume outgoing connection. */
-        other_scb = bta_ag_get_other_idle_scb(p_scb);
-        if (other_scb) {
-          other_scb->peer_addr = ag_scb->peer_addr;
-          other_scb->open_services = ag_scb->open_services;
-          other_scb->cli_sec_mask = ag_scb->cli_sec_mask;
-
-          bta_ag_resume_open(other_scb);
+  for (tBTA_AG_SCB& ag_scb : bta_ag_cb.scb) {
+    // Cancel any pending collision timers
+    if (ag_scb.in_use && alarm_is_scheduled(ag_scb.collision_timer)) {
+      alarm_cancel(ag_scb.collision_timer);
+      if (dev_addr != ag_scb.peer_addr && p_scb != &ag_scb) {
+        // Resume outgoing connection if incoming is not on the same device
+        bta_ag_resume_open(&ag_scb);
+      }
+      break;
+    }
+    if (dev_addr == ag_scb.peer_addr && p_scb != &ag_scb) {
+      // Fail the outgoing connection to clean up any upper layer states
+      bta_ag_rfc_fail(&ag_scb, tBTA_AG_DATA::kEmpty);
+      // If client port is opened, close it
+      if (ag_scb.conn_handle > 0) {
+        status = RFCOMM_RemoveConnection(ag_scb.conn_handle);
+        if (status != PORT_SUCCESS) {
+          LOG(WARNING) << __func__ << ": RFCOMM_RemoveConnection failed for "
+                       << dev_addr << ", handle "
+                       << std::to_string(ag_scb.conn_handle) << ", error "
+                       << status;
         }
       }
-
-      break;
     }
   }
 
   p_scb->peer_addr = dev_addr;
 
   /* determine connected service from port handle */
-  for (i = 0; i < BTA_AG_NUM_IDX; i++) {
+  for (uint8_t i = 0; i < BTA_AG_NUM_IDX; i++) {
     APPL_TRACE_DEBUG(
         "bta_ag_rfc_acp_open: i = %d serv_handle = %d port_handle = %d", i,
         p_scb->serv_handle[i], data.rfc.port_handle);
@@ -813,3 +805,32 @@
 
   (*bta_ag_cb.p_cback)(BTA_AG_WBS_EVT, (tBTA_AG*)&val);
 }
+
+static void bta_ag_collision_timer_cback(void* data) {
+  if (data == nullptr) {
+    LOG(ERROR) << __func__ << ": data should never be null in a timer callback";
+    return;
+  }
+  /* If the peer haven't opened AG connection     */
+  /* we will restart opening process.             */
+  bta_ag_resume_open(static_cast<tBTA_AG_SCB*>(data));
+}
+
+void bta_ag_handle_collision(tBTA_AG_SCB* p_scb,
+                             UNUSED_ATTR const tBTA_AG_DATA& data) {
+  /* Cancel SDP if it had been started. */
+  if (p_scb->p_disc_db) {
+    SDP_CancelServiceSearch(p_scb->p_disc_db);
+    bta_ag_free_db(p_scb, tBTA_AG_DATA::kEmpty);
+  }
+
+  /* reopen registered servers */
+  /* Collision may be detected before or after we close servers. */
+  if (bta_ag_is_server_closed(p_scb)) {
+    bta_ag_start_servers(p_scb, p_scb->reg_services);
+  }
+
+  /* Start timer to han */
+  alarm_set_on_mloop(p_scb->collision_timer, BTA_AG_COLLISION_TIMEOUT_MS,
+                     bta_ag_collision_timer_cback, p_scb);
+}
\ No newline at end of file
diff --git a/bta/ag/bta_ag_int.h b/bta/ag/bta_ag_int.h
index 487664f..3082f07 100644
--- a/bta/ag/bta_ag_int.h
+++ b/bta/ag/bta_ag_int.h
@@ -79,6 +79,7 @@
   BTA_AG_DISC_FAIL_EVT,
   BTA_AG_RING_TIMEOUT_EVT,
   BTA_AG_SVC_TIMEOUT_EVT,
+  BTA_AG_COLLISION_EVT,
   BTA_AG_MAX_EVT,
 };
 
@@ -306,7 +307,6 @@
 extern uint16_t bta_ag_idx_by_bdaddr(const RawAddress* peer_addr);
 extern bool bta_ag_other_scb_open(tBTA_AG_SCB* p_curr_scb);
 extern bool bta_ag_scb_open(tBTA_AG_SCB* p_curr_scb);
-extern tBTA_AG_SCB* bta_ag_get_other_idle_scb(tBTA_AG_SCB* p_curr_scb);
 extern void bta_ag_sm_execute(tBTA_AG_SCB* p_scb, uint16_t event,
                               const tBTA_AG_DATA& data);
 extern void bta_ag_sm_execute_by_handle(uint16_t handle, uint16_t event,
@@ -378,6 +378,8 @@
 extern void bta_ag_result(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
 extern void bta_ag_setcodec(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
 extern void bta_ag_send_ring(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
+extern void bta_ag_handle_collision(tBTA_AG_SCB* p_scb,
+                                    const tBTA_AG_DATA& data);
 
 /* Internal utility functions */
 extern void bta_ag_sco_codec_nego(tBTA_AG_SCB* p_scb, bool result);
diff --git a/bta/ag/bta_ag_main.cc b/bta/ag/bta_ag_main.cc
index b63f459..dd0a55d 100644
--- a/bta/ag/bta_ag_main.cc
+++ b/bta/ag/bta_ag_main.cc
@@ -68,6 +68,7 @@
   BTA_AG_RESULT,
   BTA_AG_SETCODEC,
   BTA_AG_SEND_RING,
+  BTA_AG_HANDLE_COLLISION,
   BTA_AG_NUM_ACTIONS
 };
 
@@ -133,6 +134,7 @@
     CASE_RETURN_STR(BTA_AG_DISC_FAIL_EVT)
     CASE_RETURN_STR(BTA_AG_RING_TIMEOUT_EVT)
     CASE_RETURN_STR(BTA_AG_SVC_TIMEOUT_EVT)
+    CASE_RETURN_STR(BTA_AG_COLLISION_EVT)
     default:
       return "Unknown AG Event";
   }
@@ -160,7 +162,11 @@
     bta_ag_sco_conn_close, bta_ag_sco_listen,    bta_ag_sco_open,
     bta_ag_sco_close,      bta_ag_sco_shutdown,  bta_ag_post_sco_open,
     bta_ag_post_sco_close, bta_ag_svc_conn_open, bta_ag_result,
-    bta_ag_setcodec,       bta_ag_send_ring};
+    bta_ag_setcodec,       bta_ag_send_ring,     bta_ag_handle_collision};
+
+static_assert(sizeof(bta_ag_action) / sizeof(tBTA_AG_ACTION) ==
+                  BTA_AG_NUM_ACTIONS,
+              "bta_ag_action must handle all actions");
 
 /* state table information */
 #define BTA_AG_ACTIONS 2    /* number of actions */
@@ -189,7 +195,8 @@
     /* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
     /* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
     /* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
-    /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}};
+    /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* COLLISION_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}};
 
 /* state table for opening state */
 const uint8_t bta_ag_st_opening[][BTA_AG_NUM_COLS] = {
@@ -216,7 +223,9 @@
     /* DISC_OK_EVT */ {BTA_AG_RFC_DO_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
     /* DISC_FAIL_EVT */ {BTA_AG_DISC_FAIL, BTA_AG_IGNORE, BTA_AG_INIT_ST},
     /* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
-    /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}};
+    /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* COLLISION_EVT */
+    {BTA_AG_HANDLE_COLLISION, BTA_AG_IGNORE, BTA_AG_INIT_ST}};
 
 /* state table for open state */
 const uint8_t bta_ag_st_open[][BTA_AG_NUM_COLS] = {
@@ -243,7 +252,8 @@
     /* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
     /* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
     /* RING_TOUT_EVT */ {BTA_AG_SEND_RING, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
-    /* SVC_TOUT_EVT */ {BTA_AG_START_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}};
+    /* SVC_TOUT_EVT */ {BTA_AG_START_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* COLLISION_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST}};
 
 /* state table for closing state */
 const uint8_t bta_ag_st_closing[][BTA_AG_NUM_COLS] = {
@@ -269,7 +279,19 @@
     /* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
     /* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
     /* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
-    /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}};
+    /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* COLLISION_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}};
+
+constexpr size_t BTA_AG_NUM_EVENTS =
+    BTA_AG_MAX_EVT - BTA_SYS_EVT_START(BTA_ID_AG);
+static_assert(sizeof(bta_ag_st_init) / BTA_AG_NUM_COLS == BTA_AG_NUM_EVENTS,
+              "bta_ag_st_init must handle all AG events");
+static_assert(sizeof(bta_ag_st_opening) / BTA_AG_NUM_COLS == BTA_AG_NUM_EVENTS,
+              "bta_ag_st_opening must handle all AG events");
+static_assert(sizeof(bta_ag_st_open) / BTA_AG_NUM_COLS == BTA_AG_NUM_EVENTS,
+              "bta_ag_st_open must handle all AG events");
+static_assert(sizeof(bta_ag_st_closing) / BTA_AG_NUM_COLS == BTA_AG_NUM_EVENTS,
+              "bta_ag_st_closing must handle all AG events");
 
 /* type for state table */
 typedef const uint8_t (*tBTA_AG_ST_TBL)[BTA_AG_NUM_COLS];
@@ -496,52 +518,6 @@
 
 /*******************************************************************************
  *
- * Function         bta_ag_get_other_idle_scb
- *
- * Description      Return other scb if it is in INIT st.
- *
- *
- * Returns          Pointer to other scb if INIT st, NULL otherwise.
- *
- ******************************************************************************/
-tBTA_AG_SCB* bta_ag_get_other_idle_scb(tBTA_AG_SCB* p_curr_scb) {
-  tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
-  uint8_t xx;
-
-  for (xx = 0; xx < BTA_AG_MAX_NUM_CLIENTS; xx++, p_scb++) {
-    if (p_scb->in_use && (p_scb != p_curr_scb) &&
-        (p_scb->state == BTA_AG_INIT_ST)) {
-      return p_scb;
-    }
-  }
-
-  /* no other scb found */
-  APPL_TRACE_DEBUG("bta_ag_get_other_idle_scb: No idle AG scb");
-  return nullptr;
-}
-
-/*******************************************************************************
- *
- * Function         bta_ag_collision_timer_cback
- *
- * Description      AG connection collision timer callback
- *
- *
- * Returns          void
- *
- ******************************************************************************/
-static void bta_ag_collision_timer_cback(void* data) {
-  tBTA_AG_SCB* p_scb = (tBTA_AG_SCB*)data;
-
-  APPL_TRACE_DEBUG("%s", __func__);
-
-  /* If the peer haven't opened AG connection     */
-  /* we will restart opening process.             */
-  bta_ag_resume_open(p_scb);
-}
-
-/*******************************************************************************
- *
  * Function         bta_ag_collision_cback
  *
  * Description      Get notified about collision.
@@ -559,33 +535,16 @@
 
   if (p_scb && (p_scb->state == BTA_AG_OPENING_ST)) {
     if (id == BTA_ID_SYS) {
-      LOG(WARNING) << __func__ << "AG found collision (ACL) for handle "
+      LOG(WARNING) << __func__ << ": AG found collision (ACL) for handle "
                    << unsigned(handle) << " device " << peer_addr;
     } else if (id == BTA_ID_AG) {
-      LOG(WARNING) << __func__ << "AG found collision (RFCOMM) for handle "
+      LOG(WARNING) << __func__ << ": AG found collision (RFCOMM) for handle "
                    << unsigned(handle) << " device " << peer_addr;
     } else {
-      LOG(WARNING) << __func__ << "AG found collision (UNKNOWN) for handle "
+      LOG(WARNING) << __func__ << ": AG found collision (UNKNOWN) for handle "
                    << unsigned(handle) << " device " << peer_addr;
     }
-
-    p_scb->state = BTA_AG_INIT_ST;
-
-    /* Cancel SDP if it had been started. */
-    if (p_scb->p_disc_db) {
-      SDP_CancelServiceSearch(p_scb->p_disc_db);
-      bta_ag_free_db(p_scb, tBTA_AG_DATA::kEmpty);
-    }
-
-    /* reopen registered servers */
-    /* Collision may be detected before or after we close servers. */
-    if (bta_ag_is_server_closed(p_scb)) {
-      bta_ag_start_servers(p_scb, p_scb->reg_services);
-    }
-
-    /* Start timer to han */
-    alarm_set_on_mloop(p_scb->collision_timer, BTA_AG_COLLISION_TIMEOUT_MS,
-                       bta_ag_collision_timer_cback, p_scb);
+    bta_ag_sm_execute(p_scb, BTA_AG_COLLISION_EVT, tBTA_AG_DATA::kEmpty);
   }
 }
 
@@ -600,20 +559,16 @@
  *
  ******************************************************************************/
 void bta_ag_resume_open(tBTA_AG_SCB* p_scb) {
-  if (p_scb) {
-    APPL_TRACE_DEBUG("%s: handle=%d, bd_addr=%s", __func__,
-                     bta_ag_scb_to_idx(p_scb),
-                     p_scb->peer_addr.ToString().c_str());
-    /* resume opening process.  */
-    if (p_scb->state == BTA_AG_INIT_ST) {
-      LOG(WARNING) << __func__
-                   << ": handle=" << unsigned(bta_ag_scb_to_idx(p_scb))
-                   << ", bd_addr=" << p_scb->peer_addr;
-      p_scb->state = BTA_AG_OPENING_ST;
-      bta_ag_start_open(p_scb, tBTA_AG_DATA::kEmpty);
-    }
+  if (p_scb->state == BTA_AG_INIT_ST) {
+    LOG(INFO) << __func__ << ": Resume connection to " << p_scb->peer_addr
+              << ", handle" << bta_ag_scb_to_idx(p_scb);
+    tBTA_AG_DATA open_data = {.api_open.bd_addr = p_scb->peer_addr,
+                              .api_open.services = p_scb->open_services,
+                              .api_open.sec_mask = p_scb->cli_sec_mask};
+    bta_ag_sm_execute(p_scb, BTA_AG_API_OPEN_EVT, open_data);
   } else {
-    LOG(ERROR) << __func__ << ": null p_scb";
+    VLOG(1) << __func__ << ": device " << p_scb->peer_addr
+            << " is already in state " << std::to_string(p_scb->state);
   }
 }
 
diff --git a/bta/av/bta_av_aact.cc b/bta/av/bta_av_aact.cc
index 9b07971..137e59c 100644
--- a/bta/av/bta_av_aact.cc
+++ b/bta/av/bta_av_aact.cc
@@ -264,11 +264,12 @@
  * Returns          void
  *
  ******************************************************************************/
-static void bta_av_save_addr(tBTA_AV_SCB* p_scb, const RawAddress& b) {
+static void bta_av_save_addr(tBTA_AV_SCB* p_scb, const RawAddress& bd_addr) {
   APPL_TRACE_DEBUG("%s: r:%d, s:%d", __func__, p_scb->recfg_sup,
                    p_scb->suspend_sup);
-  if (p_scb->peer_addr != b) {
-    APPL_TRACE_ERROR("%s: reset flags", __func__);
+  if (p_scb->peer_addr != bd_addr) {
+    LOG(INFO) << __func__ << ": reset flags old_addr=" << p_scb->peer_addr
+              << ", new_addr=" << bd_addr;
     /* a new addr, reset the supported flags */
     p_scb->recfg_sup = true;
     p_scb->suspend_sup = true;
@@ -276,7 +277,7 @@
 
   /* do this copy anyway, just in case the first addr matches
    * the control block one by accident */
-  p_scb->peer_addr = b;
+  p_scb->peer_addr = bd_addr;
 }
 
 /*******************************************************************************
diff --git a/bta/hf_client/bta_hf_client_act.cc b/bta/hf_client/bta_hf_client_act.cc
index 3e6c22d..e3f25f6 100644
--- a/bta/hf_client/bta_hf_client_act.cc
+++ b/bta/hf_client/bta_hf_client_act.cc
@@ -103,8 +103,8 @@
   }
 
   /* Check if RFCOMM has any incoming connection to avoid collision. */
-  RawAddress pending_bd_addr;
-  if (PORT_IsOpening(pending_bd_addr)) {
+  RawAddress pending_bd_addr = RawAddress::kEmpty;
+  if (PORT_IsOpening(&pending_bd_addr)) {
     /* Let the incoming connection goes through.                        */
     /* Issue collision for now.                                         */
     /* We will decide what to do when we find incoming connection later.*/
@@ -164,21 +164,17 @@
                      p_data->hdr.layer_specific);
     return;
   }
-
-  uint16_t lcid;
-  RawAddress dev_addr;
-  int status;
-
   /* set role */
   client_cb->role = BTA_HF_CLIENT_ACP;
 
   APPL_TRACE_DEBUG("%s: conn_handle %d", __func__, client_cb->conn_handle);
 
   /* get bd addr of peer */
-  if (PORT_SUCCESS != (status = PORT_CheckConnection(client_cb->conn_handle,
-                                                     dev_addr, &lcid))) {
-    APPL_TRACE_DEBUG("%s: error PORT_CheckConnection returned status %d",
-                     __func__, status);
+  uint16_t lcid = 0;
+  RawAddress dev_addr = RawAddress::kEmpty;
+  int status = PORT_CheckConnection(client_cb->conn_handle, &dev_addr, &lcid);
+  if (status != PORT_SUCCESS) {
+    LOG(ERROR) << __func__ << ": PORT_CheckConnection returned " << status;
   }
 
   /* Collision Handling */
diff --git a/bta/hf_client/bta_hf_client_rfc.cc b/bta/hf_client/bta_hf_client_rfc.cc
index e261c16..f3e0947 100644
--- a/bta/hf_client/bta_hf_client_rfc.cc
+++ b/bta/hf_client/bta_hf_client_rfc.cc
@@ -98,9 +98,12 @@
       APPL_TRACE_DEBUG("%s: allocating a new CB for incoming connection",
                        __func__);
       // Find the BDADDR of the peer device
-      RawAddress peer_addr;
-      uint16_t lcid;
-      PORT_CheckConnection(port_handle, peer_addr, &lcid);
+      RawAddress peer_addr = RawAddress::kEmpty;
+      uint16_t lcid = 0;
+      int status = PORT_CheckConnection(port_handle, &peer_addr, &lcid);
+      if (status != PORT_SUCCESS) {
+        LOG(ERROR) << __func__ << ": PORT_CheckConnection returned " << status;
+      }
 
       // Since we accepted a remote request we should allocate a handle first.
       uint16_t tmp_handle = -1;
diff --git a/bta/jv/bta_jv_act.cc b/bta/jv/bta_jv_act.cc
index 87e5052..7c8a655 100644
--- a/bta/jv/bta_jv_act.cc
+++ b/bta/jv/bta_jv_act.cc
@@ -480,7 +480,7 @@
 static tBTA_JV_PM_CB* bta_jv_alloc_set_pm_profile_cb(uint32_t jv_handle,
                                                      tBTA_JV_PM_ID app_id) {
   bool bRfcHandle = (jv_handle & BTA_JV_RFCOMM_MASK) != 0;
-  RawAddress peer_bd_addr;
+  RawAddress peer_bd_addr = RawAddress::kEmpty;
   int i, j;
   tBTA_JV_PM_CB** pp_cb;
 
@@ -494,8 +494,9 @@
             pp_cb = &bta_jv_cb.port_cb[j].p_pm_cb;
             if (PORT_SUCCESS !=
                 PORT_CheckConnection(bta_jv_cb.port_cb[j].port_handle,
-                                     peer_bd_addr, NULL))
+                                     &peer_bd_addr, NULL)) {
               i = BTA_JV_PM_MAX_NUM;
+            }
             break;
           }
         }
@@ -604,7 +605,7 @@
 }
 
 /** Disables the BT device manager free the resources used by java */
-void bta_jv_disable() { LOG(ERROR) << __func__; }
+void bta_jv_disable() { LOG(INFO) << __func__; }
 
 /**
  * We keep a list of PSM's that have been freed from JAVA, for reuse.
@@ -1254,7 +1255,7 @@
   tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
   tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
   tBTA_JV evt_data;
-  RawAddress rem_bda;
+  RawAddress rem_bda = RawAddress::kEmpty;
   uint16_t lcid;
   tBTA_JV_RFCOMM_CBACK* p_cback; /* the callback function */
 
@@ -1264,7 +1265,7 @@
   VLOG(2) << __func__ << ": code=" << code << ", port_handle=" << port_handle
           << ", handle=" << p_cb->handle;
 
-  PORT_CheckConnection(port_handle, rem_bda, &lcid);
+  PORT_CheckConnection(port_handle, &rem_bda, &lcid);
 
   if (code == PORT_SUCCESS) {
     evt_data.rfc_open.handle = p_cb->handle;
@@ -1451,7 +1452,7 @@
   tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
   tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
   tBTA_JV evt_data;
-  RawAddress rem_bda;
+  RawAddress rem_bda = RawAddress::kEmpty;
   uint16_t lcid;
   VLOG(2) << __func__ << ": code=" << code << ", port_handle=" << port_handle;
   if (NULL == p_cb || NULL == p_cb->p_cback) {
@@ -1465,9 +1466,13 @@
           << ", handle=" << loghex(p_cb->handle) << ", p_pcb" << p_pcb
           << ", user=" << p_pcb->rfcomm_slot_id;
 
-  PORT_CheckConnection(port_handle, rem_bda, &lcid);
+  int status = PORT_CheckConnection(port_handle, &rem_bda, &lcid);
   int failed = true;
   if (code == PORT_SUCCESS) {
+    if (status != PORT_SUCCESS) {
+      LOG(ERROR) << __func__ << ": PORT_CheckConnection returned " << status
+                 << ", although port is supposed to be connected";
+    }
     evt_data.rfc_srv_open.handle = p_pcb->handle;
     evt_data.rfc_srv_open.status = BTA_JV_SUCCESS;
     evt_data.rfc_srv_open.rem_bda = rem_bda;
@@ -1521,7 +1526,11 @@
   tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
   tBTA_JV evt_data;
 
-  if (NULL == p_cb || NULL == p_cb->p_cback) return;
+  if (NULL == p_cb || NULL == p_cb->p_cback) {
+    LOG(ERROR) << __func__ << ": p_cb=" << p_cb
+               << ", p_cb->p_cback=" << (p_cb ? p_cb->p_cback : 0);
+    return;
+  }
 
   VLOG(2) << __func__ << ": code=" << loghex(code)
           << ", port_handle=" << port_handle << ", handle=" << p_cb->handle;
diff --git a/btif/src/btif_hf.cc b/btif/src/btif_hf.cc
index 5573160..a3306ec 100644
--- a/btif/src/btif_hf.cc
+++ b/btif/src/btif_hf.cc
@@ -31,6 +31,7 @@
 #include <cstring>
 #include <ctime>
 
+#include <bta/include/bta_ag_api.h>
 #include <hardware/bluetooth.h>
 #include <hardware/bluetooth_headset_callbacks.h>
 #include <hardware/bluetooth_headset_interface.h>
@@ -327,11 +328,11 @@
                    << unsigned(p_data->open.status);
         btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_DISCONNECTED;
       } else {
-        BTIF_TRACE_WARNING(
-            "%s: AG open failed, but another device connected. status=%d "
-            "state=%d connected device=%s",
-            __func__, p_data->open.status, btif_hf_cb[idx].state,
-            btif_hf_cb[idx].connected_bda.ToString().c_str());
+        LOG(WARNING) << __func__ << ": AG open failed for "
+                     << p_data->open.bd_addr << ", error "
+                     << std::to_string(p_data->open.status)
+                     << ", local device is " << btif_hf_cb[idx].connected_bda
+                     << ". Ignoring as not expecting to open";
         break;
       }
       bt_hf_callbacks->ConnectionStateCallback(btif_hf_cb[idx].state,
diff --git a/stack/Android.bp b/stack/Android.bp
index 2b5d430..76cb172 100644
--- a/stack/Android.bp
+++ b/stack/Android.bp
@@ -197,7 +197,9 @@
         "system/bt",
         "system/bt/internal_include",
     ],
-    srcs: ["test/stack_a2dp_test.cc"],
+    srcs: [
+        "test/stack_a2dp_test.cc",
+    ],
     shared_libs: [
         "libhidlbase",
         "liblog",
@@ -221,6 +223,56 @@
     ],
 }
 
+cc_test {
+  name: "net_test_stack_rfcomm",
+  defaults: ["fluoride_defaults"],
+  host_supported: true,
+  local_include_dirs: [
+      "include",
+      "btm",
+      "l2cap",
+      "smp",
+      "rfcomm",
+      "test/common",
+  ],
+  include_dirs: [
+      "system/bt",
+      "system/bt/internal_include",
+      "system/bt/btcore/include",
+      "system/bt/hci/include",
+      "system/bt/utils/include",
+  ],
+  srcs: [
+      "rfcomm/port_api.cc",
+      "rfcomm/port_rfc.cc",
+      "rfcomm/port_utils.cc",
+      "rfcomm/rfc_l2cap_if.cc",
+      "rfcomm/rfc_mx_fsm.cc",
+      "rfcomm/rfc_port_fsm.cc",
+      "rfcomm/rfc_port_if.cc",
+      "rfcomm/rfc_ts_frames.cc",
+      "rfcomm/rfc_utils.cc",
+      "test/common/mock_btm_layer.cc",
+      "test/common/mock_btu_layer.cc",
+      "test/common/mock_l2cap_layer.cc",
+      "test/common/stack_test_packet_utils.cc",
+      "test/rfcomm/stack_rfcomm_test.cc",
+      "test/rfcomm/stack_rfcomm_test_main.cc",
+      "test/rfcomm/stack_rfcomm_test_utils.cc",
+      "test/rfcomm/stack_rfcomm_test_utils_test.cc",
+  ],
+  shared_libs: [
+      "libcutils",
+      "libprotobuf-cpp-lite",
+  ],
+  static_libs: [
+      "liblog",
+      "libgmock",
+      "libosi",
+      "libbt-protos-lite",
+  ],
+}
+
 // Bluetooth stack smp unit tests for target
 // ========================================================
 cc_test {
diff --git a/stack/include/port_api.h b/stack/include/port_api.h
index aedbe74..b0a7e63 100644
--- a/stack/include/port_api.h
+++ b/stack/include/port_api.h
@@ -309,7 +309,7 @@
  *                  p_lcid     - OUT L2CAP's LCID
  *
  ******************************************************************************/
-extern int PORT_CheckConnection(uint16_t handle, RawAddress& bd_addr,
+extern int PORT_CheckConnection(uint16_t handle, RawAddress* bd_addr,
                                 uint16_t* p_lcid);
 
 /*******************************************************************************
@@ -323,7 +323,7 @@
  *                  bd_addr    - bd_addr of the peer
  *
  ******************************************************************************/
-extern bool PORT_IsOpening(RawAddress& bd_addr);
+extern bool PORT_IsOpening(RawAddress* bd_addr);
 
 /*******************************************************************************
  *
diff --git a/stack/l2cap/l2c_api.cc b/stack/l2cap/l2c_api.cc
index 951a45b..173d0a6 100644
--- a/stack/l2cap/l2c_api.cc
+++ b/stack/l2cap/l2c_api.cc
@@ -275,7 +275,7 @@
  *
  ******************************************************************************/
 uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& p_bd_addr) {
-  return L2CA_ErtmConnectReq(psm, p_bd_addr, NULL);
+  return L2CA_ErtmConnectReq(psm, p_bd_addr, nullptr);
 }
 
 /*******************************************************************************
@@ -297,10 +297,6 @@
  ******************************************************************************/
 uint16_t L2CA_ErtmConnectReq(uint16_t psm, const RawAddress& p_bd_addr,
                              tL2CAP_ERTM_INFO* p_ertm_info) {
-  tL2C_LCB* p_lcb;
-  tL2C_CCB* p_ccb;
-  tL2C_RCB* p_rcb;
-
   VLOG(1) << __func__ << "BDA " << p_bd_addr
           << StringPrintf(" PSM: 0x%04x allowed:0x%x preferred:%d", psm,
                           (p_ertm_info) ? p_ertm_info->allowed_modes : 0,
@@ -308,36 +304,36 @@
 
   /* Fail if we have not established communications with the controller */
   if (!BTM_IsDeviceUp()) {
-    L2CAP_TRACE_WARNING("L2CAP connect req - BTU not ready");
-    return (0);
+    LOG(WARNING) << __func__ << ": BTU not ready";
+    return 0;
   }
   /* Fail if the PSM is not registered */
-  p_rcb = l2cu_find_rcb_by_psm(psm);
-  if (p_rcb == NULL) {
-    L2CAP_TRACE_WARNING("L2CAP - no RCB for L2CA_conn_req, PSM: 0x%04x", psm);
-    return (0);
+  tL2C_RCB* p_rcb = l2cu_find_rcb_by_psm(psm);
+  if (p_rcb == nullptr) {
+    LOG(WARNING) << __func__ << ": no RCB, PSM=" << loghex(psm);
+    return 0;
   }
 
   /* First, see if we already have a link to the remote */
   /* assume all ERTM l2cap connection is going over BR/EDR for now */
-  p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_BR_EDR);
-  if (p_lcb == NULL) {
+  tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_BR_EDR);
+  if (p_lcb == nullptr) {
     /* No link. Get an LCB and start link establishment */
     p_lcb = l2cu_allocate_lcb(p_bd_addr, false, BT_TRANSPORT_BR_EDR);
     /* currently use BR/EDR for ERTM mode l2cap connection */
-    if ((p_lcb == NULL) || (!l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR))) {
-      L2CAP_TRACE_WARNING(
-          "L2CAP - conn not started for PSM: 0x%04x  p_lcb: 0x%08x", psm,
-          p_lcb);
-      return (0);
+    if ((p_lcb == nullptr) || (!l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR))) {
+      LOG(WARNING) << __func__
+                   << ": connection not started for PSM=" << loghex(psm)
+                   << ", p_lcb=" << p_lcb;
+      return 0;
     }
   }
 
   /* Allocate a channel control block */
-  p_ccb = l2cu_allocate_ccb(p_lcb, 0);
-  if (p_ccb == NULL) {
-    L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_conn_req, PSM: 0x%04x", psm);
-    return (0);
+  tL2C_CCB* p_ccb = l2cu_allocate_ccb(p_lcb, 0);
+  if (p_ccb == nullptr) {
+    LOG(WARNING) << __func__ << ": no CCB, PSM=" << loghex(psm);
+    return 0;
   }
 
   /* Save registration info */
@@ -366,16 +362,14 @@
 
   /* If link is up, start the L2CAP connection */
   if (p_lcb->link_state == LST_CONNECTED) {
-    l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_REQ, NULL);
-  }
-
-  /* If link is disconnecting, save link info to retry after disconnect
-   * Possible Race condition when a reconnect occurs
-   * on the channel during a disconnect of link. This
-   * ccb will be automatically retried after link disconnect
-   * arrives
-   */
-  else if (p_lcb->link_state == LST_DISCONNECTING) {
+    l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_REQ, nullptr);
+  } else if (p_lcb->link_state == LST_DISCONNECTING) {
+    /* If link is disconnecting, save link info to retry after disconnect
+     * Possible Race condition when a reconnect occurs
+     * on the channel during a disconnect of link. This
+     * ccb will be automatically retried after link disconnect
+     * arrives
+     */
     L2CAP_TRACE_DEBUG("L2CAP API - link disconnecting: RETRY LATER");
 
     /* Save ccb so it can be started after disconnect is finished */
@@ -386,7 +380,7 @@
                   psm, p_ccb->local_cid);
 
   /* Return the local CID as our handle */
-  return (p_ccb->local_cid);
+  return p_ccb->local_cid;
 }
 
 /*******************************************************************************
diff --git a/stack/rfcomm/port_api.cc b/stack/rfcomm/port_api.cc
index 1ae8667..0bb817d 100644
--- a/stack/rfcomm/port_api.cc
+++ b/stack/rfcomm/port_api.cc
@@ -118,7 +118,7 @@
   *p_handle = 0;
 
   if ((scn == 0) || (scn >= PORT_MAX_RFC_PORTS)) {
-    /* Server Channel Number(SCN) should be in range 1...30 */
+    // Server Channel Number (SCN) should be in range [1, 30]
     LOG(ERROR) << __func__ << ": Invalid SCN, bd_addr=" << bd_addr
                << ", scn=" << static_cast<int>(scn)
                << ", is_server=" << is_server
@@ -127,8 +127,8 @@
     return (PORT_INVALID_SCN);
   }
 
-  /* For client that originate connection on the existing none initiator */
-  /* multiplexer channel DLCI should be odd */
+  // For client that originates connection on the existing none initiator
+  // multiplexer channel, DLCI should be odd.
   uint8_t dlci;
   tRFC_MCB* p_mcb = port_find_mcb(bd_addr);
   if (p_mcb && !p_mcb->is_initiator && !is_server) {
@@ -137,13 +137,13 @@
     dlci = (scn << 1);
   }
 
-  /* For the server side always allocate a new port.  On the client side */
-  /* do not allow the same (dlci, bd_addr) to be opened twice by application */
+  // On the client side, do not allow the same (dlci, bd_addr) to be opened
+  // twice by application
   tPORT* p_port;
   if (!is_server) {
     p_port = port_find_port(dlci, bd_addr);
     if (p_port != nullptr) {
-      /* if existing port is also a client port */
+      // if existing port is also a client port, error out
       if (!p_port->is_server) {
         LOG(ERROR) << __func__ << ": already at opened state "
                    << static_cast<int>(p_port->state)
@@ -153,22 +153,26 @@
                    << ", bd_addr=" << bd_addr << ", scn=" << std::to_string(scn)
                    << ", is_server=" << is_server << ", mtu=" << mtu
                    << ", uuid=" << loghex(uuid) << ", dlci=" << +dlci
-                   << ", p_mcb=" << p_mcb << ", port=" << +p_port->inx;
-        *p_handle = p_port->inx;
+                   << ", p_mcb=" << p_mcb
+                   << ", port=" << std::to_string(p_port->handle);
+        *p_handle = p_port->handle;
         return (PORT_ALREADY_OPENED);
       }
     }
   }
 
+  // On the server side, always allocate a new port.
   p_port = port_allocate_port(dlci, bd_addr);
   if (p_port == nullptr) {
     LOG(ERROR) << __func__ << ": no resources, bd_addr=" << bd_addr
                << ", scn=" << std::to_string(scn) << ", is_server=" << is_server
                << ", mtu=" << mtu << ", uuid=" << loghex(uuid)
                << ", dlci=" << +dlci;
-    return (PORT_NO_RESOURCES);
+    return PORT_NO_RESOURCES;
   }
+  *p_handle = p_port->handle;
 
+  // Get default signal state
   switch (uuid) {
     case UUID_PROTOCOL_OBEX:
       p_port->default_signal_state = PORT_OBEX_DEFAULT_SIGNAL_STATE;
@@ -189,42 +193,35 @@
       break;
   }
 
-  *p_handle = p_port->inx;
-
+  // Assign port specific values
   p_port->state = PORT_STATE_OPENING;
   p_port->uuid = uuid;
   p_port->is_server = is_server;
   p_port->scn = scn;
   p_port->ev_mask = 0;
 
-  /* If the MTU is not specified (0), keep MTU decision until the
-   * PN frame has to be send
-   * at that time connection should be established and we
-   * will know for sure our prefered MTU
-   */
-
+  // Find MTU
+  // If the MTU is not specified (0), keep MTU decision until the PN frame has
+  // to be send at that time connection should be established and we will know
+  // for sure our prefered MTU
   uint16_t rfcomm_mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
-
   if (mtu) {
     p_port->mtu = (mtu < rfcomm_mtu) ? mtu : rfcomm_mtu;
   } else {
     p_port->mtu = rfcomm_mtu;
   }
 
-  /* server doesn't need to release port when closing */
+  // Other states
+  // server doesn't need to release port when closing
   if (is_server) {
     p_port->keep_port_handle = true;
-
-    /* keep mtu that user asked, p_port->mtu could be updated during param
-     * negotiation */
+    // keep mtu that user asked, p_port->mtu could be updated during param
+    // negotiation
     p_port->keep_mtu = p_port->mtu;
   }
-
   p_port->local_ctrl.modem_signal = p_port->default_signal_state;
   p_port->local_ctrl.fc = false;
-
   p_port->p_mgmt_callback = p_mgmt_cb;
-
   p_port->bd_addr = bd_addr;
 
   LOG(INFO) << __func__ << ": bd_addr=" << bd_addr
@@ -234,12 +231,12 @@
             << ", signal_state=" << loghex(p_port->default_signal_state)
             << ", p_port=" << p_port;
 
-  /* If this is not initiator of the connection need to just wait */
+  // If this is not initiator of the connection need to just wait
   if (p_port->is_server) {
     return (PORT_SUCCESS);
   }
 
-  /* Open will be continued after security checks are passed */
+  // Open will be continued after security checks are passed
   return port_open_continue(p_port);
 }
 
@@ -286,24 +283,21 @@
  *
  ******************************************************************************/
 int RFCOMM_RemoveServer(uint16_t handle) {
-  tPORT* p_port;
-
-  RFCOMM_TRACE_API("RFCOMM_RemoveServer() handle:%d", handle);
-
   /* Check if handle is valid to avoid crashing */
   if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
-    RFCOMM_TRACE_ERROR("RFCOMM_RemoveServer() BAD handle:%d", handle);
+    LOG(ERROR) << __func__ << ": bad handle " << handle;
     return (PORT_BAD_HANDLE);
   }
-  p_port = &rfc_cb.port.port[handle - 1];
+  tPORT* p_port = &rfc_cb.port.port[handle - 1];
 
   /* Do not report any events to the client any more. */
-  p_port->p_mgmt_callback = NULL;
+  p_port->p_mgmt_callback = nullptr;
 
   if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
-    RFCOMM_TRACE_EVENT("RFCOMM_RemoveServer() Not opened:%d", handle);
+    VLOG(1) << __func__ << ": handle " << handle << " not opened";
     return (PORT_SUCCESS);
   }
+  LOG(INFO) << __func__ << ": handle=" << handle;
 
   /* this port will be deallocated after closing */
   p_port->keep_port_handle = false;
@@ -486,18 +480,19 @@
  *                  p_lcid     - OUT L2CAP's LCID
  *
  ******************************************************************************/
-int PORT_CheckConnection(uint16_t handle, RawAddress& bd_addr,
+int PORT_CheckConnection(uint16_t handle, RawAddress* bd_addr,
                          uint16_t* p_lcid) {
-  tPORT* p_port;
-
-  RFCOMM_TRACE_API("PORT_CheckConnection() handle:%d", handle);
-
   /* Check if handle is valid to avoid crashing */
   if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
     return (PORT_BAD_HANDLE);
   }
-
-  p_port = &rfc_cb.port.port[handle - 1];
+  tPORT* p_port = &rfc_cb.port.port[handle - 1];
+  RFCOMM_TRACE_DEBUG(
+      "%s: handle=%d, in_use=%d, port_state=%d, p_mcb=%p, peer_ready=%d, "
+      "rfc_state=%d",
+      __func__, handle, p_port->in_use, p_port->state, p_port->rfc.p_mcb,
+      (p_port->rfc.p_mcb ? p_port->rfc.p_mcb->peer_ready : -1),
+      p_port->rfc.state);
 
   if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
     return (PORT_NOT_OPENED);
@@ -508,7 +503,7 @@
     return (PORT_LINE_ERR);
   }
 
-  bd_addr = p_port->rfc.p_mcb->bd_addr;
+  *bd_addr = p_port->rfc.p_mcb->bd_addr;
   if (p_lcid) *p_lcid = p_port->rfc.p_mcb->lcid;
 
   return (PORT_SUCCESS);
@@ -525,28 +520,23 @@
  *                  bd_addr    - bd_addr of the peer
  *
  ******************************************************************************/
-bool PORT_IsOpening(RawAddress& bd_addr) {
-  uint8_t xx, yy;
-  tRFC_MCB* p_mcb = NULL;
-  tPORT* p_port;
-  bool found_port;
-
+bool PORT_IsOpening(RawAddress* bd_addr) {
   /* Check for any rfc_mcb which is in the middle of opening. */
-  for (xx = 0; xx < MAX_BD_CONNECTIONS; xx++) {
-    if ((rfc_cb.port.rfc_mcb[xx].state > RFC_MX_STATE_IDLE) &&
-        (rfc_cb.port.rfc_mcb[xx].state < RFC_MX_STATE_CONNECTED)) {
-      bd_addr = rfc_cb.port.rfc_mcb[xx].bd_addr;
+  for (auto& multiplexer_cb : rfc_cb.port.rfc_mcb) {
+    if ((multiplexer_cb.state > RFC_MX_STATE_IDLE) &&
+        (multiplexer_cb.state < RFC_MX_STATE_CONNECTED)) {
+      *bd_addr = multiplexer_cb.bd_addr;
       return true;
     }
 
-    if (rfc_cb.port.rfc_mcb[xx].state == RFC_MX_STATE_CONNECTED) {
-      found_port = false;
-      p_mcb = &rfc_cb.port.rfc_mcb[xx];
-      p_port = &rfc_cb.port.port[0];
+    if (multiplexer_cb.state == RFC_MX_STATE_CONNECTED) {
+      bool found_port = false;
+      tPORT* p_port = nullptr;
 
-      for (yy = 0; yy < MAX_RFC_PORTS; yy++, p_port++) {
-        if (p_port->rfc.p_mcb == p_mcb) {
+      for (tPORT& port : rfc_cb.port.port) {
+        if (port.rfc.p_mcb == &multiplexer_cb) {
           found_port = true;
+          p_port = &port;
           break;
         }
       }
@@ -554,7 +544,7 @@
       if ((!found_port) ||
           (found_port && (p_port->rfc.state < RFC_STATE_OPENED))) {
         /* Port is not established yet. */
-        bd_addr = rfc_cb.port.rfc_mcb[xx].bd_addr;
+        *bd_addr = multiplexer_cb.bd_addr;
         return true;
       }
     }
@@ -827,7 +817,7 @@
 
     events &= p_port->ev_mask;
     if (p_port->p_callback && events) {
-      p_port->p_callback(events, p_port->inx);
+      p_port->p_callback(events, p_port->handle);
     }
   }
   return (PORT_SUCCESS);
@@ -894,7 +884,7 @@
 
     events &= p_port->ev_mask;
     if (p_port->p_callback && events) {
-      p_port->p_callback(events, p_port->inx);
+      p_port->p_callback(events, p_port->handle);
     }
   }
   return (PORT_SUCCESS);
@@ -1118,7 +1108,7 @@
     events &= p_port->ev_mask;
 
     if ((p_port->p_callback != NULL) && events)
-      (p_port->p_callback)(events, p_port->inx);
+      (p_port->p_callback)(events, p_port->handle);
   }
 
   return (PORT_SUCCESS);
@@ -1306,7 +1296,7 @@
       osi_free(p_buf);
 
       if ((p_port->p_callback != NULL) && (p_port->ev_mask & PORT_EV_ERR))
-        p_port->p_callback(PORT_EV_ERR, p_port->inx);
+        p_port->p_callback(PORT_EV_ERR, p_port->handle);
 
       return (PORT_TX_FULL);
     }
@@ -1384,7 +1374,7 @@
   event &= p_port->ev_mask;
 
   /* Send event to the application */
-  if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->inx);
+  if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->handle);
 
   return (PORT_SUCCESS);
 }
@@ -1539,7 +1529,7 @@
   event &= p_port->ev_mask;
 
   /* Send event to the application */
-  if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->inx);
+  if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->handle);
 
   return (PORT_SUCCESS);
 }
@@ -1650,7 +1640,7 @@
   event &= p_port->ev_mask;
 
   /* Send event to the application */
-  if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->inx);
+  if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->handle);
 
   return (PORT_SUCCESS);
 }
diff --git a/stack/rfcomm/port_int.h b/stack/rfcomm/port_int.h
index db7d0fd..ecd8fbc 100644
--- a/stack/rfcomm/port_int.h
+++ b/stack/rfcomm/port_int.h
@@ -90,8 +90,8 @@
 typedef struct {
   alarm_t* mcb_timer;   /* MCB timer */
   fixed_queue_t* cmd_q; /* Queue for command messages on this mux */
-  uint8_t port_inx[RFCOMM_MAX_DLCI + 1]; /* Array for quick access to  */
-                                         /* tPORT based on dlci        */
+  uint8_t port_handles[RFCOMM_MAX_DLCI + 1]; /* Array for quick access to  */
+  /* port handles based on dlci        */
   RawAddress bd_addr;                    /* BD ADDR of the peer if initiator */
   uint16_t lcid;                         /* Local cid used for this channel */
   uint16_t peer_l2cap_mtu; /* Max frame that can be sent to peer L2CAP */
@@ -139,7 +139,7 @@
  * Define control block containing information about PORT connection
 */
 typedef struct {
-  uint8_t inx; /* Index of this control block in the port_info array */
+  uint8_t handle;  // Starting from 1, unique for this object
   bool in_use; /* True when structure is allocated */
 
 #define PORT_STATE_CLOSED 0
diff --git a/stack/rfcomm/port_rfc.cc b/stack/rfcomm/port_rfc.cc
index 5ec5631..3228f64 100644
--- a/stack/rfcomm/port_rfc.cc
+++ b/stack/rfcomm/port_rfc.cc
@@ -56,13 +56,11 @@
  *
  ******************************************************************************/
 int port_open_continue(tPORT* p_port) {
-  tRFC_MCB* p_mcb;
-
   RFCOMM_TRACE_EVENT("port_open_continue, p_port:%p", p_port);
 
   /* Check if multiplexer channel has already been established */
-  p_mcb = rfc_alloc_multiplexer_channel(p_port->bd_addr, true);
-  if (p_mcb == NULL) {
+  tRFC_MCB* p_mcb = rfc_alloc_multiplexer_channel(p_port->bd_addr, true);
+  if (p_mcb == nullptr) {
     RFCOMM_TRACE_WARNING("port_open_continue no mx channel");
     port_release_port(p_port);
     return (PORT_NO_RESOURCES);
@@ -70,24 +68,22 @@
 
   p_port->rfc.p_mcb = p_mcb;
 
-  p_mcb->port_inx[p_port->dlci] = p_port->inx;
+  p_mcb->port_handles[p_port->dlci] = p_port->handle;
 
   /* Connection is up and we know local and remote features, select MTU */
   port_select_mtu(p_port);
 
   if (p_mcb->state == RFC_MX_STATE_CONNECTED) {
-    RFCOMM_ParNegReq(p_mcb, p_port->dlci, p_port->mtu);
+    RFCOMM_ParameterNegotiationRequest(p_mcb, p_port->dlci, p_port->mtu);
   } else if ((p_mcb->state == RFC_MX_STATE_IDLE) ||
              (p_mcb->state == RFC_MX_STATE_DISC_WAIT_UA)) {
-    /* In RFC_MX_STATE_IDLE state, MX state machine will create connection */
-    /* In RFC_MX_STATE_DISC_WAIT_UA state, MX state machine will recreate
-     * connection */
-    /*    after disconnecting is completed */
+    // In RFC_MX_STATE_IDLE state, MX state machine will create connection
+    // In RFC_MX_STATE_DISC_WAIT_UA state, MX state machine will recreate
+    // connection after disconnecting is completed
     RFCOMM_StartReq(p_mcb);
   } else {
-    /* MX state machine ignores RFC_MX_EVENT_START_REQ in these states */
-    /* When it enters RFC_MX_STATE_CONNECTED, it will check any openning ports
-     */
+    // MX state machine ignores RFC_MX_EVENT_START_REQ in these states
+    // When it enters RFC_MX_STATE_CONNECTED, it will check any openning ports
     RFCOMM_TRACE_DEBUG(
         "port_open_continue: mx state(%d) mx channel is openning",
         p_mcb->state);
@@ -128,7 +124,8 @@
 
   if (p_mcb == NULL) return;
 
-  RFCOMM_PortNegReq(p_mcb, p_port->dlci, &p_port->user_port_pars);
+  RFCOMM_PortParameterNegotiationRequest(p_mcb, p_port->dlci,
+                                         &p_port->user_port_pars);
 }
 
 /*******************************************************************************
@@ -162,14 +159,14 @@
   if (p_port->ev_mask & PORT_EV_ERR) events |= PORT_EV_ERR;
 
   if ((p_port->p_callback != NULL) && events)
-    p_port->p_callback(events, p_port->inx);
+    p_port->p_callback(events, p_port->handle);
 
   /* Check if RFCOMM side has been closed while the message was queued */
   if ((p_mcb == NULL) || (p_port->rfc.state == RFC_STATE_CLOSED)) {
     /* Call management callback function before calling port_release_port() to
      * clear tPort */
     if (p_port->p_mgmt_callback)
-      p_port->p_mgmt_callback(PORT_CLOSED, p_port->inx);
+      p_port->p_mgmt_callback(PORT_CLOSED, p_port->handle);
 
     port_release_port(p_port);
   } else {
@@ -188,37 +185,39 @@
  *
  ******************************************************************************/
 void PORT_StartCnf(tRFC_MCB* p_mcb, uint16_t result) {
-  tPORT* p_port;
-  int i;
   bool no_ports_up = true;
 
-  RFCOMM_TRACE_EVENT("PORT_StartCnf result:%d", result);
+  RFCOMM_TRACE_EVENT("%s: result %d", __func__, result);
 
-  p_port = &rfc_cb.port.port[0];
-  for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) {
+  tPORT* p_port = &rfc_cb.port.port[0];
+  for (int i = 0; i < MAX_RFC_PORTS; i++, p_port++) {
     if (p_port->rfc.p_mcb == p_mcb) {
       no_ports_up = false;
 
-      if (result == RFCOMM_SUCCESS)
-        RFCOMM_ParNegReq(p_mcb, p_port->dlci, p_port->mtu);
-      else {
-        RFCOMM_TRACE_WARNING("PORT_StartCnf failed result:%d", result);
+      if (result == RFCOMM_SUCCESS) {
+        RFCOMM_TRACE_EVENT("%s: dlci %d", __func__, p_port->dlci);
+        RFCOMM_ParameterNegotiationRequest(p_mcb, p_port->dlci, p_port->mtu);
+      } else {
+        RFCOMM_TRACE_WARNING("%s: failed result:%d", __func__, result);
 
         /* Warning: result is also set to 4 when l2cap connection
            fails due to l2cap connect cnf (no_resources) */
-        if (result == HCI_ERR_PAGE_TIMEOUT)
+        if (result == HCI_ERR_PAGE_TIMEOUT) {
           p_port->error = PORT_PAGE_TIMEOUT;
-        else
+        } else {
           p_port->error = PORT_START_FAILED;
+        }
 
         rfc_release_multiplexer_channel(p_mcb);
 
         /* Send event to the application */
-        if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECT_ERR))
-          (p_port->p_callback)(PORT_EV_CONNECT_ERR, p_port->inx);
+        if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECT_ERR)) {
+          (p_port->p_callback)(PORT_EV_CONNECT_ERR, p_port->handle);
+        }
 
-        if (p_port->p_mgmt_callback)
-          p_port->p_mgmt_callback(PORT_START_FAILED, p_port->inx);
+        if (p_port->p_mgmt_callback) {
+          p_port->p_mgmt_callback(PORT_START_FAILED, p_port->handle);
+        }
 
         port_release_port(p_port);
       }
@@ -272,12 +271,9 @@
  ******************************************************************************/
 void PORT_ParNegInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl,
                     uint8_t k) {
+  RFCOMM_TRACE_EVENT("%s: bd_addr=%s, dlci=%d, mtu=%d", __func__,
+                     p_mcb->bd_addr.ToString().c_str(), dlci, mtu);
   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
-  uint8_t our_cl;
-  uint8_t our_k;
-
-  RFCOMM_TRACE_EVENT("PORT_ParNegInd dlci:%d mtu:%d", dlci, mtu);
-
   if (!p_port) {
     /* This can be a first request for this port */
     p_port = port_find_dlci_port(dlci);
@@ -292,9 +288,9 @@
       rfc_check_mcb_active(p_mcb);
       return;
     }
-    RFCOMM_TRACE_EVENT("%s: port_inx[dlci:%d]:%d->%d", __func__, dlci,
-                       p_mcb->port_inx[dlci], p_port->inx);
-    p_mcb->port_inx[dlci] = p_port->inx;
+    RFCOMM_TRACE_EVENT("%s: port_handles[dlci:%d]:%d->%d", __func__, dlci,
+                       p_mcb->port_handles[dlci], p_port->handle);
+    p_mcb->port_handles[dlci] = p_port->handle;
   }
 
   p_port->bd_addr = p_mcb->bd_addr;
@@ -329,6 +325,8 @@
   /* after the DLCI is already established-- the PN in that case must have cl =
    * 0. */
   /* See RFCOMM spec 5.5.3 */
+  uint8_t our_cl;
+  uint8_t our_k;
   if (cl == RFCOMM_PN_CONV_LAYER_TYPE_1) {
     our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
     our_k = 0;
@@ -346,7 +344,7 @@
     our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
     our_k = 0;
   }
-  RFCOMM_ParNegRsp(p_mcb, dlci, p_port->mtu, our_cl, our_k);
+  RFCOMM_ParameterNegotiationResponse(p_mcb, dlci, p_port->mtu, our_cl, our_k);
 }
 
 /*******************************************************************************
@@ -362,12 +360,13 @@
  ******************************************************************************/
 void PORT_ParNegCnf(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl,
                     uint8_t k) {
-  tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
-
   RFCOMM_TRACE_EVENT("PORT_ParNegCnf dlci:%d mtu:%d cl: %d k: %d", dlci, mtu,
                      cl, k);
-
-  if (!p_port) return;
+  tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+  if (!p_port) {
+    LOG(WARNING) << __func__ << ": port is null for " << p_mcb->bd_addr;
+    return;
+  }
 
   /* Flow control mechanism not set yet.  Negotiate flow control mechanism. */
   if (p_mcb->flow == PORT_FC_UNDEFINED) {
@@ -377,19 +376,17 @@
     if ((PORT_FC_DEFAULT == PORT_FC_TS710) &&
         (cl == RFCOMM_PN_CONV_LAYER_CBFC_R)) {
       RFCOMM_TRACE_WARNING("%s, negotiation fails, index=%d", __func__,
-                           p_port->inx);
+                           p_port->handle);
       rfc_send_disc(p_mcb, p_port->dlci);
       rfc_port_closed(p_port);
       return;
-    }
-    /* Our stack is configured for credit-based and they responded with
-       credit-based. */
-    else if (cl == RFCOMM_PN_CONV_LAYER_CBFC_R) {
+    } else if (cl == RFCOMM_PN_CONV_LAYER_CBFC_R) {
+      // Our stack is configured for credit-based and they responded with
+      // credit-based.
       p_mcb->flow = PORT_FC_CREDIT;
-    }
-    /* They responded with any other value.  Treat this as negotiation to
-       TS07.10. */
-    else {
+    } else {
+      // They responded with any other value.  Treat this as negotiation to
+      // TS07.10.
       p_mcb->flow = PORT_FC_TS710;
     }
   }
@@ -436,7 +433,7 @@
       RFCOMM_DlcEstablishRsp(p_mcb, dlci, 0, RFCOMM_ERROR);
       return;
     }
-    p_mcb->port_inx[dlci] = p_port->inx;
+    p_mcb->port_handles[dlci] = p_port->handle;
   }
 
   /* If L2CAP's mtu less then RFCOMM's take it */
@@ -450,10 +447,10 @@
   /* This is the server side.  If application wants to know when connection */
   /* is established, thats the place */
   if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED))
-    (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx);
+    (p_port->p_callback)(PORT_EV_CONNECTED, p_port->handle);
 
   if (p_port->p_mgmt_callback)
-    p_port->p_mgmt_callback(PORT_SUCCESS, p_port->inx);
+    p_port->p_mgmt_callback(PORT_SUCCESS, p_port->handle);
 
   p_port->state = PORT_STATE_OPENED;
 }
@@ -490,10 +487,10 @@
   rfc_timer_stop(p_mcb);
 
   if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED))
-    (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx);
+    (p_port->p_callback)(PORT_EV_CONNECTED, p_port->handle);
 
   if (p_port->p_mgmt_callback)
-    p_port->p_mgmt_callback(PORT_SUCCESS, p_port->inx);
+    p_port->p_mgmt_callback(PORT_SUCCESS, p_port->handle);
 
   p_port->state = PORT_STATE_OPENED;
 
@@ -501,7 +498,8 @@
    */
   if ((p_port->uuid == UUID_SERVCLASS_DIALUP_NETWORKING) ||
       (p_port->uuid == UUID_SERVCLASS_FAX))
-    RFCOMM_PortNegReq(p_port->rfc.p_mcb, p_port->dlci, NULL);
+    RFCOMM_PortParameterNegotiationRequest(p_port->rfc.p_mcb, p_port->dlci,
+                                           NULL);
   else
     RFCOMM_ControlReq(p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
 }
@@ -527,15 +525,15 @@
     /* This can be a first request for this port */
     p_port = port_find_dlci_port(dlci);
     if (!p_port) {
-      RFCOMM_PortNegRsp(p_mcb, dlci, p_pars, 0);
+      RFCOMM_PortParameterNegotiationResponse(p_mcb, dlci, p_pars, 0);
       return;
     }
-    p_mcb->port_inx[dlci] = p_port->inx;
+    p_mcb->port_handles[dlci] = p_port->handle;
   }
 
   /* Check if the flow control is acceptable on local side */
   p_port->peer_port_pars = *p_pars;
-  RFCOMM_PortNegRsp(p_mcb, dlci, p_pars, param_mask);
+  RFCOMM_PortParameterNegotiationResponse(p_mcb, dlci, p_pars, param_mask);
 }
 
 /*******************************************************************************
@@ -596,9 +594,9 @@
 
   p_port->peer_ctrl = *p_pars;
 
-  if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT))
+  if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT)) {
     RFCOMM_ControlReq(p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
-  else {
+  } else {
     /* If this is the first time we received control RFCOMM is connected */
     if (!(p_port->port_ctrl & PORT_CTRL_IND_RECEIVED)) {
       event |= (PORT_EV_CONNECTED & p_port->ev_mask);
@@ -615,7 +613,7 @@
 
   /* execute call back function only if the application is registered for events
    */
-  if (event && p_port->p_callback) (p_port->p_callback)(event, p_port->inx);
+  if (event && p_port->p_callback) (p_port->p_callback)(event, p_port->handle);
 
   RFCOMM_TRACE_EVENT(
       "PORT_ControlInd DTR_DSR : %d, RTS_CTS : %d, RI : %d, DCD : %d",
@@ -655,7 +653,7 @@
 
   /* execute call back function only if the application is registered for events
    */
-  if (event && p_port->p_callback) (p_port->p_callback)(event, p_port->inx);
+  if (event && p_port->p_callback) (p_port->p_callback)(event, p_port->handle);
 }
 
 /*******************************************************************************
@@ -683,7 +681,7 @@
   if (line_status & ~(PORT_ERR_OVERRUN | PORT_ERR_BREAK)) event |= PORT_EV_ERR;
 
   if ((p_port->p_callback != NULL) && (p_port->ev_mask & event))
-    p_port->p_callback((p_port->ev_mask & event), p_port->inx);
+    p_port->p_callback((p_port->ev_mask & event), p_port->handle);
 }
 
 /*******************************************************************************
@@ -695,12 +693,10 @@
  *
  ******************************************************************************/
 void PORT_DlcReleaseInd(tRFC_MCB* p_mcb, uint8_t dlci) {
+  VLOG(1) << __func__ << ": dlci=" << std::to_string(dlci)
+          << ", bd_addr=" << p_mcb->bd_addr;
   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
-
-  RFCOMM_TRACE_EVENT("PORT_DlcReleaseInd");
-
   if (!p_port) return;
-
   port_rfc_closed(p_port, PORT_CLOSED);
 }
 
@@ -775,7 +771,7 @@
    * receive data */
   if (p_port->p_data_co_callback) {
     /* Another packet is delivered to user.  Send credits to peer if required */
-    if (p_port->p_data_co_callback(p_port->inx, (uint8_t*)p_buf, -1,
+    if (p_port->p_data_co_callback(p_port->handle, (uint8_t*)p_buf, -1,
                                    DATA_CO_CALLBACK_TYPE_INCOMING)) {
       port_flow_control_peer(p_port, true, 1);
     } else {
@@ -788,8 +784,8 @@
   if (p_port->p_data_callback) {
     /* Another packet is delivered to user.  Send credits to peer if required */
     port_flow_control_peer(p_port, true, 1);
-    p_port->p_data_callback(p_port->inx, (uint8_t*)(p_buf + 1) + p_buf->offset,
-                            p_buf->len);
+    p_port->p_data_callback(p_port->handle,
+                            (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
     osi_free(p_buf);
     return;
   }
@@ -837,7 +833,7 @@
   /* Mask out all events that are not of interest to user */
   events &= p_port->ev_mask;
 
-  if (p_port->p_callback && events) p_port->p_callback(events, p_port->inx);
+  if (p_port->p_callback && events) p_port->p_callback(events, p_port->handle);
 }
 
 /*******************************************************************************
@@ -884,7 +880,8 @@
     events &= p_port->ev_mask;
 
     /* Send event to the application */
-    if (p_port->p_callback && events) (p_port->p_callback)(events, p_port->inx);
+    if (p_port->p_callback && events)
+      (p_port->p_callback)(events, p_port->handle);
 
     /* If DLCI is not 0 event applies to one port only */
     if (dlci != 0) break;
@@ -962,7 +959,7 @@
     p_port->rfc.state = RFC_STATE_CLOSED;
 
     if (p_mcb) {
-      p_mcb->port_inx[p_port->dlci] = 0;
+      p_mcb->port_handles[p_port->dlci] = 0;
 
       /* If there are no more ports opened on this MCB release it */
       rfc_check_mcb_active(p_mcb);
@@ -993,17 +990,19 @@
   }
 
   if ((p_port->p_callback != NULL) && events)
-    p_port->p_callback(events, p_port->inx);
+    p_port->p_callback(events, p_port->handle);
 
-  if (p_port->p_mgmt_callback) p_port->p_mgmt_callback(res, p_port->inx);
+  if (p_port->p_mgmt_callback) p_port->p_mgmt_callback(res, p_port->handle);
 
   p_port->rfc.state = RFC_STATE_CLOSED;
 
-  RFCOMM_TRACE_WARNING(
-      "%s: RFCOMM connection closed, index=%d, state=%d reason=%s[%d], "
-      "UUID=%04X, bd_addr=%s, is_server=%d",
-      __func__, p_port->inx, p_port->state, PORT_GetResultString(res), res,
-      p_port->uuid, p_port->bd_addr.ToString().c_str(), p_port->is_server);
+  LOG(INFO) << __func__ << ": RFCOMM connection closed, index="
+            << std::to_string(p_port->handle)
+            << ", state=" << std::to_string(p_port->state)
+            << ", reason=" << PORT_GetResultString(res) << "["
+            << std::to_string(res) << "], UUID=" << loghex(p_port->uuid)
+            << ", bd_addr=" << p_port->bd_addr
+            << ", is_server=" << p_port->is_server;
 
   port_release_port(p_port);
 }
diff --git a/stack/rfcomm/port_utils.cc b/stack/rfcomm/port_utils.cc
index 9dc05c8..7798375 100644
--- a/stack/rfcomm/port_utils.cc
+++ b/stack/rfcomm/port_utils.cc
@@ -61,36 +61,36 @@
  *
  ******************************************************************************/
 tPORT* port_allocate_port(uint8_t dlci, const RawAddress& bd_addr) {
-  tPORT* p_port = &rfc_cb.port.port[0];
-  uint8_t xx, yy;
-
-  for (xx = 0, yy = rfc_cb.rfc.last_port + 1; xx < MAX_RFC_PORTS; xx++, yy++) {
-    if (yy >= MAX_RFC_PORTS) yy = 0;
-
-    p_port = &rfc_cb.port.port[yy];
+  uint8_t port_index = rfc_cb.rfc.last_port_index + static_cast<uint8_t>(1);
+  // Loop at most MAX_RFC_PORTS items
+  for (int loop_counter = 0; loop_counter < MAX_RFC_PORTS;
+       loop_counter++, port_index++) {
+    if (port_index >= MAX_RFC_PORTS) {
+      port_index = 0;
+    }
+    tPORT* p_port = &rfc_cb.port.port[port_index];
     if (!p_port->in_use) {
+      // Assume that we already called port_release_port on this
       memset(p_port, 0, sizeof(tPORT));
-
       p_port->in_use = true;
-      p_port->inx = yy + 1;
-
-      /* During the open set default state for the port connection */
+      // handle is a port handle starting from 1
+      p_port->handle = port_index + static_cast<uint8_t>(1);
+      // During the open set default state for the port connection
       port_set_defaults(p_port);
-
       p_port->rfc.port_timer = alarm_new("rfcomm_port.port_timer");
-      rfc_cb.rfc.last_port = yy;
-
       p_port->dlci = dlci;
       p_port->bd_addr = bd_addr;
-
-      RFCOMM_TRACE_DEBUG("rfc_cb.port.port[%d]:%p allocated, last_port:%d", yy,
-                         p_port, rfc_cb.rfc.last_port);
-      VLOG(1) << __func__ << ": bd_addr:" << bd_addr;
-      return (p_port);
+      rfc_cb.rfc.last_port_index = port_index;
+      RFCOMM_TRACE_DEBUG(
+          "%s: rfc_cb.port.port[%d]:%p chosen, "
+          "last_port_index:%d, bd_addr=%s",
+          __func__, port_index, p_port, rfc_cb.rfc.last_port_index,
+          bd_addr.ToString().c_str());
+      return p_port;
     }
   }
-
-  /* If here, no free PORT found */
+  LOG(WARNING) << __func__ << ": running out of free ports for dlci "
+               << std::to_string(dlci) << ", bd_addr " << bd_addr;
   return nullptr;
 }
 
@@ -146,7 +146,7 @@
     packet_size = btm_get_max_packet_size(p_port->bd_addr);
     if (packet_size == 0) {
       /* something is very wrong */
-      RFCOMM_TRACE_WARNING("port_select_mtu bad packet size");
+      LOG(WARNING) << __func__ << ": bad packet size 0 for" << p_port->bd_addr;
       p_port->mtu = RFCOMM_DEFAULT_MTU;
     } else {
       /* We try to negotiate MTU that each packet can be split into whole
@@ -166,17 +166,16 @@
         p_port->mtu = ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) / packet_size *
                        packet_size) -
                       RFCOMM_DATA_OVERHEAD - L2CAP_PKT_OVERHEAD;
-        RFCOMM_TRACE_DEBUG(
-            "port_select_mtu selected %d based on connection speed",
-            p_port->mtu);
+        RFCOMM_TRACE_DEBUG("%s: selected %d based on connection speed",
+                           __func__, p_port->mtu);
       } else {
         p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
-        RFCOMM_TRACE_DEBUG(
-            "port_select_mtu selected %d based on l2cap PDU size", p_port->mtu);
+        RFCOMM_TRACE_DEBUG("%s: selected %d based on l2cap PDU size", __func__,
+                           p_port->mtu);
       }
     }
   } else {
-    RFCOMM_TRACE_DEBUG("port_select_mtu application selected %d", p_port->mtu);
+    RFCOMM_TRACE_DEBUG("%s: application selected %d", __func__, p_port->mtu);
   }
   p_port->credit_rx_max = (PORT_RX_HIGH_WM / p_port->mtu);
   if (p_port->credit_rx_max > PORT_RX_BUF_HIGH_WM)
@@ -188,7 +187,7 @@
   if (p_port->rx_buf_critical > PORT_RX_BUF_CRITICAL_WM)
     p_port->rx_buf_critical = PORT_RX_BUF_CRITICAL_WM;
   RFCOMM_TRACE_DEBUG(
-      "port_select_mtu credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d",
+      "%s: credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d", __func__,
       p_port->credit_rx_max, p_port->credit_rx_low, p_port->rx_buf_critical);
 }
 
@@ -226,7 +225,7 @@
 
   if (p_port->rfc.state == RFC_STATE_CLOSED) {
     if (p_port->rfc.p_mcb) {
-      p_port->rfc.p_mcb->port_inx[p_port->dlci] = 0;
+      p_port->rfc.p_mcb->port_handles[p_port->dlci] = 0;
 
       /* If there are no more ports opened on this MCB release it */
       rfc_check_mcb_active(p_port->rfc.p_mcb);
@@ -242,7 +241,8 @@
     mutex_global_unlock();
 
     if (p_port->keep_port_handle) {
-      RFCOMM_TRACE_DEBUG("%s Re-initialize handle: %d", __func__, p_port->inx);
+      RFCOMM_TRACE_DEBUG("%s Re-initialize handle: %d", __func__,
+                         p_port->handle);
 
       /* save event mask and callback */
       uint32_t mask = p_port->ev_mask;
@@ -264,7 +264,7 @@
       p_port->local_ctrl.modem_signal = p_port->default_signal_state;
       p_port->bd_addr = RawAddress::kAny;
     } else {
-      RFCOMM_TRACE_DEBUG("%s Clean-up handle: %d", __func__, p_port->inx);
+      RFCOMM_TRACE_DEBUG("%s Clean-up handle: %d", __func__, p_port->handle);
       alarm_free(p_port->rfc.port_timer);
       memset(p_port, 0, sizeof(tPORT));
     }
@@ -317,15 +317,14 @@
     return nullptr;
   }
 
-  uint8_t inx = p_mcb->port_inx[dlci];
-  if (inx == 0) {
-    LOG(WARNING) << __func__
-                 << ": Cannot find allocated RFCOMM app port for DLCI "
-                 << std::to_string(dlci) << " on " << p_mcb->bd_addr
-                 << ", p_mcb=" << p_mcb;
+  uint8_t handle = p_mcb->port_handles[dlci];
+  if (handle == 0) {
+    LOG(INFO) << __func__ << ": Cannot find allocated RFCOMM app port for DLCI "
+              << std::to_string(dlci) << " on " << p_mcb->bd_addr
+              << ", p_mcb=" << p_mcb;
     return nullptr;
   }
-  return &rfc_cb.port.port[inx - 1];
+  return &rfc_cb.port.port[handle - 1];
 }
 
 /*******************************************************************************
diff --git a/stack/rfcomm/rfc_int.h b/stack/rfcomm/rfc_int.h
index 05afa9d..22aab66 100644
--- a/stack/rfcomm/rfc_int.h
+++ b/stack/rfcomm/rfc_int.h
@@ -56,18 +56,23 @@
 
 extern void RFCOMM_DlcReleaseReq(tRFC_MCB* p_mcb, uint8_t dlci);
 
-extern void RFCOMM_ParNegReq(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu);
-extern void RFCOMM_ParNegRsp(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu,
-                             uint8_t cl, uint8_t k);
+extern void RFCOMM_ParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci,
+                                               uint16_t mtu);
+extern void RFCOMM_ParameterNegotiationResponse(tRFC_MCB* p_mcb, uint8_t dlci,
+                                                uint16_t mtu, uint8_t cl,
+                                                uint8_t k);
 
 extern void RFCOMM_TestReq(uint8_t* p_data, uint16_t len);
 
 extern void RFCOMM_FlowReq(tRFC_MCB* p_mcb, uint8_t dlci, bool state);
 
-extern void RFCOMM_PortNegReq(tRFC_MCB* p_mcb, uint8_t dlci,
-                              tPORT_STATE* p_pars);
-extern void RFCOMM_PortNegRsp(tRFC_MCB* p_mcb, uint8_t dlci,
-                              tPORT_STATE* p_pars, uint16_t param_mask);
+extern void RFCOMM_PortParameterNegotiationRequest(tRFC_MCB* p_mcb,
+                                                   uint8_t dlci,
+                                                   tPORT_STATE* p_pars);
+extern void RFCOMM_PortParameterNegotiationResponse(tRFC_MCB* p_mcb,
+                                                    uint8_t dlci,
+                                                    tPORT_STATE* p_pars,
+                                                    uint16_t param_mask);
 
 extern void RFCOMM_ControlReq(tRFC_MCB* p_mcb, uint8_t dlci,
                               tPORT_CTRL* p_pars);
@@ -221,7 +226,7 @@
   tRFC_MCB* p_rfc_lcid_mcb[MAX_L2CAP_CHANNELS];
   bool peer_rx_disabled; /* If true peer sent FCOFF */
   uint8_t last_mux;      /* Last mux allocated */
-  uint8_t last_port;     /* Last port allocated */
+  uint8_t last_port_index;  // Index of last port allocated in rfc_cb.port
 } tRFCOMM_CB;
 
 /* Main Control Block for the RFCOMM Layer (PORT and RFC) */
diff --git a/stack/rfcomm/rfc_l2cap_if.cc b/stack/rfcomm/rfc_l2cap_if.cc
index a20f399..380f5bf 100644
--- a/stack/rfcomm/rfc_l2cap_if.cc
+++ b/stack/rfcomm/rfc_l2cap_if.cc
@@ -110,14 +110,14 @@
     } else {
       /* we cannot accept connection request from peer at this state */
       /* don't update lcid */
-      p_mcb = NULL;
+      p_mcb = nullptr;
     }
   } else {
     /* store mcb even if null */
     rfc_save_lcid_mcb(p_mcb, lcid);
   }
 
-  if (p_mcb == NULL) {
+  if (p_mcb == nullptr) {
     L2CA_ConnectRsp(bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0);
     return;
   }
@@ -163,13 +163,13 @@
 
       /* update direction bit */
       for (int i = 0; i < RFCOMM_MAX_DLCI; i += 2) {
-        uint8_t idx = p_mcb->port_inx[i];
-        if (idx != 0) {
-          p_mcb->port_inx[i] = 0;
-          p_mcb->port_inx[i + 1] = idx;
-          rfc_cb.port.port[idx - 1].dlci += 1;
-          RFCOMM_TRACE_DEBUG("RFCOMM MX, port_handle=%d, DLCI[%d->%d]", idx, i,
-                             rfc_cb.port.port[idx - 1].dlci);
+        uint8_t handle = p_mcb->port_handles[i];
+        if (handle != 0) {
+          p_mcb->port_handles[i] = 0;
+          p_mcb->port_handles[i + 1] = handle;
+          rfc_cb.port.port[handle - 1].dlci += 1;
+          RFCOMM_TRACE_DEBUG("RFCOMM MX, port_handle=%d, DLCI[%d->%d]", handle,
+                             i, rfc_cb.port.port[handle - 1].dlci);
         }
       }
 
@@ -254,17 +254,16 @@
  *
  ******************************************************************************/
 void RFCOMM_DisconnectInd(uint16_t lcid, bool is_conf_needed) {
+  VLOG(1) << __func__ << ": lcid=" << loghex(lcid)
+          << ", is_conf_needed=" << is_conf_needed;
   tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
-
   if (is_conf_needed) {
     L2CA_DisconnectRsp(lcid);
   }
-
   if (!p_mcb) {
-    RFCOMM_TRACE_WARNING("RFCOMM_DisconnectInd LCID:0x%x", lcid);
+    LOG(WARNING) << __func__ << ": no mcb for lcid " << loghex(lcid);
     return;
   }
-
   rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_DISC_IND, nullptr);
 }
 
@@ -299,7 +298,7 @@
   }
 
   if (rfc_cb.rfc.rx_frame.dlci == RFCOMM_MX_DLCI) {
-    RFCOMM_TRACE_DEBUG("%s: Handle multiplexer event %d, p_mcb=%p", __func__,
+    RFCOMM_TRACE_DEBUG("%s: handle multiplexer event %d, p_mcb=%p", __func__,
                        event, p_mcb);
     /* Take special care of the Multiplexer Control Messages */
     if (event == RFC_EVENT_UIH) {
@@ -341,10 +340,11 @@
       osi_free(p_buf);
       return;
     }
-    RFCOMM_TRACE_DEBUG("%s: port_inx[dlci=%d]:%d->%d, p_mcb=%p", __func__,
+    RFCOMM_TRACE_DEBUG("%s: port_handles[dlci=%d]:%d->%d, p_mcb=%p", __func__,
                        rfc_cb.rfc.rx_frame.dlci,
-                       p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci], p_port->inx);
-    p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci] = p_port->inx;
+                       p_mcb->port_handles[rfc_cb.rfc.rx_frame.dlci],
+                       p_port->handle);
+    p_mcb->port_handles[rfc_cb.rfc.rx_frame.dlci] = p_port->handle;
     p_port->rfc.p_mcb = p_mcb;
   }
 
@@ -419,6 +419,14 @@
  *
  ******************************************************************************/
 void rfc_save_lcid_mcb(tRFC_MCB* p_mcb, uint16_t lcid) {
-  if (lcid < L2CAP_BASE_APPL_CID) return;
-  rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID] = p_mcb;
+  if (lcid < L2CAP_BASE_APPL_CID) {
+    LOG(ERROR) << __func__ << ": LCID " << lcid << " is too small";
+    return;
+  }
+  auto mcb_index = static_cast<size_t>(lcid - L2CAP_BASE_APPL_CID);
+  if (mcb_index >= MAX_L2CAP_CHANNELS) {
+    LOG(ERROR) << __func__ << ": LCID " << lcid << " is too large";
+    return;
+  }
+  rfc_cb.rfc.p_rfc_lcid_mcb[mcb_index] = p_mcb;
 }
diff --git a/stack/rfcomm/rfc_mx_fsm.cc b/stack/rfcomm/rfc_mx_fsm.cc
index dfab62f..12ed1f7 100644
--- a/stack/rfcomm/rfc_mx_fsm.cc
+++ b/stack/rfcomm/rfc_mx_fsm.cc
@@ -69,6 +69,7 @@
  *
  ******************************************************************************/
 void rfc_mx_sm_execute(tRFC_MCB* p_mcb, uint16_t event, void* p_data) {
+  RFCOMM_TRACE_DEBUG("%s: STATE=%d, EVENT=%d", __func__, p_mcb->state, event);
   switch (p_mcb->state) {
     case RFC_MX_STATE_IDLE:
       rfc_mx_sm_state_idle(p_mcb, event, p_data);
@@ -112,7 +113,7 @@
  *
  ******************************************************************************/
 void rfc_mx_sm_state_idle(tRFC_MCB* p_mcb, uint16_t event, void* p_data) {
-  RFCOMM_TRACE_EVENT("rfc_mx_sm_state_idle - evt:%d", event);
+  RFCOMM_TRACE_EVENT("%s: evt %d", __func__, event);
   switch (event) {
     case RFC_MX_EVENT_START_REQ: {
       /* Initialize L2CAP MTU */
@@ -120,7 +121,9 @@
 
       uint16_t lcid = L2CA_ConnectReq(BT_PSM_RFCOMM, p_mcb->bd_addr);
       if (lcid == 0) {
-        rfc_save_lcid_mcb(NULL, p_mcb->lcid);
+        LOG(ERROR) << __func__ << ": failed to open L2CAP channel for "
+                   << p_mcb->bd_addr;
+        rfc_save_lcid_mcb(nullptr, p_mcb->lcid);
         p_mcb->lcid = 0;
         PORT_StartCnf(p_mcb, RFCOMM_ERROR);
         return;
@@ -182,7 +185,7 @@
  ******************************************************************************/
 void rfc_mx_sm_state_wait_conn_cnf(tRFC_MCB* p_mcb, uint16_t event,
                                    void* p_data) {
-  RFCOMM_TRACE_EVENT("rfc_mx_sm_state_wait_conn_cnf - evt:%d", event);
+  RFCOMM_TRACE_EVENT("%s: evt %d", __func__, event);
   switch (event) {
     case RFC_MX_EVENT_START_REQ:
       RFCOMM_TRACE_ERROR("Mx error state %d event %d", p_mcb->state, event);
@@ -218,7 +221,7 @@
       /* we gave up outgoing connection request then try peer's request */
       if (p_mcb->pending_lcid) {
         uint16_t i;
-        uint8_t idx;
+        uint8_t handle;
 
         RFCOMM_TRACE_DEBUG(
             "RFCOMM MX retry as acceptor in collision case - evt:%d in "
@@ -233,13 +236,13 @@
 
         /* update direction bit */
         for (i = 0; i < RFCOMM_MAX_DLCI; i += 2) {
-          idx = p_mcb->port_inx[i];
-          if (idx != 0) {
-            p_mcb->port_inx[i] = 0;
-            p_mcb->port_inx[i + 1] = idx;
-            rfc_cb.port.port[idx - 1].dlci += 1;
+          handle = p_mcb->port_handles[i];
+          if (handle != 0) {
+            p_mcb->port_handles[i] = 0;
+            p_mcb->port_handles[i + 1] = handle;
+            rfc_cb.port.port[handle - 1].dlci += 1;
             RFCOMM_TRACE_DEBUG("RFCOMM MX - DLCI:%d -> %d", i,
-                               rfc_cb.port.port[idx - 1].dlci);
+                               rfc_cb.port.port[handle - 1].dlci);
           }
         }
 
@@ -264,7 +267,7 @@
  *
  ******************************************************************************/
 void rfc_mx_sm_state_configure(tRFC_MCB* p_mcb, uint16_t event, void* p_data) {
-  RFCOMM_TRACE_EVENT("rfc_mx_sm_state_configure - evt:%d", event);
+  RFCOMM_TRACE_EVENT("%s: event %d", __func__, event);
   switch (event) {
     case RFC_MX_EVENT_START_REQ:
     case RFC_MX_EVENT_CONN_CNF:
@@ -286,6 +289,8 @@
       return;
 
     case RFC_EVENT_TIMEOUT:
+      LOG(ERROR) << __func__ << ": L2CAP configuration timeout for "
+                 << p_mcb->bd_addr;
       p_mcb->state = RFC_MX_STATE_IDLE;
       L2CA_DisconnectReq(p_mcb->lcid);
 
@@ -308,7 +313,7 @@
  ******************************************************************************/
 void rfc_mx_sm_sabme_wait_ua(tRFC_MCB* p_mcb, uint16_t event,
                              UNUSED_ATTR void* p_data) {
-  RFCOMM_TRACE_EVENT("rfc_mx_sm_sabme_wait_ua - evt:%d", event);
+  RFCOMM_TRACE_EVENT("%s: event %d", __func__, event);
   switch (event) {
     case RFC_MX_EVENT_START_REQ:
     case RFC_MX_EVENT_CONN_CNF:
@@ -368,7 +373,7 @@
  *
  ******************************************************************************/
 void rfc_mx_sm_state_wait_sabme(tRFC_MCB* p_mcb, uint16_t event, void* p_data) {
-  RFCOMM_TRACE_EVENT("rfc_mx_sm_state_wait_sabme - evt:%d", event);
+  RFCOMM_TRACE_EVENT("%s: event %d", __func__, event);
   switch (event) {
     case RFC_MX_EVENT_DISC_IND:
       p_mcb->state = RFC_MX_STATE_IDLE;
@@ -431,7 +436,7 @@
  ******************************************************************************/
 void rfc_mx_sm_state_connected(tRFC_MCB* p_mcb, uint16_t event,
                                UNUSED_ATTR void* p_data) {
-  RFCOMM_TRACE_EVENT("rfc_mx_sm_state_connected - evt:%d", event);
+  RFCOMM_TRACE_EVENT("%s: event %d", __func__, event);
 
   switch (event) {
     case RFC_EVENT_TIMEOUT:
@@ -475,7 +480,7 @@
                                   void* p_data) {
   BT_HDR* p_buf;
 
-  RFCOMM_TRACE_EVENT("rfc_mx_sm_state_disc_wait_ua - evt:%d", event);
+  RFCOMM_TRACE_EVENT("%s: event %d", __func__, event);
   switch (event) {
     case RFC_EVENT_UA:
     case RFC_EVENT_DM:
@@ -549,12 +554,8 @@
  *
  ******************************************************************************/
 static void rfc_mx_send_config_req(tRFC_MCB* p_mcb) {
-  tL2CAP_CFG_INFO cfg;
-
   RFCOMM_TRACE_EVENT("rfc_mx_send_config_req");
-
-  memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
-
+  tL2CAP_CFG_INFO cfg = {};
   cfg.mtu_present = true;
   cfg.mtu = L2CAP_MTU_SIZE;
 
@@ -580,11 +581,15 @@
  *
  ******************************************************************************/
 static void rfc_mx_conf_cnf(tRFC_MCB* p_mcb, tL2CAP_CFG_INFO* p_cfg) {
-  RFCOMM_TRACE_EVENT("rfc_mx_conf_cnf p_cfg:%08x res:%d ", p_cfg,
+  RFCOMM_TRACE_EVENT("rfc_mx_conf_cnf p_cfg:%08x result:%d ", p_cfg,
                      (p_cfg) ? p_cfg->result : 0);
 
   if (p_cfg->result != L2CAP_CFG_OK) {
+    LOG(ERROR) << __func__ << ": failed to configure L2CAP for "
+               << p_mcb->bd_addr;
     if (p_mcb->is_initiator) {
+      LOG(ERROR) << __func__ << ": disconnect L2CAP due to config failure for "
+                 << p_mcb->bd_addr;
       PORT_StartCnf(p_mcb, p_cfg->result);
       L2CA_DisconnectReq(p_mcb->lcid);
     }
@@ -619,10 +624,11 @@
 static void rfc_mx_conf_ind(tRFC_MCB* p_mcb, tL2CAP_CFG_INFO* p_cfg) {
   /* Save peer L2CAP MTU if present */
   /* RFCOMM adds 3-4 bytes in the beginning and 1 bytes FCS */
-  if (p_cfg->mtu_present)
+  if (p_cfg->mtu_present) {
     p_mcb->peer_l2cap_mtu = p_cfg->mtu - RFCOMM_MIN_OFFSET - 1;
-  else
+  } else {
     p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1;
+  }
 
   p_cfg->mtu_present = false;
   p_cfg->flush_to_present = false;
diff --git a/stack/rfcomm/rfc_port_fsm.cc b/stack/rfcomm/rfc_port_fsm.cc
index 4ff4628..947c23b 100644
--- a/stack/rfcomm/rfc_port_fsm.cc
+++ b/stack/rfcomm/rfc_port_fsm.cc
@@ -64,8 +64,11 @@
  *
  ******************************************************************************/
 void rfc_port_sm_execute(tPORT* p_port, uint16_t event, void* p_data) {
+  VLOG(1) << __func__ << ": PORT=" << std::to_string(p_port->handle)
+          << ", STATE=" << std::to_string(p_port->rfc.state)
+          << ", EVENT=" << event;
   if (!p_port) {
-    RFCOMM_TRACE_WARNING("NULL port event %d", event);
+    LOG(WARNING) << __func__ << ": NULL port event " << event;
     return;
   }
 
@@ -143,7 +146,8 @@
       return;
 
     case RFC_EVENT_DM:
-      RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__, p_port->inx);
+      RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__,
+                           p_port->handle);
       rfc_port_closed(p_port);
       return;
 
@@ -194,7 +198,7 @@
 
     case RFC_EVENT_CLEAR:
       RFCOMM_TRACE_WARNING("%s, RFC_EVENT_CLEAR, index=%d", __func__,
-                           p_port->inx);
+                           p_port->handle);
       rfc_port_closed(p_port);
       return;
 
@@ -210,7 +214,8 @@
       return;
 
     case RFC_EVENT_DM:
-      RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__, p_port->inx);
+      RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__,
+                           p_port->handle);
       p_port->rfc.p_mcb->is_disc_initiator = true;
       PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci,
                            p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
@@ -219,7 +224,7 @@
 
     case RFC_EVENT_DISC:
       RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DISC, index=%d", __func__,
-                           p_port->inx);
+                           p_port->handle);
       rfc_send_ua(p_port->rfc.p_mcb, p_port->dlci);
       PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci,
                            p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
@@ -282,7 +287,7 @@
 
     case RFC_EVENT_CLEAR:
       RFCOMM_TRACE_WARNING("%s, RFC_EVENT_CLEAR, index=%d", __func__,
-                           p_port->inx);
+                           p_port->handle);
       btm_sec_abort_access_req(p_port->rfc.p_mcb->bd_addr);
       rfc_port_closed(p_port);
       return;
@@ -339,7 +344,8 @@
     case RFC_EVENT_SEC_COMPLETE:
       if (*((uint8_t*)p_data) != BTM_SUCCESS) {
         RFCOMM_TRACE_ERROR("%s, RFC_EVENT_SEC_COMPLETE, index=%d, result=%d",
-                           __func__, event, p_port->inx, *((uint8_t*)p_data));
+                           __func__, event, p_port->handle,
+                           *((uint8_t*)p_data));
         p_port->rfc.p_mcb->is_disc_initiator = true;
         PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci, 0,
                              RFCOMM_SECURITY_ERR);
@@ -359,7 +365,7 @@
 
     case RFC_EVENT_CLOSE:
       RFCOMM_TRACE_WARNING("%s, RFC_EVENT_CLOSE, index=%d", __func__,
-                           p_port->inx);
+                           p_port->handle);
       btm_sec_abort_access_req(p_port->rfc.p_mcb->bd_addr);
       rfc_port_closed(p_port);
       return;
@@ -403,7 +409,7 @@
 
     case RFC_EVENT_CLEAR:
       RFCOMM_TRACE_WARNING("%s, RFC_EVENT_CLEAR, index=%d", __func__,
-                           p_port->inx);
+                           p_port->handle);
       rfc_port_closed(p_port);
       return;
 
@@ -435,7 +441,8 @@
       return;
 
     case RFC_EVENT_DM:
-      RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__, p_port->inx);
+      RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM, index=%d", __func__,
+                           p_port->handle);
       PORT_DlcReleaseInd(p_port->rfc.p_mcb, p_port->dlci);
       rfc_port_closed(p_port);
       return;
@@ -484,7 +491,7 @@
 
     case RFC_EVENT_CLEAR:
       RFCOMM_TRACE_WARNING("%s, RFC_EVENT_CLEAR, index=%d", __func__, event,
-                           p_port->inx);
+                           p_port->handle);
       rfc_port_closed(p_port);
       return;
 
@@ -498,7 +505,7 @@
 
     case RFC_EVENT_DM:
       RFCOMM_TRACE_WARNING("%s, RFC_EVENT_DM|RFC_EVENT_UA[%d], index=%d",
-                           __func__, event, p_port->inx);
+                           __func__, event, p_port->handle);
       rfc_port_closed(p_port);
       return;
 
@@ -517,7 +524,7 @@
 
     case RFC_EVENT_TIMEOUT:
       RFCOMM_TRACE_ERROR("%s, RFC_EVENT_TIMEOUT, index=%d", __func__,
-                         p_port->inx);
+                         p_port->handle);
       rfc_port_closed(p_port);
       return;
   }
@@ -545,7 +552,9 @@
  *
  ******************************************************************************/
 void rfc_process_pn(tRFC_MCB* p_mcb, bool is_command, MX_FRAME* p_frame) {
-  tPORT* p_port;
+  RFCOMM_TRACE_DEBUG("%s: is_initiator=%d, is_cmd=%d, state=%d, bd_addr=%s",
+                     __func__, p_mcb->is_initiator, is_command, p_mcb->state,
+                     p_mcb->bd_addr.ToString().c_str());
   uint8_t dlci = p_frame->dlci;
 
   if (is_command) {
@@ -563,7 +572,7 @@
     return;
   }
   /* If we are not awaiting response just ignore it */
-  p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+  tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
   if ((p_port == nullptr) || !(p_port->rfc.expected_rsp & RFC_RSP_PN)) {
     LOG(WARNING) << ": Ignore unwanted response, p_mcb=" << p_mcb
                  << ", bd_addr=" << p_mcb->bd_addr
diff --git a/stack/rfcomm/rfc_port_if.cc b/stack/rfcomm/rfc_port_if.cc
index 2ce5f9e..097d774 100644
--- a/stack/rfcomm/rfc_port_if.cc
+++ b/stack/rfcomm/rfc_port_if.cc
@@ -115,7 +115,7 @@
 
 /*******************************************************************************
  *
- * Function         RFCOMM_ParNegReq
+ * Function         RFCOMM_ParameterNegotiationRequest
  *
  * Description      This function is called by the user app to start
  *                  DLC parameter negotiation.  Port emulation can send this
@@ -124,7 +124,8 @@
  *                  block.
  *
  ******************************************************************************/
-void RFCOMM_ParNegReq(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu) {
+void RFCOMM_ParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci,
+                                        uint16_t mtu) {
   uint8_t flow;
   uint8_t cl;
   uint8_t k;
@@ -166,14 +167,14 @@
 
 /*******************************************************************************
  *
- * Function         RFCOMM_ParNegRsp
+ * Function         RFCOMM_ParameterNegotiationResponse
  *
  * Description      This function is called by the user app to acknowledge
  *                  DLC parameter negotiation.
  *
  ******************************************************************************/
-void RFCOMM_ParNegRsp(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl,
-                      uint8_t k) {
+void RFCOMM_ParameterNegotiationResponse(tRFC_MCB* p_mcb, uint8_t dlci,
+                                         uint16_t mtu, uint8_t cl, uint8_t k) {
   if (p_mcb->state != RFC_MX_STATE_CONNECTED) return;
 
   /* Send Parameter Negotiation Response UIH frame */
@@ -182,7 +183,7 @@
 
 /*******************************************************************************
  *
- * Function         RFCOMM_PortNegReq
+ * Function         RFCOMM_PortParameterNegotiationRequest
  *
  * Description      This function is called by the user app to start
  *                  Remote Port parameter negotiation.  Port emulation can
@@ -191,7 +192,8 @@
  *                  control block.
  *
  ******************************************************************************/
-void RFCOMM_PortNegReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars) {
+void RFCOMM_PortParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci,
+                                            tPORT_STATE* p_pars) {
   if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
     PORT_PortNegCnf(p_mcb, dlci, nullptr, RFCOMM_ERROR);
     return;
@@ -215,14 +217,15 @@
 
 /*******************************************************************************
  *
- * Function         RFCOMM_PortNegRsp
+ * Function         RFCOMM_PortParameterNegotiationResponse
  *
  * Description      This function is called by the user app to acknowledge
  *                  Port parameters negotiation.
  *
  ******************************************************************************/
-void RFCOMM_PortNegRsp(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars,
-                       uint16_t param_mask) {
+void RFCOMM_PortParameterNegotiationResponse(tRFC_MCB* p_mcb, uint8_t dlci,
+                                             tPORT_STATE* p_pars,
+                                             uint16_t param_mask) {
   if (p_mcb->state != RFC_MX_STATE_CONNECTED) return;
 
   rfc_send_rpn(p_mcb, dlci, false, p_pars, param_mask);
diff --git a/stack/rfcomm/rfc_ts_frames.cc b/stack/rfcomm/rfc_ts_frames.cc
index 0c8ce09..51fbcac 100644
--- a/stack/rfcomm/rfc_ts_frames.cc
+++ b/stack/rfcomm/rfc_ts_frames.cc
@@ -153,14 +153,19 @@
   uint8_t credits;
 
   p_buf->offset -= RFCOMM_CTRL_FRAME_LEN;
-  if (p_buf->len > 127) p_buf->offset--;
+  if (p_buf->len > 127) {
+    p_buf->offset--;
+  }
 
-  if (dlci)
+  if (dlci) {
     credits = (uint8_t)p_buf->layer_specific;
-  else
+  } else {
     credits = 0;
+  }
 
-  if (credits) p_buf->offset--;
+  if (credits) {
+    p_buf->offset--;
+  }
 
   p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
 
@@ -218,11 +223,11 @@
   ** We will use the fact that we reply in the same context so rx_frame can
   *still be used.
   */
-  if (is_command)
+  if (is_command) {
     *p_data++ = RFCOMM_PN_PRIORITY_0;
-  else
+  } else {
     *p_data++ = rfc_cb.rfc.rx_frame.u.pn.priority;
-
+  }
   *p_data++ = RFCOMM_T1_DSEC;
   *p_data++ = mtu & 0xFF;
   *p_data++ = mtu >> 8;
@@ -527,8 +532,9 @@
     p_frame->credit = *p_data++;
     p_buf->len--;
     p_buf->offset++;
-  } else
+  } else {
     p_frame->credit = 0;
+  }
 
   if (p_buf->len != len) {
     RFCOMM_TRACE_ERROR("Bad Length2 %d %d", p_buf->len, len);
@@ -589,8 +595,9 @@
         /* we assume that this is ok to allow bad implementations to work */
         RFCOMM_TRACE_ERROR("Bad UIH - response");
         return (RFC_EVENT_UIH);
-      } else
+      } else {
         return (RFC_EVENT_UIH);
+      }
   }
 
   return (RFC_EVENT_BAD_FRAME);
@@ -609,7 +616,6 @@
   MX_FRAME* p_rx_frame = &rfc_cb.rfc.rx_frame;
   uint16_t length = p_buf->len;
   uint8_t ea, cr, mx_len;
-  bool is_command;
 
   p_rx_frame->ea = *p_data & RFCOMM_EA;
   p_rx_frame->cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
@@ -625,7 +631,7 @@
 
   length--;
 
-  is_command = p_rx_frame->cr;
+  bool is_command = p_rx_frame->cr;
 
   ea = *p_data & RFCOMM_EA;
 
@@ -644,8 +650,8 @@
     return;
   }
 
-  RFCOMM_TRACE_DEBUG("%s: type=%d, p_mcb=%p", __func__, p_rx_frame->type,
-                     p_mcb);
+  RFCOMM_TRACE_DEBUG("%s: type=0x%02x, bd_addr=%s", __func__, p_rx_frame->type,
+                     p_mcb->bd_addr.ToString().c_str());
   switch (p_rx_frame->type) {
     case RFCOMM_MX_PN:
       if (length != RFCOMM_MX_PN_LEN) {
diff --git a/stack/rfcomm/rfc_utils.cc b/stack/rfcomm/rfc_utils.cc
index 74e336a..616e24e 100644
--- a/stack/rfcomm/rfc_utils.cc
+++ b/stack/rfcomm/rfc_utils.cc
@@ -285,7 +285,7 @@
   uint16_t i;
 
   for (i = 0; i < RFCOMM_MAX_DLCI; i++) {
-    if (p_mcb->port_inx[i] != 0) {
+    if (p_mcb->port_handles[i] != 0) {
       p_mcb->is_disc_initiator = false;
       return;
     }
@@ -353,7 +353,7 @@
 
   /* If multiplexer channel was up mark it as down */
   if (p_mcb) {
-    p_mcb->port_inx[p_port->dlci] = 0;
+    p_mcb->port_handles[p_port->dlci] = 0;
 
     /* If there are no more ports opened on this MCB release it */
     rfc_check_mcb_active(p_mcb);
diff --git a/stack/test/common/mock_btm_layer.cc b/stack/test/common/mock_btm_layer.cc
new file mode 100644
index 0000000..1405c55
--- /dev/null
+++ b/stack/test/common/mock_btm_layer.cc
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "mock_btm_layer.h"
+
+static bluetooth::manager::MockBtmSecurityInternalInterface*
+    btm_security_internal_interface = nullptr;
+
+void bluetooth::manager::SetMockSecurityInternalInterface(
+    MockBtmSecurityInternalInterface* mock_btm_security_internal_interface) {
+  btm_security_internal_interface = mock_btm_security_internal_interface;
+}
+
+void btm_sec_abort_access_req(const RawAddress& bd_addr) {
+  btm_security_internal_interface->AbortAccessRequest(bd_addr);
+}
+
+tBTM_STATUS btm_sec_mx_access_request(const RawAddress& bd_addr, uint16_t psm,
+                                      bool is_originator, uint32_t mx_proto_id,
+                                      uint32_t mx_chan_id,
+                                      tBTM_SEC_CALLBACK* p_callback,
+                                      void* p_ref_data) {
+  return btm_security_internal_interface->MultiplexingProtocolAccessRequest(
+      bd_addr, psm, is_originator, mx_proto_id, mx_chan_id, p_callback,
+      p_ref_data);
+}
+
+uint16_t btm_get_max_packet_size(const RawAddress& addr) {
+  return RFCOMM_DEFAULT_MTU;
+}
\ No newline at end of file
diff --git a/stack/test/common/mock_btm_layer.h b/stack/test/common/mock_btm_layer.h
new file mode 100644
index 0000000..45f32d1
--- /dev/null
+++ b/stack/test/common/mock_btm_layer.h
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "btm_int.h"
+
+namespace bluetooth {
+namespace manager {
+
+class BtmSecurityInternalInterface {
+ public:
+  virtual void AbortAccessRequest(const RawAddress& bd_addr) = 0;
+  virtual tBTM_STATUS MultiplexingProtocolAccessRequest(
+      const RawAddress& bd_addr, uint16_t psm, bool is_originator,
+      uint32_t mx_proto_id, uint32_t mx_chan_id, tBTM_SEC_CALLBACK* p_callback,
+      void* p_ref_data) = 0;
+  virtual ~BtmSecurityInternalInterface() = default;
+};
+
+class MockBtmSecurityInternalInterface : public BtmSecurityInternalInterface {
+ public:
+  MOCK_METHOD1(AbortAccessRequest, void(const RawAddress& bd_addr));
+  MOCK_METHOD7(MultiplexingProtocolAccessRequest,
+               tBTM_STATUS(const RawAddress& bd_addr, uint16_t psm,
+                           bool is_originator, uint32_t mx_proto_id,
+                           uint32_t mx_chan_id, tBTM_SEC_CALLBACK* p_callback,
+                           void* p_ref_data));
+};
+
+/**
+ * Set the {@link MockBtmSecurityInternalInterface} for testing
+ *
+ * @param mock_btm_security_internal_interface pointer to mock btm security
+ * internal interface, could be null
+ */
+void SetMockSecurityInternalInterface(
+    MockBtmSecurityInternalInterface* mock_btm_security_internal_interface);
+
+}  // namespace manager
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/stack/test/common/mock_btu_layer.cc b/stack/test/common/mock_btu_layer.cc
new file mode 100644
index 0000000..f5bbf7a
--- /dev/null
+++ b/stack/test/common/mock_btu_layer.cc
@@ -0,0 +1,21 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <base/message_loop/message_loop.h>
+
+base::MessageLoop* get_message_loop() { return nullptr; }
\ No newline at end of file
diff --git a/stack/test/common/mock_l2cap_layer.cc b/stack/test/common/mock_l2cap_layer.cc
new file mode 100644
index 0000000..9f08d56
--- /dev/null
+++ b/stack/test/common/mock_l2cap_layer.cc
@@ -0,0 +1,59 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#include "mock_l2cap_layer.h"
+
+static bluetooth::l2cap::MockL2capInterface* l2cap_interface = nullptr;
+
+void bluetooth::l2cap::SetMockInterface(
+    MockL2capInterface* mock_l2cap_interface) {
+  l2cap_interface = mock_l2cap_interface;
+}
+
+uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info) {
+  VLOG(1) << __func__ << ": psm=" << psm << ", p_cb_info=" << p_cb_info;
+  return l2cap_interface->Register(psm, p_cb_info);
+}
+
+uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& bd_addr) {
+  return l2cap_interface->ConnectRequest(psm, bd_addr);
+}
+
+bool L2CA_ConnectRsp(const RawAddress& bd_addr, uint8_t id, uint16_t lcid,
+                     uint16_t result, uint16_t status) {
+  return l2cap_interface->ConnectResponse(bd_addr, id, lcid, result, status);
+}
+
+bool L2CA_DisconnectReq(uint16_t cid) {
+  return l2cap_interface->DisconnectRequest(cid);
+}
+
+bool L2CA_DisconnectRsp(uint16_t cid) {
+  return l2cap_interface->DisconnectResponse(cid);
+}
+
+bool L2CA_ConfigReq(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
+  return l2cap_interface->ConfigRequest(cid, p_cfg);
+}
+
+bool L2CA_ConfigRsp(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
+  return l2cap_interface->ConfigResponse(cid, p_cfg);
+}
+
+uint8_t L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) {
+  return l2cap_interface->DataWrite(cid, p_data);
+}
diff --git a/stack/test/common/mock_l2cap_layer.h b/stack/test/common/mock_l2cap_layer.h
new file mode 100644
index 0000000..78c8a9c
--- /dev/null
+++ b/stack/test/common/mock_l2cap_layer.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "l2c_api.h"
+
+namespace bluetooth {
+namespace l2cap {
+
+class L2capInterface {
+ public:
+  virtual uint16_t Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info) = 0;
+  virtual uint16_t ConnectRequest(uint16_t psm, const RawAddress& bd_addr) = 0;
+  virtual bool ConnectResponse(const RawAddress& bd_addr, uint8_t id,
+                               uint16_t lcid, uint16_t result,
+                               uint16_t status) = 0;
+  virtual bool DisconnectRequest(uint16_t cid) = 0;
+  virtual bool DisconnectResponse(uint16_t cid) = 0;
+  virtual bool ConfigRequest(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) = 0;
+  virtual bool ConfigResponse(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) = 0;
+  virtual uint8_t DataWrite(uint16_t cid, BT_HDR* p_data) = 0;
+  virtual ~L2capInterface() = default;
+};
+
+class MockL2capInterface : public L2capInterface {
+ public:
+  MOCK_METHOD2(Register, uint16_t(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info));
+  MOCK_METHOD2(ConnectRequest,
+               uint16_t(uint16_t psm, const RawAddress& bd_addr));
+  MOCK_METHOD5(ConnectResponse,
+               bool(const RawAddress& bd_addr, uint8_t id, uint16_t lcid,
+                    uint16_t result, uint16_t status));
+  MOCK_METHOD1(DisconnectRequest, bool(uint16_t cid));
+  MOCK_METHOD1(DisconnectResponse, bool(uint16_t cid));
+  MOCK_METHOD2(ConfigRequest, bool(uint16_t cid, tL2CAP_CFG_INFO* p_cfg));
+  MOCK_METHOD2(ConfigResponse, bool(uint16_t cid, tL2CAP_CFG_INFO* p_cfg));
+  MOCK_METHOD2(DataWrite, uint8_t(uint16_t cid, BT_HDR* p_data));
+};
+
+/**
+ * Set the {@link MockL2capInterface} for testing
+ *
+ * @param mock_l2cap_interface pointer to mock l2cap interface, could be null
+ */
+void SetMockInterface(MockL2capInterface* mock_l2cap_interface);
+
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/stack/test/common/stack_test_packet_utils.cc b/stack/test/common/stack_test_packet_utils.cc
new file mode 100644
index 0000000..74fc57d
--- /dev/null
+++ b/stack/test/common/stack_test_packet_utils.cc
@@ -0,0 +1,96 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "hci_layer.h"
+#include "l2c_api.h"
+#include "osi/include/allocator.h"
+
+#include "stack_test_packet_utils.h"
+
+namespace bluetooth {
+
+std::vector<uint8_t> CreateL2capDataPacket(uint16_t lcid,
+                                           const std::vector<uint8_t>& data) {
+  // Data in little endian order
+  std::vector<uint8_t> result;
+  auto data_size = static_cast<uint16_t>(data.size());
+  result.push_back(static_cast<uint8_t>(data_size));
+  result.push_back(static_cast<uint8_t>(data_size >> 8));
+  result.push_back(static_cast<uint8_t>(lcid));
+  result.push_back(static_cast<uint8_t>(lcid >> 8));
+  result.insert(result.end(), data.begin(), data.end());
+  return result;
+}
+
+std::vector<uint8_t> CreateAclPacket(uint16_t handle, uint8_t pb, uint8_t bc,
+                                     const std::vector<uint8_t>& data) {
+  // Data in little endian order
+  std::vector<uint8_t> result;
+  result.push_back(static_cast<uint8_t>(handle & 0x0F));
+  uint8_t second_byte = 0;
+  second_byte |= (bc << 6) & 0b11000000;
+  second_byte |= (pb << 4) & 0b00110000;
+  second_byte |= (handle >> 8) & 0b00001111;
+  result.push_back(second_byte);
+  auto data_size = static_cast<uint16_t>(data.size());
+  result.push_back(static_cast<uint8_t>(data_size));
+  result.push_back(static_cast<uint8_t>(data_size >> 8));
+  result.insert(result.end(), data.begin(), data.end());
+  return result;
+}
+
+BT_HDR* AllocateWrappedIncomingL2capAclPacket(const uint8_t* acl_packet_bytes,
+                                              size_t buffer_length) {
+  size_t packet_size = buffer_length + BT_HDR_SIZE;
+  auto packet = reinterpret_cast<BT_HDR*>(osi_malloc(packet_size));
+  // Add ACL packet overhead + L2CAP packet overhead
+  packet->offset = 4 + L2CAP_PKT_OVERHEAD;
+  packet->len = static_cast<uint16_t>(buffer_length - 4 - L2CAP_PKT_OVERHEAD);
+  packet->layer_specific = 0;
+  packet->event = MSG_HC_TO_STACK_HCI_ACL;
+  memcpy(packet->data, acl_packet_bytes, buffer_length);
+  return packet;
+}
+
+BT_HDR* AllocateWrappedIncomingL2capAclPacket(
+    const std::vector<uint8_t>& buffer) {
+  return AllocateWrappedIncomingL2capAclPacket(buffer.data(), buffer.size());
+}
+
+BT_HDR* AllocateWrappedOutgoingL2capAclPacket(const uint8_t* acl_packet_bytes,
+                                              size_t buffer_length) {
+  size_t acl_l2cap_header_size = 4 + L2CAP_PKT_OVERHEAD;
+  CHECK_GE(L2CAP_MIN_OFFSET, static_cast<int>(acl_l2cap_header_size));
+  size_t packet_size =
+      BT_HDR_SIZE + L2CAP_MIN_OFFSET + buffer_length - acl_l2cap_header_size;
+  auto packet = reinterpret_cast<BT_HDR*>(osi_malloc(packet_size));
+  packet->offset = L2CAP_MIN_OFFSET;
+  packet->len = static_cast<uint16_t>(buffer_length - acl_l2cap_header_size);
+  packet->layer_specific = 0;
+  packet->event = 0;
+  memcpy(packet->data + packet->offset - acl_l2cap_header_size,
+         acl_packet_bytes, buffer_length);
+  return packet;
+}
+
+BT_HDR* AllocateWrappedOutgoingL2capAclPacket(
+    const std::vector<uint8_t>& buffer) {
+  return AllocateWrappedOutgoingL2capAclPacket(buffer.data(), buffer.size());
+}
+
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/stack/test/common/stack_test_packet_utils.h b/stack/test/common/stack_test_packet_utils.h
new file mode 100644
index 0000000..fcbc5a9
--- /dev/null
+++ b/stack/test/common/stack_test_packet_utils.h
@@ -0,0 +1,78 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include "bt_types.h"
+
+namespace bluetooth {
+
+/**
+ * Create L2CAP data packet
+ *
+ * @param lcid
+ * @param data
+ * @return vector of bytes
+ */
+std::vector<uint8_t> CreateL2capDataPacket(uint16_t lcid,
+                                           const std::vector<uint8_t>& data);
+
+/**
+ * Create ACL data packet
+ *
+ * @param handle ACL connection hanle
+ * @param pb pb byte
+ * @param bc bc byte
+ * @param data frame data
+ * @return vector of bytes
+ */
+std::vector<uint8_t> CreateAclPacket(uint16_t handle, uint8_t pb, uint8_t bc,
+                                     const std::vector<uint8_t>& data);
+
+/**
+ * Given an array of ACL packet bytes from BTSNOOP log, allocate an OSI
+ * allocated BT_HDR pointer to a packet that can be processed by L2CAP
+ * application layer
+ *
+ * Note: BT_HDR offset is configured for incoming packets
+ *
+ * @param acl_packet_bytes pointer to array of ACL packet bytes
+ * @param buffer_length length of the packet buffer
+ * @return BT_HDR pointer to an OSI heap allocated packet
+ */
+BT_HDR* AllocateWrappedIncomingL2capAclPacket(const uint8_t* acl_packet_bytes,
+                                              size_t buffer_length);
+BT_HDR* AllocateWrappedIncomingL2capAclPacket(
+    const std::vector<uint8_t>& buffer);
+
+/**
+ * Given an array of ACL packet bytes from BTSNOOP log, allocate an OSI
+ * allocated BT_HDR pointer to a packet that can be processed by L2CAP
+ * application layer
+ *
+ * Note: BT_HDR offset is configured for outgoing packets
+ *
+ * @param acl_packet_bytes pointer to array of ACL packet bytes
+ * @param buffer_length length of the packet buffer
+ * @return BT_HDR pointer to an OSI heap allocated packet
+ */
+BT_HDR* AllocateWrappedOutgoingL2capAclPacket(const uint8_t* acl_packet_bytes,
+                                              size_t buffer_length);
+BT_HDR* AllocateWrappedOutgoingL2capAclPacket(
+    const std::vector<uint8_t>& buffer);
+
+}  // namespace bluetooth
diff --git a/stack/test/rfcomm/stack_rfcomm_test.cc b/stack/test/rfcomm/stack_rfcomm_test.cc
new file mode 100644
index 0000000..3d9da3f
--- /dev/null
+++ b/stack/test/rfcomm/stack_rfcomm_test.cc
@@ -0,0 +1,892 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "bt_types.h"
+#include "btm_api.h"
+#include "l2c_api.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+
+#include "btm_int.h"
+#include "rfc_int.h"
+
+#include "mock_btm_layer.h"
+#include "mock_l2cap_layer.h"
+#include "stack_rfcomm_test_utils.h"
+#include "stack_test_packet_utils.h"
+
+std::string DumpByteBufferToString(uint8_t* p_data, size_t len) {
+  std::stringstream str;
+  str.setf(std::ios_base::hex, std::ios::basefield);
+  str.setf(std::ios_base::uppercase);
+  str.fill('0');
+  for (size_t i = 0; i < len; ++i) {
+    str << std::setw(2) << static_cast<uint16_t>(p_data[i]);
+    str << " ";
+  }
+  return str.str();
+}
+
+std::string DumpBtHdrToString(BT_HDR* p_hdr) {
+  uint8_t* p_hdr_data = p_hdr->data + p_hdr->offset;
+  return DumpByteBufferToString(p_hdr_data, p_hdr->len);
+}
+
+void PrintTo(BT_HDR* value, ::std::ostream* os) {
+  *os << DumpBtHdrToString(value);
+}
+
+void PrintTo(tL2CAP_CFG_INFO* value, ::std::ostream* os) {
+  *os << DumpByteBufferToString((uint8_t*)value, sizeof(tL2CAP_CFG_INFO));
+}
+
+namespace {
+
+using testing::_;
+using testing::DoAll;
+using testing::Return;
+using testing::Test;
+using testing::StrictMock;
+using testing::SaveArg;
+using testing::SaveArgPointee;
+using testing::Pointee;
+using testing::StrEq;
+using testing::NotNull;
+
+using bluetooth::CreateL2capDataPacket;
+using bluetooth::CreateAclPacket;
+using bluetooth::AllocateWrappedIncomingL2capAclPacket;
+using bluetooth::AllocateWrappedOutgoingL2capAclPacket;
+
+using bluetooth::rfcomm::GetDlci;
+using bluetooth::rfcomm::GetAddressField;
+using bluetooth::rfcomm::GetControlField;
+using bluetooth::rfcomm::CreateMccPnFrame;
+using bluetooth::rfcomm::CreateMccMscFrame;
+using bluetooth::rfcomm::CreateMultiplexerControlFrame;
+using bluetooth::rfcomm::CreateRfcommPacket;
+using bluetooth::rfcomm::CreateQuickDataPacket;
+using bluetooth::rfcomm::CreateQuickPnPacket;
+using bluetooth::rfcomm::CreateQuickSabmPacket;
+using bluetooth::rfcomm::CreateQuickUaPacket;
+using bluetooth::rfcomm::CreateQuickMscPacket;
+
+MATCHER_P(PointerMemoryEqual, ptr,
+          DumpByteBufferToString((uint8_t*)ptr, sizeof(*ptr))) {
+  return memcmp(arg, ptr, sizeof(*ptr)) == 0;
+}
+
+MATCHER_P(BtHdrEqual, expected, DumpBtHdrToString(expected)) {
+  auto arg_hdr = static_cast<BT_HDR*>(arg);
+  uint8_t* arg_data = arg_hdr->data + arg_hdr->offset;
+  auto expected_hdr = static_cast<BT_HDR*>(expected);
+  uint8_t* expected_data = expected_hdr->data + expected_hdr->offset;
+  return memcmp(arg_data, expected_data, expected_hdr->len) == 0;
+}
+
+bluetooth::rfcomm::MockRfcommCallback* rfcomm_callback = nullptr;
+
+void port_mgmt_cback_0(uint32_t code, uint16_t port_handle) {
+  rfcomm_callback->PortManagementCallback(code, port_handle, 0);
+}
+
+void port_mgmt_cback_1(uint32_t code, uint16_t port_handle) {
+  rfcomm_callback->PortManagementCallback(code, port_handle, 1);
+}
+
+void port_event_cback_0(uint32_t code, uint16_t port_handle) {
+  rfcomm_callback->PortEventCallback(code, port_handle, 0);
+}
+
+void port_event_cback_1(uint32_t code, uint16_t port_handle) {
+  rfcomm_callback->PortEventCallback(code, port_handle, 1);
+}
+
+RawAddress GetTestAddress(int index) {
+  CHECK_LT(index, UINT8_MAX);
+  RawAddress result = {
+      {0xAA, 0x00, 0x11, 0x22, 0x33, static_cast<uint8_t>(index)}};
+  return result;
+}
+
+class StackRfcommTest : public Test {
+ public:
+  void StartServerPort(uint16_t uuid, uint8_t scn, uint16_t mtu,
+                       tPORT_CALLBACK* management_callback,
+                       tPORT_CALLBACK* event_callback,
+                       uint16_t* server_handle) {
+    VLOG(1) << "Step 1";
+    ASSERT_EQ(RFCOMM_CreateConnection(uuid, scn, true, mtu, RawAddress::kAny,
+                                      server_handle, management_callback),
+              PORT_SUCCESS);
+    ASSERT_EQ(PORT_SetEventMask(*server_handle, PORT_EV_RXCHAR), PORT_SUCCESS);
+    ASSERT_EQ(PORT_SetEventCallback(*server_handle, event_callback),
+              PORT_SUCCESS);
+  }
+
+  void ConnectServerL2cap(const RawAddress& peer_addr, uint16_t acl_handle,
+                          uint16_t lcid) {
+    VLOG(1) << "Step 1";
+    // Remote device connect to this channel, we shall accept
+    static const uint8_t cmd_id = 0x07;
+    EXPECT_CALL(l2cap_interface_,
+                ConnectResponse(peer_addr, cmd_id, lcid, L2CAP_CONN_OK, 0));
+    tL2CAP_CFG_INFO cfg_req = {.mtu_present = true, .mtu = L2CAP_MTU_SIZE};
+    EXPECT_CALL(l2cap_interface_,
+                ConfigRequest(lcid, PointerMemoryEqual(&cfg_req)))
+        .WillOnce(Return(true));
+    l2cap_appl_info_.pL2CA_ConnectInd_Cb(peer_addr, lcid, BT_PSM_RFCOMM,
+                                         cmd_id);
+
+    VLOG(1) << "Step 2";
+    // MTU configuration is done
+    cfg_req.mtu_present = false;
+    l2cap_appl_info_.pL2CA_ConfigCfm_Cb(lcid, &cfg_req);
+
+    VLOG(1) << "Step 3";
+    // Remote device also ask to configure MTU size
+    EXPECT_CALL(l2cap_interface_,
+                ConfigResponse(lcid, PointerMemoryEqual(&cfg_req)))
+        .WillOnce(Return(true));
+    l2cap_appl_info_.pL2CA_ConfigInd_Cb(lcid, &cfg_req);
+
+    VLOG(1) << "Step 4";
+    // Remote device connect to server channel 0
+    BT_HDR* sabm_channel_0 = AllocateWrappedIncomingL2capAclPacket(
+        CreateQuickSabmPacket(RFCOMM_MX_DLCI, lcid, acl_handle));
+    BT_HDR* ua_channel_0 = AllocateWrappedOutgoingL2capAclPacket(
+        CreateQuickUaPacket(RFCOMM_MX_DLCI, lcid, acl_handle));
+    EXPECT_CALL(l2cap_interface_, DataWrite(lcid, BtHdrEqual(ua_channel_0)))
+        .WillOnce(Return(L2CAP_DW_SUCCESS));
+    // Packet should be freed by RFCOMM
+    l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, sabm_channel_0);
+    osi_free(ua_channel_0);
+  }
+
+  void ConnectServerPort(const RawAddress& peer_addr, uint16_t port_handle,
+                         uint8_t scn, uint16_t mtu, uint16_t acl_handle,
+                         uint16_t lcid, int port_callback_index) {
+    VLOG(1) << "Step 1";
+    // Negotiate parameters on scn
+    BT_HDR* uih_pn_cmd_from_peer = AllocateWrappedIncomingL2capAclPacket(
+        CreateQuickPnPacket(true, GetDlci(false, scn), true, mtu,
+                            RFCOMM_PN_CONV_LAYER_CBFC_I >> 4, 0, RFCOMM_K_MAX,
+                            lcid, acl_handle));
+    BT_HDR* uih_pn_rsp_to_peer = AllocateWrappedOutgoingL2capAclPacket(
+        CreateQuickPnPacket(false, GetDlci(false, scn), false, mtu,
+                            RFCOMM_PN_CONV_LAYER_CBFC_R >> 4, 0, RFCOMM_K_MAX,
+                            lcid, acl_handle));
+    EXPECT_CALL(l2cap_interface_,
+                DataWrite(lcid, BtHdrEqual(uih_pn_rsp_to_peer)))
+        .WillOnce(Return(L2CAP_DW_SUCCESS));
+    // uih_pn_cmd_from_peer should be freed by this method
+    l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, uih_pn_cmd_from_peer);
+    osi_free(uih_pn_rsp_to_peer);
+
+    VLOG(1) << "Step 2";
+    // Remote device connect to scn
+    tBTM_SEC_CALLBACK* security_callback = nullptr;
+    void* p_port = nullptr;
+    BT_HDR* sabm_channel_dlci = AllocateWrappedIncomingL2capAclPacket(
+        CreateQuickSabmPacket(GetDlci(false, scn), lcid, acl_handle));
+    EXPECT_CALL(btm_security_internal_interface_,
+                MultiplexingProtocolAccessRequest(peer_addr, BT_PSM_RFCOMM,
+                                                  false, BTM_SEC_PROTO_RFCOMM,
+                                                  scn, NotNull(), NotNull()))
+        .WillOnce(DoAll(SaveArg<5>(&security_callback), SaveArg<6>(&p_port),
+                        Return(BTM_SUCCESS)));
+    // sabm_channel_dlci should be freed by this method
+    l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, sabm_channel_dlci);
+
+    VLOG(1) << "Step 3";
+    // Confirm security check should trigger port as connected
+    EXPECT_CALL(
+        rfcomm_callback_,
+        PortManagementCallback(PORT_SUCCESS, port_handle, port_callback_index));
+    BT_HDR* ua_channel_dlci = AllocateWrappedOutgoingL2capAclPacket(
+        CreateQuickUaPacket(GetDlci(false, scn), lcid, acl_handle));
+    EXPECT_CALL(l2cap_interface_, DataWrite(lcid, BtHdrEqual(ua_channel_dlci)))
+        .WillOnce(Return(L2CAP_DW_SUCCESS));
+    ASSERT_TRUE(security_callback);
+    security_callback(&peer_addr, BT_TRANSPORT_BR_EDR, p_port, BTM_SUCCESS);
+    osi_free(ua_channel_dlci);
+
+    VLOG(1) << "Step 4";
+    // Remote also need to configure its modem signal before we can send data
+    BT_HDR* uih_msc_cmd_from_peer = AllocateWrappedIncomingL2capAclPacket(
+        CreateQuickMscPacket(true, GetDlci(false, scn), lcid, acl_handle, true,
+                             false, true, true, false, true));
+    BT_HDR* uih_msc_response_to_peer = AllocateWrappedOutgoingL2capAclPacket(
+        CreateQuickMscPacket(false, GetDlci(false, scn), lcid, acl_handle,
+                             false, false, true, true, false, true));
+    // We also have to do modem configuration ourself
+    EXPECT_CALL(l2cap_interface_,
+                DataWrite(lcid, BtHdrEqual(uih_msc_response_to_peer)))
+        .WillOnce(Return(L2CAP_DW_SUCCESS));
+    BT_HDR* uih_msc_cmd_to_peer = AllocateWrappedOutgoingL2capAclPacket(
+        CreateQuickMscPacket(false, GetDlci(false, scn), lcid, acl_handle, true,
+                             false, true, true, false, true));
+    EXPECT_CALL(l2cap_interface_,
+                DataWrite(lcid, BtHdrEqual(uih_msc_cmd_to_peer)))
+        .WillOnce(Return(L2CAP_DW_SUCCESS));
+    // uih_msc_cmd_from_peer should be freed by this method
+    l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, uih_msc_cmd_from_peer);
+    osi_free(uih_msc_response_to_peer);
+
+    VLOG(1) << "Step 5";
+    // modem configuration is done
+    BT_HDR* uih_msc_response_from_peer = AllocateWrappedIncomingL2capAclPacket(
+        CreateQuickMscPacket(true, GetDlci(false, scn), lcid, acl_handle, false,
+                             false, true, true, false, true));
+    // uih_msc_response_from_peer should be freed by this method
+    l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, uih_msc_response_from_peer);
+  }
+
+  void StartClientPort(const RawAddress& peer_bd_addr, uint16_t uuid,
+                       uint8_t scn, uint16_t mtu,
+                       tPORT_CALLBACK* management_callback,
+                       tPORT_CALLBACK* event_callback, uint16_t lcid,
+                       uint16_t acl_handle, uint16_t* client_handle,
+                       bool is_first_connection) {
+    VLOG(1) << "Step 1";
+    BT_HDR* uih_pn_channel_3 =
+        AllocateWrappedOutgoingL2capAclPacket(CreateQuickPnPacket(
+            true, GetDlci(false, scn), true, mtu, RFCOMM_PN_CONV_LAYER_TYPE_1,
+            RFCOMM_PN_PRIORITY_0, RFCOMM_K, lcid, acl_handle));
+    if (is_first_connection) {
+      EXPECT_CALL(l2cap_interface_, ConnectRequest(BT_PSM_RFCOMM, peer_bd_addr))
+          .WillOnce(Return(lcid));
+    } else {
+      EXPECT_CALL(l2cap_interface_,
+                  DataWrite(lcid, BtHdrEqual(uih_pn_channel_3)))
+          .WillOnce(Return(L2CAP_DW_SUCCESS));
+    }
+    ASSERT_EQ(RFCOMM_CreateConnection(uuid, scn, false, mtu, peer_bd_addr,
+                                      client_handle, management_callback),
+              PORT_SUCCESS);
+    ASSERT_EQ(PORT_SetEventMask(*client_handle, PORT_EV_RXCHAR), PORT_SUCCESS);
+    ASSERT_EQ(PORT_SetEventCallback(*client_handle, event_callback),
+              PORT_SUCCESS);
+    osi_free(uih_pn_channel_3);
+  }
+
+  void TestConnectClientPortL2cap(uint16_t acl_handle, uint16_t lcid) {
+    VLOG(1) << "Step 1";
+    // Send configuration request when L2CAP connect is succsseful
+    tL2CAP_CFG_INFO cfg_req = {.mtu_present = true, .mtu = L2CAP_MTU_SIZE};
+    EXPECT_CALL(l2cap_interface_,
+                ConfigRequest(lcid, PointerMemoryEqual(&cfg_req)))
+        .WillOnce(Return(true));
+    l2cap_appl_info_.pL2CA_ConnectCfm_Cb(lcid, L2CAP_CONN_OK);
+
+    VLOG(1) << "Step 2";
+    // Remote device confirms our configuration request
+    cfg_req.mtu_present = false;
+    l2cap_appl_info_.pL2CA_ConfigCfm_Cb(lcid, &cfg_req);
+
+    VLOG(1) << "Step 3";
+    // Remote device also asks to configure MTU
+    // Once configuration is done, we connect to multiplexer control channel 0
+    EXPECT_CALL(l2cap_interface_,
+                ConfigResponse(lcid, PointerMemoryEqual(&cfg_req)))
+        .WillOnce(Return(true));
+    // multiplexer control channel's DLCI is always 0
+    BT_HDR* sabm_channel_0 = AllocateWrappedOutgoingL2capAclPacket(
+        CreateQuickSabmPacket(RFCOMM_MX_DLCI, lcid, acl_handle));
+    EXPECT_CALL(l2cap_interface_, DataWrite(lcid, BtHdrEqual(sabm_channel_0)))
+        .WillOnce(Return(L2CAP_DW_SUCCESS));
+    l2cap_appl_info_.pL2CA_ConfigInd_Cb(lcid, &cfg_req);
+    osi_free(sabm_channel_0);
+  }
+
+  void ConnectClientPort(const RawAddress& peer_addr, uint16_t port_handle,
+                         uint8_t scn, uint16_t mtu, uint16_t acl_handle,
+                         uint16_t lcid, int port_callback_index,
+                         bool is_first_connection) {
+    VLOG(1) << "Step 1";
+    if (is_first_connection) {
+      VLOG(1) << "Step 1.5";
+      // Once remote accept multiplexer control channel 0
+      // We change to desired channel on non-initiating device (remote device)
+      BT_HDR* ua_channel_0 = AllocateWrappedIncomingL2capAclPacket(
+          CreateQuickUaPacket(RFCOMM_MX_DLCI, lcid, acl_handle));
+      BT_HDR* uih_pn_channel_3 =
+          AllocateWrappedOutgoingL2capAclPacket(CreateQuickPnPacket(
+              true, GetDlci(false, scn), true, mtu,
+              RFCOMM_PN_CONV_LAYER_CBFC_I >> 4, RFCOMM_PN_PRIORITY_0,
+              RFCOMM_K_MAX, lcid, acl_handle));
+      EXPECT_CALL(l2cap_interface_,
+                  DataWrite(lcid, BtHdrEqual(uih_pn_channel_3)))
+          .WillOnce(Return(L2CAP_DW_SUCCESS));
+      l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, ua_channel_0);
+      osi_free(uih_pn_channel_3);
+    }
+
+    VLOG(1) << "Step 2";
+    // Once remote accept service channel change, we start security procedure
+    BT_HDR* uih_pn_channel_3_accept =
+        AllocateWrappedIncomingL2capAclPacket(CreateQuickPnPacket(
+            false, GetDlci(false, scn), false, mtu,
+            RFCOMM_PN_CONV_LAYER_CBFC_I >> 4, RFCOMM_PN_PRIORITY_0,
+            RFCOMM_K_MAX, lcid, acl_handle));
+    tBTM_SEC_CALLBACK* security_callback = nullptr;
+    void* p_port = nullptr;
+    EXPECT_CALL(btm_security_internal_interface_,
+                MultiplexingProtocolAccessRequest(peer_addr, BT_PSM_RFCOMM,
+                                                  true, BTM_SEC_PROTO_RFCOMM,
+                                                  scn, NotNull(), NotNull()))
+        .WillOnce(DoAll(SaveArg<5>(&security_callback), SaveArg<6>(&p_port),
+                        Return(BTM_SUCCESS)));
+    l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, uih_pn_channel_3_accept);
+
+    VLOG(1) << "Step 3";
+    // Once security procedure is done, we officially connect to target scn
+    BT_HDR* sabm_channel_3 = AllocateWrappedOutgoingL2capAclPacket(
+        CreateQuickSabmPacket(GetDlci(false, scn), lcid, acl_handle));
+    EXPECT_CALL(l2cap_interface_, DataWrite(lcid, BtHdrEqual(sabm_channel_3)))
+        .WillOnce(Return(L2CAP_DW_SUCCESS));
+    ASSERT_TRUE(security_callback);
+    security_callback(&peer_addr, BT_TRANSPORT_BR_EDR, p_port, BTM_SUCCESS);
+    osi_free(sabm_channel_3);
+
+    VLOG(1) << "Step 4";
+    // When target scn is accepted by remote, we need to configure modem signal
+    // state beofre using the port
+    EXPECT_CALL(
+        rfcomm_callback_,
+        PortManagementCallback(PORT_SUCCESS, port_handle, port_callback_index));
+    BT_HDR* uih_msc_cmd = AllocateWrappedOutgoingL2capAclPacket(
+        CreateQuickMscPacket(true, GetDlci(false, scn), lcid, acl_handle, true,
+                             false, true, true, false, true));
+    EXPECT_CALL(l2cap_interface_, DataWrite(lcid, BtHdrEqual(uih_msc_cmd)))
+        .WillOnce(Return(L2CAP_DW_SUCCESS));
+    BT_HDR* ua_channel_3 = AllocateWrappedIncomingL2capAclPacket(
+        CreateQuickUaPacket(GetDlci(false, scn), lcid, acl_handle));
+    l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, ua_channel_3);
+    osi_free(uih_msc_cmd);
+
+    VLOG(1) << "Step 5";
+    // modem configuration is done
+    BT_HDR* uih_msc_response = AllocateWrappedIncomingL2capAclPacket(
+        CreateQuickMscPacket(false, GetDlci(false, scn), lcid, acl_handle,
+                             false, false, true, true, false, true));
+    l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, uih_msc_response);
+
+    VLOG(1) << "Step 6";
+    // Remote also need to configure its modem signal before we can send data
+    BT_HDR* uih_msc_cmd_from_peer = AllocateWrappedIncomingL2capAclPacket(
+        CreateQuickMscPacket(false, GetDlci(false, scn), lcid, acl_handle, true,
+                             false, true, true, false, true));
+    BT_HDR* uih_msc_response_to_peer = AllocateWrappedOutgoingL2capAclPacket(
+        CreateQuickMscPacket(true, GetDlci(false, scn), lcid, acl_handle, false,
+                             false, true, true, false, true));
+    EXPECT_CALL(l2cap_interface_,
+                DataWrite(lcid, BtHdrEqual(uih_msc_response_to_peer)))
+        .WillOnce(Return(L2CAP_DW_SUCCESS));
+    l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, uih_msc_cmd_from_peer);
+    osi_free(uih_msc_response_to_peer);
+  }
+
+  void SendAndVerifyOutgoingTransmission(uint16_t port_handle,
+                                         bool is_initiator, uint8_t scn,
+                                         bool cr, const std::string& message,
+                                         int credits, uint16_t acl_handle,
+                                         uint16_t lcid) {
+    VLOG(1) << "Step 1";
+    BT_HDR* data_packet = AllocateWrappedOutgoingL2capAclPacket(
+        CreateQuickDataPacket(GetDlci(is_initiator, scn), cr, lcid, acl_handle,
+                              credits, message));
+    uint16_t transmitted_length = 0;
+    EXPECT_CALL(l2cap_interface_, DataWrite(lcid, BtHdrEqual(data_packet)))
+        .WillOnce(Return(L2CAP_DW_SUCCESS));
+    ASSERT_EQ(PORT_WriteData(port_handle, message.data(), message.size(),
+                             &transmitted_length),
+              PORT_SUCCESS);
+    ASSERT_EQ(transmitted_length, message.size());
+  }
+
+  void ReceiveAndVerifyIncomingTransmission(uint16_t port_handle,
+                                            bool is_initiator, uint8_t scn,
+                                            bool cr, const std::string& message,
+                                            int credits, uint16_t acl_handle,
+                                            uint16_t lcid,
+                                            int port_callback_index) {
+    VLOG(1) << "Step 1";
+    BT_HDR* data_packet = AllocateWrappedIncomingL2capAclPacket(
+        CreateQuickDataPacket(GetDlci(is_initiator, scn), cr, lcid, acl_handle,
+                              credits, message));
+    EXPECT_CALL(rfcomm_callback_,
+                PortEventCallback(_, port_handle, port_callback_index));
+    l2cap_appl_info_.pL2CA_DataInd_Cb(lcid, data_packet);
+
+    VLOG(1) << "Step 2";
+    char buffer[L2CAP_MTU_SIZE] = {};
+    uint16_t length = 0;
+    int status = PORT_ReadData(port_handle, buffer, L2CAP_MTU_SIZE, &length);
+    ASSERT_EQ(status, PORT_SUCCESS);
+    ASSERT_THAT(buffer, StrEq(message));
+  }
+
+ protected:
+  void SetUp() override {
+    Test::SetUp();
+    bluetooth::manager::SetMockSecurityInternalInterface(
+        &btm_security_internal_interface_);
+    bluetooth::l2cap::SetMockInterface(&l2cap_interface_);
+    rfcomm_callback = &rfcomm_callback_;
+    EXPECT_CALL(l2cap_interface_, Register(BT_PSM_RFCOMM, _))
+        .WillOnce(
+            DoAll(SaveArgPointee<1>(&l2cap_appl_info_), Return(BT_PSM_RFCOMM)));
+    RFCOMM_Init();
+    rfc_cb.trace_level = BT_TRACE_LEVEL_DEBUG;
+  }
+
+  void TearDown() override {
+    rfcomm_callback = nullptr;
+    bluetooth::l2cap::SetMockInterface(nullptr);
+    bluetooth::manager::SetMockSecurityInternalInterface(nullptr);
+    testing::Test::TearDown();
+  }
+  StrictMock<bluetooth::manager::MockBtmSecurityInternalInterface>
+      btm_security_internal_interface_;
+  StrictMock<bluetooth::l2cap::MockL2capInterface> l2cap_interface_;
+  StrictMock<bluetooth::rfcomm::MockRfcommCallback> rfcomm_callback_;
+  tL2CAP_APPL_INFO l2cap_appl_info_;
+};
+
+TEST_F(StackRfcommTest, SingleServerConnectionHelloWorld) {
+  // Prepare a server channel at kTestChannelNumber0
+  static const uint16_t acl_handle = 0x0009;
+  static const uint16_t lcid = 0x0054;
+  static const uint16_t test_uuid = 0x1112;
+  static const uint8_t test_scn = 8;
+  static const uint16_t test_mtu = 1600;
+  static const RawAddress test_address = GetTestAddress(0);
+  uint16_t server_handle = 0;
+  ASSERT_NO_FATAL_FAILURE(StartServerPort(test_uuid, test_scn, test_mtu,
+                                          port_mgmt_cback_0, port_event_cback_0,
+                                          &server_handle));
+  ASSERT_NO_FATAL_FAILURE(ConnectServerL2cap(test_address, acl_handle, lcid));
+  ASSERT_NO_FATAL_FAILURE(ConnectServerPort(
+      test_address, server_handle, test_scn, test_mtu, acl_handle, lcid, 0));
+  ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+      server_handle, false, test_scn, true, "Hello World!\r", 50, acl_handle,
+      lcid, 0));
+  ASSERT_NO_FATAL_FAILURE(
+      SendAndVerifyOutgoingTransmission(server_handle, false, test_scn, false,
+                                        "\r!dlroW olleH", 4, acl_handle, lcid));
+}
+
+TEST_F(StackRfcommTest, MultiServerPortSameDeviceHelloWorld) {
+  // Prepare a server channel at kTestChannelNumber0
+  static const uint16_t acl_handle = 0x0009;
+  static const uint16_t lcid = 0x0054;
+  static const uint16_t test_mtu = 1600;
+  static const RawAddress test_address = GetTestAddress(0);
+
+  // Service 0
+  uint16_t server_handle_0 = 0;
+  static const uint8_t test_scn_0 = 8;
+  static const uint16_t test_uuid_0 = 0x1112;
+  ASSERT_NO_FATAL_FAILURE(StartServerPort(test_uuid_0, test_scn_0, test_mtu,
+                                          port_mgmt_cback_0, port_event_cback_0,
+                                          &server_handle_0));
+  ASSERT_NO_FATAL_FAILURE(ConnectServerL2cap(test_address, acl_handle, lcid));
+  ASSERT_NO_FATAL_FAILURE(ConnectServerPort(test_address, server_handle_0,
+                                            test_scn_0, test_mtu, acl_handle,
+                                            lcid, 0));
+
+  // Service 1
+  uint16_t server_handle_1 = 0;
+  static const uint8_t test_scn_1 = 10;
+  static const uint16_t test_uuid_1 = 0x111F;
+  ASSERT_NE(test_scn_1, test_scn_0);
+  ASSERT_NE(test_uuid_1, test_uuid_0);
+  ASSERT_NO_FATAL_FAILURE(StartServerPort(test_uuid_1, test_scn_1, test_mtu,
+                                          port_mgmt_cback_1, port_event_cback_1,
+                                          &server_handle_1));
+  // No L2CAP setup for 2nd device
+  ASSERT_NO_FATAL_FAILURE(ConnectServerPort(test_address, server_handle_1,
+                                            test_scn_1, test_mtu, acl_handle,
+                                            lcid, 1));
+
+  // Use service 0
+  ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+      server_handle_0, false, test_scn_0, true, "Hello World0!\r", 50,
+      acl_handle, lcid, 0));
+  ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+      server_handle_0, false, test_scn_0, false, "\r!0dlroW olleH", 4,
+      acl_handle, lcid));
+  // Use service 1
+  ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+      server_handle_1, false, test_scn_1, true, "Hello World1!\r", 50,
+      acl_handle, lcid, 1));
+  ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+      server_handle_1, false, test_scn_1, false, "\r!1dlroW olleH", 4,
+      acl_handle, lcid));
+}
+
+TEST_F(StackRfcommTest, SameServerPortMultiDeviceHelloWorld) {
+  // Prepare a server channel at kTestChannelNumber0
+  static const uint16_t test_mtu = 1600;
+  static const uint8_t test_scn = 3;
+  static const uint16_t test_uuid = 0x1112;
+
+  // Service 0
+  static const RawAddress test_address_0 = GetTestAddress(0);
+  static const uint16_t acl_handle_0 = 0x0009;
+  static const uint16_t lcid_0 = 0x0054;
+  uint16_t server_handle_0 = 0;
+  ASSERT_NO_FATAL_FAILURE(StartServerPort(test_uuid, test_scn, test_mtu,
+                                          port_mgmt_cback_0, port_event_cback_0,
+                                          &server_handle_0));
+  ASSERT_NO_FATAL_FAILURE(
+      ConnectServerL2cap(test_address_0, acl_handle_0, lcid_0));
+  ASSERT_NO_FATAL_FAILURE(ConnectServerPort(test_address_0, server_handle_0,
+                                            test_scn, test_mtu, acl_handle_0,
+                                            lcid_0, 0));
+
+  // Service 1
+  static const RawAddress test_address_1 = GetTestAddress(1);
+  static const uint16_t acl_handle_1 = 0x0012;
+  static const uint16_t lcid_1 = 0x0045;
+  uint16_t server_handle_1 = 0;
+  ASSERT_NO_FATAL_FAILURE(StartServerPort(test_uuid, test_scn, test_mtu,
+                                          port_mgmt_cback_1, port_event_cback_1,
+                                          &server_handle_1));
+  ASSERT_NO_FATAL_FAILURE(
+      ConnectServerL2cap(test_address_1, acl_handle_1, lcid_1));
+  ASSERT_NO_FATAL_FAILURE(ConnectServerPort(test_address_1, server_handle_1,
+                                            test_scn, test_mtu, acl_handle_1,
+                                            lcid_1, 1));
+
+  // Use service 0
+  ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+      server_handle_0, false, test_scn, true, "Hello World0!\r", 50,
+      acl_handle_0, lcid_0, 0));
+  ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+      server_handle_0, false, test_scn, false, "\r!0dlroW olleH", 4,
+      acl_handle_0, lcid_0));
+  // Use service 1
+  ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+      server_handle_1, false, test_scn, true, "Hello World1!\r", 50,
+      acl_handle_1, lcid_1, 1));
+  ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+      server_handle_1, false, test_scn, false, "\r!1dlroW olleH", 4,
+      acl_handle_1, lcid_1));
+}
+
+TEST_F(StackRfcommTest, SingleClientConnectionHelloWorld) {
+  static const uint16_t acl_handle = 0x0009;
+  static const uint16_t lcid = 0x0054;
+  static const uint16_t test_uuid = 0x1112;
+  static const uint8_t test_scn = 8;
+  static const uint16_t test_mtu = 1600;
+  static const RawAddress test_address = GetTestAddress(0);
+  uint16_t client_handle = 0;
+  ASSERT_NO_FATAL_FAILURE(StartClientPort(
+      test_address, test_uuid, test_scn, test_mtu, port_mgmt_cback_0,
+      port_event_cback_0, lcid, acl_handle, &client_handle, true));
+  ASSERT_NO_FATAL_FAILURE(TestConnectClientPortL2cap(acl_handle, lcid));
+  ASSERT_NO_FATAL_FAILURE(ConnectClientPort(test_address, client_handle,
+                                            test_scn, test_mtu, acl_handle,
+                                            lcid, 0, true));
+  ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+      client_handle, false, test_scn, true, "\r!dlroW olleH", -1, acl_handle,
+      lcid));
+  ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+      client_handle, false, test_scn, false, "Hello World!\r", -1, acl_handle,
+      lcid, 0));
+}
+
+TEST_F(StackRfcommTest, MultiClientPortSameDeviceHelloWorld) {
+  static const uint16_t acl_handle = 0x0009;
+  static const uint16_t lcid = 0x0054;
+  static const uint16_t test_mtu = 1600;
+  static const RawAddress test_address = GetTestAddress(0);
+
+  // Connection 0
+  static const uint16_t test_uuid_0 = 0x1112;
+  static const uint8_t test_scn_0 = 8;
+  uint16_t client_handle_0 = 0;
+  ASSERT_NO_FATAL_FAILURE(StartClientPort(
+      test_address, test_uuid_0, test_scn_0, test_mtu, port_mgmt_cback_0,
+      port_event_cback_0, lcid, acl_handle, &client_handle_0, true));
+  ASSERT_NO_FATAL_FAILURE(TestConnectClientPortL2cap(acl_handle, lcid));
+  ASSERT_NO_FATAL_FAILURE(ConnectClientPort(test_address, client_handle_0,
+                                            test_scn_0, test_mtu, acl_handle,
+                                            lcid, 0, true));
+
+  // Connection 1
+  static const uint16_t test_uuid_1 = 0x111F;
+  static const uint8_t test_scn_1 = 10;
+  uint16_t client_handle_1 = 0;
+  ASSERT_NO_FATAL_FAILURE(StartClientPort(
+      test_address, test_uuid_1, test_scn_1, test_mtu, port_mgmt_cback_1,
+      port_event_cback_1, lcid, acl_handle, &client_handle_1, false));
+  ASSERT_NO_FATAL_FAILURE(ConnectClientPort(test_address, client_handle_1,
+                                            test_scn_1, test_mtu, acl_handle,
+                                            lcid, 1, false));
+
+  // Use connection 0
+  ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+      client_handle_0, false, test_scn_0, true, "\r!dlroW olleH", -1,
+      acl_handle, lcid));
+  ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+      client_handle_0, false, test_scn_0, false, "Hello World!\r", -1,
+      acl_handle, lcid, 0));
+
+  // Use connection 1
+  ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+      client_handle_1, false, test_scn_1, true, "\r!dlroW olleH", -1,
+      acl_handle, lcid));
+  ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+      client_handle_1, false, test_scn_1, false, "Hello World!\r", -1,
+      acl_handle, lcid, 1));
+}
+
+TEST_F(StackRfcommTest, SameClientPortMultiDeviceHelloWorld) {
+  static const uint16_t test_uuid = 0x1112;
+  static const uint8_t test_scn = 8;
+  static const uint16_t test_mtu = 1600;
+
+  // Connection 0
+  static const RawAddress test_address_0 = GetTestAddress(0);
+  static const uint16_t acl_handle_0 = 0x0009;
+  static const uint16_t lcid_0 = 0x0054;
+  uint16_t client_handle_0 = 0;
+  ASSERT_NO_FATAL_FAILURE(StartClientPort(
+      test_address_0, test_uuid, test_scn, test_mtu, port_mgmt_cback_0,
+      port_event_cback_0, lcid_0, acl_handle_0, &client_handle_0, true));
+  ASSERT_NO_FATAL_FAILURE(TestConnectClientPortL2cap(acl_handle_0, lcid_0));
+  ASSERT_NO_FATAL_FAILURE(ConnectClientPort(test_address_0, client_handle_0,
+                                            test_scn, test_mtu, acl_handle_0,
+                                            lcid_0, 0, true));
+
+  // Connection 1
+  static const RawAddress test_address_1 = GetTestAddress(1);
+  static const uint16_t acl_handle_1 = 0x0012;
+  static const uint16_t lcid_1 = 0x0045;
+  uint16_t client_handle_1 = 0;
+  ASSERT_NO_FATAL_FAILURE(StartClientPort(
+      test_address_1, test_uuid, test_scn, test_mtu, port_mgmt_cback_1,
+      port_event_cback_1, lcid_1, acl_handle_1, &client_handle_1, true));
+  ASSERT_NO_FATAL_FAILURE(TestConnectClientPortL2cap(acl_handle_1, lcid_1));
+  ASSERT_NO_FATAL_FAILURE(ConnectClientPort(test_address_1, client_handle_1,
+                                            test_scn, test_mtu, acl_handle_1,
+                                            lcid_1, 1, true));
+
+  // Use connection 0
+  ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+      client_handle_0, false, test_scn, true, "\r!dlroW olleH", -1,
+      acl_handle_0, lcid_0));
+  ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+      client_handle_0, false, test_scn, false, "Hello World!\r", -1,
+      acl_handle_0, lcid_0, 0));
+
+  // Use connection 1
+  ASSERT_NO_FATAL_FAILURE(SendAndVerifyOutgoingTransmission(
+      client_handle_1, false, test_scn, true, "\r!dlroW olleH", -1,
+      acl_handle_1, lcid_1));
+  ASSERT_NO_FATAL_FAILURE(ReceiveAndVerifyIncomingTransmission(
+      client_handle_1, false, test_scn, false, "Hello World!\r", -1,
+      acl_handle_1, lcid_1, 1));
+}
+
+TEST_F(StackRfcommTest, TestConnectionCollision) {
+  static const uint16_t acl_handle = 0x0008;
+  static const uint16_t old_lcid = 0x004a;
+  static const uint16_t new_lcid = 0x005c;
+  static const uint16_t test_uuid = 0x1112;
+  static const uint8_t test_server_scn = 3;
+  static const uint8_t test_peer_scn = 10;
+  // Must be smaller than L2CAP_MTU_SIZE by at least 4 bytes
+  static const uint16_t test_mtu = 1000;
+  static const RawAddress test_address = GetTestAddress(0);
+  uint16_t server_handle = 0;
+  VLOG(1) << "Step 1";
+  // Prepare a server port
+  int status = RFCOMM_CreateConnection(test_uuid, test_server_scn, true,
+                                       test_mtu, RawAddress::kAny,
+                                       &server_handle, port_mgmt_cback_0);
+  ASSERT_EQ(status, PORT_SUCCESS);
+  status = PORT_SetEventMask(server_handle, PORT_EV_RXCHAR);
+  ASSERT_EQ(status, PORT_SUCCESS);
+  status = PORT_SetEventCallback(server_handle, port_event_cback_0);
+  ASSERT_EQ(status, PORT_SUCCESS);
+
+  VLOG(1) << "Step 2";
+  // Try to connect to a client port
+  uint16_t client_handle_1 = 0;
+  EXPECT_CALL(l2cap_interface_, ConnectRequest(BT_PSM_RFCOMM, test_address))
+      .Times(1)
+      .WillOnce(Return(old_lcid));
+  status = RFCOMM_CreateConnection(test_uuid, test_peer_scn, false, test_mtu,
+                                   test_address, &client_handle_1,
+                                   port_mgmt_cback_1);
+  ASSERT_EQ(status, PORT_SUCCESS);
+  status = PORT_SetEventMask(client_handle_1, PORT_EV_RXCHAR);
+  ASSERT_EQ(status, PORT_SUCCESS);
+  status = PORT_SetEventCallback(client_handle_1, port_event_cback_1);
+  ASSERT_EQ(status, PORT_SUCCESS);
+
+  VLOG(1) << "Step 3";
+  // While our connection is pending, remote device tries to connect to
+  // new_lcid, with L2CAP command id: pending_cmd_id
+  static const uint8_t pending_cmd_id = 0x05;
+  // RFCOMM starts timer for collision:
+  l2cap_appl_info_.pL2CA_ConnectInd_Cb(test_address, new_lcid, BT_PSM_RFCOMM,
+                                       pending_cmd_id);
+
+  VLOG(1) << "Step 4";
+  // Remote reject our connection request saying PSM not allowed
+  // This should trigger RFCOMM to accept remote L2CAP connection at new_lcid
+  EXPECT_CALL(l2cap_interface_, ConnectResponse(test_address, pending_cmd_id,
+                                                new_lcid, L2CAP_CONN_OK, 0))
+      .WillOnce(Return(true));
+  // Followed by configure request for MTU size
+  tL2CAP_CFG_INFO our_cfg_req = {.mtu_present = true, .mtu = L2CAP_MTU_SIZE};
+  EXPECT_CALL(l2cap_interface_,
+              ConfigRequest(new_lcid, PointerMemoryEqual(&our_cfg_req)))
+      .WillOnce(Return(true));
+  l2cap_appl_info_.pL2CA_ConnectCfm_Cb(old_lcid, L2CAP_CONN_NO_PSM);
+
+  VLOG(1) << "Step 5";
+  // Remote device also ask to configure MTU size as well
+  tL2CAP_CFG_INFO peer_cfg_req = {.mtu_present = true, .mtu = test_mtu};
+  // We responded by saying OK
+  tL2CAP_CFG_INFO our_cfg_rsp = {.result = L2CAP_CFG_OK,
+                                 .mtu = peer_cfg_req.mtu};
+  EXPECT_CALL(l2cap_interface_,
+              ConfigResponse(new_lcid, PointerMemoryEqual(&our_cfg_rsp)))
+      .WillOnce(Return(true));
+  l2cap_appl_info_.pL2CA_ConfigInd_Cb(new_lcid, &peer_cfg_req);
+
+  VLOG(1) << "Step 6";
+  // Remote device accepted our MTU size
+  tL2CAP_CFG_INFO peer_cfg_rsp = {.mtu_present = true, .mtu = L2CAP_MTU_SIZE};
+  l2cap_appl_info_.pL2CA_ConfigCfm_Cb(new_lcid, &peer_cfg_rsp);
+
+  // L2CAP collision and connection setup done
+
+  VLOG(1) << "Step 7";
+  // Remote device connect multiplexer channel
+  BT_HDR* sabm_channel_0 = AllocateWrappedIncomingL2capAclPacket(
+      CreateQuickSabmPacket(RFCOMM_MX_DLCI, new_lcid, acl_handle));
+  // We accept
+  BT_HDR* ua_channel_0 = AllocateWrappedOutgoingL2capAclPacket(
+      CreateQuickUaPacket(RFCOMM_MX_DLCI, new_lcid, acl_handle));
+  EXPECT_CALL(l2cap_interface_, DataWrite(new_lcid, BtHdrEqual(ua_channel_0)))
+      .WillOnce(Return(L2CAP_DW_SUCCESS));
+  // And immediately try to configure test_peer_scn
+  BT_HDR* uih_pn_cmd_to_peer = AllocateWrappedOutgoingL2capAclPacket(
+      CreateQuickPnPacket(false, GetDlci(true, test_peer_scn), true, test_mtu,
+                          RFCOMM_PN_CONV_LAYER_CBFC_I >> 4, 0, RFCOMM_K_MAX,
+                          new_lcid, acl_handle));
+  EXPECT_CALL(l2cap_interface_,
+              DataWrite(new_lcid, BtHdrEqual(uih_pn_cmd_to_peer)))
+      .WillOnce(Return(L2CAP_DW_SUCCESS));
+  // Packet should be freed by this method
+  l2cap_appl_info_.pL2CA_DataInd_Cb(new_lcid, sabm_channel_0);
+  osi_free(ua_channel_0);
+  osi_free(uih_pn_cmd_to_peer);
+
+  VLOG(1) << "Step 8";
+  // Peer tries to configure test_server_scn
+  BT_HDR* uih_pn_cmd_from_peer = AllocateWrappedIncomingL2capAclPacket(
+      CreateQuickPnPacket(true, GetDlci(false, test_server_scn), true, test_mtu,
+                          RFCOMM_PN_CONV_LAYER_CBFC_I >> 4, 0, RFCOMM_K_MAX,
+                          new_lcid, acl_handle));
+  // We, as acceptor, must accept
+  BT_HDR* uih_pn_rsp_to_peer = AllocateWrappedOutgoingL2capAclPacket(
+      CreateQuickPnPacket(false, GetDlci(false, test_server_scn), false,
+                          test_mtu, RFCOMM_PN_CONV_LAYER_CBFC_R >> 4, 0,
+                          RFCOMM_K_MAX, new_lcid, acl_handle));
+  EXPECT_CALL(l2cap_interface_,
+              DataWrite(new_lcid, BtHdrEqual(uih_pn_rsp_to_peer)))
+      .Times(1)
+      .WillOnce(Return(L2CAP_DW_SUCCESS));
+  l2cap_appl_info_.pL2CA_DataInd_Cb(new_lcid, uih_pn_cmd_from_peer);
+  osi_free(uih_pn_rsp_to_peer);
+
+  VLOG(1) << "Step 9";
+  // Remote never replies our configuration request for test_peer_scn
+  // But instead connect to test_server_scn directly
+  BT_HDR* sabm_server_scn =
+      AllocateWrappedIncomingL2capAclPacket(CreateQuickSabmPacket(
+          GetDlci(false, test_server_scn), new_lcid, acl_handle));
+  // We must do security check first
+  tBTM_SEC_CALLBACK* security_callback = nullptr;
+  void* p_port = nullptr;
+  EXPECT_CALL(btm_security_internal_interface_,
+              MultiplexingProtocolAccessRequest(
+                  test_address, BT_PSM_RFCOMM, false, BTM_SEC_PROTO_RFCOMM,
+                  test_server_scn, NotNull(), NotNull()))
+      .WillOnce(DoAll(SaveArg<5>(&security_callback), SaveArg<6>(&p_port),
+                      Return(BTM_SUCCESS)));
+  l2cap_appl_info_.pL2CA_DataInd_Cb(new_lcid, sabm_server_scn);
+
+  VLOG(1) << "Step 10";
+  // After security check, we accept the connection
+  ASSERT_TRUE(security_callback);
+  BT_HDR* ua_server_scn =
+      AllocateWrappedOutgoingL2capAclPacket(CreateQuickUaPacket(
+          GetDlci(false, test_server_scn), new_lcid, acl_handle));
+  EXPECT_CALL(l2cap_interface_, DataWrite(new_lcid, BtHdrEqual(ua_server_scn)))
+      .WillOnce(Return(L2CAP_DW_SUCCESS));
+  // Callback should come from server port instead, client port will timeout
+  // in 20 seconds
+  EXPECT_CALL(rfcomm_callback_,
+              PortManagementCallback(PORT_SUCCESS, server_handle, 0));
+  security_callback(&test_address, BT_TRANSPORT_BR_EDR, p_port, BTM_SUCCESS);
+  osi_free(ua_server_scn);
+
+  VLOG(1) << "Step 11";
+  // MPX_CTRL Modem Status Command (MSC)
+  BT_HDR* uih_msc_cmd_from_peer = AllocateWrappedIncomingL2capAclPacket(
+      CreateQuickMscPacket(true, GetDlci(false, test_server_scn), new_lcid,
+                           acl_handle, true, false, true, true, false, true));
+  BT_HDR* uih_msc_rsp_to_peer = AllocateWrappedOutgoingL2capAclPacket(
+      CreateQuickMscPacket(false, GetDlci(false, test_server_scn), new_lcid,
+                           acl_handle, false, false, true, true, false, true));
+  // MPX_CTRL Modem Status Response (MSC)
+  EXPECT_CALL(l2cap_interface_,
+              DataWrite(new_lcid, BtHdrEqual(uih_msc_rsp_to_peer)))
+      .WillOnce(Return(L2CAP_DW_SUCCESS));
+  BT_HDR* uih_msc_cmd_to_peer = AllocateWrappedOutgoingL2capAclPacket(
+      CreateQuickMscPacket(false, GetDlci(false, test_server_scn), new_lcid,
+                           acl_handle, true, false, true, true, false, true));
+  EXPECT_CALL(l2cap_interface_,
+              DataWrite(new_lcid, BtHdrEqual(uih_msc_cmd_to_peer)))
+      .WillOnce(Return(L2CAP_DW_SUCCESS));
+  l2cap_appl_info_.pL2CA_DataInd_Cb(new_lcid, uih_msc_cmd_from_peer);
+  osi_free(uih_msc_rsp_to_peer);
+  osi_free(uih_msc_cmd_to_peer);
+
+  VLOG(1) << "Step 12";
+  BT_HDR* uih_msc_rsp_from_peer = AllocateWrappedIncomingL2capAclPacket(
+      CreateQuickMscPacket(true, GetDlci(false, test_server_scn), new_lcid,
+                           acl_handle, false, false, true, true, false, true));
+  l2cap_appl_info_.pL2CA_DataInd_Cb(new_lcid, uih_msc_rsp_from_peer);
+}
+
+}  // namespace
diff --git a/stack/test/rfcomm/stack_rfcomm_test_main.cc b/stack/test/rfcomm/stack_rfcomm_test_main.cc
new file mode 100644
index 0000000..b6a7b25
--- /dev/null
+++ b/stack/test/rfcomm/stack_rfcomm_test_main.cc
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <base/command_line.h>
+#include <base/logging.h>
+#include <base/strings/string_piece.h>
+#include <base/strings/string_util.h>
+#include <gtest/gtest.h>
+
+#include <string>
+
+#include "bt_trace.h"
+
+// Override LogMsg method so that we can output log via VLOG(1)
+void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {
+  char buffer[256];
+  va_list args;
+  va_start(args, fmt_str);
+  vsnprintf(buffer, 256, fmt_str, args);
+  VLOG(1) << buffer;
+  va_end(args);
+}
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+
+  if (base::CommandLine::InitializedForCurrentProcess()) {
+    LOG(FATAL) << "base::CommandLine::Init should not be called twice";
+    return 1;
+  }
+
+  const char* log_level_arg = nullptr;
+  for (int i = 0; i < argc; ++i) {
+    if (base::StartsWith(base::StringPiece(argv[i]), base::StringPiece("--v="),
+                         base::CompareCase::INSENSITIVE_ASCII)) {
+      log_level_arg = argv[i];
+    }
+  }
+  if (log_level_arg == nullptr) {
+    log_level_arg = "--v=0";
+  }
+  const char* logging_argv[] = {"bt_stack", log_level_arg};
+  // Init command line object with logging switches
+  if (!base::CommandLine::Init(2, logging_argv)) {
+    LOG(FATAL) << "base::CommandLine::Init failed, arg0=" << logging_argv[0]
+               << ", arg1=" << logging_argv[1];
+    return 1;
+  }
+
+  logging::LoggingSettings log_settings;
+  if (!logging::InitLogging(log_settings)) {
+    LOG(ERROR) << "Failed to set up logging";
+  }
+
+  // Android already logs thread_id, proc_id, timestamp, so disable those.
+  logging::SetLogItems(false, false, false, false);
+
+  return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/stack/test/rfcomm/stack_rfcomm_test_utils.cc b/stack/test/rfcomm/stack_rfcomm_test_utils.cc
new file mode 100644
index 0000000..f7745c9
--- /dev/null
+++ b/stack/test/rfcomm/stack_rfcomm_test_utils.cc
@@ -0,0 +1,223 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <bitset>
+#include <string>
+#include <vector>
+
+#include "rfc_int.h"
+#include "stack_test_packet_utils.h"
+
+#include "stack_rfcomm_test_utils.h"
+
+namespace bluetooth {
+namespace rfcomm {
+
+uint8_t GetDlci(bool on_originator_side, uint8_t scn) {
+  return static_cast<uint8_t>((scn << 1) + (on_originator_side ? 1 : 0));
+}
+
+uint8_t GetAddressField(bool ea, bool cr, uint8_t dlci) {
+  std::bitset<8> address;
+  address.set(0, ea);
+  // For UIH frame, cr for initiating device is 1, otherwise 0
+  // Otherwise:
+  //  Command: Initiator -> Responder: 1
+  //  Command: Responder -> Initiator 0
+  //  Response: Initiator -> Responder 0
+  //  Response: Responder -> Initiator 1
+  // Initiator is defined by the one who send SABM=1 command
+  address.set(1, cr);
+  address |= dlci << 2;
+  return static_cast<uint8_t>(address.to_ulong());
+}
+
+uint8_t GetControlField(bool pf, uint8_t frame_type) {
+  std::bitset<8> control;
+  control |= frame_type;
+  control.set(4, pf);
+  return static_cast<uint8_t>(control.to_ulong());
+}
+
+uint8_t GetFrameTypeFromControlField(uint8_t control_field) {
+  return static_cast<uint8_t>(control_field & ~(0b10000));
+}
+
+std::vector<uint8_t> CreateMccPnFrame(uint8_t dlci, uint8_t i_bits,
+                                      uint8_t cl_bits, uint8_t priority,
+                                      uint8_t timer_value, uint16_t rfcomm_mtu,
+                                      uint8_t max_num_retransmission,
+                                      uint8_t err_recovery_window_k) {
+  // Data in little endian order
+  std::vector<uint8_t> result;
+  result.push_back(static_cast<uint8_t>(dlci & 0b00111111));
+  result.push_back(static_cast<uint8_t>((cl_bits << 4) | (i_bits & 0x0F)));
+  result.push_back(static_cast<uint8_t>(priority & 0b00111111));
+  result.push_back(timer_value);
+  result.push_back(static_cast<uint8_t>(rfcomm_mtu));
+  result.push_back(static_cast<uint8_t>(rfcomm_mtu >> 8));
+  result.push_back(max_num_retransmission);
+  result.push_back(static_cast<uint8_t>(err_recovery_window_k & 0b111));
+  return result;
+}
+
+std::vector<uint8_t> CreateMccMscFrame(uint8_t dlci, bool fc, bool rtc,
+                                       bool rtr, bool ic, bool dv) {
+  // Data in little endian order
+  std::vector<uint8_t> result;
+  result.push_back(static_cast<uint8_t>((dlci << 2) | 0b11));
+  std::bitset<8> v24_signals;
+  // EA = 1, single byte
+  v24_signals.set(0, true);
+  v24_signals.set(1, fc);
+  v24_signals.set(2, rtc);
+  v24_signals.set(3, rtr);
+  v24_signals.set(6, ic);
+  v24_signals.set(7, dv);
+  result.push_back(static_cast<uint8_t>(v24_signals.to_ulong()));
+  return result;
+}
+
+std::vector<uint8_t> CreateMultiplexerControlFrame(
+    uint8_t command_type, bool cr, const std::vector<uint8_t>& data) {
+  // Data in little endian order
+  std::vector<uint8_t> result;
+  std::bitset<8> header;
+  header.set(0, true);  // EA is always 1
+  header.set(1, cr);
+  header |= command_type << 2;
+  result.push_back(static_cast<uint8_t>(header.to_ulong()));
+  // 7 bit length + EA(1)
+  result.push_back(static_cast<uint8_t>((data.size() << 1) + 1));
+  result.insert(result.end(), data.begin(), data.end());
+  return result;
+}
+
+std::vector<uint8_t> CreateRfcommPacket(uint8_t address, uint8_t control,
+                                        int credits,
+                                        const std::vector<uint8_t>& data) {
+  // Data in little endian order
+  std::vector<uint8_t> result;
+  result.push_back(address);
+  result.push_back(control);
+  size_t length = data.size();
+  if ((length & 0b1000000) != 0) {
+    // 15 bits of length in little endian order + EA(0)
+    // Lower 7 bits + EA(0)
+    result.push_back(static_cast<uint8_t>(length) << 1);
+    // Upper 8 bits
+    result.push_back(static_cast<uint8_t>(length >> 8));
+  } else {
+    // 7 bits of length + EA(1)
+    result.push_back(static_cast<uint8_t>((length << 1) + 1));
+  }
+  if (credits > 0) {
+    result.push_back(static_cast<uint8_t>(credits));
+  }
+  result.insert(result.end(), data.begin(), data.end());
+  if (GetFrameTypeFromControlField(control) == RFCOMM_UIH) {
+    result.push_back(rfc_calc_fcs(2, result.data()));
+  } else {
+    result.push_back(
+        rfc_calc_fcs(static_cast<uint16_t>(result.size()), result.data()));
+  }
+  return result;
+}
+
+std::vector<uint8_t> CreateQuickUaPacket(uint8_t dlci, uint16_t l2cap_lcid,
+                                         uint16_t acl_handle) {
+  uint8_t address_field = GetAddressField(true, true, dlci);
+  uint8_t control_field = GetControlField(true, RFCOMM_UA);
+  std::vector<uint8_t> rfcomm_packet =
+      CreateRfcommPacket(address_field, control_field, -1, {});
+  std::vector<uint8_t> l2cap_packet =
+      CreateL2capDataPacket(l2cap_lcid, rfcomm_packet);
+  return CreateAclPacket(acl_handle, 0b10, 0b00, l2cap_packet);
+}
+
+std::vector<uint8_t> CreateQuickSabmPacket(uint8_t dlci, uint16_t l2cap_lcid,
+                                           uint16_t acl_handle) {
+  uint8_t address_field = GetAddressField(true, true, dlci);
+  uint8_t control_field = GetControlField(true, RFCOMM_SABME);
+  std::vector<uint8_t> rfcomm_packet =
+      CreateRfcommPacket(address_field, control_field, -1, {});
+  std::vector<uint8_t> l2cap_packet =
+      CreateL2capDataPacket(l2cap_lcid, rfcomm_packet);
+  return CreateAclPacket(acl_handle, 0b10, 0b00, l2cap_packet);
+}
+
+std::vector<uint8_t> CreateQuickPnPacket(bool rfc_cr, uint8_t target_dlci,
+                                         bool mx_cr, uint16_t rfc_mtu,
+                                         uint8_t cl, uint8_t priority,
+                                         uint8_t k, uint16_t l2cap_lcid,
+                                         uint16_t acl_handle) {
+  uint8_t address_field = GetAddressField(true, rfc_cr, RFCOMM_MX_DLCI);
+  uint8_t control_field = GetControlField(false, RFCOMM_UIH);
+  std::vector<uint8_t> mcc_pn_data = CreateMccPnFrame(
+      target_dlci, 0x0, cl, priority, RFCOMM_T1_DSEC, rfc_mtu, RFCOMM_N2, k);
+  std::vector<uint8_t> mcc_payload =
+      CreateMultiplexerControlFrame(0x20, mx_cr, mcc_pn_data);
+  std::vector<uint8_t> rfcomm_packet =
+      CreateRfcommPacket(address_field, control_field, -1, mcc_payload);
+  std::vector<uint8_t> l2cap_packet =
+      CreateL2capDataPacket(l2cap_lcid, rfcomm_packet);
+  return CreateAclPacket(acl_handle, 0b10, 0b00, l2cap_packet);
+}
+
+std::vector<uint8_t> CreateQuickMscPacket(bool rfc_cr, uint8_t dlci,
+                                          uint16_t l2cap_lcid,
+                                          uint16_t acl_handle, bool mx_cr,
+                                          bool fc, bool rtc, bool rtr, bool ic,
+                                          bool dv) {
+  uint8_t address_field = GetAddressField(true, rfc_cr, RFCOMM_MX_DLCI);
+  uint8_t control_field = GetControlField(false, RFCOMM_UIH);
+  std::vector<uint8_t> mcc_msc_data =
+      CreateMccMscFrame(dlci, fc, rtc, rtr, ic, dv);
+  std::vector<uint8_t> mcc_payload =
+      CreateMultiplexerControlFrame(0x38, mx_cr, mcc_msc_data);
+  std::vector<uint8_t> rfcomm_packet =
+      CreateRfcommPacket(address_field, control_field, -1, mcc_payload);
+  std::vector<uint8_t> l2cap_packet =
+      CreateL2capDataPacket(l2cap_lcid, rfcomm_packet);
+  return CreateAclPacket(acl_handle, 0b10, 0b00, l2cap_packet);
+}
+
+std::vector<uint8_t> CreateQuickDataPacket(uint8_t dlci, bool cr,
+                                           uint16_t l2cap_lcid,
+                                           uint16_t acl_handle, int credits,
+                                           const std::vector<uint8_t>& data) {
+  uint8_t address_field = GetAddressField(true, cr, dlci);
+  uint8_t control_field =
+      GetControlField(credits > 0 ? true : false, RFCOMM_UIH);
+  std::vector<uint8_t> rfcomm_packet =
+      CreateRfcommPacket(address_field, control_field, credits, data);
+  std::vector<uint8_t> l2cap_packet =
+      CreateL2capDataPacket(l2cap_lcid, rfcomm_packet);
+  return CreateAclPacket(acl_handle, 0b10, 0b00, l2cap_packet);
+}
+
+std::vector<uint8_t> CreateQuickDataPacket(uint8_t dlci, bool cr,
+                                           uint16_t l2cap_lcid,
+                                           uint16_t acl_handle, int credits,
+                                           const std::string& str) {
+  std::vector<uint8_t> data(str.begin(), str.end());
+  return CreateQuickDataPacket(dlci, cr, l2cap_lcid, acl_handle, credits, data);
+}
+
+}  // namespace rfcomm
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/stack/test/rfcomm/stack_rfcomm_test_utils.h b/stack/test/rfcomm/stack_rfcomm_test_utils.h
new file mode 100644
index 0000000..c7fee43
--- /dev/null
+++ b/stack/test/rfcomm/stack_rfcomm_test_utils.h
@@ -0,0 +1,232 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include <vector>
+
+#include <gmock/gmock.h>
+
+#include "bt_types.h"
+
+namespace bluetooth {
+namespace rfcomm {
+
+class RfcommCallback {
+ public:
+  virtual void PortManagementCallback(uint32_t code, uint16_t port_handle,
+                                      uint16_t callback_index) = 0;
+  virtual void PortEventCallback(uint32_t code, uint16_t port_handle,
+                                 uint16_t callback_index) = 0;
+  virtual ~RfcommCallback() = default;
+};
+
+class MockRfcommCallback : public RfcommCallback {
+ public:
+  MOCK_METHOD3(PortManagementCallback, void(uint32_t code, uint16_t port_handle,
+                                            uint16_t callback_index));
+  MOCK_METHOD3(PortEventCallback, void(uint32_t code, uint16_t port_handle,
+                                       uint16_t callback_index));
+};
+
+/**
+ * Create DLCI using direction of service channel number
+ *
+ * @param on_originator_side is this a channel on initiator side
+ * @param scn service channel number
+ * @return DLCI
+ */
+uint8_t GetDlci(bool on_originator_side, uint8_t scn);
+
+/**
+ * Create address field in RFCOMM packet
+ *
+ * @param ea end of field byte, true if field only has 1 byte, false otherwise
+ * @param cr command and response bit, true if packet is from initiator,
+ *           false otherwise, not actual "command" and "response"
+ * @param dlci DLCI of this pcaket, RFCOMM_MX_DLCI for multiplexer control
+ * @return address field
+ */
+uint8_t GetAddressField(bool ea, bool cr, uint8_t dlci);
+
+/**
+ * Create control field in RFCOMM packet
+ *
+ * @param pf Poll/Finish bit, normally 1 for multiplexer control channel
+ * @param frame_type frame type
+ * @return control field
+ */
+uint8_t GetControlField(bool pf, uint8_t frame_type);
+
+/**
+ * Create Multiplexer control channel parameter negotiation frame
+ *
+ * @param dlci DLCI to be configured
+ * @param i_bits i bits
+ * @param cl_bits cl bits
+ * @param priority priority
+ * @param timer_value timer value
+ * @param rfcomm_mtu rfcomm mtu
+ * @param max_num_retransmission maximum number of retransmission
+ * @param err_recovery_window_k error recovery window k
+ * @return vector of bytes of this frame
+ */
+std::vector<uint8_t> CreateMccPnFrame(uint8_t dlci, uint8_t i_bits,
+                                      uint8_t cl_bits, uint8_t priority,
+                                      uint8_t timer_value, uint16_t rfcomm_mtu,
+                                      uint8_t max_num_retransmission,
+                                      uint8_t err_recovery_window_k);
+/**
+ * Create Multiplexer Control Modem Status Configuration Frame
+ *
+ * @param dlci DLCI to be configured
+ * @param fc flow control
+ * @param rtc ready to communicate
+ * @param rtr ready to receive
+ * @param ic incoming call indicator
+ * @param dv is data valid
+ * @return vector of bytes
+ */
+std::vector<uint8_t> CreateMccMscFrame(uint8_t dlci, bool fc, bool rtc,
+                                       bool rtr, bool ic, bool dv);
+
+/**
+ * Create Multiplexer Control Frame
+ *
+ * @param command_type type of command
+ * @param cr command or response flag, true when this is a command, false when
+ *           this is a response, regardless of connection direction
+ * @param data frame data
+ * @return vector of bytes
+ */
+std::vector<uint8_t> CreateMultiplexerControlFrame(
+    uint8_t command_type, bool cr, const std::vector<uint8_t>& data);
+
+/**
+ * Create a general RFCOMM packet
+ *
+ * @param address address byte
+ * @param control control byte
+ * @param credits number of credits, <= 0 will cause this to be ignored
+ * @param data frame data
+ * @return vector of bytes
+ */
+std::vector<uint8_t> CreateRfcommPacket(uint8_t address, uint8_t control,
+                                        int credits,
+                                        const std::vector<uint8_t>& data);
+/*
+ * Various shortcut for getting frequently used packets
+ */
+
+/**
+ * Create SABM packet that is used to connect to a service channel number in a
+ * multiplexer
+ *
+ * @param dlci DLCI to be connected
+ * @param l2cap_lcid L2CAP channel ID
+ * @param acl_handle ACL handle
+ * @return vector of bytes of unwrapped ACL packet
+ */
+std::vector<uint8_t> CreateQuickSabmPacket(uint8_t dlci, uint16_t l2cap_lcid,
+                                           uint16_t acl_handle);
+
+/**
+ * Create UA packet that is used to acknowledge service channel connection
+ *
+ * @param dlci DLCI to be connected
+ * @param l2cap_lcid L2CAP channel ID
+ * @param acl_handle ACL handle
+ * @return vector of bytes of unwrapped ACL packet
+ */
+std::vector<uint8_t> CreateQuickUaPacket(uint8_t dlci, uint16_t l2cap_lcid,
+                                         uint16_t acl_handle);
+
+/**
+ * Create parameter negotiation packet used to setup parameters for a DLCI
+ *
+ * @param rfc_cr RFCOMM command/response bit, true of initiator
+ * @param target_dlci DLCI to be configured
+ * @param mx_cr multiplexer command or reponse, regardless of initiator
+ * @param rfc_mtu RFCOMM mtu to be used for DLCI
+ * @param cl CL bit
+ * @param priority prirority
+ * @param k error recovery window k
+ * @param l2cap_lcid L2CAP channel ID
+ * @param acl_handle ACL handle
+ * @return vector of bytes of unwrapped ACL packet
+ */
+std::vector<uint8_t> CreateQuickPnPacket(bool rfc_cr, uint8_t target_dlci,
+                                         bool mx_cr, uint16_t rfc_mtu,
+                                         uint8_t cl, uint8_t priority,
+                                         uint8_t k, uint16_t l2cap_lcid,
+                                         uint16_t acl_handle);
+
+/**
+ * Create modem signal control packet
+ *
+ * @param rfc_cr RFCOMM command/response bit, true of initiator
+ * @param dlci DLCI to be configured
+ * @param l2cap_lcid L2CAP channel ID
+ * @param acl_handle ACL handle
+ * @param mx_cr multiplexer command or reponse, regardless of initiator
+ * @param fc flow control
+ * @param rtc ready to communicate
+ * @param rtr ready to receive
+ * @param ic incoming call indicator
+ * @param dv data valid
+ * @return vector of bytes of unwrapped ACL packet
+ */
+std::vector<uint8_t> CreateQuickMscPacket(bool rfc_cr, uint8_t dlci,
+                                          uint16_t l2cap_lcid,
+                                          uint16_t acl_handle, bool mx_cr,
+                                          bool fc, bool rtc, bool rtr, bool ic,
+                                          bool dv);
+
+/**
+ * Create a quick RFCOMM data packet
+ *
+ * @param dlci DLCI of this packet
+ * @param cr command or control, true for initiator
+ * @param l2cap_lcid L2CAP channel ID
+ * @param acl_handle ACL handle
+ * @param credits number of credits
+ * @param data data bytes
+ * @return vector of bytes of unwrapped ACL packet
+ */
+std::vector<uint8_t> CreateQuickDataPacket(uint8_t dlci, bool cr,
+                                           uint16_t l2cap_lcid,
+                                           uint16_t acl_handle, int credits,
+                                           const std::vector<uint8_t>& data);
+
+/**
+ * Create a quick RFCOMM data packet
+ *
+ * @param dlci DLCI of this packet
+ * @param cr command or control, true for initiator
+ * @param l2cap_lcid L2CAP channel ID
+ * @param acl_handle ACL handle
+ * @param credits number of credits
+ * @param str message in string format
+ * @return vector of bytes of unwrapped ACL packet
+ */
+std::vector<uint8_t> CreateQuickDataPacket(uint8_t dlci, bool cr,
+                                           uint16_t l2cap_lcid,
+                                           uint16_t acl_handle, int credits,
+                                           const std::string& str);
+
+}  // namespace rfcomm
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/stack/test/rfcomm/stack_rfcomm_test_utils_test.cc b/stack/test/rfcomm/stack_rfcomm_test_utils_test.cc
new file mode 100644
index 0000000..3d9a2d5
--- /dev/null
+++ b/stack/test/rfcomm/stack_rfcomm_test_utils_test.cc
@@ -0,0 +1,246 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <string>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "rfcdefs.h"
+#include "stack_rfcomm_test_utils.h"
+#include "stack_test_packet_utils.h"
+
+namespace {
+
+using testing::ElementsAreArray;
+
+using bluetooth::CreateL2capDataPacket;
+using bluetooth::CreateAclPacket;
+using bluetooth::AllocateWrappedIncomingL2capAclPacket;
+
+using bluetooth::rfcomm::GetDlci;
+using bluetooth::rfcomm::GetAddressField;
+using bluetooth::rfcomm::GetControlField;
+using bluetooth::rfcomm::CreateMccPnFrame;
+using bluetooth::rfcomm::CreateMccMscFrame;
+using bluetooth::rfcomm::CreateMultiplexerControlFrame;
+using bluetooth::rfcomm::CreateRfcommPacket;
+using bluetooth::rfcomm::CreateQuickDataPacket;
+using bluetooth::rfcomm::CreateQuickPnPacket;
+using bluetooth::rfcomm::CreateQuickSabmPacket;
+using bluetooth::rfcomm::CreateQuickUaPacket;
+using bluetooth::rfcomm::CreateQuickMscPacket;
+
+const uint8_t kIncomingSabmChannel0[] = {0x08, 0x20, 0x08, 0x00, 0x04, 0x00,
+                                         0x5c, 0x00, 0x03, 0x3f, 0x01, 0x1c};
+
+TEST(RfcommTestPacketGeneratorTest, TestGenerateSabmChannel0Packet) {
+  uint8_t dlci = GetDlci(false, 0);
+  EXPECT_EQ(dlci, 0);
+  uint8_t address_field = GetAddressField(true, true, dlci);
+  EXPECT_EQ(address_field, 0x03);
+  uint8_t control_field = GetControlField(true, RFCOMM_SABME);
+  EXPECT_EQ(control_field, 0x3F);
+  std::vector<uint8_t> rfcomm_packet =
+      CreateRfcommPacket(address_field, control_field, -1, {});
+  std::vector<uint8_t> l2cap_packet =
+      CreateL2capDataPacket(0x005c, rfcomm_packet);
+  std::vector<uint8_t> acl_packet =
+      CreateAclPacket(0x0008, 0b10, 0b00, l2cap_packet);
+  EXPECT_THAT(acl_packet, ElementsAreArray(kIncomingSabmChannel0));
+}
+
+TEST(RfcommTestPacketGeneratorTest, TestQuickGenerateSabmChannel0Packet) {
+  EXPECT_THAT(CreateQuickSabmPacket(RFCOMM_MX_DLCI, 0x005c, 0x0008),
+              ElementsAreArray(kIncomingSabmChannel0));
+}
+
+const uint8_t kOutgoingUaChannel0[] = {0x08, 0x20, 0x08, 0x00, 0x04, 0x00,
+                                       0x00, 0x17, 0x03, 0x73, 0x01, 0xd7};
+
+TEST(RfcommTestPacketGeneratorTest, TestGenerateUaPacket) {
+  uint8_t dlci = GetDlci(false, 0);
+  EXPECT_EQ(dlci, 0);
+  uint8_t address_field = GetAddressField(true, true, dlci);
+  EXPECT_EQ(address_field, 0x03);
+  uint8_t control_field = GetControlField(true, RFCOMM_UA);
+  EXPECT_EQ(control_field, 0x73);
+  std::vector<uint8_t> rfcomm_packet =
+      CreateRfcommPacket(address_field, control_field, -1, {});
+  std::vector<uint8_t> l2cap_packet =
+      CreateL2capDataPacket(0x1700, rfcomm_packet);
+  std::vector<uint8_t> acl_packet =
+      CreateAclPacket(0x0008, 0b10, 0b00, l2cap_packet);
+  EXPECT_THAT(acl_packet, ElementsAreArray(kOutgoingUaChannel0));
+}
+
+TEST(RfcommTestPacketGeneratorTest, TestQuickGenerateUaPacket) {
+  EXPECT_THAT(CreateQuickUaPacket(RFCOMM_MX_DLCI, 0x1700, 0x0008),
+              ElementsAreArray(kOutgoingUaChannel0));
+}
+
+const uint8_t kIncomingUihPnSetChannelTo3[] = {
+    0x08, 0x20, 0x12, 0x00, 0x0e, 0x00, 0x5c, 0x00, 0x03, 0xef, 0x15,
+    0x83, 0x11, 0x06, 0xf0, 0x00, 0x00, 0x74, 0x03, 0x00, 0x01, 0x70};
+
+TEST(RfcommTestPacketGeneratorTest, TestGenerateUihPnSetChannel3Packet) {
+  uint8_t dlci = GetDlci(false, 0);
+  EXPECT_EQ(dlci, 0);
+  uint8_t address_field = GetAddressField(true, true, dlci);
+  EXPECT_EQ(address_field, 0x03);
+  uint8_t control_field = GetControlField(false, RFCOMM_UIH);
+  EXPECT_EQ(control_field, 0xEF);
+  uint8_t new_dlci = GetDlci(false, 3);
+  EXPECT_EQ(new_dlci, 6);
+  std::vector<uint8_t> mcc_pn_data =
+      CreateMccPnFrame(new_dlci, 0x0, 0xF, 0, 0, 884, 0, 1);
+  std::vector<uint8_t> mcc_payload =
+      CreateMultiplexerControlFrame(0x20, true, mcc_pn_data);
+  std::vector<uint8_t> rfcomm_packet =
+      CreateRfcommPacket(address_field, control_field, -1, mcc_payload);
+  std::vector<uint8_t> l2cap_packet =
+      CreateL2capDataPacket(0x005c, rfcomm_packet);
+  std::vector<uint8_t> acl_packet =
+      CreateAclPacket(0x0008, 0b10, 0b00, l2cap_packet);
+  EXPECT_THAT(acl_packet, ElementsAreArray(kIncomingUihPnSetChannelTo3));
+}
+
+TEST(RfcommTestPacketGeneratorTest, TestQuickGenerateUihPnSetChannel3Packet) {
+  EXPECT_THAT(CreateQuickPnPacket(true, GetDlci(false, 3), true, 884, 0xF, 0, 1,
+                                  0x005c, 0x0008),
+              ElementsAreArray(kIncomingUihPnSetChannelTo3));
+}
+
+const uint8_t kIncomingSabmChannel3[] = {0x08, 0x20, 0x08, 0x00, 0x04, 0x00,
+                                         0x5c, 0x00, 0x1b, 0x3f, 0x01, 0xd3};
+
+TEST(RfcommTestPacketGeneratorTest, TestGenerateSabmChannel3Packet) {
+  uint8_t dlci = GetDlci(false, 3);
+  EXPECT_EQ(dlci, 6);
+  uint8_t address_field = GetAddressField(true, true, dlci);
+  EXPECT_EQ(address_field, 0x1b);
+  uint8_t control_field = GetControlField(true, RFCOMM_SABME);
+  EXPECT_EQ(control_field, 0x3F);
+  std::vector<uint8_t> rfcomm_packet =
+      CreateRfcommPacket(address_field, control_field, -1, {});
+  std::vector<uint8_t> l2cap_packet =
+      CreateL2capDataPacket(0x005c, rfcomm_packet);
+  std::vector<uint8_t> acl_packet =
+      CreateAclPacket(0x0008, 0b10, 0b00, l2cap_packet);
+  EXPECT_THAT(acl_packet, ElementsAreArray(kIncomingSabmChannel3));
+}
+
+TEST(RfcommTestPacketGeneratorTest, TestGenerateQuickSabmChannel3Packet) {
+  EXPECT_THAT(CreateQuickSabmPacket(GetDlci(false, 3), 0x005c, 0x0008),
+              ElementsAreArray(kIncomingSabmChannel3));
+}
+
+const uint8_t kIncomingUihMscCmdFrame[] = {0x08, 0x20, 0x0c, 0x00, 0x08, 0x00,
+                                           0x5c, 0x00, 0x03, 0xef, 0x09, 0xe3,
+                                           0x05, 0x1b, 0x8d, 0x70};
+
+TEST(RfcommTestPacketGeneratorTest, TestGenerateUihMscCmdPacket) {
+  uint8_t dlci = GetDlci(false, 0);
+  EXPECT_EQ(dlci, 0);
+  uint8_t address_field = GetAddressField(true, true, dlci);
+  EXPECT_EQ(address_field, 0x03);
+  uint8_t control_field = GetControlField(false, RFCOMM_UIH);
+  EXPECT_EQ(control_field, 0xEF);
+  uint8_t new_dlci = GetDlci(false, 3);
+  EXPECT_EQ(new_dlci, 6);
+  std::vector<uint8_t> mcc_msc_data =
+      CreateMccMscFrame(new_dlci, false, true, true, false, true);
+  std::vector<uint8_t> mcc_payload =
+      CreateMultiplexerControlFrame(0x38, true, mcc_msc_data);
+  std::vector<uint8_t> rfcomm_packet =
+      CreateRfcommPacket(address_field, control_field, -1, mcc_payload);
+  std::vector<uint8_t> l2cap_packet =
+      CreateL2capDataPacket(0x005c, rfcomm_packet);
+  std::vector<uint8_t> acl_packet =
+      CreateAclPacket(0x0008, 0b10, 0b00, l2cap_packet);
+  EXPECT_THAT(acl_packet, ElementsAreArray(kIncomingUihMscCmdFrame));
+}
+
+TEST(RfcommTestPacketGeneratorTest, TestQuickGenerateUihMscCmdPacket) {
+  EXPECT_THAT(CreateQuickMscPacket(true, GetDlci(false, 3), 0x005c, 0x0008,
+                                   true, false, true, true, false, true),
+              ElementsAreArray(kIncomingUihMscCmdFrame));
+}
+
+const uint8_t kIncomingUihMscResponseFrame[] = {
+    0x08, 0x20, 0x0c, 0x00, 0x08, 0x00, 0x5c, 0x00,
+    0x03, 0xef, 0x09, 0xe1, 0x05, 0x1b, 0x8d, 0x70};
+
+TEST(RfcommTestPacketGeneratorTest, TestGenerateUihMscResponsePacket) {
+  uint8_t dlci = GetDlci(false, 0);
+  EXPECT_EQ(dlci, 0);
+  uint8_t address_field = GetAddressField(true, true, dlci);
+  EXPECT_EQ(address_field, 0x03);
+  uint8_t control_field = GetControlField(false, RFCOMM_UIH);
+  EXPECT_EQ(control_field, 0xEF);
+  uint8_t new_dlci = GetDlci(false, 3);
+  EXPECT_EQ(new_dlci, 6);
+  std::vector<uint8_t> mcc_msc_data =
+      CreateMccMscFrame(new_dlci, false, true, true, false, true);
+  std::vector<uint8_t> mcc_payload =
+      CreateMultiplexerControlFrame(0x38, false, mcc_msc_data);
+  std::vector<uint8_t> rfcomm_packet =
+      CreateRfcommPacket(address_field, control_field, -1, mcc_payload);
+  std::vector<uint8_t> l2cap_packet =
+      CreateL2capDataPacket(0x005c, rfcomm_packet);
+  std::vector<uint8_t> acl_packet =
+      CreateAclPacket(0x0008, 0b10, 0b00, l2cap_packet);
+  EXPECT_THAT(acl_packet, ElementsAreArray(kIncomingUihMscResponseFrame));
+}
+
+TEST(RfcommTestPacketGeneratorTest, TestQuickGenerateUihMscResponsePacket) {
+  EXPECT_THAT(CreateQuickMscPacket(true, GetDlci(false, 3), 0x005c, 0x0008,
+                                   false, false, true, true, false, true),
+              ElementsAreArray(kIncomingUihMscResponseFrame));
+}
+
+const uint8_t kIncomingBrsfFrame[] = {0x08, 0x20, 0x15, 0x00, 0x11, 0x00, 0x5c,
+                                      0x00, 0x1b, 0xff, 0x19, 0x06, 0x41, 0x54,
+                                      0x2b, 0x42, 0x52, 0x53, 0x46, 0x3d, 0x39,
+                                      0x35, 0x39, 0x0d, 0x93};
+
+TEST(RfcommTestPacketGeneratorTest, TestGenerateDataPacket) {
+  uint8_t dlci = GetDlci(false, 3);
+  EXPECT_EQ(dlci, 6);
+  uint8_t address_field = GetAddressField(true, true, dlci);
+  EXPECT_EQ(address_field, 0x1B);
+  uint8_t control_field = GetControlField(true, RFCOMM_UIH);
+  EXPECT_EQ(control_field, 0xFF);
+  const std::string data_str = "AT+BRSF=959\r";
+  const std::vector<uint8_t> data(data_str.begin(), data_str.end());
+  std::vector<uint8_t> rfcomm_packet =
+      CreateRfcommPacket(address_field, control_field, 6, data);
+  std::vector<uint8_t> l2cap_packet =
+      CreateL2capDataPacket(0x005c, rfcomm_packet);
+  std::vector<uint8_t> acl_packet =
+      CreateAclPacket(0x0008, 0b10, 0b00, l2cap_packet);
+  EXPECT_THAT(acl_packet, ElementsAreArray(kIncomingBrsfFrame));
+}
+
+TEST(RfcommTestPacketGeneratorTest, TestQuickGenerateDataPacket) {
+  EXPECT_THAT(CreateQuickDataPacket(GetDlci(false, 3), true, 0x005c, 0x0008, 6,
+                                    "AT+BRSF=959\r"),
+              ElementsAreArray(kIncomingBrsfFrame));
+}
+
+}  // namespace
\ No newline at end of file
diff --git a/test/run_unit_tests.sh b/test/run_unit_tests.sh
index 9fc0676..066e8e1 100755
--- a/test/run_unit_tests.sh
+++ b/test/run_unit_tests.sh
@@ -20,10 +20,11 @@
   net_test_btu_message_loop
   net_test_osi
   net_test_performance
+  net_test_stack_rfcomm
 )
 
 known_remote_tests=(
-  net_test_rfcomm
+  net_test_rfcomm_suite
 )
 
 
diff --git a/test/suite/Android.bp b/test/suite/Android.bp
index fb501c7..ed5b531 100644
--- a/test/suite/Android.bp
+++ b/test/suite/Android.bp
@@ -28,7 +28,7 @@
 // Bluetooth test suite for target
 // ========================================================
 cc_test {
-    name: "net_test_rfcomm",
+    name: "net_test_rfcomm_suite",
     defaults: ["fluoride_defaults"],
     include_dirs: ["system/bt"],
     srcs: [