普通文本  |  893行  |  39.88 KB

/******************************************************************************
 *
 *  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