You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
890 lines
40 KiB
890 lines
40 KiB
/******************************************************************************
|
|
*
|
|
* 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 "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, L2CAP_CFG_OK, {});
|
|
|
|
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, L2CAP_CFG_OK, {});
|
|
|
|
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(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
|
|
l2cap_appl_info_.pL2CA_ConfigCfm_Cb(new_lcid, L2CAP_CFG_OK, {});
|
|
|
|
// 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
|