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