| /* |
| * Copyright 2017 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 "link_layer_controller.h" |
| |
| #include <hci/hci_packets.h> |
| #ifdef ROOTCANAL_LMP |
| #include <lmp.h> |
| #endif /* ROOTCANAL_LMP */ |
| |
| #include "crypto_toolbox/crypto_toolbox.h" |
| #include "os/log.h" |
| #include "packet/raw_builder.h" |
| |
| using std::vector; |
| using namespace std::chrono; |
| using bluetooth::hci::Address; |
| using bluetooth::hci::AddressType; |
| using bluetooth::hci::AddressWithType; |
| using bluetooth::hci::EventCode; |
| using bluetooth::hci::SubeventCode; |
| |
| using namespace model::packets; |
| using model::packets::PacketType; |
| using namespace std::literals; |
| |
| namespace rootcanal { |
| |
| constexpr uint16_t kNumCommandPackets = 0x01; |
| |
| constexpr milliseconds kNoDelayMs(0); |
| |
| // TODO: Model Rssi? |
| static uint8_t GetRssi() { |
| static uint8_t rssi = 0; |
| rssi += 5; |
| if (rssi > 128) { |
| rssi = rssi % 7; |
| } |
| return -(rssi); |
| } |
| |
| void LinkLayerController::SendLeLinkLayerPacketWithRssi( |
| Address source, Address dest, uint8_t rssi, |
| std::unique_ptr<model::packets::LinkLayerPacketBuilder> packet) { |
| std::shared_ptr<model::packets::RssiWrapperBuilder> shared_packet = |
| model::packets::RssiWrapperBuilder::Create(source, dest, rssi, |
| std::move(packet)); |
| ScheduleTask(kNoDelayMs, [this, shared_packet]() { |
| send_to_remote_(shared_packet, Phy::Type::LOW_ENERGY); |
| }); |
| } |
| |
| #ifdef ROOTCANAL_LMP |
| LinkLayerController::LinkLayerController(const DeviceProperties& properties) |
| : properties_(properties), lm_(nullptr, link_manager_destroy) { |
| auto ops = (struct LinkManagerOps){ |
| .user_pointer = this, |
| .get_handle = |
| [](void* user, const uint8_t(*address)[6]) { |
| auto controller = static_cast<LinkLayerController*>(user); |
| |
| return controller->connections_.GetHandleOnlyAddress( |
| Address(*address)); |
| }, |
| |
| .get_address = |
| [](void* user, uint16_t handle, uint8_t(*result)[6]) { |
| auto controller = static_cast<LinkLayerController*>(user); |
| |
| auto address = |
| controller->connections_.GetAddress(handle).GetAddress(); |
| std::copy(address.data(), address.data() + 6, |
| reinterpret_cast<uint8_t*>(result)); |
| }, |
| |
| .extended_features = |
| [](void* user, uint8_t features_page) { |
| auto controller = static_cast<LinkLayerController*>(user); |
| |
| return controller->properties_.GetExtendedFeatures(features_page); |
| }, |
| |
| .send_hci_event = |
| [](void* user, const uint8_t* data, uintptr_t len) { |
| auto controller = static_cast<LinkLayerController*>(user); |
| |
| auto event_code = static_cast<EventCode>(data[0]); |
| auto payload = std::make_unique<bluetooth::packet::RawBuilder>( |
| std::vector(data + 2, data + len)); |
| |
| controller->send_event_(bluetooth::hci::EventBuilder::Create( |
| event_code, std::move(payload))); |
| }, |
| |
| .send_lmp_packet = |
| [](void* user, const uint8_t(*to)[6], const uint8_t* data, |
| uintptr_t len) { |
| auto controller = static_cast<LinkLayerController*>(user); |
| |
| auto payload = std::make_unique<bluetooth::packet::RawBuilder>( |
| std::vector(data, data + len)); |
| |
| Address source = controller->properties_.GetAddress(); |
| Address dest(*to); |
| |
| controller->SendLinkLayerPacket(model::packets::LmpBuilder::Create( |
| source, dest, std::move(payload))); |
| }}; |
| |
| lm_.reset(link_manager_create(ops)); |
| } |
| #else |
| LinkLayerController::LinkLayerController(const DeviceProperties& properties) |
| : properties_(properties) {} |
| #endif |
| |
| void LinkLayerController::SendLeLinkLayerPacket( |
| std::unique_ptr<model::packets::LinkLayerPacketBuilder> packet) { |
| std::shared_ptr<model::packets::LinkLayerPacketBuilder> shared_packet = |
| std::move(packet); |
| ScheduleTask(kNoDelayMs, [this, shared_packet]() { |
| send_to_remote_(shared_packet, Phy::Type::LOW_ENERGY); |
| }); |
| } |
| |
| void LinkLayerController::SendLinkLayerPacket( |
| std::unique_ptr<model::packets::LinkLayerPacketBuilder> packet) { |
| std::shared_ptr<model::packets::LinkLayerPacketBuilder> shared_packet = |
| std::move(packet); |
| ScheduleTask(kNoDelayMs, [this, shared_packet]() { |
| send_to_remote_(shared_packet, Phy::Type::BR_EDR); |
| }); |
| } |
| |
| ErrorCode LinkLayerController::SendLeCommandToRemoteByAddress( |
| OpCode opcode, const Address& remote, const Address& local) { |
| switch (opcode) { |
| case (OpCode::LE_READ_REMOTE_FEATURES): |
| SendLeLinkLayerPacket( |
| model::packets::LeReadRemoteFeaturesBuilder::Create(local, remote)); |
| break; |
| default: |
| LOG_INFO("Dropping unhandled command 0x%04x", |
| static_cast<uint16_t>(opcode)); |
| return ErrorCode::UNKNOWN_HCI_COMMAND; |
| } |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::SendCommandToRemoteByAddress( |
| OpCode opcode, bluetooth::packet::PacketView<true> args, |
| const Address& remote) { |
| Address local_address = properties_.GetAddress(); |
| |
| switch (opcode) { |
| case (OpCode::REMOTE_NAME_REQUEST): |
| // LMP features get requested with remote name requests. |
| SendLinkLayerPacket(model::packets::ReadRemoteLmpFeaturesBuilder::Create( |
| local_address, remote)); |
| SendLinkLayerPacket(model::packets::RemoteNameRequestBuilder::Create( |
| local_address, remote)); |
| break; |
| case (OpCode::READ_REMOTE_SUPPORTED_FEATURES): |
| SendLinkLayerPacket( |
| model::packets::ReadRemoteSupportedFeaturesBuilder::Create( |
| local_address, remote)); |
| break; |
| case (OpCode::READ_REMOTE_EXTENDED_FEATURES): { |
| uint8_t page_number = |
| (args.begin() + 2).extract<uint8_t>(); // skip the handle |
| SendLinkLayerPacket( |
| model::packets::ReadRemoteExtendedFeaturesBuilder::Create( |
| local_address, remote, page_number)); |
| } break; |
| case (OpCode::READ_REMOTE_VERSION_INFORMATION): |
| SendLinkLayerPacket( |
| model::packets::ReadRemoteVersionInformationBuilder::Create( |
| local_address, remote)); |
| break; |
| case (OpCode::READ_CLOCK_OFFSET): |
| SendLinkLayerPacket(model::packets::ReadClockOffsetBuilder::Create( |
| local_address, remote)); |
| break; |
| default: |
| LOG_INFO("Dropping unhandled command 0x%04x", |
| static_cast<uint16_t>(opcode)); |
| return ErrorCode::UNKNOWN_HCI_COMMAND; |
| } |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::SendCommandToRemoteByHandle( |
| OpCode opcode, bluetooth::packet::PacketView<true> args, uint16_t handle) { |
| if (!connections_.HasHandle(handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| switch (opcode) { |
| case (OpCode::LE_READ_REMOTE_FEATURES): |
| return SendLeCommandToRemoteByAddress( |
| opcode, connections_.GetAddress(handle).GetAddress(), |
| connections_.GetOwnAddress(handle).GetAddress()); |
| default: |
| return SendCommandToRemoteByAddress( |
| opcode, args, connections_.GetAddress(handle).GetAddress()); |
| } |
| } |
| |
| ErrorCode LinkLayerController::SendAclToRemote( |
| bluetooth::hci::AclView acl_packet) { |
| uint16_t handle = acl_packet.GetHandle(); |
| if (!connections_.HasHandle(handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| AddressWithType my_address = connections_.GetOwnAddress(handle); |
| AddressWithType destination = connections_.GetAddress(handle); |
| Phy::Type phy = connections_.GetPhyType(handle); |
| |
| ScheduleTask(kNoDelayMs, [this, handle]() { |
| std::vector<bluetooth::hci::CompletedPackets> completed_packets; |
| bluetooth::hci::CompletedPackets cp; |
| cp.connection_handle_ = handle; |
| cp.host_num_of_completed_packets_ = kNumCommandPackets; |
| completed_packets.push_back(cp); |
| send_event_(bluetooth::hci::NumberOfCompletedPacketsBuilder::Create( |
| completed_packets)); |
| }); |
| |
| auto acl_payload = acl_packet.GetPayload(); |
| |
| std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr = |
| std::make_unique<bluetooth::packet::RawBuilder>(); |
| std::vector<uint8_t> payload_bytes(acl_payload.begin(), acl_payload.end()); |
| |
| uint16_t first_two_bytes = |
| static_cast<uint16_t>(acl_packet.GetHandle()) + |
| (static_cast<uint16_t>(acl_packet.GetPacketBoundaryFlag()) << 12) + |
| (static_cast<uint16_t>(acl_packet.GetBroadcastFlag()) << 14); |
| raw_builder_ptr->AddOctets2(first_two_bytes); |
| raw_builder_ptr->AddOctets2(static_cast<uint16_t>(payload_bytes.size())); |
| raw_builder_ptr->AddOctets(payload_bytes); |
| |
| auto acl = model::packets::AclBuilder::Create(my_address.GetAddress(), |
| destination.GetAddress(), |
| std::move(raw_builder_ptr)); |
| |
| switch (phy) { |
| case Phy::Type::BR_EDR: |
| SendLinkLayerPacket(std::move(acl)); |
| break; |
| case Phy::Type::LOW_ENERGY: |
| SendLeLinkLayerPacket(std::move(acl)); |
| break; |
| } |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::SendScoToRemote( |
| bluetooth::hci::ScoView sco_packet) { |
| uint16_t handle = sco_packet.GetHandle(); |
| if (!connections_.HasScoHandle(handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| // TODO: SCO flow control |
| Address source = properties_.GetAddress(); |
| Address destination = connections_.GetScoAddress(handle); |
| |
| auto sco_data = sco_packet.GetData(); |
| std::vector<uint8_t> sco_data_bytes(sco_data.begin(), sco_data.end()); |
| |
| SendLinkLayerPacket(model::packets::ScoBuilder::Create( |
| source, destination, |
| std::make_unique<bluetooth::packet::RawBuilder>(sco_data_bytes))); |
| return ErrorCode::SUCCESS; |
| } |
| |
| void LinkLayerController::IncomingPacket( |
| model::packets::LinkLayerPacketView incoming) { |
| ASSERT(incoming.IsValid()); |
| if (incoming.GetType() == PacketType::RSSI_WRAPPER) { |
| auto rssi_wrapper = model::packets::RssiWrapperView::Create(incoming); |
| ASSERT(rssi_wrapper.IsValid()); |
| auto wrapped = |
| model::packets::LinkLayerPacketView::Create(rssi_wrapper.GetPayload()); |
| IncomingPacketWithRssi(wrapped, rssi_wrapper.GetRssi()); |
| } else { |
| IncomingPacketWithRssi(incoming, GetRssi()); |
| } |
| } |
| |
| void LinkLayerController::IncomingPacketWithRssi( |
| model::packets::LinkLayerPacketView incoming, uint8_t rssi) { |
| ASSERT(incoming.IsValid()); |
| auto destination_address = incoming.GetDestinationAddress(); |
| |
| // Match broadcasts |
| bool address_matches = (destination_address == Address::kEmpty); |
| |
| // Match addresses from device properties |
| if (destination_address == properties_.GetAddress() || |
| destination_address == properties_.GetLeAddress()) { |
| address_matches = true; |
| } |
| |
| // Check current connection address |
| if (destination_address == le_connecting_rpa_) { |
| address_matches = true; |
| } |
| |
| // Check advertising addresses |
| for (const auto& advertiser : advertisers_) { |
| if (advertiser.IsEnabled() && |
| advertiser.GetAddress().GetAddress() == destination_address) { |
| address_matches = true; |
| } |
| } |
| |
| // Check connection addresses |
| auto source_address = incoming.GetSourceAddress(); |
| auto handle = connections_.GetHandleOnlyAddress(source_address); |
| if (handle != kReservedHandle) { |
| if (connections_.GetOwnAddress(handle).GetAddress() == |
| destination_address) { |
| address_matches = true; |
| } |
| } |
| |
| // Drop packets not addressed to me |
| if (!address_matches) { |
| LOG_INFO("Dropping packet not addressed to me %s->%s", |
| source_address.ToString().c_str(), |
| destination_address.ToString().c_str()); |
| return; |
| } |
| |
| switch (incoming.GetType()) { |
| case model::packets::PacketType::ACL: |
| IncomingAclPacket(incoming); |
| break; |
| case model::packets::PacketType::SCO: |
| IncomingScoPacket(incoming); |
| break; |
| case model::packets::PacketType::DISCONNECT: |
| IncomingDisconnectPacket(incoming); |
| break; |
| #ifdef ROOTCANAL_LMP |
| case model::packets::PacketType::LMP: |
| IncomingLmpPacket(incoming); |
| break; |
| #else |
| case model::packets::PacketType::ENCRYPT_CONNECTION: |
| IncomingEncryptConnection(incoming); |
| break; |
| case model::packets::PacketType::ENCRYPT_CONNECTION_RESPONSE: |
| IncomingEncryptConnectionResponse(incoming); |
| break; |
| case model::packets::PacketType::IO_CAPABILITY_REQUEST: |
| IncomingIoCapabilityRequestPacket(incoming); |
| break; |
| case model::packets::PacketType::IO_CAPABILITY_RESPONSE: |
| IncomingIoCapabilityResponsePacket(incoming); |
| break; |
| case model::packets::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE: |
| IncomingIoCapabilityNegativeResponsePacket(incoming); |
| break; |
| case PacketType::KEYPRESS_NOTIFICATION: |
| IncomingKeypressNotificationPacket(incoming); |
| break; |
| case (model::packets::PacketType::PASSKEY): |
| IncomingPasskeyPacket(incoming); |
| break; |
| case (model::packets::PacketType::PASSKEY_FAILED): |
| IncomingPasskeyFailedPacket(incoming); |
| break; |
| case (model::packets::PacketType::PIN_REQUEST): |
| IncomingPinRequestPacket(incoming); |
| break; |
| case (model::packets::PacketType::PIN_RESPONSE): |
| IncomingPinResponsePacket(incoming); |
| break; |
| #endif /* ROOTCANAL_LMP */ |
| case model::packets::PacketType::INQUIRY: |
| if (inquiry_scans_enabled_) { |
| IncomingInquiryPacket(incoming, rssi); |
| } |
| break; |
| case model::packets::PacketType::INQUIRY_RESPONSE: |
| IncomingInquiryResponsePacket(incoming); |
| break; |
| case PacketType::ISO: |
| IncomingIsoPacket(incoming); |
| break; |
| case PacketType::ISO_CONNECTION_REQUEST: |
| IncomingIsoConnectionRequestPacket(incoming); |
| break; |
| case PacketType::ISO_CONNECTION_RESPONSE: |
| IncomingIsoConnectionResponsePacket(incoming); |
| break; |
| case model::packets::PacketType::LE_ADVERTISEMENT: |
| if (le_scan_enable_ != bluetooth::hci::OpCode::NONE || le_connect_) { |
| IncomingLeAdvertisementPacket(incoming, rssi); |
| } |
| break; |
| case model::packets::PacketType::LE_CONNECT: |
| IncomingLeConnectPacket(incoming); |
| break; |
| case model::packets::PacketType::LE_CONNECT_COMPLETE: |
| IncomingLeConnectCompletePacket(incoming); |
| break; |
| case model::packets::PacketType::LE_CONNECTION_PARAMETER_REQUEST: |
| IncomingLeConnectionParameterRequest(incoming); |
| break; |
| case model::packets::PacketType::LE_CONNECTION_PARAMETER_UPDATE: |
| IncomingLeConnectionParameterUpdate(incoming); |
| break; |
| case model::packets::PacketType::LE_ENCRYPT_CONNECTION: |
| IncomingLeEncryptConnection(incoming); |
| break; |
| case model::packets::PacketType::LE_ENCRYPT_CONNECTION_RESPONSE: |
| IncomingLeEncryptConnectionResponse(incoming); |
| break; |
| case (model::packets::PacketType::LE_READ_REMOTE_FEATURES): |
| IncomingLeReadRemoteFeatures(incoming); |
| break; |
| case (model::packets::PacketType::LE_READ_REMOTE_FEATURES_RESPONSE): |
| IncomingLeReadRemoteFeaturesResponse(incoming); |
| break; |
| case model::packets::PacketType::LE_SCAN: |
| // TODO: Check Advertising flags and see if we are scannable. |
| IncomingLeScanPacket(incoming); |
| break; |
| case model::packets::PacketType::LE_SCAN_RESPONSE: |
| if (le_scan_enable_ != bluetooth::hci::OpCode::NONE && |
| le_scan_type_ == 1) { |
| IncomingLeScanResponsePacket(incoming, rssi); |
| } |
| break; |
| case model::packets::PacketType::PAGE: |
| if (page_scans_enabled_) { |
| IncomingPagePacket(incoming); |
| } |
| break; |
| case model::packets::PacketType::PAGE_RESPONSE: |
| IncomingPageResponsePacket(incoming); |
| break; |
| case model::packets::PacketType::PAGE_REJECT: |
| IncomingPageRejectPacket(incoming); |
| break; |
| case (model::packets::PacketType::REMOTE_NAME_REQUEST): |
| IncomingRemoteNameRequest(incoming); |
| break; |
| case (model::packets::PacketType::REMOTE_NAME_REQUEST_RESPONSE): |
| IncomingRemoteNameRequestResponse(incoming); |
| break; |
| case (model::packets::PacketType::READ_REMOTE_SUPPORTED_FEATURES): |
| IncomingReadRemoteSupportedFeatures(incoming); |
| break; |
| case (model::packets::PacketType::READ_REMOTE_SUPPORTED_FEATURES_RESPONSE): |
| IncomingReadRemoteSupportedFeaturesResponse(incoming); |
| break; |
| case (model::packets::PacketType::READ_REMOTE_LMP_FEATURES): |
| IncomingReadRemoteLmpFeatures(incoming); |
| break; |
| case (model::packets::PacketType::READ_REMOTE_LMP_FEATURES_RESPONSE): |
| IncomingReadRemoteLmpFeaturesResponse(incoming); |
| break; |
| case (model::packets::PacketType::READ_REMOTE_EXTENDED_FEATURES): |
| IncomingReadRemoteExtendedFeatures(incoming); |
| break; |
| case (model::packets::PacketType::READ_REMOTE_EXTENDED_FEATURES_RESPONSE): |
| IncomingReadRemoteExtendedFeaturesResponse(incoming); |
| break; |
| case (model::packets::PacketType::READ_REMOTE_VERSION_INFORMATION): |
| IncomingReadRemoteVersion(incoming); |
| break; |
| case (model::packets::PacketType::READ_REMOTE_VERSION_INFORMATION_RESPONSE): |
| IncomingReadRemoteVersionResponse(incoming); |
| break; |
| case (model::packets::PacketType::READ_CLOCK_OFFSET): |
| IncomingReadClockOffset(incoming); |
| break; |
| case (model::packets::PacketType::READ_CLOCK_OFFSET_RESPONSE): |
| IncomingReadClockOffsetResponse(incoming); |
| break; |
| case (model::packets::PacketType::RSSI_WRAPPER): |
| LOG_ERROR("Dropping double-wrapped RSSI packet"); |
| break; |
| case model::packets::PacketType::SCO_CONNECTION_REQUEST: |
| IncomingScoConnectionRequest(incoming); |
| break; |
| case model::packets::PacketType::SCO_CONNECTION_RESPONSE: |
| IncomingScoConnectionResponse(incoming); |
| break; |
| case model::packets::PacketType::SCO_DISCONNECT: |
| IncomingScoDisconnect(incoming); |
| break; |
| default: |
| LOG_WARN("Dropping unhandled packet of type %s", |
| model::packets::PacketTypeText(incoming.GetType()).c_str()); |
| } |
| } |
| |
| void LinkLayerController::IncomingAclPacket( |
| model::packets::LinkLayerPacketView incoming) { |
| auto acl = model::packets::AclView::Create(incoming); |
| ASSERT(acl.IsValid()); |
| auto payload = acl.GetPayload(); |
| std::shared_ptr<std::vector<uint8_t>> payload_bytes = |
| std::make_shared<std::vector<uint8_t>>(payload.begin(), payload.end()); |
| |
| LOG_INFO("Acl Packet [%d] %s -> %s", static_cast<int>(payload_bytes->size()), |
| incoming.GetSourceAddress().ToString().c_str(), |
| incoming.GetDestinationAddress().ToString().c_str()); |
| |
| bluetooth::hci::PacketView<bluetooth::hci::kLittleEndian> raw_packet( |
| payload_bytes); |
| auto acl_view = bluetooth::hci::AclView::Create(raw_packet); |
| ASSERT(acl_view.IsValid()); |
| |
| uint16_t local_handle = |
| connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); |
| |
| std::vector<uint8_t> payload_data(acl_view.GetPayload().begin(), |
| acl_view.GetPayload().end()); |
| uint16_t acl_buffer_size = properties_.GetAclDataPacketSize(); |
| int num_packets = |
| (payload_data.size() + acl_buffer_size - 1) / acl_buffer_size; |
| |
| auto pb_flag_controller_to_host = acl_view.GetPacketBoundaryFlag(); |
| if (pb_flag_controller_to_host == |
| bluetooth::hci::PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE) { |
| pb_flag_controller_to_host = |
| bluetooth::hci::PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE; |
| } |
| for (int i = 0; i < num_packets; i++) { |
| size_t start_index = acl_buffer_size * i; |
| size_t end_index = |
| std::min(start_index + acl_buffer_size, payload_data.size()); |
| std::vector<uint8_t> fragment(&payload_data[start_index], |
| &payload_data[end_index]); |
| std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr = |
| std::make_unique<bluetooth::packet::RawBuilder>(fragment); |
| auto acl_packet = bluetooth::hci::AclBuilder::Create( |
| local_handle, pb_flag_controller_to_host, acl_view.GetBroadcastFlag(), |
| std::move(raw_builder_ptr)); |
| pb_flag_controller_to_host = |
| bluetooth::hci::PacketBoundaryFlag::CONTINUING_FRAGMENT; |
| |
| send_acl_(std::move(acl_packet)); |
| } |
| } |
| |
| void LinkLayerController::IncomingScoPacket( |
| model::packets::LinkLayerPacketView incoming) { |
| Address source = incoming.GetSourceAddress(); |
| uint16_t sco_handle = connections_.GetScoHandle(source); |
| if (!connections_.HasScoHandle(sco_handle)) { |
| LOG_INFO("Spurious SCO packet from %s", source.ToString().c_str()); |
| return; |
| } |
| |
| auto sco = model::packets::ScoView::Create(incoming); |
| ASSERT(sco.IsValid()); |
| auto sco_data = sco.GetPayload(); |
| std::vector<uint8_t> sco_data_bytes(sco_data.begin(), sco_data.end()); |
| |
| LOG_INFO("Sco Packet [%d] %s -> %s", static_cast<int>(sco_data_bytes.size()), |
| incoming.GetSourceAddress().ToString().c_str(), |
| incoming.GetDestinationAddress().ToString().c_str()); |
| |
| send_sco_(bluetooth::hci::ScoBuilder::Create( |
| sco_handle, bluetooth::hci::PacketStatusFlag::CORRECTLY_RECEIVED, |
| sco_data_bytes)); |
| } |
| |
| void LinkLayerController::IncomingRemoteNameRequest( |
| model::packets::LinkLayerPacketView packet) { |
| auto view = model::packets::RemoteNameRequestView::Create(packet); |
| ASSERT(view.IsValid()); |
| |
| SendLinkLayerPacket(model::packets::RemoteNameRequestResponseBuilder::Create( |
| packet.GetDestinationAddress(), packet.GetSourceAddress(), |
| properties_.GetName())); |
| } |
| |
| void LinkLayerController::IncomingRemoteNameRequestResponse( |
| model::packets::LinkLayerPacketView packet) { |
| auto view = model::packets::RemoteNameRequestResponseView::Create(packet); |
| ASSERT(view.IsValid()); |
| |
| if (properties_.IsUnmasked(EventCode::REMOTE_NAME_REQUEST_COMPLETE)) { |
| send_event_(bluetooth::hci::RemoteNameRequestCompleteBuilder::Create( |
| ErrorCode::SUCCESS, packet.GetSourceAddress(), view.GetName())); |
| } |
| } |
| |
| void LinkLayerController::IncomingReadRemoteLmpFeatures( |
| model::packets::LinkLayerPacketView packet) { |
| SendLinkLayerPacket( |
| model::packets::ReadRemoteLmpFeaturesResponseBuilder::Create( |
| packet.GetDestinationAddress(), packet.GetSourceAddress(), |
| properties_.GetExtendedFeatures(1))); |
| } |
| |
| void LinkLayerController::IncomingReadRemoteLmpFeaturesResponse( |
| model::packets::LinkLayerPacketView packet) { |
| auto view = model::packets::ReadRemoteLmpFeaturesResponseView::Create(packet); |
| ASSERT(view.IsValid()); |
| if (properties_.IsUnmasked( |
| EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION)) { |
| send_event_( |
| bluetooth::hci::RemoteHostSupportedFeaturesNotificationBuilder::Create( |
| packet.GetSourceAddress(), view.GetFeatures())); |
| } |
| } |
| |
| void LinkLayerController::IncomingReadRemoteSupportedFeatures( |
| model::packets::LinkLayerPacketView packet) { |
| SendLinkLayerPacket( |
| model::packets::ReadRemoteSupportedFeaturesResponseBuilder::Create( |
| packet.GetDestinationAddress(), packet.GetSourceAddress(), |
| properties_.GetSupportedFeatures())); |
| } |
| |
| void LinkLayerController::IncomingReadRemoteSupportedFeaturesResponse( |
| model::packets::LinkLayerPacketView packet) { |
| auto view = |
| model::packets::ReadRemoteSupportedFeaturesResponseView::Create(packet); |
| ASSERT(view.IsValid()); |
| Address source = packet.GetSourceAddress(); |
| uint16_t handle = connections_.GetHandleOnlyAddress(source); |
| if (handle == kReservedHandle) { |
| LOG_INFO("Discarding response from a disconnected device %s", |
| source.ToString().c_str()); |
| return; |
| } |
| if (properties_.IsUnmasked( |
| EventCode::READ_REMOTE_SUPPORTED_FEATURES_COMPLETE)) { |
| send_event_( |
| bluetooth::hci::ReadRemoteSupportedFeaturesCompleteBuilder::Create( |
| ErrorCode::SUCCESS, handle, view.GetFeatures())); |
| } |
| } |
| |
| void LinkLayerController::IncomingReadRemoteExtendedFeatures( |
| model::packets::LinkLayerPacketView packet) { |
| auto view = model::packets::ReadRemoteExtendedFeaturesView::Create(packet); |
| ASSERT(view.IsValid()); |
| uint8_t page_number = view.GetPageNumber(); |
| uint8_t error_code = static_cast<uint8_t>(ErrorCode::SUCCESS); |
| if (page_number > properties_.GetExtendedFeaturesMaximumPageNumber()) { |
| error_code = static_cast<uint8_t>(ErrorCode::INVALID_LMP_OR_LL_PARAMETERS); |
| } |
| SendLinkLayerPacket( |
| model::packets::ReadRemoteExtendedFeaturesResponseBuilder::Create( |
| packet.GetDestinationAddress(), packet.GetSourceAddress(), error_code, |
| page_number, properties_.GetExtendedFeaturesMaximumPageNumber(), |
| properties_.GetExtendedFeatures(view.GetPageNumber()))); |
| } |
| |
| void LinkLayerController::IncomingReadRemoteExtendedFeaturesResponse( |
| model::packets::LinkLayerPacketView packet) { |
| auto view = |
| model::packets::ReadRemoteExtendedFeaturesResponseView::Create(packet); |
| ASSERT(view.IsValid()); |
| Address source = packet.GetSourceAddress(); |
| uint16_t handle = connections_.GetHandleOnlyAddress(source); |
| if (handle == kReservedHandle) { |
| LOG_INFO("Discarding response from a disconnected device %s", |
| source.ToString().c_str()); |
| return; |
| } |
| if (properties_.IsUnmasked( |
| EventCode::READ_REMOTE_EXTENDED_FEATURES_COMPLETE)) { |
| send_event_( |
| bluetooth::hci::ReadRemoteExtendedFeaturesCompleteBuilder::Create( |
| static_cast<ErrorCode>(view.GetStatus()), handle, |
| view.GetPageNumber(), view.GetMaxPageNumber(), view.GetFeatures())); |
| } |
| } |
| |
| void LinkLayerController::IncomingReadRemoteVersion( |
| model::packets::LinkLayerPacketView packet) { |
| SendLinkLayerPacket( |
| model::packets::ReadRemoteVersionInformationResponseBuilder::Create( |
| packet.GetDestinationAddress(), packet.GetSourceAddress(), |
| properties_.GetLmpPalVersion(), properties_.GetLmpPalSubversion(), |
| properties_.GetManufacturerName())); |
| } |
| |
| void LinkLayerController::IncomingReadRemoteVersionResponse( |
| model::packets::LinkLayerPacketView packet) { |
| auto view = |
| model::packets::ReadRemoteVersionInformationResponseView::Create(packet); |
| ASSERT(view.IsValid()); |
| Address source = packet.GetSourceAddress(); |
| uint16_t handle = connections_.GetHandleOnlyAddress(source); |
| if (handle == kReservedHandle) { |
| LOG_INFO("Discarding response from a disconnected device %s", |
| source.ToString().c_str()); |
| return; |
| } |
| if (properties_.IsUnmasked( |
| EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE)) { |
| send_event_( |
| bluetooth::hci::ReadRemoteVersionInformationCompleteBuilder::Create( |
| ErrorCode::SUCCESS, handle, view.GetLmpVersion(), |
| view.GetManufacturerName(), view.GetLmpSubversion())); |
| } |
| } |
| |
| void LinkLayerController::IncomingReadClockOffset( |
| model::packets::LinkLayerPacketView packet) { |
| SendLinkLayerPacket(model::packets::ReadClockOffsetResponseBuilder::Create( |
| packet.GetDestinationAddress(), packet.GetSourceAddress(), |
| properties_.GetClockOffset())); |
| } |
| |
| void LinkLayerController::IncomingReadClockOffsetResponse( |
| model::packets::LinkLayerPacketView packet) { |
| auto view = model::packets::ReadClockOffsetResponseView::Create(packet); |
| ASSERT(view.IsValid()); |
| Address source = packet.GetSourceAddress(); |
| uint16_t handle = connections_.GetHandleOnlyAddress(source); |
| if (handle == kReservedHandle) { |
| LOG_INFO("Discarding response from a disconnected device %s", |
| source.ToString().c_str()); |
| return; |
| } |
| if (properties_.IsUnmasked(EventCode::READ_CLOCK_OFFSET_COMPLETE)) { |
| send_event_(bluetooth::hci::ReadClockOffsetCompleteBuilder::Create( |
| ErrorCode::SUCCESS, handle, view.GetOffset())); |
| } |
| } |
| |
| void LinkLayerController::IncomingDisconnectPacket( |
| model::packets::LinkLayerPacketView incoming) { |
| LOG_INFO("Disconnect Packet"); |
| auto disconnect = model::packets::DisconnectView::Create(incoming); |
| ASSERT(disconnect.IsValid()); |
| |
| Address peer = incoming.GetSourceAddress(); |
| uint16_t handle = connections_.GetHandleOnlyAddress(peer); |
| if (handle == kReservedHandle) { |
| LOG_INFO("Discarding disconnect from a disconnected device %s", |
| peer.ToString().c_str()); |
| return; |
| } |
| ASSERT_LOG(connections_.Disconnect(handle), |
| "GetHandle() returned invalid handle %hx", handle); |
| |
| uint8_t reason = disconnect.GetReason(); |
| SendDisconnectionCompleteEvent(handle, reason); |
| #ifdef ROOTCANAL_LMP |
| ASSERT(link_manager_remove_link( |
| lm_.get(), reinterpret_cast<uint8_t(*)[6]>(peer.data()))); |
| #endif |
| } |
| |
| #ifndef ROOTCANAL_LMP |
| void LinkLayerController::IncomingEncryptConnection( |
| model::packets::LinkLayerPacketView incoming) { |
| LOG_INFO("IncomingEncryptConnection"); |
| |
| // TODO: Check keys |
| Address peer = incoming.GetSourceAddress(); |
| uint16_t handle = connections_.GetHandleOnlyAddress(peer); |
| if (handle == kReservedHandle) { |
| LOG_INFO("Unknown connection @%s", peer.ToString().c_str()); |
| return; |
| } |
| if (properties_.IsUnmasked(EventCode::ENCRYPTION_CHANGE)) { |
| send_event_(bluetooth::hci::EncryptionChangeBuilder::Create( |
| ErrorCode::SUCCESS, handle, bluetooth::hci::EncryptionEnabled::ON)); |
| } |
| |
| uint16_t count = security_manager_.ReadKey(peer); |
| if (count == 0) { |
| LOG_ERROR("NO KEY HERE for %s", peer.ToString().c_str()); |
| return; |
| } |
| auto array = security_manager_.GetKey(peer); |
| std::vector<uint8_t> key_vec{array.begin(), array.end()}; |
| SendLinkLayerPacket(model::packets::EncryptConnectionResponseBuilder::Create( |
| properties_.GetAddress(), peer, key_vec)); |
| } |
| |
| void LinkLayerController::IncomingEncryptConnectionResponse( |
| model::packets::LinkLayerPacketView incoming) { |
| LOG_INFO("IncomingEncryptConnectionResponse"); |
| // TODO: Check keys |
| uint16_t handle = |
| connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); |
| if (handle == kReservedHandle) { |
| LOG_INFO("Unknown connection @%s", |
| incoming.GetSourceAddress().ToString().c_str()); |
| return; |
| } |
| if (properties_.IsUnmasked(EventCode::ENCRYPTION_CHANGE)) { |
| send_event_(bluetooth::hci::EncryptionChangeBuilder::Create( |
| ErrorCode::SUCCESS, handle, bluetooth::hci::EncryptionEnabled::ON)); |
| } |
| } |
| #endif /* !ROOTCANAL_LMP */ |
| |
| void LinkLayerController::IncomingInquiryPacket( |
| model::packets::LinkLayerPacketView incoming, uint8_t rssi) { |
| auto inquiry = model::packets::InquiryView::Create(incoming); |
| ASSERT(inquiry.IsValid()); |
| |
| Address peer = incoming.GetSourceAddress(); |
| |
| switch (inquiry.GetInquiryType()) { |
| case (model::packets::InquiryType::STANDARD): { |
| SendLinkLayerPacket(model::packets::InquiryResponseBuilder::Create( |
| properties_.GetAddress(), peer, |
| properties_.GetPageScanRepetitionMode(), |
| properties_.GetClassOfDevice(), properties_.GetClockOffset())); |
| } break; |
| case (model::packets::InquiryType::RSSI): { |
| SendLinkLayerPacket( |
| model::packets::InquiryResponseWithRssiBuilder::Create( |
| properties_.GetAddress(), peer, |
| properties_.GetPageScanRepetitionMode(), |
| properties_.GetClassOfDevice(), properties_.GetClockOffset(), |
| rssi)); |
| } break; |
| case (model::packets::InquiryType::EXTENDED): { |
| SendLinkLayerPacket( |
| model::packets::ExtendedInquiryResponseBuilder::Create( |
| properties_.GetAddress(), peer, |
| properties_.GetPageScanRepetitionMode(), |
| properties_.GetClassOfDevice(), properties_.GetClockOffset(), |
| rssi, properties_.GetExtendedInquiryData())); |
| |
| } break; |
| default: |
| LOG_WARN("Unhandled Incoming Inquiry of type %d", |
| static_cast<int>(inquiry.GetType())); |
| return; |
| } |
| // TODO: Send an Inquiry Response Notification Event 7.7.74 |
| } |
| |
| void LinkLayerController::IncomingInquiryResponsePacket( |
| model::packets::LinkLayerPacketView incoming) { |
| auto basic_inquiry_response = |
| model::packets::BasicInquiryResponseView::Create(incoming); |
| ASSERT(basic_inquiry_response.IsValid()); |
| std::vector<uint8_t> eir; |
| |
| switch (basic_inquiry_response.GetInquiryType()) { |
| case (model::packets::InquiryType::STANDARD): { |
| // TODO: Support multiple inquiries in the same packet. |
| auto inquiry_response = |
| model::packets::InquiryResponseView::Create(basic_inquiry_response); |
| ASSERT(inquiry_response.IsValid()); |
| |
| auto page_scan_repetition_mode = |
| (bluetooth::hci::PageScanRepetitionMode) |
| inquiry_response.GetPageScanRepetitionMode(); |
| |
| std::vector<bluetooth::hci::InquiryResponse> responses; |
| responses.emplace_back(); |
| responses.back().bd_addr_ = inquiry_response.GetSourceAddress(); |
| responses.back().page_scan_repetition_mode_ = page_scan_repetition_mode; |
| responses.back().class_of_device_ = inquiry_response.GetClassOfDevice(); |
| responses.back().clock_offset_ = inquiry_response.GetClockOffset(); |
| if (properties_.IsUnmasked(EventCode::INQUIRY_RESULT)) { |
| send_event_(bluetooth::hci::InquiryResultBuilder::Create(responses)); |
| } |
| } break; |
| |
| case (model::packets::InquiryType::RSSI): { |
| auto inquiry_response = |
| model::packets::InquiryResponseWithRssiView::Create( |
| basic_inquiry_response); |
| ASSERT(inquiry_response.IsValid()); |
| |
| auto page_scan_repetition_mode = |
| (bluetooth::hci::PageScanRepetitionMode) |
| inquiry_response.GetPageScanRepetitionMode(); |
| |
| std::vector<bluetooth::hci::InquiryResponseWithRssi> responses; |
| responses.emplace_back(); |
| responses.back().address_ = inquiry_response.GetSourceAddress(); |
| responses.back().page_scan_repetition_mode_ = page_scan_repetition_mode; |
| responses.back().class_of_device_ = inquiry_response.GetClassOfDevice(); |
| responses.back().clock_offset_ = inquiry_response.GetClockOffset(); |
| responses.back().rssi_ = inquiry_response.GetRssi(); |
| if (properties_.IsUnmasked(EventCode::INQUIRY_RESULT_WITH_RSSI)) { |
| send_event_( |
| bluetooth::hci::InquiryResultWithRssiBuilder::Create(responses)); |
| } |
| } break; |
| |
| case (model::packets::InquiryType::EXTENDED): { |
| auto inquiry_response = |
| model::packets::ExtendedInquiryResponseView::Create( |
| basic_inquiry_response); |
| ASSERT(inquiry_response.IsValid()); |
| |
| std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr = |
| std::make_unique<bluetooth::packet::RawBuilder>(); |
| raw_builder_ptr->AddOctets1(kNumCommandPackets); |
| raw_builder_ptr->AddAddress(inquiry_response.GetSourceAddress()); |
| raw_builder_ptr->AddOctets1(inquiry_response.GetPageScanRepetitionMode()); |
| raw_builder_ptr->AddOctets1(0x00); // _reserved_ |
| auto class_of_device = inquiry_response.GetClassOfDevice(); |
| for (unsigned int i = 0; i < class_of_device.kLength; i++) { |
| raw_builder_ptr->AddOctets1(class_of_device.cod[i]); |
| } |
| raw_builder_ptr->AddOctets2(inquiry_response.GetClockOffset()); |
| raw_builder_ptr->AddOctets1(inquiry_response.GetRssi()); |
| raw_builder_ptr->AddOctets(inquiry_response.GetExtendedData()); |
| |
| if (properties_.IsUnmasked(EventCode::EXTENDED_INQUIRY_RESULT)) { |
| send_event_(bluetooth::hci::EventBuilder::Create( |
| bluetooth::hci::EventCode::EXTENDED_INQUIRY_RESULT, |
| std::move(raw_builder_ptr))); |
| } |
| } break; |
| default: |
| LOG_WARN("Unhandled Incoming Inquiry Response of type %d", |
| static_cast<int>(basic_inquiry_response.GetInquiryType())); |
| } |
| } |
| |
| #ifndef ROOTCANAL_LMP |
| void LinkLayerController::IncomingIoCapabilityRequestPacket( |
| model::packets::LinkLayerPacketView incoming) { |
| Address peer = incoming.GetSourceAddress(); |
| uint16_t handle = connections_.GetHandle(AddressWithType( |
| peer, bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS)); |
| if (handle == kReservedHandle) { |
| LOG_INFO("Device not connected %s", peer.ToString().c_str()); |
| return; |
| } |
| |
| if (!properties_.GetSecureSimplePairingSupported()) { |
| LOG_WARN("Trying PIN pairing for %s", |
| incoming.GetDestinationAddress().ToString().c_str()); |
| SendLinkLayerPacket( |
| model::packets::IoCapabilityNegativeResponseBuilder::Create( |
| incoming.GetDestinationAddress(), incoming.GetSourceAddress(), |
| static_cast<uint8_t>( |
| ErrorCode::UNSUPPORTED_REMOTE_OR_LMP_FEATURE))); |
| if (!security_manager_.AuthenticationInProgress()) { |
| security_manager_.AuthenticationRequest(incoming.GetSourceAddress(), |
| handle, false); |
| } |
| security_manager_.SetPinRequested(peer); |
| if (properties_.IsUnmasked(EventCode::PIN_CODE_REQUEST)) { |
| send_event_(bluetooth::hci::PinCodeRequestBuilder::Create( |
| incoming.GetSourceAddress())); |
| } |
| return; |
| } |
| |
| auto request = model::packets::IoCapabilityRequestView::Create(incoming); |
| ASSERT(request.IsValid()); |
| |
| uint8_t io_capability = request.GetIoCapability(); |
| uint8_t oob_data_present = request.GetOobDataPresent(); |
| uint8_t authentication_requirements = request.GetAuthenticationRequirements(); |
| |
| if (properties_.IsUnmasked(EventCode::IO_CAPABILITY_RESPONSE)) { |
| send_event_(bluetooth::hci::IoCapabilityResponseBuilder::Create( |
| peer, static_cast<bluetooth::hci::IoCapability>(io_capability), |
| static_cast<bluetooth::hci::OobDataPresent>(oob_data_present), |
| static_cast<bluetooth::hci::AuthenticationRequirements>( |
| authentication_requirements))); |
| } |
| |
| bool pairing_started = security_manager_.AuthenticationInProgress(); |
| if (!pairing_started) { |
| security_manager_.AuthenticationRequest(peer, handle, false); |
| StartSimplePairing(peer); |
| } |
| |
| security_manager_.SetPeerIoCapability(peer, io_capability, oob_data_present, |
| authentication_requirements); |
| if (pairing_started) { |
| PairingType pairing_type = security_manager_.GetSimplePairingType(); |
| if (pairing_type != PairingType::INVALID) { |
| ScheduleTask(kNoDelayMs, [this, peer, pairing_type]() { |
| AuthenticateRemoteStage1(peer, pairing_type); |
| }); |
| } else { |
| LOG_INFO("Security Manager returned INVALID"); |
| } |
| } |
| } |
| |
| void LinkLayerController::IncomingIoCapabilityResponsePacket( |
| model::packets::LinkLayerPacketView incoming) { |
| auto response = model::packets::IoCapabilityResponseView::Create(incoming); |
| ASSERT(response.IsValid()); |
| if (!properties_.GetSecureSimplePairingSupported()) { |
| LOG_WARN("Only simple pairing mode is implemented"); |
| SendLinkLayerPacket( |
| model::packets::IoCapabilityNegativeResponseBuilder::Create( |
| incoming.GetDestinationAddress(), incoming.GetSourceAddress(), |
| static_cast<uint8_t>( |
| ErrorCode::UNSUPPORTED_REMOTE_OR_LMP_FEATURE))); |
| return; |
| } |
| |
| Address peer = incoming.GetSourceAddress(); |
| uint8_t io_capability = response.GetIoCapability(); |
| uint8_t oob_data_present = response.GetOobDataPresent(); |
| uint8_t authentication_requirements = |
| response.GetAuthenticationRequirements(); |
| |
| security_manager_.SetPeerIoCapability(peer, io_capability, oob_data_present, |
| authentication_requirements); |
| |
| if (properties_.IsUnmasked(EventCode::IO_CAPABILITY_RESPONSE)) { |
| send_event_(bluetooth::hci::IoCapabilityResponseBuilder::Create( |
| peer, static_cast<bluetooth::hci::IoCapability>(io_capability), |
| static_cast<bluetooth::hci::OobDataPresent>(oob_data_present), |
| static_cast<bluetooth::hci::AuthenticationRequirements>( |
| authentication_requirements))); |
| } |
| |
| PairingType pairing_type = security_manager_.GetSimplePairingType(); |
| if (pairing_type != PairingType::INVALID) { |
| ScheduleTask(kNoDelayMs, [this, peer, pairing_type]() { |
| AuthenticateRemoteStage1(peer, pairing_type); |
| }); |
| } else { |
| LOG_INFO("Security Manager returned INVALID"); |
| } |
| } |
| |
| void LinkLayerController::IncomingIoCapabilityNegativeResponsePacket( |
| model::packets::LinkLayerPacketView incoming) { |
| Address peer = incoming.GetSourceAddress(); |
| |
| ASSERT(security_manager_.GetAuthenticationAddress() == peer); |
| |
| security_manager_.InvalidateIoCapabilities(); |
| LOG_INFO("%s doesn't support SSP, try PIN", |
| incoming.GetSourceAddress().ToString().c_str()); |
| security_manager_.SetPinRequested(peer); |
| if (properties_.IsUnmasked(EventCode::PIN_CODE_REQUEST)) { |
| send_event_(bluetooth::hci::PinCodeRequestBuilder::Create( |
| incoming.GetSourceAddress())); |
| } |
| } |
| #endif /* !ROOTCANAL_LMP */ |
| |
| void LinkLayerController::IncomingIsoPacket(LinkLayerPacketView incoming) { |
| auto iso = IsoDataPacketView::Create(incoming); |
| ASSERT(iso.IsValid()); |
| |
| uint16_t cis_handle = iso.GetHandle(); |
| if (!connections_.HasCisHandle(cis_handle)) { |
| LOG_INFO("Dropping ISO packet to unknown handle 0x%hx", cis_handle); |
| return; |
| } |
| if (!connections_.HasConnectedCis(cis_handle)) { |
| LOG_INFO("Dropping ISO packet to a disconnected handle 0x%hx", cis_handle); |
| return; |
| } |
| |
| auto sc = iso.GetSc(); |
| switch (sc) { |
| case StartContinuation::START: { |
| auto iso_start = IsoStartView::Create(iso); |
| ASSERT(iso_start.IsValid()); |
| if (iso.GetCmplt() == Complete::COMPLETE) { |
| send_iso_(bluetooth::hci::IsoWithoutTimestampBuilder::Create( |
| cis_handle, bluetooth::hci::IsoPacketBoundaryFlag::COMPLETE_SDU, |
| 0 /* seq num */, bluetooth::hci::IsoPacketStatusFlag::VALID, |
| std::make_unique<bluetooth::packet::RawBuilder>( |
| std::vector<uint8_t>(iso_start.GetPayload().begin(), |
| iso_start.GetPayload().end())))); |
| } else { |
| send_iso_(bluetooth::hci::IsoWithoutTimestampBuilder::Create( |
| cis_handle, bluetooth::hci::IsoPacketBoundaryFlag::FIRST_FRAGMENT, |
| 0 /* seq num */, bluetooth::hci::IsoPacketStatusFlag::VALID, |
| std::make_unique<bluetooth::packet::RawBuilder>( |
| std::vector<uint8_t>(iso_start.GetPayload().begin(), |
| iso_start.GetPayload().end())))); |
| } |
| } break; |
| case StartContinuation::CONTINUATION: { |
| auto continuation = IsoContinuationView::Create(iso); |
| ASSERT(continuation.IsValid()); |
| if (iso.GetCmplt() == Complete::COMPLETE) { |
| send_iso_(bluetooth::hci::IsoWithoutTimestampBuilder::Create( |
| cis_handle, bluetooth::hci::IsoPacketBoundaryFlag::LAST_FRAGMENT, |
| 0 /* seq num */, bluetooth::hci::IsoPacketStatusFlag::VALID, |
| std::make_unique<bluetooth::packet::RawBuilder>( |
| std::vector<uint8_t>(continuation.GetPayload().begin(), |
| continuation.GetPayload().end())))); |
| } else { |
| send_iso_(bluetooth::hci::IsoWithoutTimestampBuilder::Create( |
| cis_handle, |
| bluetooth::hci::IsoPacketBoundaryFlag::CONTINUATION_FRAGMENT, |
| 0 /* seq num */, bluetooth::hci::IsoPacketStatusFlag::VALID, |
| std::make_unique<bluetooth::packet::RawBuilder>( |
| std::vector<uint8_t>(continuation.GetPayload().begin(), |
| continuation.GetPayload().end())))); |
| } |
| } break; |
| } |
| } |
| |
| void LinkLayerController::HandleIso(bluetooth::hci::IsoView iso) { |
| auto cis_handle = iso.GetConnectionHandle(); |
| if (!connections_.HasCisHandle(cis_handle)) { |
| LOG_INFO("Dropping ISO packet to unknown handle 0x%hx", cis_handle); |
| return; |
| } |
| if (!connections_.HasConnectedCis(cis_handle)) { |
| LOG_INFO("Dropping ISO packet to disconnected handle 0x%hx", cis_handle); |
| return; |
| } |
| |
| auto acl_handle = connections_.GetAclHandleForCisHandle(cis_handle); |
| uint16_t remote_handle = |
| connections_.GetRemoteCisHandleForCisHandle(cis_handle); |
| model::packets::StartContinuation start_flag = |
| model::packets::StartContinuation::START; |
| model::packets::Complete complete_flag = model::packets::Complete::COMPLETE; |
| switch (iso.GetPbFlag()) { |
| case bluetooth::hci::IsoPacketBoundaryFlag::COMPLETE_SDU: |
| start_flag = model::packets::StartContinuation::START; |
| complete_flag = model::packets::Complete::COMPLETE; |
| break; |
| case bluetooth::hci::IsoPacketBoundaryFlag::CONTINUATION_FRAGMENT: |
| start_flag = model::packets::StartContinuation::CONTINUATION; |
| complete_flag = model::packets::Complete::INCOMPLETE; |
| break; |
| case bluetooth::hci::IsoPacketBoundaryFlag::FIRST_FRAGMENT: |
| start_flag = model::packets::StartContinuation::START; |
| complete_flag = model::packets::Complete::INCOMPLETE; |
| break; |
| case bluetooth::hci::IsoPacketBoundaryFlag::LAST_FRAGMENT: |
| start_flag = model::packets::StartContinuation::CONTINUATION; |
| complete_flag = model::packets::Complete::INCOMPLETE; |
| break; |
| } |
| if (start_flag == model::packets::StartContinuation::START) { |
| if (iso.GetTsFlag() == bluetooth::hci::TimeStampFlag::PRESENT) { |
| auto timestamped = bluetooth::hci::IsoWithTimestampView::Create(iso); |
| ASSERT(timestamped.IsValid()); |
| uint32_t timestamp = timestamped.GetTimeStamp(); |
| std::unique_ptr<bluetooth::packet::RawBuilder> payload = |
| std::make_unique<bluetooth::packet::RawBuilder>(); |
| for (const auto it : timestamped.GetPayload()) { |
| payload->AddOctets1(it); |
| } |
| |
| SendLeLinkLayerPacket(model::packets::IsoStartBuilder::Create( |
| connections_.GetOwnAddress(acl_handle).GetAddress(), |
| connections_.GetAddress(acl_handle).GetAddress(), remote_handle, |
| complete_flag, timestamp, std::move(payload))); |
| } else { |
| auto pkt = bluetooth::hci::IsoWithoutTimestampView::Create(iso); |
| ASSERT(pkt.IsValid()); |
| |
| auto payload = |
| std::make_unique<bluetooth::packet::RawBuilder>(std::vector<uint8_t>( |
| pkt.GetPayload().begin(), pkt.GetPayload().end())); |
| |
| SendLeLinkLayerPacket(model::packets::IsoStartBuilder::Create( |
| connections_.GetOwnAddress(acl_handle).GetAddress(), |
| connections_.GetAddress(acl_handle).GetAddress(), remote_handle, |
| complete_flag, 0, std::move(payload))); |
| } |
| } else { |
| auto pkt = bluetooth::hci::IsoWithoutTimestampView::Create(iso); |
| ASSERT(pkt.IsValid()); |
| std::unique_ptr<bluetooth::packet::RawBuilder> payload = |
| std::make_unique<bluetooth::packet::RawBuilder>(std::vector<uint8_t>( |
| pkt.GetPayload().begin(), pkt.GetPayload().end())); |
| SendLeLinkLayerPacket(model::packets::IsoContinuationBuilder::Create( |
| connections_.GetOwnAddress(acl_handle).GetAddress(), |
| connections_.GetAddress(acl_handle).GetAddress(), remote_handle, |
| complete_flag, std::move(payload))); |
| } |
| } |
| |
| void LinkLayerController::IncomingIsoConnectionRequestPacket( |
| LinkLayerPacketView incoming) { |
| auto req = IsoConnectionRequestView::Create(incoming); |
| ASSERT(req.IsValid()); |
| std::vector<bluetooth::hci::CisParametersConfig> stream_configs; |
| bluetooth::hci::CisParametersConfig stream_config; |
| |
| stream_config.max_sdu_m_to_s_ = req.GetMaxSduMToS(); |
| stream_config.max_sdu_s_to_m_ = req.GetMaxSduSToM(); |
| |
| stream_configs.push_back(stream_config); |
| |
| uint8_t group_id = req.GetCigId(); |
| |
| /* CIG should be created by the local host before use */ |
| bluetooth::hci::CreateCisConfig config; |
| config.cis_connection_handle_ = req.GetRequesterCisHandle(); |
| |
| config.acl_connection_handle_ = |
| connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); |
| connections_.CreatePendingCis(config); |
| connections_.SetRemoteCisHandle(config.cis_connection_handle_, |
| req.GetRequesterCisHandle()); |
| if (properties_.IsUnmasked(EventCode::LE_META_EVENT)) { |
| send_event_(bluetooth::hci::LeCisRequestBuilder::Create( |
| config.acl_connection_handle_, config.cis_connection_handle_, group_id, |
| req.GetId())); |
| } |
| } |
| |
| void LinkLayerController::IncomingIsoConnectionResponsePacket( |
| LinkLayerPacketView incoming) { |
| auto response = IsoConnectionResponseView::Create(incoming); |
| ASSERT(response.IsValid()); |
| |
| bluetooth::hci::CreateCisConfig config; |
| config.acl_connection_handle_ = response.GetRequesterAclHandle(); |
| config.cis_connection_handle_ = response.GetRequesterCisHandle(); |
| if (!connections_.HasPendingCisConnection(config.cis_connection_handle_)) { |
| LOG_INFO("Ignoring connection response with unknown CIS handle 0x%04hx", |
| config.cis_connection_handle_); |
| return; |
| } |
| ErrorCode status = static_cast<ErrorCode>(response.GetStatus()); |
| if (status != ErrorCode::SUCCESS) { |
| if (properties_.IsUnmasked(EventCode::LE_META_EVENT)) { |
| send_event_(bluetooth::hci::LeCisEstablishedBuilder::Create( |
| status, config.cis_connection_handle_, 0, 0, 0, 0, |
| bluetooth::hci::SecondaryPhyType::NO_PACKETS, |
| bluetooth::hci::SecondaryPhyType::NO_PACKETS, 0, 0, 0, 0, 0, 0, 0, |
| 0)); |
| } |
| return; |
| } |
| connections_.SetRemoteCisHandle(config.cis_connection_handle_, |
| response.GetResponderCisHandle()); |
| connections_.ConnectCis(config.cis_connection_handle_); |
| auto stream_parameters = |
| connections_.GetStreamParameters(config.cis_connection_handle_); |
| auto group_parameters = |
| connections_.GetGroupParameters(stream_parameters.group_id); |
| // TODO: Which of these are important enough to fake? |
| uint32_t cig_sync_delay = 0x100; |
| uint32_t cis_sync_delay = 0x200; |
| uint32_t latency_m_to_s = group_parameters.max_transport_latency_m_to_s; |
| uint32_t latency_s_to_m = group_parameters.max_transport_latency_s_to_m; |
| uint8_t nse = 1; |
| uint8_t bn_m_to_s = 0; |
| uint8_t bn_s_to_m = 0; |
| uint8_t ft_m_to_s = 0; |
| uint8_t ft_s_to_m = 0; |
| uint8_t max_pdu_m_to_s = 0x40; |
| uint8_t max_pdu_s_to_m = 0x40; |
| uint16_t iso_interval = 0x100; |
| if (properties_.IsUnmasked(EventCode::LE_META_EVENT)) { |
| send_event_(bluetooth::hci::LeCisEstablishedBuilder::Create( |
| status, config.cis_connection_handle_, cig_sync_delay, cis_sync_delay, |
| latency_m_to_s, latency_s_to_m, |
| bluetooth::hci::SecondaryPhyType::NO_PACKETS, |
| bluetooth::hci::SecondaryPhyType::NO_PACKETS, nse, bn_m_to_s, bn_s_to_m, |
| ft_m_to_s, ft_s_to_m, max_pdu_m_to_s, max_pdu_s_to_m, iso_interval)); |
| } |
| } |
| |
| #ifndef ROOTCANAL_LMP |
| void LinkLayerController::IncomingKeypressNotificationPacket( |
| model::packets::LinkLayerPacketView incoming) { |
| auto keypress = model::packets::KeypressNotificationView::Create(incoming); |
| ASSERT(keypress.IsValid()); |
| auto notification_type = keypress.GetNotificationType(); |
| if (notification_type > |
| model::packets::PasskeyNotificationType::ENTRY_COMPLETED) { |
| LOG_WARN("Dropping unknown notification type %d", |
| static_cast<int>(notification_type)); |
| return; |
| } |
| if (properties_.IsUnmasked(EventCode::KEYPRESS_NOTIFICATION)) { |
| send_event_(bluetooth::hci::KeypressNotificationBuilder::Create( |
| incoming.GetSourceAddress(), |
| static_cast<bluetooth::hci::KeypressNotificationType>( |
| notification_type))); |
| } |
| } |
| #endif /* !ROOTCANAL_LMP */ |
| |
| static bool rpa_matches_irk( |
| Address rpa, std::array<uint8_t, LinkLayerController::kIrkSize> irk) { |
| // 1.3.2.3 Private device address resolution |
| uint8_t hash[3] = {rpa.address[0], rpa.address[1], rpa.address[2]}; |
| uint8_t prand[3] = {rpa.address[3], rpa.address[4], rpa.address[5]}; |
| |
| // generate X = E irk(R0, R1, R2) and R is random address 3 LSO |
| auto x = bluetooth::crypto_toolbox::aes_128(irk, &prand[0], 3); |
| |
| // If the hashes match, this is the IRK |
| return (memcmp(x.data(), &hash[0], 3) == 0); |
| } |
| |
| static Address generate_rpa( |
| std::array<uint8_t, LinkLayerController::kIrkSize> irk) { |
| // most significant bit, bit7, bit6 is 01 to be resolvable random |
| // Bits of the random part of prand shall not be all 1 or all 0 |
| std::array<uint8_t, 3> prand; |
| prand[0] = std::rand(); |
| prand[1] = std::rand(); |
| prand[2] = std::rand(); |
| |
| constexpr uint8_t BLE_RESOLVE_ADDR_MSB = 0x40; |
| prand[2] &= ~0xC0; // BLE Address mask |
| if ((prand[0] == 0x00 && prand[1] == 0x00 && prand[2] == 0x00) || |
| (prand[0] == 0xFF && prand[1] == 0xFF && prand[2] == 0x3F)) { |
| prand[0] = (uint8_t)(std::rand() % 0xFE + 1); |
| } |
| prand[2] |= BLE_RESOLVE_ADDR_MSB; |
| |
| Address rpa; |
| rpa.address[3] = prand[0]; |
| rpa.address[4] = prand[1]; |
| rpa.address[5] = prand[2]; |
| |
| /* encrypt with IRK */ |
| bluetooth::crypto_toolbox::Octet16 p = |
| bluetooth::crypto_toolbox::aes_128(irk, prand.data(), 3); |
| |
| /* set hash to be LSB of rpAddress */ |
| rpa.address[0] = p[0]; |
| rpa.address[1] = p[1]; |
| rpa.address[2] = p[2]; |
| LOG_INFO("RPA %s", rpa.ToString().c_str()); |
| return rpa; |
| } |
| |
| void LinkLayerController::IncomingLeAdvertisementPacket( |
| model::packets::LinkLayerPacketView incoming, uint8_t rssi) { |
| // TODO: Handle multiple advertisements per packet. |
| |
| Address address = incoming.GetSourceAddress(); |
| auto advertisement = model::packets::LeAdvertisementView::Create(incoming); |
| ASSERT(advertisement.IsValid()); |
| auto address_type = advertisement.GetAddressType(); |
| auto adv_type = advertisement.GetAdvertisementType(); |
| |
| if (le_scan_enable_ == bluetooth::hci::OpCode::LE_SET_SCAN_ENABLE) { |
| vector<uint8_t> ad = advertisement.GetData(); |
| |
| std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr = |
| std::make_unique<bluetooth::packet::RawBuilder>(); |
| raw_builder_ptr->AddOctets1( |
| static_cast<uint8_t>(bluetooth::hci::SubeventCode::ADVERTISING_REPORT)); |
| raw_builder_ptr->AddOctets1(0x01); // num reports |
| raw_builder_ptr->AddOctets1(static_cast<uint8_t>(adv_type)); |
| raw_builder_ptr->AddOctets1(static_cast<uint8_t>(address_type)); |
| raw_builder_ptr->AddAddress(address); |
| raw_builder_ptr->AddOctets1(ad.size()); |
| raw_builder_ptr->AddOctets(ad); |
| raw_builder_ptr->AddOctets1(rssi); |
| if (properties_.IsUnmasked(EventCode::LE_META_EVENT)) { |
| send_event_(bluetooth::hci::EventBuilder::Create( |
| bluetooth::hci::EventCode::LE_META_EVENT, |
| std::move(raw_builder_ptr))); |
| } |
| } |
| |
| if (le_scan_enable_ == bluetooth::hci::OpCode::LE_SET_EXTENDED_SCAN_ENABLE) { |
| vector<uint8_t> ad = advertisement.GetData(); |
| |
| std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr = |
| std::make_unique<bluetooth::packet::RawBuilder>(); |
| raw_builder_ptr->AddOctets1(static_cast<uint8_t>( |
| bluetooth::hci::SubeventCode::EXTENDED_ADVERTISING_REPORT)); |
| raw_builder_ptr->AddOctets1(0x01); // num reports |
| switch (adv_type) { |
| case model::packets::AdvertisementType::ADV_IND: |
| raw_builder_ptr->AddOctets1(0x13); |
| break; |
| case model::packets::AdvertisementType::ADV_DIRECT_IND: |
| raw_builder_ptr->AddOctets1(0x15); |
| break; |
| case model::packets::AdvertisementType::ADV_SCAN_IND: |
| raw_builder_ptr->AddOctets1(0x12); |
| break; |
| case model::packets::AdvertisementType::ADV_NONCONN_IND: |
| raw_builder_ptr->AddOctets1(0x10); |
| break; |
| case model::packets::AdvertisementType::SCAN_RESPONSE: |
| raw_builder_ptr->AddOctets1(0x1b); // 0x1a for ADV_SCAN_IND scan |
| return; |
| } |
| raw_builder_ptr->AddOctets1(0x00); // Reserved |
| raw_builder_ptr->AddOctets1(static_cast<uint8_t>(address_type)); |
| raw_builder_ptr->AddAddress(address); |
| raw_builder_ptr->AddOctets1(1); // Primary_PHY |
| raw_builder_ptr->AddOctets1(0); // Secondary_PHY |
| raw_builder_ptr->AddOctets1(0xFF); // Advertising_SID - not provided |
| raw_builder_ptr->AddOctets1(0x7F); // Tx_Power - Not available |
| raw_builder_ptr->AddOctets1(rssi); |
| raw_builder_ptr->AddOctets2(0); // Periodic_Advertising_Interval - None |
| raw_builder_ptr->AddOctets1(0); // Direct_Address_Type - PUBLIC |
| raw_builder_ptr->AddAddress(Address::kEmpty); // Direct_Address |
| raw_builder_ptr->AddOctets1(ad.size()); |
| raw_builder_ptr->AddOctets(ad); |
| if (properties_.IsUnmasked(EventCode::LE_META_EVENT)) { |
| send_event_(bluetooth::hci::EventBuilder::Create( |
| bluetooth::hci::EventCode::LE_META_EVENT, |
| std::move(raw_builder_ptr))); |
| } |
| } |
| |
| // Active scanning |
| if (le_scan_enable_ != bluetooth::hci::OpCode::NONE && le_scan_type_ == 1) { |
| SendLeLinkLayerPacket(model::packets::LeScanBuilder::Create( |
| properties_.GetLeAddress(), address)); |
| } |
| |
| if (!le_connect_ || le_pending_connect_) { |
| return; |
| } |
| if (!(adv_type == model::packets::AdvertisementType::ADV_IND || |
| adv_type == model::packets::AdvertisementType::ADV_DIRECT_IND)) { |
| return; |
| } |
| Address resolved_address = address; |
| uint8_t resolved_address_type = static_cast<uint8_t>(address_type); |
| bool resolved = false; |
| Address rpa; |
| if (le_resolving_list_enabled_) { |
| for (const auto& entry : le_resolving_list_) { |
| if (rpa_matches_irk(address, entry.peer_irk)) { |
| LOG_INFO("Matched against IRK for %s", |
| entry.address.ToString().c_str()); |
| resolved = true; |
| resolved_address = entry.address; |
| resolved_address_type = entry.address_type; |
| rpa = generate_rpa(entry.local_irk); |
| } |
| } |
| } |
| |
| // Connect |
| if ((le_peer_address_ == address && |
| le_peer_address_type_ == static_cast<uint8_t>(address_type)) || |
| (LeFilterAcceptListContainsDevice(address, |
| static_cast<uint8_t>(address_type))) || |
| (resolved && |
| LeFilterAcceptListContainsDevice( |
| resolved_address, static_cast<uint8_t>(resolved_address_type)))) { |
| if (!connections_.CreatePendingLeConnection(AddressWithType( |
| address, static_cast<bluetooth::hci::AddressType>(address_type)))) { |
| LOG_WARN( |
| "CreatePendingLeConnection failed for connection to %s (type %hhx)", |
| incoming.GetSourceAddress().ToString().c_str(), address_type); |
| } |
| Address own_address; |
| auto own_address_type = |
| static_cast<bluetooth::hci::OwnAddressType>(le_address_type_); |
| switch (own_address_type) { |
| case bluetooth::hci::OwnAddressType::PUBLIC_DEVICE_ADDRESS: |
| own_address = properties_.GetAddress(); |
| break; |
| case bluetooth::hci::OwnAddressType::RANDOM_DEVICE_ADDRESS: |
| own_address = properties_.GetLeAddress(); |
| break; |
| case bluetooth::hci::OwnAddressType::RESOLVABLE_OR_PUBLIC_ADDRESS: |
| if (resolved) { |
| own_address = rpa; |
| le_connecting_rpa_ = rpa; |
| } else { |
| own_address = properties_.GetAddress(); |
| } |
| break; |
| case bluetooth::hci::OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS: |
| if (resolved) { |
| own_address = rpa; |
| le_connecting_rpa_ = rpa; |
| } else { |
| own_address = properties_.GetLeAddress(); |
| } |
| break; |
| } |
| LOG_INFO("Connecting to %s (type %hhx) own_address %s (type %hhx)", |
| incoming.GetSourceAddress().ToString().c_str(), address_type, |
| own_address.ToString().c_str(), le_address_type_); |
| le_pending_connect_ = true; |
| le_scan_enable_ = bluetooth::hci::OpCode::NONE; |
| |
| SendLeLinkLayerPacket(model::packets::LeConnectBuilder::Create( |
| own_address, incoming.GetSourceAddress(), le_connection_interval_min_, |
| le_connection_interval_max_, le_connection_latency_, |
| le_connection_supervision_timeout_, |
| static_cast<uint8_t>(le_address_type_))); |
| } |
| } |
| |
| void LinkLayerController::IncomingScoConnectionRequest( |
| model::packets::LinkLayerPacketView incoming) { |
| Address address = incoming.GetSourceAddress(); |
| auto request = model::packets::ScoConnectionRequestView::Create(incoming); |
| ASSERT(request.IsValid()); |
| |
| LOG_INFO("Received eSCO connection request from %s", |
| address.ToString().c_str()); |
| |
| // Automatically reject if connection request was already sent |
| // from the current device. |
| if (connections_.HasPendingScoConnection(address)) { |
| LOG_INFO( |
| "Rejecting eSCO connection request from %s, " |
| "an eSCO connection already exist with this device", |
| address.ToString().c_str()); |
| |
| SendLinkLayerPacket(model::packets::ScoConnectionResponseBuilder::Create( |
| properties_.GetAddress(), address, |
| (uint8_t)ErrorCode::SYNCHRONOUS_CONNECTION_LIMIT_EXCEEDED, 0, 0, 0, 0, |
| 0, 0)); |
| return; |
| } |
| |
| // Create local connection context. |
| ScoConnectionParameters connection_parameters = { |
| request.GetTransmitBandwidth(), request.GetReceiveBandwidth(), |
| request.GetMaxLatency(), request.GetVoiceSetting(), |
| request.GetRetransmissionEffort(), request.GetPacketType()}; |
| |
| bool extended = connection_parameters.IsExtended(); |
| connections_.CreateScoConnection( |
| address, connection_parameters, |
| extended ? ScoState::SCO_STATE_SENT_ESCO_CONNECTION_REQUEST |
| : ScoState::SCO_STATE_SENT_SCO_CONNECTION_REQUEST); |
| |
| // Send connection request event and wait for Accept or Reject command. |
| send_event_(bluetooth::hci::ConnectionRequestBuilder::Create( |
| address, ClassOfDevice(), |
| extended ? bluetooth::hci::ConnectionRequestLinkType::ESCO |
| : bluetooth::hci::ConnectionRequestLinkType::SCO)); |
| } |
| |
| void LinkLayerController::IncomingScoConnectionResponse( |
| model::packets::LinkLayerPacketView incoming) { |
| Address address = incoming.GetSourceAddress(); |
| auto response = model::packets::ScoConnectionResponseView::Create(incoming); |
| ASSERT(response.IsValid()); |
| auto status = ErrorCode(response.GetStatus()); |
| bool is_legacy = connections_.IsLegacyScoConnection(address); |
| |
| LOG_INFO("Received eSCO connection response with status 0x%02x from %s", |
| static_cast<unsigned>(status), |
| incoming.GetSourceAddress().ToString().c_str()); |
| |
| if (status == ErrorCode::SUCCESS) { |
| bool extended = response.GetExtended(); |
| ScoLinkParameters link_parameters = { |
| response.GetTransmissionInterval(), |
| response.GetRetransmissionWindow(), |
| response.GetRxPacketLength(), |
| response.GetTxPacketLength(), |
| response.GetAirMode(), |
| extended, |
| }; |
| connections_.AcceptPendingScoConnection(address, link_parameters); |
| if (is_legacy) { |
| send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( |
| ErrorCode::SUCCESS, connections_.GetScoHandle(address), address, |
| bluetooth::hci::LinkType::SCO, bluetooth::hci::Enable::DISABLED)); |
| } else { |
| send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create( |
| ErrorCode::SUCCESS, connections_.GetScoHandle(address), address, |
| extended ? bluetooth::hci::ScoLinkType::ESCO |
| : bluetooth::hci::ScoLinkType::SCO, |
| extended ? response.GetTransmissionInterval() : 0, |
| extended ? response.GetRetransmissionWindow() : 0, |
| extended ? response.GetRxPacketLength() : 0, |
| extended ? response.GetTxPacketLength() : 0, |
| bluetooth::hci::ScoAirMode(response.GetAirMode()))); |
| } |
| } else { |
| connections_.CancelPendingScoConnection(address); |
| if (is_legacy) { |
| send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( |
| status, 0, address, bluetooth::hci::LinkType::SCO, |
| bluetooth::hci::Enable::DISABLED)); |
| } else { |
| ScoConnectionParameters connection_parameters = |
| connections_.GetScoConnectionParameters(address); |
| send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create( |
| status, 0, address, |
| connection_parameters.IsExtended() ? bluetooth::hci::ScoLinkType::ESCO |
| : bluetooth::hci::ScoLinkType::SCO, |
| 0, 0, 0, 0, bluetooth::hci::ScoAirMode::TRANSPARENT)); |
| } |
| } |
| } |
| |
| void LinkLayerController::IncomingScoDisconnect( |
| model::packets::LinkLayerPacketView incoming) { |
| Address address = incoming.GetSourceAddress(); |
| auto request = model::packets::ScoDisconnectView::Create(incoming); |
| ASSERT(request.IsValid()); |
| auto reason = request.GetReason(); |
| uint16_t handle = connections_.GetScoHandle(address); |
| |
| LOG_INFO( |
| "Received eSCO disconnection request with" |
| " reason 0x%02x from %s", |
| static_cast<unsigned>(reason), |
| incoming.GetSourceAddress().ToString().c_str()); |
| |
| if (handle != kReservedHandle) { |
| connections_.Disconnect(handle); |
| SendDisconnectionCompleteEvent(handle, reason); |
| } |
| } |
| |
| #ifdef ROOTCANAL_LMP |
| void LinkLayerController::IncomingLmpPacket( |
| model::packets::LinkLayerPacketView incoming) { |
| Address address = incoming.GetSourceAddress(); |
| auto request = model::packets::LmpView::Create(incoming); |
| ASSERT(request.IsValid()); |
| auto payload = request.GetPayload(); |
| auto packet = std::vector(payload.begin(), payload.end()); |
| |
| ASSERT(link_manager_ingest_lmp( |
| lm_.get(), reinterpret_cast<uint8_t(*)[6]>(address.data()), packet.data(), |
| packet.size())); |
| } |
| #endif /* ROOTCANAL_LMP */ |
| |
| uint16_t LinkLayerController::HandleLeConnection( |
| AddressWithType address, AddressWithType own_address, uint8_t role, |
| uint16_t connection_interval, uint16_t connection_latency, |
| uint16_t supervision_timeout, |
| bool send_le_channel_selection_algorithm_event) { |
| // Note: the HCI_LE_Connection_Complete event is not sent if the |
| // HCI_LE_Enhanced_Connection_Complete event (see Section 7.7.65.10) is |
| // unmasked. |
| |
| uint16_t handle = connections_.CreateLeConnection(address, own_address); |
| if (handle == kReservedHandle) { |
| LOG_WARN("No pending connection for connection from %s", |
| address.ToString().c_str()); |
| return kReservedHandle; |
| } |
| |
| if (properties_.IsUnmasked(EventCode::LE_META_EVENT) && |
| properties_.GetLeEventSupported( |
| SubeventCode::ENHANCED_CONNECTION_COMPLETE)) { |
| send_event_(bluetooth::hci::LeEnhancedConnectionCompleteBuilder::Create( |
| ErrorCode::SUCCESS, handle, static_cast<bluetooth::hci::Role>(role), |
| address.GetAddressType(), address.GetAddress(), |
| Address(), // TODO local resolvable private address, if applicable |
| Address(), // TODO Peer resolvable private address, if applicable |
| connection_interval, connection_latency, supervision_timeout, |
| static_cast<bluetooth::hci::ClockAccuracy>(0x00))); |
| } else if (properties_.IsUnmasked(EventCode::LE_META_EVENT) && |
| properties_.GetLeEventSupported( |
| SubeventCode::CONNECTION_COMPLETE)) { |
| send_event_(bluetooth::hci::LeConnectionCompleteBuilder::Create( |
| ErrorCode::SUCCESS, handle, static_cast<bluetooth::hci::Role>(role), |
| address.GetAddressType(), address.GetAddress(), connection_interval, |
| connection_latency, supervision_timeout, |
| static_cast<bluetooth::hci::ClockAccuracy>(0x00))); |
| } |
| |
| // Note: the HCI_LE_Connection_Complete event is immediately followed by |
| // an HCI_LE_Channel_Selection_Algorithm event if the connection is created |
| // using the LE_Extended_Create_Connection command (see Section 7.7.8.66). |
| if (send_le_channel_selection_algorithm_event && |
| properties_.IsUnmasked(EventCode::LE_META_EVENT) && |
| properties_.GetLeEventSupported( |
| SubeventCode::CHANNEL_SELECTION_ALGORITHM)) { |
| // The selection channel algorithm probably will have no impact |
| // on emulation. |
| send_event_(bluetooth::hci::LeChannelSelectionAlgorithmBuilder::Create( |
| handle, bluetooth::hci::ChannelSelectionAlgorithm::ALGORITHM_1)); |
| } |
| |
| if (own_address.GetAddress() == le_connecting_rpa_) { |
| le_connecting_rpa_ = Address::kEmpty; |
| } |
| return handle; |
| } |
| |
| void LinkLayerController::IncomingLeConnectPacket( |
| model::packets::LinkLayerPacketView incoming) { |
| auto connect = model::packets::LeConnectView::Create(incoming); |
| ASSERT(connect.IsValid()); |
| uint16_t connection_interval = (connect.GetLeConnectionIntervalMax() + |
| connect.GetLeConnectionIntervalMin()) / |
| 2; |
| if (!connections_.CreatePendingLeConnection(AddressWithType( |
| incoming.GetSourceAddress(), static_cast<bluetooth::hci::AddressType>( |
| connect.GetAddressType())))) { |
| LOG_WARN( |
| "CreatePendingLeConnection failed for connection from %s (type " |
| "%hhx)", |
| incoming.GetSourceAddress().ToString().c_str(), |
| connect.GetAddressType()); |
| return; |
| } |
| bluetooth::hci::AddressWithType my_address{}; |
| bool matched_advertiser = false; |
| size_t set = 0; |
| for (size_t i = 0; i < advertisers_.size(); i++) { |
| AddressWithType advertiser_address = advertisers_[i].GetAddress(); |
| if (incoming.GetDestinationAddress() == advertiser_address.GetAddress()) { |
| my_address = advertiser_address; |
| matched_advertiser = true; |
| set = i; |
| } |
| } |
| |
| if (!matched_advertiser) { |
| LOG_INFO("Dropping unmatched connection request to %s", |
| incoming.GetSourceAddress().ToString().c_str()); |
| return; |
| } |
| |
| if (!advertisers_[set].IsConnectable()) { |
| LOG_INFO( |
| "Rejecting connection request from %s to non-connectable advertiser", |
| incoming.GetSourceAddress().ToString().c_str()); |
| return; |
| } |
| |
| uint16_t handle = HandleLeConnection( |
| AddressWithType( |
| incoming.GetSourceAddress(), |
| static_cast<bluetooth::hci::AddressType>(connect.GetAddressType())), |
| my_address, static_cast<uint8_t>(bluetooth::hci::Role::PERIPHERAL), |
| connection_interval, connect.GetLeConnectionLatency(), |
| connect.GetLeConnectionSupervisionTimeout(), false); |
| |
| SendLeLinkLayerPacket(model::packets::LeConnectCompleteBuilder::Create( |
| incoming.GetDestinationAddress(), incoming.GetSourceAddress(), |
| connection_interval, connect.GetLeConnectionLatency(), |
| connect.GetLeConnectionSupervisionTimeout(), |
| static_cast<uint8_t>(my_address.GetAddressType()))); |
| |
| advertisers_[set].Disable(); |
| |
| if (advertisers_[set].IsExtended()) { |
| uint8_t num_advertisements = advertisers_[set].GetNumAdvertisingEvents(); |
| if (properties_.GetLeEventSupported( |
| bluetooth::hci::SubeventCode::ADVERTISING_SET_TERMINATED)) { |
| send_event_(bluetooth::hci::LeAdvertisingSetTerminatedBuilder::Create( |
| ErrorCode::SUCCESS, set, handle, num_advertisements)); |
| } |
| } |
| } |
| |
| void LinkLayerController::IncomingLeConnectCompletePacket( |
| model::packets::LinkLayerPacketView incoming) { |
| auto complete = model::packets::LeConnectCompleteView::Create(incoming); |
| ASSERT(complete.IsValid()); |
| HandleLeConnection( |
| AddressWithType( |
| incoming.GetSourceAddress(), |
| static_cast<bluetooth::hci::AddressType>(complete.GetAddressType())), |
| AddressWithType( |
| incoming.GetDestinationAddress(), |
| static_cast<bluetooth::hci::AddressType>(le_address_type_)), |
| static_cast<uint8_t>(bluetooth::hci::Role::CENTRAL), |
| complete.GetLeConnectionInterval(), complete.GetLeConnectionLatency(), |
| complete.GetLeConnectionSupervisionTimeout(), le_extended_connect_); |
| le_connect_ = false; |
| le_extended_connect_ = false; |
| le_pending_connect_ = false; |
| } |
| |
| void LinkLayerController::IncomingLeConnectionParameterRequest( |
| model::packets::LinkLayerPacketView incoming) { |
| auto request = |
| model::packets::LeConnectionParameterRequestView::Create(incoming); |
| ASSERT(request.IsValid()); |
| Address peer = incoming.GetSourceAddress(); |
| uint16_t handle = connections_.GetHandleOnlyAddress(peer); |
| if (handle == kReservedHandle) { |
| LOG_INFO("@%s: Unknown connection @%s", |
| incoming.GetDestinationAddress().ToString().c_str(), |
| peer.ToString().c_str()); |
| return; |
| } |
| if (properties_.IsUnmasked(EventCode::LE_META_EVENT) && |
| properties_.GetLeEventSupported( |
| bluetooth::hci::SubeventCode::CONNECTION_UPDATE_COMPLETE)) { |
| send_event_( |
| bluetooth::hci::LeRemoteConnectionParameterRequestBuilder::Create( |
| handle, request.GetIntervalMin(), request.GetIntervalMax(), |
| request.GetLatency(), request.GetTimeout())); |
| } |
| } |
| |
| void LinkLayerController::IncomingLeConnectionParameterUpdate( |
| model::packets::LinkLayerPacketView incoming) { |
| auto update = |
| model::packets::LeConnectionParameterUpdateView::Create(incoming); |
| ASSERT(update.IsValid()); |
| Address peer = incoming.GetSourceAddress(); |
| uint16_t handle = connections_.GetHandleOnlyAddress(peer); |
| if (handle == kReservedHandle) { |
| LOG_INFO("@%s: Unknown connection @%s", |
| incoming.GetDestinationAddress().ToString().c_str(), |
| peer.ToString().c_str()); |
| return; |
| } |
| if (properties_.IsUnmasked(EventCode::LE_META_EVENT) && |
| properties_.GetLeEventSupported( |
| bluetooth::hci::SubeventCode::CONNECTION_UPDATE_COMPLETE)) { |
| send_event_(bluetooth::hci::LeConnectionUpdateCompleteBuilder::Create( |
| static_cast<ErrorCode>(update.GetStatus()), handle, |
| update.GetInterval(), update.GetLatency(), update.GetTimeout())); |
| } |
| } |
| |
| void LinkLayerController::IncomingLeEncryptConnection( |
| model::packets::LinkLayerPacketView incoming) { |
| LOG_INFO("IncomingLeEncryptConnection"); |
| |
| Address peer = incoming.GetSourceAddress(); |
| uint16_t handle = connections_.GetHandleOnlyAddress(peer); |
| if (handle == kReservedHandle) { |
| LOG_INFO("@%s: Unknown connection @%s", |
| incoming.GetDestinationAddress().ToString().c_str(), |
| peer.ToString().c_str()); |
| return; |
| } |
| auto le_encrypt = model::packets::LeEncryptConnectionView::Create(incoming); |
| ASSERT(le_encrypt.IsValid()); |
| |
| // TODO: Save keys to check |
| |
| if (properties_.IsUnmasked(EventCode::LE_META_EVENT)) { |
| send_event_(bluetooth::hci::LeLongTermKeyRequestBuilder::Create( |
| handle, le_encrypt.GetRand(), le_encrypt.GetEdiv())); |
| } |
| } |
| |
| void LinkLayerController::IncomingLeEncryptConnectionResponse( |
| model::packets::LinkLayerPacketView incoming) { |
| LOG_INFO("IncomingLeEncryptConnectionResponse"); |
| // TODO: Check keys |
| uint16_t handle = |
| connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); |
| if (handle == kReservedHandle) { |
| LOG_INFO("@%s: Unknown connection @%s", |
| incoming.GetDestinationAddress().ToString().c_str(), |
| incoming.GetSourceAddress().ToString().c_str()); |
| return; |
| } |
| ErrorCode status = ErrorCode::SUCCESS; |
| auto response = |
| model::packets::LeEncryptConnectionResponseView::Create(incoming); |
| ASSERT(response.IsValid()); |
| |
| // Zero LTK is a rejection |
| if (response.GetLtk() == std::array<uint8_t, 16>()) { |
| status = ErrorCode::AUTHENTICATION_FAILURE; |
| } |
| |
| if (connections_.IsEncrypted(handle)) { |
| if (properties_.IsUnmasked(EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE)) { |
| send_event_(bluetooth::hci::EncryptionKeyRefreshCompleteBuilder::Create( |
| status, handle)); |
| } |
| } else { |
| connections_.Encrypt(handle); |
| if (properties_.IsUnmasked(EventCode::ENCRYPTION_CHANGE)) { |
| send_event_(bluetooth::hci::EncryptionChangeBuilder::Create( |
| status, handle, bluetooth::hci::EncryptionEnabled::ON)); |
| } |
| } |
| } |
| |
| void LinkLayerController::IncomingLeReadRemoteFeatures( |
| model::packets::LinkLayerPacketView incoming) { |
| uint16_t handle = |
| connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); |
| ErrorCode status = ErrorCode::SUCCESS; |
| if (handle == kReservedHandle) { |
| LOG_WARN("@%s: Unknown connection @%s", |
| incoming.GetDestinationAddress().ToString().c_str(), |
| incoming.GetSourceAddress().ToString().c_str()); |
| } |
| SendLeLinkLayerPacket( |
| model::packets::LeReadRemoteFeaturesResponseBuilder::Create( |
| incoming.GetDestinationAddress(), incoming.GetSourceAddress(), |
| properties_.GetLeSupportedFeatures(), static_cast<uint8_t>(status))); |
| } |
| |
| void LinkLayerController::IncomingLeReadRemoteFeaturesResponse( |
| model::packets::LinkLayerPacketView incoming) { |
| uint16_t handle = |
| connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); |
| ErrorCode status = ErrorCode::SUCCESS; |
| auto response = |
| model::packets::LeReadRemoteFeaturesResponseView::Create(incoming); |
| ASSERT(response.IsValid()); |
| if (handle == kReservedHandle) { |
| LOG_INFO("@%s: Unknown connection @%s", |
| incoming.GetDestinationAddress().ToString().c_str(), |
| incoming.GetSourceAddress().ToString().c_str()); |
| status = ErrorCode::UNKNOWN_CONNECTION; |
| } else { |
| status = static_cast<ErrorCode>(response.GetStatus()); |
| } |
| if (properties_.IsUnmasked(EventCode::LE_META_EVENT)) { |
| send_event_(bluetooth::hci::LeReadRemoteFeaturesCompleteBuilder::Create( |
| status, handle, response.GetFeatures())); |
| } |
| } |
| |
| void LinkLayerController::IncomingLeScanPacket( |
| model::packets::LinkLayerPacketView incoming) { |
| for (auto& advertiser : advertisers_) { |
| auto to_send = advertiser.GetScanResponse(incoming.GetDestinationAddress(), |
| incoming.GetSourceAddress()); |
| if (to_send != nullptr) { |
| SendLeLinkLayerPacket(std::move(to_send)); |
| } |
| } |
| } |
| |
| void LinkLayerController::IncomingLeScanResponsePacket( |
| model::packets::LinkLayerPacketView incoming, uint8_t rssi) { |
| auto scan_response = model::packets::LeScanResponseView::Create(incoming); |
| ASSERT(scan_response.IsValid()); |
| vector<uint8_t> ad = scan_response.GetData(); |
| auto adv_type = scan_response.GetAdvertisementType(); |
| auto address_type = scan_response.GetAddressType(); |
| if (le_scan_enable_ == bluetooth::hci::OpCode::LE_SET_SCAN_ENABLE) { |
| if (adv_type != model::packets::AdvertisementType::SCAN_RESPONSE) { |
| return; |
| } |
| bluetooth::hci::LeAdvertisingResponseRaw report; |
| report.event_type_ = bluetooth::hci::AdvertisingEventType::SCAN_RESPONSE; |
| report.address_ = incoming.GetSourceAddress(); |
| report.address_type_ = |
| static_cast<bluetooth::hci::AddressType>(address_type); |
| report.advertising_data_ = scan_response.GetData(); |
| report.rssi_ = rssi; |
| |
| if (properties_.IsUnmasked(EventCode::LE_META_EVENT) && |
| properties_.GetLeEventSupported( |
| bluetooth::hci::SubeventCode::ADVERTISING_REPORT)) { |
| send_event_( |
| bluetooth::hci::LeAdvertisingReportRawBuilder::Create({report})); |
| } |
| } |
| |
| if (le_scan_enable_ == bluetooth::hci::OpCode::LE_SET_EXTENDED_SCAN_ENABLE && |
| properties_.IsUnmasked(EventCode::LE_META_EVENT) && |
| properties_.GetLeEventSupported( |
| bluetooth::hci::SubeventCode::EXTENDED_ADVERTISING_REPORT)) { |
| bluetooth::hci::LeExtendedAdvertisingResponse report{}; |
| report.address_ = incoming.GetSourceAddress(); |
| report.address_type_ = |
| static_cast<bluetooth::hci::DirectAdvertisingAddressType>(address_type); |
| report.legacy_ = true; |
| report.scannable_ = true; |
| report.connectable_ = true; // TODO: false if ADV_SCAN_IND |
| report.scan_response_ = true; |
| report.primary_phy_ = bluetooth::hci::PrimaryPhyType::LE_1M; |
| report.advertising_sid_ = 0xFF; |
| report.tx_power_ = 0x7F; |
| report.advertising_data_ = ad; |
| report.rssi_ = rssi; |
| send_event_( |
| bluetooth::hci::LeExtendedAdvertisingReportBuilder::Create({report})); |
| } |
| } |
| |
| #ifndef ROOTCANAL_LMP |
| void LinkLayerController::IncomingPasskeyPacket( |
| model::packets::LinkLayerPacketView incoming) { |
| auto passkey = model::packets::PasskeyView::Create(incoming); |
| ASSERT(passkey.IsValid()); |
| SaveKeyAndAuthenticate('P', incoming.GetSourceAddress()); |
| } |
| |
| void LinkLayerController::IncomingPasskeyFailedPacket( |
| model::packets::LinkLayerPacketView incoming) { |
| auto failed = model::packets::PasskeyFailedView::Create(incoming); |
| ASSERT(failed.IsValid()); |
| auto current_peer = incoming.GetSourceAddress(); |
| security_manager_.AuthenticationRequestFinished(); |
| ScheduleTask(kNoDelayMs, [this, current_peer]() { |
| if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { |
| send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( |
| ErrorCode::AUTHENTICATION_FAILURE, current_peer)); |
| } |
| }); |
| } |
| |
| void LinkLayerController::IncomingPinRequestPacket( |
| model::packets::LinkLayerPacketView incoming) { |
| auto request = model::packets::PinRequestView::Create(incoming); |
| ASSERT(request.IsValid()); |
| auto peer = incoming.GetSourceAddress(); |
| auto handle = connections_.GetHandle(AddressWithType( |
| peer, bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS)); |
| if (handle == kReservedHandle) { |
| LOG_INFO("Dropping %s request (no connection)", peer.ToString().c_str()); |
| auto wrong_pin = request.GetPinCode(); |
| wrong_pin[0] = wrong_pin[0]++; |
| SendLinkLayerPacket(model::packets::PinResponseBuilder::Create( |
| properties_.GetAddress(), peer, wrong_pin)); |
| return; |
| } |
| if (security_manager_.AuthenticationInProgress()) { |
| auto current_peer = security_manager_.GetAuthenticationAddress(); |
| if (current_peer != peer) { |
| LOG_INFO("Dropping %s request (%s in progress)", peer.ToString().c_str(), |
| current_peer.ToString().c_str()); |
| auto wrong_pin = request.GetPinCode(); |
| wrong_pin[0] = wrong_pin[0]++; |
| SendLinkLayerPacket(model::packets::PinResponseBuilder::Create( |
| properties_.GetAddress(), peer, wrong_pin)); |
| return; |
| } |
| } else { |
| LOG_INFO("Incoming authentication request %s", peer.ToString().c_str()); |
| security_manager_.AuthenticationRequest(peer, handle, false); |
| } |
| auto current_peer = security_manager_.GetAuthenticationAddress(); |
| security_manager_.SetRemotePin(peer, request.GetPinCode()); |
| if (security_manager_.GetPinRequested(peer)) { |
| if (security_manager_.GetLocalPinResponseReceived(peer)) { |
| SendLinkLayerPacket(model::packets::PinResponseBuilder::Create( |
| properties_.GetAddress(), peer, request.GetPinCode())); |
| if (security_manager_.PinCompare()) { |
| LOG_INFO("Authenticating %s", peer.ToString().c_str()); |
| SaveKeyAndAuthenticate('L', peer); // Legacy |
| } else { |
| security_manager_.AuthenticationRequestFinished(); |
| ScheduleTask(kNoDelayMs, [this, peer]() { |
| if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { |
| send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( |
| ErrorCode::AUTHENTICATION_FAILURE, peer)); |
| } |
| }); |
| } |
| } |
| } else { |
| LOG_INFO("PIN pairing %s", properties_.GetAddress().ToString().c_str()); |
| ScheduleTask(kNoDelayMs, [this, peer]() { |
| security_manager_.SetPinRequested(peer); |
| if (properties_.IsUnmasked(EventCode::PIN_CODE_REQUEST)) { |
| send_event_(bluetooth::hci::PinCodeRequestBuilder::Create(peer)); |
| } |
| }); |
| } |
| } |
| |
| void LinkLayerController::IncomingPinResponsePacket( |
| model::packets::LinkLayerPacketView incoming) { |
| auto request = model::packets::PinResponseView::Create(incoming); |
| ASSERT(request.IsValid()); |
| auto peer = incoming.GetSourceAddress(); |
| auto handle = connections_.GetHandle(AddressWithType( |
| peer, bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS)); |
| if (handle == kReservedHandle) { |
| LOG_INFO("Dropping %s request (no connection)", peer.ToString().c_str()); |
| return; |
| } |
| if (security_manager_.AuthenticationInProgress()) { |
| auto current_peer = security_manager_.GetAuthenticationAddress(); |
| if (current_peer != peer) { |
| LOG_INFO("Dropping %s request (%s in progress)", peer.ToString().c_str(), |
| current_peer.ToString().c_str()); |
| return; |
| } |
| } else { |
| LOG_INFO("Dropping response without authentication request %s", |
| peer.ToString().c_str()); |
| return; |
| } |
| auto current_peer = security_manager_.GetAuthenticationAddress(); |
| security_manager_.SetRemotePin(peer, request.GetPinCode()); |
| if (security_manager_.GetPinRequested(peer)) { |
| if (security_manager_.GetLocalPinResponseReceived(peer)) { |
| SendLinkLayerPacket(model::packets::PinResponseBuilder::Create( |
| properties_.GetAddress(), peer, request.GetPinCode())); |
| if (security_manager_.PinCompare()) { |
| LOG_INFO("Authenticating %s", peer.ToString().c_str()); |
| SaveKeyAndAuthenticate('L', peer); // Legacy |
| } else { |
| security_manager_.AuthenticationRequestFinished(); |
| ScheduleTask(kNoDelayMs, [this, peer]() { |
| if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { |
| send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( |
| ErrorCode::AUTHENTICATION_FAILURE, peer)); |
| } |
| }); |
| } |
| } |
| } else { |
| LOG_INFO("PIN pairing %s", properties_.GetAddress().ToString().c_str()); |
| ScheduleTask(kNoDelayMs, [this, peer]() { |
| security_manager_.SetPinRequested(peer); |
| if (properties_.IsUnmasked(EventCode::PIN_CODE_REQUEST)) { |
| send_event_(bluetooth::hci::PinCodeRequestBuilder::Create(peer)); |
| } |
| }); |
| } |
| } |
| #endif /* !ROOTCANAL_LMP */ |
| |
| void LinkLayerController::IncomingPagePacket( |
| model::packets::LinkLayerPacketView incoming) { |
| auto page = model::packets::PageView::Create(incoming); |
| ASSERT(page.IsValid()); |
| LOG_INFO("from %s", incoming.GetSourceAddress().ToString().c_str()); |
| |
| if (!connections_.CreatePendingConnection( |
| incoming.GetSourceAddress(), properties_.GetAuthenticationEnable())) { |
| // Send a response to indicate that we're busy, or drop the packet? |
| LOG_WARN("Failed to create a pending connection for %s", |
| incoming.GetSourceAddress().ToString().c_str()); |
| } |
| |
| #ifdef ROOTCANAL_LMP |
| ASSERT(link_manager_add_link(lm_.get(), |
| reinterpret_cast<const uint8_t(*)[6]>( |
| incoming.GetSourceAddress().data()))); |
| #endif |
| |
| bluetooth::hci::Address source_address{}; |
| bluetooth::hci::Address::FromString(page.GetSourceAddress().ToString(), |
| source_address); |
| |
| if (properties_.IsUnmasked(EventCode::CONNECTION_REQUEST)) { |
| send_event_(bluetooth::hci::ConnectionRequestBuilder::Create( |
| source_address, page.GetClassOfDevice(), |
| bluetooth::hci::ConnectionRequestLinkType::ACL)); |
| } |
| } |
| |
| void LinkLayerController::IncomingPageRejectPacket( |
| model::packets::LinkLayerPacketView incoming) { |
| LOG_INFO("%s", incoming.GetSourceAddress().ToString().c_str()); |
| auto reject = model::packets::PageRejectView::Create(incoming); |
| ASSERT(reject.IsValid()); |
| LOG_INFO("Sending CreateConnectionComplete"); |
| if (properties_.IsUnmasked(EventCode::CONNECTION_COMPLETE)) { |
| send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( |
| static_cast<ErrorCode>(reject.GetReason()), 0x0eff, |
| incoming.GetSourceAddress(), bluetooth::hci::LinkType::ACL, |
| bluetooth::hci::Enable::DISABLED)); |
| } |
| } |
| |
| void LinkLayerController::IncomingPageResponsePacket( |
| model::packets::LinkLayerPacketView incoming) { |
| Address peer = incoming.GetSourceAddress(); |
| LOG_INFO("%s", peer.ToString().c_str()); |
| #ifndef ROOTCANAL_LMP |
| bool awaiting_authentication = connections_.AuthenticatePendingConnection(); |
| #endif /* !ROOTCANAL_LMP */ |
| uint16_t handle = |
| connections_.CreateConnection(peer, incoming.GetDestinationAddress()); |
| if (handle == kReservedHandle) { |
| LOG_WARN("No free handles"); |
| return; |
| } |
| if (properties_.IsUnmasked(EventCode::CONNECTION_COMPLETE)) { |
| send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( |
| ErrorCode::SUCCESS, handle, incoming.GetSourceAddress(), |
| bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED)); |
| } |
| |
| #ifndef ROOTCANAL_LMP |
| if (awaiting_authentication) { |
| ScheduleTask(kNoDelayMs, [this, peer, handle]() { |
| HandleAuthenticationRequest(peer, handle); |
| }); |
| } |
| #endif /* !ROOTCANAL_LMP */ |
| } |
| |
| void LinkLayerController::TimerTick() { |
| if (inquiry_timer_task_id_ != kInvalidTaskId) Inquiry(); |
| LeAdvertising(); |
| #ifdef ROOTCANAL_LMP |
| link_manager_tick(lm_.get()); |
| #endif /* ROOTCANAL_LMP */ |
| } |
| |
| void LinkLayerController::Close() { |
| for (auto handle : connections_.GetAclHandles()) { |
| Disconnect(handle, static_cast<uint8_t>(ErrorCode::CONNECTION_TIMEOUT)); |
| } |
| } |
| |
| void LinkLayerController::LeAdvertising() { |
| steady_clock::time_point now = steady_clock::now(); |
| for (auto& advertiser : advertisers_) { |
| auto event = advertiser.GetEvent(now); |
| if (event != nullptr) { |
| send_event_(std::move(event)); |
| } |
| |
| auto advertisement = advertiser.GetAdvertisement(now); |
| if (advertisement != nullptr) { |
| SendLeLinkLayerPacket(std::move(advertisement)); |
| } |
| } |
| } |
| |
| void LinkLayerController::RegisterEventChannel( |
| const std::function<void(std::shared_ptr<bluetooth::hci::EventBuilder>)>& |
| callback) { |
| send_event_ = callback; |
| } |
| |
| void LinkLayerController::RegisterAclChannel( |
| const std::function<void(std::shared_ptr<bluetooth::hci::AclBuilder>)>& |
| callback) { |
| send_acl_ = callback; |
| } |
| |
| void LinkLayerController::RegisterScoChannel( |
| const std::function<void(std::shared_ptr<bluetooth::hci::ScoBuilder>)>& |
| callback) { |
| send_sco_ = callback; |
| } |
| |
| void LinkLayerController::RegisterIsoChannel( |
| const std::function<void(std::shared_ptr<bluetooth::hci::IsoBuilder>)>& |
| callback) { |
| send_iso_ = callback; |
| } |
| |
| void LinkLayerController::RegisterRemoteChannel( |
| const std::function<void( |
| std::shared_ptr<model::packets::LinkLayerPacketBuilder>, Phy::Type)>& |
| callback) { |
| send_to_remote_ = callback; |
| } |
| |
| void LinkLayerController::RegisterTaskScheduler( |
| std::function<AsyncTaskId(milliseconds, const TaskCallback&)> |
| event_scheduler) { |
| schedule_task_ = event_scheduler; |
| } |
| |
| AsyncTaskId LinkLayerController::ScheduleTask(milliseconds delay_ms, |
| const TaskCallback& callback) { |
| if (schedule_task_) { |
| return schedule_task_(delay_ms, callback); |
| } else { |
| callback(); |
| return 0; |
| } |
| } |
| |
| void LinkLayerController::RegisterPeriodicTaskScheduler( |
| std::function<AsyncTaskId(milliseconds, milliseconds, const TaskCallback&)> |
| periodic_event_scheduler) { |
| schedule_periodic_task_ = periodic_event_scheduler; |
| } |
| |
| void LinkLayerController::CancelScheduledTask(AsyncTaskId task_id) { |
| if (schedule_task_ && cancel_task_) { |
| cancel_task_(task_id); |
| } |
| } |
| |
| void LinkLayerController::RegisterTaskCancel( |
| std::function<void(AsyncTaskId)> task_cancel) { |
| cancel_task_ = task_cancel; |
| } |
| |
| #ifdef ROOTCANAL_LMP |
| void LinkLayerController::ForwardToLm(bluetooth::hci::CommandView command) { |
| auto packet = std::vector(command.begin(), command.end()); |
| ASSERT(link_manager_ingest_hci(lm_.get(), packet.data(), packet.size())); |
| } |
| #else |
| void LinkLayerController::StartSimplePairing(const Address& address) { |
| // IO Capability Exchange (See the Diagram in the Spec) |
| if (properties_.IsUnmasked(EventCode::IO_CAPABILITY_REQUEST)) { |
| send_event_(bluetooth::hci::IoCapabilityRequestBuilder::Create(address)); |
| } |
| |
| // Get a Key, then authenticate |
| // PublicKeyExchange(address); |
| // AuthenticateRemoteStage1(address); |
| // AuthenticateRemoteStage2(address); |
| } |
| |
| void LinkLayerController::AuthenticateRemoteStage1(const Address& peer, |
| PairingType pairing_type) { |
| ASSERT(security_manager_.GetAuthenticationAddress() == peer); |
| // TODO: Public key exchange first? |
| switch (pairing_type) { |
| case PairingType::AUTO_CONFIRMATION: |
| if (properties_.IsUnmasked(EventCode::USER_CONFIRMATION_REQUEST)) { |
| send_event_(bluetooth::hci::UserConfirmationRequestBuilder::Create( |
| peer, 123456)); |
| } |
| break; |
| case PairingType::CONFIRM_Y_N: |
| if (properties_.IsUnmasked(EventCode::USER_CONFIRMATION_REQUEST)) { |
| send_event_(bluetooth::hci::UserConfirmationRequestBuilder::Create( |
| peer, 123456)); |
| } |
| break; |
| case PairingType::DISPLAY_PIN: |
| if (properties_.IsUnmasked(EventCode::USER_PASSKEY_NOTIFICATION)) { |
| send_event_(bluetooth::hci::UserPasskeyNotificationBuilder::Create( |
| peer, 123456)); |
| } |
| break; |
| case PairingType::DISPLAY_AND_CONFIRM: |
| if (properties_.IsUnmasked(EventCode::USER_CONFIRMATION_REQUEST)) { |
| send_event_(bluetooth::hci::UserConfirmationRequestBuilder::Create( |
| peer, 123456)); |
| } |
| break; |
| case PairingType::INPUT_PIN: |
| if (properties_.IsUnmasked(EventCode::USER_PASSKEY_REQUEST)) { |
| send_event_(bluetooth::hci::UserPasskeyRequestBuilder::Create(peer)); |
| } |
| break; |
| case PairingType::OUT_OF_BAND: |
| LOG_INFO("Oob data request for %s", peer.ToString().c_str()); |
| if (properties_.IsUnmasked(EventCode::REMOTE_OOB_DATA_REQUEST)) { |
| send_event_(bluetooth::hci::RemoteOobDataRequestBuilder::Create(peer)); |
| } |
| break; |
| case PairingType::PEER_HAS_OUT_OF_BAND: |
| LOG_INFO("Trusting that %s has OOB data", peer.ToString().c_str()); |
| SaveKeyAndAuthenticate('P', peer); |
| break; |
| default: |
| LOG_ALWAYS_FATAL("Invalid PairingType %d", |
| static_cast<int>(pairing_type)); |
| } |
| } |
| |
| void LinkLayerController::AuthenticateRemoteStage2(const Address& peer) { |
| uint16_t handle = security_manager_.GetAuthenticationHandle(); |
| ASSERT(security_manager_.GetAuthenticationAddress() == peer); |
| // Check key in security_manager_ ? |
| if (security_manager_.IsInitiator()) { |
| if (properties_.IsUnmasked(EventCode::AUTHENTICATION_COMPLETE)) { |
| send_event_(bluetooth::hci::AuthenticationCompleteBuilder::Create( |
| ErrorCode::SUCCESS, handle)); |
| } |
| } |
| } |
| |
| ErrorCode LinkLayerController::LinkKeyRequestReply( |
| const Address& peer, const std::array<uint8_t, 16>& key) { |
| security_manager_.WriteKey(peer, key); |
| security_manager_.AuthenticationRequestFinished(); |
| |
| ScheduleTask(kNoDelayMs, [this, peer]() { AuthenticateRemoteStage2(peer); }); |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LinkKeyRequestNegativeReply( |
| const Address& address) { |
| security_manager_.DeleteKey(address); |
| // Simple pairing to get a key |
| uint16_t handle = connections_.GetHandleOnlyAddress(address); |
| if (handle == kReservedHandle) { |
| LOG_INFO("Device not connected %s", address.ToString().c_str()); |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| if (properties_.GetSecureSimplePairingSupported()) { |
| if (!security_manager_.AuthenticationInProgress()) { |
| security_manager_.AuthenticationRequest(address, handle, false); |
| } |
| |
| ScheduleTask(kNoDelayMs, |
| [this, address]() { StartSimplePairing(address); }); |
| } else { |
| LOG_INFO("PIN pairing %s", properties_.GetAddress().ToString().c_str()); |
| ScheduleTask(kNoDelayMs, [this, address]() { |
| security_manager_.SetPinRequested(address); |
| if (properties_.IsUnmasked(EventCode::PIN_CODE_REQUEST)) { |
| send_event_(bluetooth::hci::PinCodeRequestBuilder::Create(address)); |
| } |
| }); |
| } |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::IoCapabilityRequestReply( |
| const Address& peer, uint8_t io_capability, uint8_t oob_data_present_flag, |
| uint8_t authentication_requirements) { |
| security_manager_.SetLocalIoCapability( |
| peer, io_capability, oob_data_present_flag, authentication_requirements); |
| |
| PairingType pairing_type = security_manager_.GetSimplePairingType(); |
| |
| if (pairing_type != PairingType::INVALID) { |
| ScheduleTask(kNoDelayMs, [this, peer, pairing_type]() { |
| AuthenticateRemoteStage1(peer, pairing_type); |
| }); |
| SendLinkLayerPacket(model::packets::IoCapabilityResponseBuilder::Create( |
| properties_.GetAddress(), peer, io_capability, oob_data_present_flag, |
| authentication_requirements)); |
| } else { |
| LOG_INFO("Requesting remote capability"); |
| |
| SendLinkLayerPacket(model::packets::IoCapabilityRequestBuilder::Create( |
| properties_.GetAddress(), peer, io_capability, oob_data_present_flag, |
| authentication_requirements)); |
| } |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::IoCapabilityRequestNegativeReply( |
| const Address& peer, ErrorCode reason) { |
| if (security_manager_.GetAuthenticationAddress() != peer) { |
| return ErrorCode::AUTHENTICATION_FAILURE; |
| } |
| |
| security_manager_.InvalidateIoCapabilities(); |
| |
| SendLinkLayerPacket( |
| model::packets::IoCapabilityNegativeResponseBuilder::Create( |
| properties_.GetAddress(), peer, static_cast<uint8_t>(reason))); |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| void LinkLayerController::SaveKeyAndAuthenticate(uint8_t key_type, |
| const Address& peer) { |
| std::array<uint8_t, 16> key_vec{'k', |
| 'e', |
| 'y', |
| ' ', |
| key_type, |
| 5, |
| 6, |
| 7, |
| 8, |
| 9, |
| 10, |
| 11, |
| 12, |
| 13, |
| static_cast<uint8_t>(key_id_ >> 8u), |
| static_cast<uint8_t>(key_id_)}; |
| key_id_ += 1; |
| security_manager_.WriteKey(peer, key_vec); |
| |
| security_manager_.AuthenticationRequestFinished(); |
| |
| if (key_type == 'L') { |
| // Legacy |
| ScheduleTask(kNoDelayMs, [this, peer, key_vec]() { |
| if (properties_.IsUnmasked(EventCode::LINK_KEY_NOTIFICATION)) { |
| send_event_(bluetooth::hci::LinkKeyNotificationBuilder::Create( |
| peer, key_vec, bluetooth::hci::KeyType::AUTHENTICATED_P192)); |
| } |
| }); |
| } else { |
| ScheduleTask(kNoDelayMs, [this, peer]() { |
| if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { |
| send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( |
| ErrorCode::SUCCESS, peer)); |
| } |
| }); |
| |
| ScheduleTask(kNoDelayMs, [this, peer, key_vec]() { |
| if (properties_.IsUnmasked(EventCode::LINK_KEY_NOTIFICATION)) { |
| send_event_(bluetooth::hci::LinkKeyNotificationBuilder::Create( |
| peer, key_vec, bluetooth::hci::KeyType::AUTHENTICATED_P256)); |
| } |
| }); |
| } |
| |
| ScheduleTask(kNoDelayMs, [this, peer]() { AuthenticateRemoteStage2(peer); }); |
| } |
| |
| ErrorCode LinkLayerController::PinCodeRequestReply(const Address& peer, |
| std::vector<uint8_t> pin) { |
| LOG_INFO("%s", properties_.GetAddress().ToString().c_str()); |
| auto current_peer = security_manager_.GetAuthenticationAddress(); |
| if (peer != current_peer) { |
| LOG_INFO("%s: %s != %s", properties_.GetAddress().ToString().c_str(), |
| peer.ToString().c_str(), current_peer.ToString().c_str()); |
| security_manager_.AuthenticationRequestFinished(); |
| ScheduleTask(kNoDelayMs, [this, current_peer]() { |
| if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { |
| send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( |
| ErrorCode::AUTHENTICATION_FAILURE, current_peer)); |
| } |
| }); |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| if (!security_manager_.GetPinRequested(peer)) { |
| LOG_INFO("No Pin Requested for %s", peer.ToString().c_str()); |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| security_manager_.SetLocalPin(peer, pin); |
| if (security_manager_.GetRemotePinResponseReceived(peer)) { |
| if (security_manager_.PinCompare()) { |
| LOG_INFO("Authenticating %s", peer.ToString().c_str()); |
| SaveKeyAndAuthenticate('L', peer); // Legacy |
| } else { |
| security_manager_.AuthenticationRequestFinished(); |
| ScheduleTask(kNoDelayMs, [this, peer]() { |
| if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { |
| send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( |
| ErrorCode::AUTHENTICATION_FAILURE, peer)); |
| } |
| }); |
| } |
| } else { |
| SendLinkLayerPacket(model::packets::PinRequestBuilder::Create( |
| properties_.GetAddress(), peer, pin)); |
| } |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::PinCodeRequestNegativeReply( |
| const Address& peer) { |
| auto current_peer = security_manager_.GetAuthenticationAddress(); |
| security_manager_.AuthenticationRequestFinished(); |
| ScheduleTask(kNoDelayMs, [this, current_peer]() { |
| if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { |
| send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( |
| ErrorCode::AUTHENTICATION_FAILURE, current_peer)); |
| } |
| }); |
| if (peer != current_peer) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| if (!security_manager_.GetPinRequested(peer)) { |
| LOG_INFO("No Pin Requested for %s", peer.ToString().c_str()); |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::UserConfirmationRequestReply( |
| const Address& peer) { |
| if (security_manager_.GetAuthenticationAddress() != peer) { |
| return ErrorCode::AUTHENTICATION_FAILURE; |
| } |
| SaveKeyAndAuthenticate('U', peer); |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::UserConfirmationRequestNegativeReply( |
| const Address& peer) { |
| auto current_peer = security_manager_.GetAuthenticationAddress(); |
| security_manager_.AuthenticationRequestFinished(); |
| ScheduleTask(kNoDelayMs, [this, current_peer]() { |
| if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { |
| send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( |
| ErrorCode::AUTHENTICATION_FAILURE, current_peer)); |
| } |
| }); |
| if (peer != current_peer) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::UserPasskeyRequestReply(const Address& peer, |
| uint32_t numeric_value) { |
| if (security_manager_.GetAuthenticationAddress() != peer) { |
| return ErrorCode::AUTHENTICATION_FAILURE; |
| } |
| SendLinkLayerPacket(model::packets::PasskeyBuilder::Create( |
| properties_.GetAddress(), peer, numeric_value)); |
| SaveKeyAndAuthenticate('P', peer); |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::UserPasskeyRequestNegativeReply( |
| const Address& peer) { |
| auto current_peer = security_manager_.GetAuthenticationAddress(); |
| security_manager_.AuthenticationRequestFinished(); |
| ScheduleTask(kNoDelayMs, [this, current_peer]() { |
| if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { |
| send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( |
| ErrorCode::AUTHENTICATION_FAILURE, current_peer)); |
| } |
| }); |
| if (peer != current_peer) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::RemoteOobDataRequestReply( |
| const Address& peer, const std::array<uint8_t, 16>& c, |
| const std::array<uint8_t, 16>& r) { |
| if (security_manager_.GetAuthenticationAddress() != peer) { |
| return ErrorCode::AUTHENTICATION_FAILURE; |
| } |
| LOG_INFO("TODO:Do something with the OOB data c=%d r=%d", c[0], r[0]); |
| SaveKeyAndAuthenticate('o', peer); |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::RemoteOobDataRequestNegativeReply( |
| const Address& peer) { |
| auto current_peer = security_manager_.GetAuthenticationAddress(); |
| security_manager_.AuthenticationRequestFinished(); |
| ScheduleTask(kNoDelayMs, [this, current_peer]() { |
| if (properties_.IsUnmasked(EventCode::SIMPLE_PAIRING_COMPLETE)) { |
| send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( |
| ErrorCode::AUTHENTICATION_FAILURE, current_peer)); |
| } |
| }); |
| if (peer != current_peer) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::RemoteOobExtendedDataRequestReply( |
| const Address& peer, const std::array<uint8_t, 16>& c192, |
| const std::array<uint8_t, 16>& r192, const std::array<uint8_t, 16>& c256, |
| const std::array<uint8_t, 16>& r256) { |
| if (security_manager_.GetAuthenticationAddress() != peer) { |
| return ErrorCode::AUTHENTICATION_FAILURE; |
| } |
| LOG_INFO( |
| "TODO:Do something with the OOB data c192=%d r192=%d c256=%d r256=%d", |
| c192[0], r192[0], c256[0], r256[0]); |
| SaveKeyAndAuthenticate('O', peer); |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::SendKeypressNotification( |
| const Address& peer, |
| bluetooth::hci::KeypressNotificationType notification_type) { |
| if (notification_type > |
| bluetooth::hci::KeypressNotificationType::ENTRY_COMPLETED) { |
| return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| |
| SendLinkLayerPacket(model::packets::KeypressNotificationBuilder::Create( |
| properties_.GetAddress(), peer, |
| static_cast<model::packets::PasskeyNotificationType>(notification_type))); |
| return ErrorCode::SUCCESS; |
| } |
| |
| void LinkLayerController::HandleAuthenticationRequest(const Address& address, |
| uint16_t handle) { |
| security_manager_.AuthenticationRequest(address, handle, true); |
| if (properties_.IsUnmasked(EventCode::LINK_KEY_REQUEST)) { |
| send_event_(bluetooth::hci::LinkKeyRequestBuilder::Create(address)); |
| } |
| } |
| |
| ErrorCode LinkLayerController::AuthenticationRequested(uint16_t handle) { |
| if (!connections_.HasHandle(handle)) { |
| LOG_INFO("Authentication Requested for unknown handle %04x", handle); |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| AddressWithType remote = connections_.GetAddress(handle); |
| |
| ScheduleTask(kNoDelayMs, [this, remote, handle]() { |
| HandleAuthenticationRequest(remote.GetAddress(), handle); |
| }); |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| void LinkLayerController::HandleSetConnectionEncryption( |
| const Address& peer, uint16_t handle, uint8_t encryption_enable) { |
| // TODO: Block ACL traffic or at least guard against it |
| |
| if (connections_.IsEncrypted(handle) && encryption_enable) { |
| if (properties_.IsUnmasked(EventCode::ENCRYPTION_CHANGE)) { |
| send_event_(bluetooth::hci::EncryptionChangeBuilder::Create( |
| ErrorCode::SUCCESS, handle, |
| static_cast<bluetooth::hci::EncryptionEnabled>(encryption_enable))); |
| } |
| return; |
| } |
| |
| uint16_t count = security_manager_.ReadKey(peer); |
| if (count == 0) { |
| LOG_ERROR("NO KEY HERE for %s", peer.ToString().c_str()); |
| return; |
| } |
| auto array = security_manager_.GetKey(peer); |
| std::vector<uint8_t> key_vec{array.begin(), array.end()}; |
| SendLinkLayerPacket(model::packets::EncryptConnectionBuilder::Create( |
| properties_.GetAddress(), peer, key_vec)); |
| } |
| |
| ErrorCode LinkLayerController::SetConnectionEncryption( |
| uint16_t handle, uint8_t encryption_enable) { |
| if (!connections_.HasHandle(handle)) { |
| LOG_INFO("Set Connection Encryption for unknown handle %04x", handle); |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| if (connections_.IsEncrypted(handle) && !encryption_enable) { |
| return ErrorCode::ENCRYPTION_MODE_NOT_ACCEPTABLE; |
| } |
| AddressWithType remote = connections_.GetAddress(handle); |
| |
| if (security_manager_.ReadKey(remote.GetAddress()) == 0) { |
| return ErrorCode::PIN_OR_KEY_MISSING; |
| } |
| |
| ScheduleTask(kNoDelayMs, [this, remote, handle, encryption_enable]() { |
| HandleSetConnectionEncryption(remote.GetAddress(), handle, |
| encryption_enable); |
| }); |
| return ErrorCode::SUCCESS; |
| } |
| #endif /* ROOTCANAL_LMP */ |
| |
| ErrorCode LinkLayerController::AcceptConnectionRequest(const Address& bd_addr, |
| bool try_role_switch) { |
| if (connections_.HasPendingConnection(bd_addr)) { |
| LOG_INFO("Accepting connection request from %s", |
| bd_addr.ToString().c_str()); |
| ScheduleTask(kNoDelayMs, [this, bd_addr, try_role_switch]() { |
| LOG_INFO("Accepted connection from %s", bd_addr.ToString().c_str()); |
| MakePeripheralConnection(bd_addr, try_role_switch); |
| }); |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| // The HCI command Accept Connection may be used to accept incoming SCO |
| // connection requests. |
| if (connections_.HasPendingScoConnection(bd_addr)) { |
| ErrorCode status = ErrorCode::SUCCESS; |
| uint16_t sco_handle = 0; |
| ScoLinkParameters link_parameters = {}; |
| ScoConnectionParameters connection_parameters = |
| connections_.GetScoConnectionParameters(bd_addr); |
| |
| if (!connections_.AcceptPendingScoConnection(bd_addr, |
| connection_parameters)) { |
| connections_.CancelPendingScoConnection(bd_addr); |
| status = ErrorCode::SCO_INTERVAL_REJECTED; // TODO: proper status code |
| } else { |
| sco_handle = connections_.GetScoHandle(bd_addr); |
| link_parameters = connections_.GetScoLinkParameters(bd_addr); |
| } |
| |
| // Send eSCO connection response to peer. |
| SendLinkLayerPacket(model::packets::ScoConnectionResponseBuilder::Create( |
| properties_.GetAddress(), bd_addr, (uint8_t)status, |
| link_parameters.transmission_interval, |
| link_parameters.retransmission_window, link_parameters.rx_packet_length, |
| link_parameters.tx_packet_length, link_parameters.air_mode, |
| link_parameters.extended)); |
| |
| // Schedule HCI Connection Complete event. |
| ScheduleTask(kNoDelayMs, [this, status, sco_handle, bd_addr]() { |
| send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( |
| ErrorCode(status), sco_handle, bd_addr, bluetooth::hci::LinkType::SCO, |
| bluetooth::hci::Enable::DISABLED)); |
| }); |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| LOG_INFO("No pending connection for %s", bd_addr.ToString().c_str()); |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| void LinkLayerController::MakePeripheralConnection(const Address& addr, |
| bool try_role_switch) { |
| LOG_INFO("Sending page response to %s", addr.ToString().c_str()); |
| SendLinkLayerPacket(model::packets::PageResponseBuilder::Create( |
| properties_.GetAddress(), addr, try_role_switch)); |
| |
| uint16_t handle = |
| connections_.CreateConnection(addr, properties_.GetAddress()); |
| if (handle == kReservedHandle) { |
| LOG_INFO("CreateConnection failed"); |
| return; |
| } |
| LOG_INFO("CreateConnection returned handle 0x%x", handle); |
| if (properties_.IsUnmasked(EventCode::CONNECTION_COMPLETE)) { |
| send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( |
| ErrorCode::SUCCESS, handle, addr, bluetooth::hci::LinkType::ACL, |
| bluetooth::hci::Enable::DISABLED)); |
| } |
| } |
| |
| ErrorCode LinkLayerController::RejectConnectionRequest(const Address& addr, |
| uint8_t reason) { |
| if (!connections_.HasPendingConnection(addr)) { |
| LOG_INFO("No pending connection for %s", addr.ToString().c_str()); |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| ScheduleTask(kNoDelayMs, [this, addr, reason]() { |
| RejectPeripheralConnection(addr, reason); |
| }); |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| void LinkLayerController::RejectPeripheralConnection(const Address& addr, |
| uint8_t reason) { |
| LOG_INFO("Sending page reject to %s (reason 0x%02hhx)", |
| addr.ToString().c_str(), reason); |
| SendLinkLayerPacket(model::packets::PageRejectBuilder::Create( |
| properties_.GetAddress(), addr, reason)); |
| |
| if (properties_.IsUnmasked(EventCode::CONNECTION_COMPLETE)) { |
| send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( |
| static_cast<ErrorCode>(reason), 0xeff, addr, |
| bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED)); |
| } |
| } |
| |
| ErrorCode LinkLayerController::CreateConnection(const Address& addr, uint16_t, |
| uint8_t, uint16_t, |
| uint8_t allow_role_switch) { |
| if (!connections_.CreatePendingConnection( |
| addr, properties_.GetAuthenticationEnable() == 1)) { |
| return ErrorCode::CONTROLLER_BUSY; |
| } |
| #ifdef ROOTCANAL_LMP |
| ASSERT(link_manager_add_link( |
| lm_.get(), reinterpret_cast<const uint8_t(*)[6]>(addr.data()))); |
| #endif |
| |
| SendLinkLayerPacket(model::packets::PageBuilder::Create( |
| properties_.GetAddress(), addr, properties_.GetClassOfDevice(), |
| allow_role_switch)); |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::CreateConnectionCancel(const Address& addr) { |
| if (!connections_.CancelPendingConnection(addr)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| return ErrorCode::SUCCESS; |
| } |
| |
| void LinkLayerController::SendDisconnectionCompleteEvent(uint16_t handle, |
| uint8_t reason) { |
| if (properties_.IsUnmasked(EventCode::DISCONNECTION_COMPLETE)) { |
| ScheduleTask(kNoDelayMs, [this, handle, reason]() { |
| send_event_(bluetooth::hci::DisconnectionCompleteBuilder::Create( |
| ErrorCode::SUCCESS, handle, ErrorCode(reason))); |
| }); |
| } |
| } |
| |
| ErrorCode LinkLayerController::Disconnect(uint16_t handle, uint8_t reason) { |
| if (connections_.HasScoHandle(handle)) { |
| const Address remote = connections_.GetScoAddress(handle); |
| LOG_INFO("Disconnecting eSCO connection with %s", |
| remote.ToString().c_str()); |
| |
| SendLinkLayerPacket(model::packets::ScoDisconnectBuilder::Create( |
| properties_.GetAddress(), remote, reason)); |
| |
| connections_.Disconnect(handle); |
| SendDisconnectionCompleteEvent(handle, reason); |
| return ErrorCode::SUCCESS; |
| } |
| |
| if (!connections_.HasHandle(handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| const AddressWithType remote = connections_.GetAddress(handle); |
| |
| if (connections_.GetPhyType(handle) == Phy::Type::BR_EDR) { |
| LOG_INFO("Disconnecting ACL connection with %s", remote.ToString().c_str()); |
| |
| uint16_t sco_handle = connections_.GetScoHandle(remote.GetAddress()); |
| if (sco_handle != kReservedHandle) { |
| SendLinkLayerPacket(model::packets::ScoDisconnectBuilder::Create( |
| properties_.GetAddress(), remote.GetAddress(), reason)); |
| |
| connections_.Disconnect(sco_handle); |
| SendDisconnectionCompleteEvent(sco_handle, reason); |
| } |
| |
| SendLinkLayerPacket(model::packets::DisconnectBuilder::Create( |
| properties_.GetAddress(), remote.GetAddress(), reason)); |
| |
| } else { |
| LOG_INFO("Disconnecting LE connection with %s", remote.ToString().c_str()); |
| |
| SendLeLinkLayerPacket(model::packets::DisconnectBuilder::Create( |
| connections_.GetOwnAddress(handle).GetAddress(), remote.GetAddress(), |
| reason)); |
| } |
| |
| connections_.Disconnect(handle); |
| SendDisconnectionCompleteEvent(handle, reason); |
| #ifdef ROOTCANAL_LMP |
| ASSERT(link_manager_remove_link( |
| lm_.get(), reinterpret_cast<uint8_t(*)[6]>(remote.GetAddress().data()))); |
| #endif |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::ChangeConnectionPacketType(uint16_t handle, |
| uint16_t types) { |
| if (!connections_.HasHandle(handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| ScheduleTask(kNoDelayMs, [this, handle, types]() { |
| if (properties_.IsUnmasked(EventCode::CONNECTION_PACKET_TYPE_CHANGED)) { |
| send_event_(bluetooth::hci::ConnectionPacketTypeChangedBuilder::Create( |
| ErrorCode::SUCCESS, handle, types)); |
| } |
| }); |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::ChangeConnectionLinkKey(uint16_t handle) { |
| if (!connections_.HasHandle(handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| // TODO: implement real logic |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| |
| ErrorCode LinkLayerController::CentralLinkKey(uint8_t /* key_flag */) { |
| // TODO: implement real logic |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| |
| ErrorCode LinkLayerController::HoldMode(uint16_t handle, |
| uint16_t hold_mode_max_interval, |
| uint16_t hold_mode_min_interval) { |
| if (!connections_.HasHandle(handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| if (hold_mode_max_interval < hold_mode_min_interval) { |
| return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| |
| // TODO: implement real logic |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| |
| ErrorCode LinkLayerController::SniffMode(uint16_t handle, |
| uint16_t sniff_max_interval, |
| uint16_t sniff_min_interval, |
| uint16_t sniff_attempt, |
| uint16_t sniff_timeout) { |
| if (!connections_.HasHandle(handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| if (sniff_max_interval < sniff_min_interval || sniff_attempt < 0x0001 || |
| sniff_attempt > 0x7FFF || sniff_timeout > 0x7FFF) { |
| return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| |
| // TODO: implement real logic |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| |
| ErrorCode LinkLayerController::ExitSniffMode(uint16_t handle) { |
| if (!connections_.HasHandle(handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| // TODO: implement real logic |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| |
| ErrorCode LinkLayerController::QosSetup(uint16_t handle, uint8_t service_type, |
| uint32_t /* token_rate */, |
| uint32_t /* peak_bandwidth */, |
| uint32_t /* latency */, |
| uint32_t /* delay_variation */) { |
| if (!connections_.HasHandle(handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| if (service_type > 0x02) { |
| return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| |
| // TODO: implement real logic |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| |
| ErrorCode LinkLayerController::RoleDiscovery(uint16_t handle) { |
| if (!connections_.HasHandle(handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| // TODO: Implement real logic |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::SwitchRole(Address /* bd_addr */, |
| uint8_t /* role */) { |
| // TODO: implement real logic |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| |
| ErrorCode LinkLayerController::WriteLinkPolicySettings(uint16_t handle, |
| uint16_t) { |
| if (!connections_.HasHandle(handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::WriteDefaultLinkPolicySettings( |
| uint16_t settings) { |
| if (settings > 7 /* Sniff + Hold + Role switch */) { |
| return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| default_link_policy_settings_ = settings; |
| return ErrorCode::SUCCESS; |
| } |
| |
| uint16_t LinkLayerController::ReadDefaultLinkPolicySettings() { |
| return default_link_policy_settings_; |
| } |
| |
| void LinkLayerController::ReadLocalOobData() { |
| std::array<uint8_t, 16> c_array( |
| {'c', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '0', '0', '0', '0', '0', '0', |
| static_cast<uint8_t>((oob_id_ % 0x10000) >> 8u), |
| static_cast<uint8_t>(oob_id_ % 0x100)}); |
| |
| std::array<uint8_t, 16> r_array( |
| {'r', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '0', '0', '0', '0', '0', '0', |
| static_cast<uint8_t>((oob_id_ % 0x10000) >> 8u), |
| static_cast<uint8_t>(oob_id_ % 0x100)}); |
| |
| send_event_(bluetooth::hci::ReadLocalOobDataCompleteBuilder::Create( |
| 1, ErrorCode::SUCCESS, c_array, r_array)); |
| oob_id_ += 1; |
| } |
| |
| void LinkLayerController::ReadLocalOobExtendedData() { |
| std::array<uint8_t, 16> c_192_array( |
| {'c', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '1', '9', '2', '0', '0', '0', |
| static_cast<uint8_t>((oob_id_ % 0x10000) >> 8u), |
| static_cast<uint8_t>(oob_id_ % 0x100)}); |
| |
| std::array<uint8_t, 16> r_192_array( |
| {'r', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '1', '9', '2', '0', '0', '0', |
| static_cast<uint8_t>((oob_id_ % 0x10000) >> 8u), |
| static_cast<uint8_t>(oob_id_ % 0x100)}); |
| |
| std::array<uint8_t, 16> c_256_array( |
| {'c', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '2', '5', '6', '0', '0', '0', |
| static_cast<uint8_t>((oob_id_ % 0x10000) >> 8u), |
| static_cast<uint8_t>(oob_id_ % 0x100)}); |
| |
| std::array<uint8_t, 16> r_256_array( |
| {'r', ' ', 'a', 'r', 'r', 'a', 'y', ' ', '2', '5', '6', '0', '0', '0', |
| static_cast<uint8_t>((oob_id_ % 0x10000) >> 8u), |
| static_cast<uint8_t>(oob_id_ % 0x100)}); |
| |
| send_event_(bluetooth::hci::ReadLocalOobExtendedDataCompleteBuilder::Create( |
| 1, ErrorCode::SUCCESS, c_192_array, r_192_array, c_256_array, |
| r_256_array)); |
| oob_id_ += 1; |
| } |
| |
| ErrorCode LinkLayerController::FlowSpecification( |
| uint16_t handle, uint8_t flow_direction, uint8_t service_type, |
| uint32_t /* token_rate */, uint32_t /* token_bucket_size */, |
| uint32_t /* peak_bandwidth */, uint32_t /* access_latency */) { |
| if (!connections_.HasHandle(handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| if (flow_direction > 0x01 || service_type > 0x02) { |
| return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| |
| // TODO: implement real logic |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| |
| ErrorCode LinkLayerController::WriteLinkSupervisionTimeout(uint16_t handle, |
| uint16_t) { |
| if (!connections_.HasHandle(handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::SetLeExtendedAddress(uint8_t set, |
| Address address) { |
| advertisers_[set].SetAddress(address); |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::SetLeExtendedAdvertisingData( |
| uint8_t set, const std::vector<uint8_t>& data) { |
| advertisers_[set].SetData(data); |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::SetLeExtendedScanResponseData( |
| uint8_t set, const std::vector<uint8_t>& data) { |
| advertisers_[set].SetScanResponse(data); |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::SetLeExtendedAdvertisingParameters( |
| uint8_t set, uint16_t interval_min, uint16_t interval_max, |
| bluetooth::hci::LegacyAdvertisingProperties type, |
| bluetooth::hci::OwnAddressType own_address_type, |
| bluetooth::hci::PeerAddressType peer_address_type, Address peer, |
| bluetooth::hci::AdvertisingFilterPolicy filter_policy, uint8_t tx_power) { |
| model::packets::AdvertisementType ad_type; |
| switch (type) { |
| case bluetooth::hci::LegacyAdvertisingProperties::ADV_IND: |
| ad_type = model::packets::AdvertisementType::ADV_IND; |
| peer = Address::kEmpty; |
| break; |
| case bluetooth::hci::LegacyAdvertisingProperties::ADV_NONCONN_IND: |
| ad_type = model::packets::AdvertisementType::ADV_NONCONN_IND; |
| peer = Address::kEmpty; |
| break; |
| case bluetooth::hci::LegacyAdvertisingProperties::ADV_SCAN_IND: |
| ad_type = model::packets::AdvertisementType::ADV_SCAN_IND; |
| peer = Address::kEmpty; |
| break; |
| case bluetooth::hci::LegacyAdvertisingProperties::ADV_DIRECT_IND_HIGH: |
| ad_type = model::packets::AdvertisementType::ADV_DIRECT_IND; |
| break; |
| case bluetooth::hci::LegacyAdvertisingProperties::ADV_DIRECT_IND_LOW: |
| ad_type = model::packets::AdvertisementType::SCAN_RESPONSE; |
| break; |
| } |
| auto interval_ms = |
| static_cast<int>((interval_max + interval_min) * 0.625 / 2); |
| |
| AddressWithType peer_address; |
| switch (peer_address_type) { |
| case bluetooth::hci::PeerAddressType::PUBLIC_DEVICE_OR_IDENTITY_ADDRESS: |
| peer_address = AddressWithType( |
| peer, bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS); |
| break; |
| case bluetooth::hci::PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS: |
| peer_address = AddressWithType( |
| peer, bluetooth::hci::AddressType::RANDOM_DEVICE_ADDRESS); |
| break; |
| } |
| |
| bluetooth::hci::AddressType own_address_address_type; |
| switch (own_address_type) { |
| case bluetooth::hci::OwnAddressType::RANDOM_DEVICE_ADDRESS: |
| own_address_address_type = |
| bluetooth::hci::AddressType::RANDOM_DEVICE_ADDRESS; |
| break; |
| case bluetooth::hci::OwnAddressType::PUBLIC_DEVICE_ADDRESS: |
| own_address_address_type = |
| bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS; |
| break; |
| case bluetooth::hci::OwnAddressType::RESOLVABLE_OR_PUBLIC_ADDRESS: |
| own_address_address_type = |
| bluetooth::hci::AddressType::PUBLIC_IDENTITY_ADDRESS; |
| break; |
| case bluetooth::hci::OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS: |
| own_address_address_type = |
| bluetooth::hci::AddressType::RANDOM_IDENTITY_ADDRESS; |
| break; |
| } |
| |
| bluetooth::hci::LeScanningFilterPolicy scanning_filter_policy; |
| switch (filter_policy) { |
| case bluetooth::hci::AdvertisingFilterPolicy::ALL_DEVICES: |
| scanning_filter_policy = |
| bluetooth::hci::LeScanningFilterPolicy::ACCEPT_ALL; |
| break; |
| case bluetooth::hci::AdvertisingFilterPolicy::LISTED_SCAN: |
| scanning_filter_policy = |
| bluetooth::hci::LeScanningFilterPolicy::FILTER_ACCEPT_LIST_ONLY; |
| break; |
| case bluetooth::hci::AdvertisingFilterPolicy::LISTED_CONNECT: |
| scanning_filter_policy = |
| bluetooth::hci::LeScanningFilterPolicy::CHECK_INITIATORS_IDENTITY; |
| break; |
| case bluetooth::hci::AdvertisingFilterPolicy::LISTED_SCAN_AND_CONNECT: |
| scanning_filter_policy = bluetooth::hci::LeScanningFilterPolicy:: |
| FILTER_ACCEPT_LIST_AND_INITIATORS_IDENTITY; |
| break; |
| } |
| |
| advertisers_[set].InitializeExtended( |
| set, own_address_address_type, peer_address, scanning_filter_policy, |
| ad_type, std::chrono::milliseconds(interval_ms), tx_power); |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeRemoveAdvertisingSet(uint8_t set) { |
| if (set >= advertisers_.size()) { |
| return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| advertisers_[set].Disable(); |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeClearAdvertisingSets() { |
| for (auto& advertiser : advertisers_) { |
| if (advertiser.IsEnabled()) { |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| } |
| for (auto& advertiser : advertisers_) { |
| advertiser.Clear(); |
| } |
| return ErrorCode::SUCCESS; |
| } |
| |
| void LinkLayerController::LeConnectionUpdateComplete( |
| uint16_t handle, uint16_t interval_min, uint16_t interval_max, |
| uint16_t latency, uint16_t supervision_timeout) { |
| ErrorCode status = ErrorCode::SUCCESS; |
| if (!connections_.HasHandle(handle)) { |
| status = ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| if (interval_min < 6 || interval_max > 0xC80 || interval_min > interval_max || |
| interval_max < interval_min || latency > 0x1F3 || |
| supervision_timeout < 0xA || supervision_timeout > 0xC80 || |
| // The Supervision_Timeout in milliseconds (*10) shall be larger than (1 + |
| // Connection_Latency) * Connection_Interval_Max (* 5/4) * 2 |
| supervision_timeout <= ((((1 + latency) * interval_max * 10) / 4) / 10)) { |
| status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| uint16_t interval = (interval_min + interval_max) / 2; |
| |
| SendLeLinkLayerPacket(LeConnectionParameterUpdateBuilder::Create( |
| connections_.GetOwnAddress(handle).GetAddress(), |
| connections_.GetAddress(handle).GetAddress(), |
| static_cast<uint8_t>(ErrorCode::SUCCESS), interval, latency, |
| supervision_timeout)); |
| |
| if (properties_.IsUnmasked(EventCode::LE_META_EVENT) && |
| properties_.GetLeEventSupported( |
| bluetooth::hci::SubeventCode::CONNECTION_UPDATE_COMPLETE)) { |
| send_event_(bluetooth::hci::LeConnectionUpdateCompleteBuilder::Create( |
| status, handle, interval, latency, supervision_timeout)); |
| } |
| } |
| |
| ErrorCode LinkLayerController::LeConnectionUpdate( |
| uint16_t handle, uint16_t interval_min, uint16_t interval_max, |
| uint16_t latency, uint16_t supervision_timeout) { |
| if (!connections_.HasHandle(handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| SendLeLinkLayerPacket(LeConnectionParameterRequestBuilder::Create( |
| connections_.GetOwnAddress(handle).GetAddress(), |
| connections_.GetAddress(handle).GetAddress(), interval_min, interval_max, |
| latency, supervision_timeout)); |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeRemoteConnectionParameterRequestReply( |
| uint16_t connection_handle, uint16_t interval_min, uint16_t interval_max, |
| uint16_t timeout, uint16_t latency, uint16_t minimum_ce_length, |
| uint16_t maximum_ce_length) { |
| if (!connections_.HasHandle(connection_handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| if ((interval_min > interval_max) || |
| (minimum_ce_length > maximum_ce_length)) { |
| return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| |
| ScheduleTask(kNoDelayMs, [this, connection_handle, interval_min, interval_max, |
| latency, timeout]() { |
| LeConnectionUpdateComplete(connection_handle, interval_min, interval_max, |
| latency, timeout); |
| }); |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeRemoteConnectionParameterRequestNegativeReply( |
| uint16_t connection_handle, bluetooth::hci::ErrorCode reason) { |
| if (!connections_.HasHandle(connection_handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| uint16_t interval = 0; |
| uint16_t latency = 0; |
| uint16_t timeout = 0; |
| SendLeLinkLayerPacket(LeConnectionParameterUpdateBuilder::Create( |
| connections_.GetOwnAddress(connection_handle).GetAddress(), |
| connections_.GetAddress(connection_handle).GetAddress(), |
| static_cast<uint8_t>(reason), interval, latency, timeout)); |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeFilterAcceptListClear() { |
| if (FilterAcceptListBusy()) { |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| |
| le_connect_list_.clear(); |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeSetAddressResolutionEnable(bool enable) { |
| if (ResolvingListBusy()) { |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| |
| le_resolving_list_enabled_ = enable; |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeResolvingListClear() { |
| if (ResolvingListBusy()) { |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| |
| le_resolving_list_.clear(); |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeFilterAcceptListAddDevice(Address addr, |
| uint8_t addr_type) { |
| if (FilterAcceptListBusy()) { |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| std::tuple<Address, uint8_t> new_tuple = std::make_tuple(addr, addr_type); |
| for (auto dev : le_connect_list_) { |
| if (dev == new_tuple) { |
| return ErrorCode::SUCCESS; |
| } |
| } |
| if (LeFilterAcceptListFull()) { |
| return ErrorCode::MEMORY_CAPACITY_EXCEEDED; |
| } |
| le_connect_list_.emplace_back(new_tuple); |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeResolvingListAddDevice( |
| Address addr, uint8_t addr_type, std::array<uint8_t, kIrkSize> peerIrk, |
| std::array<uint8_t, kIrkSize> localIrk) { |
| if (ResolvingListBusy()) { |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| if (LeResolvingListFull()) { |
| return ErrorCode::MEMORY_CAPACITY_EXCEEDED; |
| } |
| le_resolving_list_.emplace_back( |
| ResolvingListEntry{addr, addr_type, peerIrk, localIrk}); |
| return ErrorCode::SUCCESS; |
| } |
| |
| bool LinkLayerController::HasAclConnection() { |
| return (connections_.GetAclHandles().size() > 0); |
| } |
| |
| void LinkLayerController::LeSetPrivacyMode(uint8_t address_type, Address addr, |
| uint8_t mode) { |
| // set mode for addr |
| LOG_INFO("address type = %d ", address_type); |
| LOG_INFO("address = %s ", addr.ToString().c_str()); |
| LOG_INFO("mode = %d ", mode); |
| } |
| |
| void LinkLayerController::LeReadIsoTxSync(uint16_t /* handle */) {} |
| |
| void LinkLayerController::LeSetCigParameters( |
| uint8_t cig_id, uint32_t sdu_interval_m_to_s, uint32_t sdu_interval_s_to_m, |
| bluetooth::hci::ClockAccuracy clock_accuracy, |
| bluetooth::hci::Packing packing, bluetooth::hci::Enable framing, |
| uint16_t max_transport_latency_m_to_s, |
| uint16_t max_transport_latency_s_to_m, |
| std::vector<bluetooth::hci::CisParametersConfig> cis_config) { |
| if (properties_.IsUnmasked(EventCode::LE_META_EVENT)) { |
| send_event_(connections_.SetCigParameters( |
| cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, clock_accuracy, |
| packing, framing, max_transport_latency_m_to_s, |
| max_transport_latency_s_to_m, cis_config)); |
| } |
| } |
| |
| ErrorCode LinkLayerController::LeCreateCis( |
| std::vector<bluetooth::hci::CreateCisConfig> cis_config) { |
| if (connections_.HasPendingCis()) { |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| for (auto& config : cis_config) { |
| if (!connections_.HasHandle(config.acl_connection_handle_)) { |
| LOG_INFO("Unknown ACL handle %04x", config.acl_connection_handle_); |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| if (!connections_.HasCisHandle(config.cis_connection_handle_)) { |
| LOG_INFO("Unknown CIS handle %04x", config.cis_connection_handle_); |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| } |
| for (auto& config : cis_config) { |
| connections_.CreatePendingCis(config); |
| auto own_address = |
| connections_.GetOwnAddress(config.acl_connection_handle_); |
| auto peer_address = connections_.GetAddress(config.acl_connection_handle_); |
| StreamParameters stream_parameters = |
| connections_.GetStreamParameters(config.cis_connection_handle_); |
| GroupParameters group_parameters = |
| connections_.GetGroupParameters(stream_parameters.group_id); |
| |
| SendLeLinkLayerPacket(model::packets::IsoConnectionRequestBuilder::Create( |
| own_address.GetAddress(), peer_address.GetAddress(), |
| stream_parameters.group_id, group_parameters.sdu_interval_m_to_s, |
| group_parameters.sdu_interval_s_to_m, group_parameters.interleaved, |
| group_parameters.framed, group_parameters.max_transport_latency_m_to_s, |
| group_parameters.max_transport_latency_s_to_m, |
| stream_parameters.stream_id, stream_parameters.max_sdu_m_to_s, |
| stream_parameters.max_sdu_s_to_m, config.cis_connection_handle_, |
| config.acl_connection_handle_)); |
| } |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeRemoveCig(uint8_t cig_id) { |
| return connections_.RemoveCig(cig_id); |
| } |
| |
| ErrorCode LinkLayerController::LeAcceptCisRequest(uint16_t cis_handle) { |
| if (!connections_.HasPendingCisConnection(cis_handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| auto acl_handle = connections_.GetPendingAclHandle(cis_handle); |
| |
| connections_.ConnectCis(cis_handle); |
| |
| SendLeLinkLayerPacket(model::packets::IsoConnectionResponseBuilder::Create( |
| connections_.GetOwnAddress(acl_handle).GetAddress(), |
| connections_.GetAddress(acl_handle).GetAddress(), |
| static_cast<uint8_t>(ErrorCode::SUCCESS), cis_handle, acl_handle, |
| connections_.GetRemoteCisHandleForCisHandle(cis_handle))); |
| |
| // Both sides have to send LeCisEstablished event |
| |
| uint32_t cig_sync_delay = 0x100; |
| uint32_t cis_sync_delay = 0x200; |
| uint32_t latency_m_to_s = 0x200; |
| uint32_t latency_s_to_m = 0x200; |
| uint8_t nse = 1; |
| uint8_t bn_m_to_s = 0; |
| uint8_t bn_s_to_m = 0; |
| uint8_t ft_m_to_s = 0; |
| uint8_t ft_s_to_m = 0; |
| uint8_t max_pdu_m_to_s = 0x40; |
| uint8_t max_pdu_s_to_m = 0x40; |
| uint16_t iso_interval = 0x100; |
| if (properties_.IsUnmasked(EventCode::LE_META_EVENT)) { |
| send_event_(bluetooth::hci::LeCisEstablishedBuilder::Create( |
| ErrorCode::SUCCESS, cis_handle, cig_sync_delay, cis_sync_delay, |
| latency_m_to_s, latency_s_to_m, |
| bluetooth::hci::SecondaryPhyType::NO_PACKETS, |
| bluetooth::hci::SecondaryPhyType::NO_PACKETS, nse, bn_m_to_s, bn_s_to_m, |
| ft_m_to_s, ft_s_to_m, max_pdu_m_to_s, max_pdu_s_to_m, iso_interval)); |
| } |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeRejectCisRequest(uint16_t cis_handle, |
| ErrorCode reason) { |
| if (!connections_.HasPendingCisConnection(cis_handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| auto acl_handle = connections_.GetPendingAclHandle(cis_handle); |
| |
| SendLeLinkLayerPacket(model::packets::IsoConnectionResponseBuilder::Create( |
| connections_.GetOwnAddress(acl_handle).GetAddress(), |
| connections_.GetAddress(acl_handle).GetAddress(), |
| static_cast<uint8_t>(reason), acl_handle, cis_handle, kReservedHandle)); |
| connections_.RejectCis(cis_handle); |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeCreateBig( |
| uint8_t /* big_handle */, uint8_t /* advertising_handle */, |
| uint8_t /* num_bis */, uint32_t /* sdu_interval */, uint16_t /* max_sdu */, |
| uint16_t /* max_transport_latency */, uint8_t /* rtn */, |
| bluetooth::hci::SecondaryPhyType /* phy */, |
| bluetooth::hci::Packing /* packing */, bluetooth::hci::Enable /* framing */, |
| bluetooth::hci::Enable /* encryption */, |
| std::vector<uint16_t> /* broadcast_code */) { |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeTerminateBig(uint8_t /* big_handle */, |
| ErrorCode /* reason */) { |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeBigCreateSync( |
| uint8_t /* big_handle */, uint16_t /* sync_handle */, |
| bluetooth::hci::Enable /* encryption */, |
| std::vector<uint16_t> /* broadcast_code */, uint8_t /* mse */, |
| uint16_t /* big_sync_timeout */, std::vector<uint8_t> /* bis */) { |
| return ErrorCode::SUCCESS; |
| } |
| |
| void LinkLayerController::LeBigTerminateSync(uint8_t /* big_handle */) {} |
| |
| ErrorCode LinkLayerController::LeRequestPeerSca(uint16_t /* request_handle */) { |
| return ErrorCode::SUCCESS; |
| } |
| |
| void LinkLayerController::LeSetupIsoDataPath( |
| uint16_t /* connection_handle */, |
| bluetooth::hci::DataPathDirection /* data_path_direction */, |
| uint8_t /* data_path_id */, uint64_t /* codec_id */, |
| uint32_t /* controller_Delay */, |
| std::vector<uint8_t> /* codec_configuration */) {} |
| |
| void LinkLayerController::LeRemoveIsoDataPath( |
| uint16_t /* connection_handle */, |
| bluetooth::hci::RemoveDataPathDirection /* remove_data_path_direction */) {} |
| |
| void LinkLayerController::HandleLeEnableEncryption( |
| uint16_t handle, std::array<uint8_t, 8> rand, uint16_t ediv, |
| std::array<uint8_t, 16> ltk) { |
| // TODO: Check keys |
| // TODO: Block ACL traffic or at least guard against it |
| if (!connections_.HasHandle(handle)) { |
| return; |
| } |
| SendLeLinkLayerPacket(model::packets::LeEncryptConnectionBuilder::Create( |
| connections_.GetOwnAddress(handle).GetAddress(), |
| connections_.GetAddress(handle).GetAddress(), rand, ediv, ltk)); |
| } |
| |
| ErrorCode LinkLayerController::LeEnableEncryption(uint16_t handle, |
| std::array<uint8_t, 8> rand, |
| uint16_t ediv, |
| std::array<uint8_t, 16> ltk) { |
| if (!connections_.HasHandle(handle)) { |
| LOG_INFO("Unknown handle %04x", handle); |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| ScheduleTask(kNoDelayMs, [this, handle, rand, ediv, ltk]() { |
| HandleLeEnableEncryption(handle, rand, ediv, ltk); |
| }); |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeLongTermKeyRequestReply( |
| uint16_t handle, std::array<uint8_t, 16> ltk) { |
| if (!connections_.HasHandle(handle)) { |
| LOG_INFO("Unknown handle %04x", handle); |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| // TODO: Check keys |
| if (connections_.IsEncrypted(handle)) { |
| if (properties_.IsUnmasked(EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE)) { |
| send_event_(bluetooth::hci::EncryptionKeyRefreshCompleteBuilder::Create( |
| ErrorCode::SUCCESS, handle)); |
| } |
| } else { |
| connections_.Encrypt(handle); |
| if (properties_.IsUnmasked(EventCode::ENCRYPTION_CHANGE)) { |
| send_event_(bluetooth::hci::EncryptionChangeBuilder::Create( |
| ErrorCode::SUCCESS, handle, bluetooth::hci::EncryptionEnabled::ON)); |
| } |
| } |
| SendLeLinkLayerPacket( |
| model::packets::LeEncryptConnectionResponseBuilder::Create( |
| connections_.GetOwnAddress(handle).GetAddress(), |
| connections_.GetAddress(handle).GetAddress(), |
| std::array<uint8_t, 8>(), uint16_t(), ltk)); |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeLongTermKeyRequestNegativeReply( |
| uint16_t handle) { |
| if (!connections_.HasHandle(handle)) { |
| LOG_INFO("Unknown handle %04x", handle); |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| SendLeLinkLayerPacket( |
| model::packets::LeEncryptConnectionResponseBuilder::Create( |
| connections_.GetOwnAddress(handle).GetAddress(), |
| connections_.GetAddress(handle).GetAddress(), |
| std::array<uint8_t, 8>(), uint16_t(), std::array<uint8_t, 16>())); |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::SetLeAdvertisingEnable( |
| uint8_t le_advertising_enable) { |
| if (!le_advertising_enable) { |
| advertisers_[0].Disable(); |
| return ErrorCode::SUCCESS; |
| } |
| auto interval_ms = (properties_.GetLeAdvertisingIntervalMax() + |
| properties_.GetLeAdvertisingIntervalMin()) * |
| 0.625 / 2; |
| |
| Address own_address = properties_.GetAddress(); |
| if (properties_.GetLeAdvertisingOwnAddressType() == |
| static_cast<uint8_t>( |
| bluetooth::hci::AddressType::RANDOM_DEVICE_ADDRESS) || |
| properties_.GetLeAdvertisingOwnAddressType() == |
| static_cast<uint8_t>( |
| bluetooth::hci::AddressType::RANDOM_IDENTITY_ADDRESS)) { |
| if (properties_.GetLeAddress().ToString() == "bb:bb:bb:ba:d0:1e" || |
| properties_.GetLeAddress() == Address::kEmpty) { |
| return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| own_address = properties_.GetLeAddress(); |
| } |
| auto own_address_with_type = AddressWithType( |
| own_address, static_cast<bluetooth::hci::AddressType>( |
| properties_.GetLeAdvertisingOwnAddressType())); |
| |
| auto interval = std::chrono::milliseconds(static_cast<uint64_t>(interval_ms)); |
| if (interval < std::chrono::milliseconds(20)) { |
| return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| advertisers_[0].Initialize( |
| own_address_with_type, |
| bluetooth::hci::AddressWithType( |
| properties_.GetLeAdvertisingPeerAddress(), |
| static_cast<bluetooth::hci::AddressType>( |
| properties_.GetLeAdvertisingPeerAddressType())), |
| static_cast<bluetooth::hci::LeScanningFilterPolicy>( |
| properties_.GetLeAdvertisingFilterPolicy()), |
| static_cast<model::packets::AdvertisementType>( |
| properties_.GetLeAdvertisementType()), |
| properties_.GetLeAdvertisement(), properties_.GetLeScanResponse(), |
| interval); |
| advertisers_[0].Enable(); |
| return ErrorCode::SUCCESS; |
| } |
| |
| void LinkLayerController::LeDisableAdvertisingSets() { |
| for (auto& advertiser : advertisers_) { |
| advertiser.Disable(); |
| } |
| } |
| |
| uint8_t LinkLayerController::LeReadNumberOfSupportedAdvertisingSets() { |
| return advertisers_.size(); |
| } |
| |
| ErrorCode LinkLayerController::SetLeExtendedAdvertisingEnable( |
| bluetooth::hci::Enable enable, |
| const std::vector<bluetooth::hci::EnabledSet>& enabled_sets) { |
| for (const auto& set : enabled_sets) { |
| if (set.advertising_handle_ > advertisers_.size()) { |
| return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| } |
| for (const auto& set : enabled_sets) { |
| auto handle = set.advertising_handle_; |
| if (enable == bluetooth::hci::Enable::ENABLED) { |
| advertisers_[handle].EnableExtended(10ms * set.duration_); |
| } else { |
| advertisers_[handle].Disable(); |
| } |
| } |
| return ErrorCode::SUCCESS; |
| } |
| |
| bool LinkLayerController::ListBusy(uint16_t ignore) { |
| if (le_connect_) { |
| LOG_INFO("le_connect_"); |
| if (!(ignore & DeviceProperties::kLeListIgnoreConnections)) { |
| return true; |
| } |
| } |
| if (le_scan_enable_ != bluetooth::hci::OpCode::NONE) { |
| LOG_INFO("le_scan_enable"); |
| if (!(ignore & DeviceProperties::kLeListIgnoreScanEnable)) { |
| return true; |
| } |
| } |
| for (auto advertiser : advertisers_) { |
| if (advertiser.IsEnabled()) { |
| LOG_INFO("Advertising"); |
| if (!(ignore & DeviceProperties::kLeListIgnoreAdvertising)) { |
| return true; |
| } |
| } |
| } |
| // TODO: Add HCI_LE_Periodic_Advertising_Create_Sync |
| return false; |
| } |
| |
| bool LinkLayerController::FilterAcceptListBusy() { |
| return ListBusy(properties_.GetLeFilterAcceptListIgnoreReasons()); |
| } |
| |
| bool LinkLayerController::ResolvingListBusy() { |
| return ListBusy(properties_.GetLeResolvingListIgnoreReasons()); |
| } |
| |
| ErrorCode LinkLayerController::LeFilterAcceptListRemoveDevice( |
| Address addr, uint8_t addr_type) { |
| if (FilterAcceptListBusy()) { |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| std::tuple<Address, uint8_t> erase_tuple = std::make_tuple(addr, addr_type); |
| for (size_t i = 0; i < le_connect_list_.size(); i++) { |
| if (le_connect_list_[i] == erase_tuple) { |
| le_connect_list_.erase(le_connect_list_.begin() + i); |
| } |
| } |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::LeResolvingListRemoveDevice(Address addr, |
| uint8_t addr_type) { |
| if (ResolvingListBusy()) { |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| for (size_t i = 0; i < le_connect_list_.size(); i++) { |
| auto curr = le_connect_list_[i]; |
| if (std::get<0>(curr) == addr && std::get<1>(curr) == addr_type) { |
| le_resolving_list_.erase(le_resolving_list_.begin() + i); |
| } |
| } |
| return ErrorCode::SUCCESS; |
| } |
| |
| bool LinkLayerController::LeFilterAcceptListContainsDevice(Address addr, |
| uint8_t addr_type) { |
| std::tuple<Address, uint8_t> sought_tuple = std::make_tuple(addr, addr_type); |
| for (size_t i = 0; i < le_connect_list_.size(); i++) { |
| if (le_connect_list_[i] == sought_tuple) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool LinkLayerController::LeResolvingListContainsDevice(Address addr, |
| uint8_t addr_type) { |
| for (size_t i = 0; i < le_connect_list_.size(); i++) { |
| auto curr = le_connect_list_[i]; |
| if (std::get<0>(curr) == addr && std::get<1>(curr) == addr_type) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool LinkLayerController::LeFilterAcceptListFull() { |
| return le_connect_list_.size() >= properties_.GetLeFilterAcceptListSize(); |
| } |
| |
| bool LinkLayerController::LeResolvingListFull() { |
| return le_resolving_list_.size() >= properties_.GetLeResolvingListSize(); |
| } |
| |
| void LinkLayerController::Reset() { |
| connections_ = AclConnectionHandler(); |
| le_connect_list_.clear(); |
| le_resolving_list_.clear(); |
| le_resolving_list_enabled_ = false; |
| le_connecting_rpa_ = Address(); |
| LeDisableAdvertisingSets(); |
| le_scan_enable_ = bluetooth::hci::OpCode::NONE; |
| le_connect_ = false; |
| le_extended_connect_ = false; |
| le_pending_connect_ = false; |
| if (inquiry_timer_task_id_ != kInvalidTaskId) { |
| CancelScheduledTask(inquiry_timer_task_id_); |
| inquiry_timer_task_id_ = kInvalidTaskId; |
| } |
| last_inquiry_ = steady_clock::now(); |
| page_scans_enabled_ = false; |
| inquiry_scans_enabled_ = false; |
| } |
| |
| void LinkLayerController::StartInquiry(milliseconds timeout) { |
| inquiry_timer_task_id_ = ScheduleTask(milliseconds(timeout), [this]() { |
| LinkLayerController::InquiryTimeout(); |
| }); |
| } |
| |
| void LinkLayerController::InquiryCancel() { |
| ASSERT(inquiry_timer_task_id_ != kInvalidTaskId); |
| CancelScheduledTask(inquiry_timer_task_id_); |
| inquiry_timer_task_id_ = kInvalidTaskId; |
| } |
| |
| void LinkLayerController::InquiryTimeout() { |
| if (inquiry_timer_task_id_ != kInvalidTaskId) { |
| inquiry_timer_task_id_ = kInvalidTaskId; |
| if (properties_.IsUnmasked(EventCode::INQUIRY_COMPLETE)) { |
| send_event_( |
| bluetooth::hci::InquiryCompleteBuilder::Create(ErrorCode::SUCCESS)); |
| } |
| } |
| } |
| |
| void LinkLayerController::SetInquiryMode(uint8_t mode) { |
| inquiry_mode_ = static_cast<model::packets::InquiryType>(mode); |
| } |
| |
| void LinkLayerController::SetInquiryLAP(uint64_t lap) { inquiry_lap_ = lap; } |
| |
| void LinkLayerController::SetInquiryMaxResponses(uint8_t max) { |
| inquiry_max_responses_ = max; |
| } |
| |
| void LinkLayerController::Inquiry() { |
| steady_clock::time_point now = steady_clock::now(); |
| if (duration_cast<milliseconds>(now - last_inquiry_) < milliseconds(2000)) { |
| return; |
| } |
| |
| SendLinkLayerPacket(model::packets::InquiryBuilder::Create( |
| properties_.GetAddress(), Address::kEmpty, inquiry_mode_)); |
| last_inquiry_ = now; |
| } |
| |
| void LinkLayerController::SetInquiryScanEnable(bool enable) { |
| inquiry_scans_enabled_ = enable; |
| } |
| |
| void LinkLayerController::SetPageScanEnable(bool enable) { |
| page_scans_enabled_ = enable; |
| } |
| |
| ErrorCode LinkLayerController::AddScoConnection(uint16_t connection_handle, |
| uint16_t packet_type) { |
| if (!connections_.HasHandle(connection_handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| Address bd_addr = connections_.GetAddress(connection_handle).GetAddress(); |
| if (connections_.HasPendingScoConnection(bd_addr)) { |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| |
| LOG_INFO("Creating SCO connection with %s", bd_addr.ToString().c_str()); |
| |
| // Save connection parameters. |
| ScoConnectionParameters connection_parameters = { |
| 8000, |
| 8000, |
| 0xffff, |
| 0x60 /* 16bit CVSD */, |
| (uint8_t)bluetooth::hci::RetransmissionEffort::NO_RETRANSMISSION, |
| (uint16_t)((uint16_t)((packet_type >> 5) & 0x7u) | |
| (uint16_t)bluetooth::hci::SynchronousPacketTypeBits:: |
| NO_2_EV3_ALLOWED | |
| (uint16_t)bluetooth::hci::SynchronousPacketTypeBits:: |
| NO_3_EV3_ALLOWED | |
| (uint16_t)bluetooth::hci::SynchronousPacketTypeBits:: |
| NO_2_EV5_ALLOWED | |
| (uint16_t)bluetooth::hci::SynchronousPacketTypeBits:: |
| NO_3_EV5_ALLOWED)}; |
| connections_.CreateScoConnection( |
| connections_.GetAddress(connection_handle).GetAddress(), |
| connection_parameters, SCO_STATE_PENDING, true); |
| |
| // Send SCO connection request to peer. |
| SendLinkLayerPacket(model::packets::ScoConnectionRequestBuilder::Create( |
| properties_.GetAddress(), bd_addr, |
| connection_parameters.transmit_bandwidth, |
| connection_parameters.receive_bandwidth, |
| connection_parameters.max_latency, connection_parameters.voice_setting, |
| connection_parameters.retransmission_effort, |
| connection_parameters.packet_type)); |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::SetupSynchronousConnection( |
| uint16_t connection_handle, uint32_t transmit_bandwidth, |
| uint32_t receive_bandwidth, uint16_t max_latency, uint16_t voice_setting, |
| uint8_t retransmission_effort, uint16_t packet_types) { |
| if (!connections_.HasHandle(connection_handle)) { |
| return ErrorCode::UNKNOWN_CONNECTION; |
| } |
| |
| Address bd_addr = connections_.GetAddress(connection_handle).GetAddress(); |
| if (connections_.HasPendingScoConnection(bd_addr)) { |
| // This command may be used to modify an exising eSCO link. |
| // Skip for now. TODO: should return an event |
| // HCI_Synchronous_Connection_Changed on both sides. |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| |
| LOG_INFO("Creating eSCO connection with %s", bd_addr.ToString().c_str()); |
| |
| // Save connection parameters. |
| ScoConnectionParameters connection_parameters = { |
| transmit_bandwidth, receive_bandwidth, max_latency, |
| voice_setting, retransmission_effort, packet_types}; |
| connections_.CreateScoConnection( |
| connections_.GetAddress(connection_handle).GetAddress(), |
| connection_parameters, SCO_STATE_PENDING); |
| |
| // Send eSCO connection request to peer. |
| SendLinkLayerPacket(model::packets::ScoConnectionRequestBuilder::Create( |
| properties_.GetAddress(), bd_addr, transmit_bandwidth, receive_bandwidth, |
| max_latency, voice_setting, retransmission_effort, packet_types)); |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::AcceptSynchronousConnection( |
| Address bd_addr, uint32_t transmit_bandwidth, uint32_t receive_bandwidth, |
| uint16_t max_latency, uint16_t voice_setting, uint8_t retransmission_effort, |
| uint16_t packet_types) { |
| LOG_INFO("Accepting eSCO connection request from %s", |
| bd_addr.ToString().c_str()); |
| |
| if (!connections_.HasPendingScoConnection(bd_addr)) { |
| LOG_INFO("No pending eSCO connection for %s", bd_addr.ToString().c_str()); |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| |
| ErrorCode status = ErrorCode::SUCCESS; |
| uint16_t sco_handle = 0; |
| ScoLinkParameters link_parameters = {}; |
| ScoConnectionParameters connection_parameters = { |
| transmit_bandwidth, receive_bandwidth, max_latency, |
| voice_setting, retransmission_effort, packet_types}; |
| |
| if (!connections_.AcceptPendingScoConnection(bd_addr, |
| connection_parameters)) { |
| connections_.CancelPendingScoConnection(bd_addr); |
| status = ErrorCode::STATUS_UNKNOWN; // TODO: proper status code |
| } else { |
| sco_handle = connections_.GetScoHandle(bd_addr); |
| link_parameters = connections_.GetScoLinkParameters(bd_addr); |
| } |
| |
| // Send eSCO connection response to peer. |
| SendLinkLayerPacket(model::packets::ScoConnectionResponseBuilder::Create( |
| properties_.GetAddress(), bd_addr, (uint8_t)status, |
| link_parameters.transmission_interval, |
| link_parameters.retransmission_window, link_parameters.rx_packet_length, |
| link_parameters.tx_packet_length, link_parameters.air_mode, |
| link_parameters.extended)); |
| |
| // Schedule HCI Synchronous Connection Complete event. |
| ScheduleTask(kNoDelayMs, [this, status, sco_handle, bd_addr, |
| link_parameters]() { |
| send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create( |
| ErrorCode(status), sco_handle, bd_addr, |
| link_parameters.extended ? bluetooth::hci::ScoLinkType::ESCO |
| : bluetooth::hci::ScoLinkType::SCO, |
| link_parameters.extended ? link_parameters.transmission_interval : 0, |
| link_parameters.extended ? link_parameters.retransmission_window : 0, |
| link_parameters.extended ? link_parameters.rx_packet_length : 0, |
| link_parameters.extended ? link_parameters.tx_packet_length : 0, |
| bluetooth::hci::ScoAirMode(link_parameters.air_mode))); |
| }); |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| ErrorCode LinkLayerController::RejectSynchronousConnection(Address bd_addr, |
| uint16_t reason) { |
| LOG_INFO("Rejecting eSCO connection request from %s", |
| bd_addr.ToString().c_str()); |
| |
| if (reason == (uint8_t)ErrorCode::SUCCESS) { |
| reason = (uint8_t)ErrorCode::REMOTE_USER_TERMINATED_CONNECTION; |
| } |
| if (!connections_.HasPendingScoConnection(bd_addr)) { |
| return ErrorCode::COMMAND_DISALLOWED; |
| } |
| |
| connections_.CancelPendingScoConnection(bd_addr); |
| |
| // Send eSCO connection response to peer. |
| SendLinkLayerPacket(model::packets::ScoConnectionResponseBuilder::Create( |
| properties_.GetAddress(), bd_addr, reason, 0, 0, 0, 0, 0, 0)); |
| |
| // Schedule HCI Synchronous Connection Complete event. |
| ScheduleTask(kNoDelayMs, [this, reason, bd_addr]() { |
| send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create( |
| ErrorCode(reason), 0, bd_addr, bluetooth::hci::ScoLinkType::ESCO, 0, 0, |
| 0, 0, bluetooth::hci::ScoAirMode::TRANSPARENT)); |
| }); |
| |
| return ErrorCode::SUCCESS; |
| } |
| |
| } // namespace rootcanal |