From 3dfb5f8ab621e9822f99ab25956e7822eab2b26c Mon Sep 17 00:00:00 2001
From: Jack He <siyuanh@google.com>
Date: Fri, 20 Apr 2018 22:04:21 -0700
Subject: [PATCH] RFCOMM: Add unit tests for connection scenarios

Unit tests:
* Add net_test_stack_rfcomm
* Use a compiler trick to compile production RFCOMM code against L2CAP
  and BTM header, but fake L2CAP and BTM source code so that we can stub
  statically defined L2CAP and BTM code using mocks
* Rename net_test_rfcomm to net_test_rfcomm_suite
* Add mocked L2CAP and BTM layer to allow packet replay from L2CAP layer
  to RFCOMM layer in order to reproduce time dependent issues such as
  connection collision
* Add a number of utility methods that generates RFCOMM packet bytes
  using supported parameters
* Add unit test for above utility methods
* Add suite of unit tests named StackRfcommTest, including:
 - SingleServerConnectionHelloWorld
 - MultiServerPortSameDeviceHelloWorld
 - SameServerPortMultiDeviceHelloWorld
 - SingleClientConnectionHelloWorld
 - SameClientPortMultiDeviceHelloWorld
* These tests supply L2CAP packets and API calls to trigger RFCOMM
  connection setup in various scenarios
* Added logging method to output debug log via VLOG(1) logging level and
  allow compile time configuration of these logs through a constant flag

Bug: 77224743
Test: ./test/run_unit_tests.sh net_test_stack_rfcomm
      testplans/details/158641/3975
Change-Id: I9d59843603cd36394c3736670bcf3c39dea26674
---
 system/stack/Android.bp                       |  54 +-
 system/stack/test/common/mock_btm_layer.cc    |  45 ++
 system/stack/test/common/mock_btm_layer.h     |  57 ++
 system/stack/test/common/mock_btu_layer.cc    |  21 +
 system/stack/test/common/mock_l2cap_layer.cc  |  59 ++
 system/stack/test/common/mock_l2cap_layer.h   |  65 ++
 .../test/common/stack_test_packet_utils.cc    |  96 +++
 .../test/common/stack_test_packet_utils.h     |  78 ++
 system/stack/test/rfcomm/stack_rfcomm_test.cc | 715 ++++++++++++++++++
 .../test/rfcomm/stack_rfcomm_test_main.cc     |  74 ++
 .../test/rfcomm/stack_rfcomm_test_utils.cc    | 223 ++++++
 .../test/rfcomm/stack_rfcomm_test_utils.h     | 232 ++++++
 .../rfcomm/stack_rfcomm_test_utils_test.cc    | 246 ++++++
 system/test/run_unit_tests.sh                 |   3 +-
 system/test/suite/Android.bp                  |   2 +-
 15 files changed, 1967 insertions(+), 3 deletions(-)
 create mode 100644 system/stack/test/common/mock_btm_layer.cc
 create mode 100644 system/stack/test/common/mock_btm_layer.h
 create mode 100644 system/stack/test/common/mock_btu_layer.cc
 create mode 100644 system/stack/test/common/mock_l2cap_layer.cc
 create mode 100644 system/stack/test/common/mock_l2cap_layer.h
 create mode 100644 system/stack/test/common/stack_test_packet_utils.cc
 create mode 100644 system/stack/test/common/stack_test_packet_utils.h
 create mode 100644 system/stack/test/rfcomm/stack_rfcomm_test.cc
 create mode 100644 system/stack/test/rfcomm/stack_rfcomm_test_main.cc
 create mode 100644 system/stack/test/rfcomm/stack_rfcomm_test_utils.cc
 create mode 100644 system/stack/test/rfcomm/stack_rfcomm_test_utils.h
 create mode 100644 system/stack/test/rfcomm/stack_rfcomm_test_utils_test.cc

diff --git a/system/stack/Android.bp b/system/stack/Android.bp
index 4025e6e7a84..1b62a2f9e5e 100644
--- a/system/stack/Android.bp
+++ b/system/stack/Android.bp
@@ -197,7 +197,9 @@ cc_test {
         "packages/modules/Bluetooth/system",
         "packages/modules/Bluetooth/system/internal_include",
     ],
-    srcs: ["test/stack_a2dp_test.cc"],
+    srcs: [
+        "test/stack_a2dp_test.cc",
+    ],
     shared_libs: [
         "libhidlbase",
         "liblog",
@@ -221,6 +223,56 @@ cc_test {
     ],
 }
 
+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: [
+      "packages/modules/Bluetooth/system",
+      "packages/modules/Bluetooth/system/internal_include",
+      "packages/modules/Bluetooth/system/btcore/include",
+      "packages/modules/Bluetooth/system/hci/include",
+      "packages/modules/Bluetooth/system/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/system/stack/test/common/mock_btm_layer.cc b/system/stack/test/common/mock_btm_layer.cc
new file mode 100644
index 00000000000..1405c55446c
--- /dev/null
+++ b/system/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/system/stack/test/common/mock_btm_layer.h b/system/stack/test/common/mock_btm_layer.h
new file mode 100644
index 00000000000..45f32d1dc5b
--- /dev/null
+++ b/system/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/system/stack/test/common/mock_btu_layer.cc b/system/stack/test/common/mock_btu_layer.cc
new file mode 100644
index 00000000000..f5bbf7a0f4c
--- /dev/null
+++ b/system/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/system/stack/test/common/mock_l2cap_layer.cc b/system/stack/test/common/mock_l2cap_layer.cc
new file mode 100644
index 00000000000..9f08d567308
--- /dev/null
+++ b/system/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/system/stack/test/common/mock_l2cap_layer.h b/system/stack/test/common/mock_l2cap_layer.h
new file mode 100644
index 00000000000..78c8a9c6d02
--- /dev/null
+++ b/system/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/system/stack/test/common/stack_test_packet_utils.cc b/system/stack/test/common/stack_test_packet_utils.cc
new file mode 100644
index 00000000000..74fc57d25d0
--- /dev/null
+++ b/system/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/system/stack/test/common/stack_test_packet_utils.h b/system/stack/test/common/stack_test_packet_utils.h
new file mode 100644
index 00000000000..fcbc5a9d18e
--- /dev/null
+++ b/system/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/system/stack/test/rfcomm/stack_rfcomm_test.cc b/system/stack/test/rfcomm/stack_rfcomm_test.cc
new file mode 100644
index 00000000000..8d3d8859dde
--- /dev/null
+++ b/system/stack/test/rfcomm/stack_rfcomm_test.cc
@@ -0,0 +1,715 @@
+/******************************************************************************
+ *
+ *  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));
+}
+
+}  // namespace
diff --git a/system/stack/test/rfcomm/stack_rfcomm_test_main.cc b/system/stack/test/rfcomm/stack_rfcomm_test_main.cc
new file mode 100644
index 00000000000..b6a7b256e78
--- /dev/null
+++ b/system/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/system/stack/test/rfcomm/stack_rfcomm_test_utils.cc b/system/stack/test/rfcomm/stack_rfcomm_test_utils.cc
new file mode 100644
index 00000000000..f7745c9e25f
--- /dev/null
+++ b/system/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/system/stack/test/rfcomm/stack_rfcomm_test_utils.h b/system/stack/test/rfcomm/stack_rfcomm_test_utils.h
new file mode 100644
index 00000000000..c7fee43f7e0
--- /dev/null
+++ b/system/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/system/stack/test/rfcomm/stack_rfcomm_test_utils_test.cc b/system/stack/test/rfcomm/stack_rfcomm_test_utils_test.cc
new file mode 100644
index 00000000000..3d9a2d5b0c9
--- /dev/null
+++ b/system/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/system/test/run_unit_tests.sh b/system/test/run_unit_tests.sh
index 9fc0676aca4..066e8e11bef 100755
--- a/system/test/run_unit_tests.sh
+++ b/system/test/run_unit_tests.sh
@@ -20,10 +20,11 @@ known_tests=(
   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/system/test/suite/Android.bp b/system/test/suite/Android.bp
index 2db721de1ca..5904cd5910e 100644
--- a/system/test/suite/Android.bp
+++ b/system/test/suite/Android.bp
@@ -28,7 +28,7 @@ cc_test {
 // Bluetooth test suite for target
 // ========================================================
 cc_test {
-    name: "net_test_rfcomm",
+    name: "net_test_rfcomm_suite",
     defaults: ["fluoride_defaults"],
     include_dirs: ["packages/modules/Bluetooth/system"],
     srcs: [
-- 
GitLab