@@ -5065,32 +5065,39 @@ void LinkLayerController::IncomingPageResponsePacket(
50655065 WARNING (id_, " No free handles" );
50665066 return ;
50675067 }
5068+
50685069 CancelScheduledTask (page_timeout_task_id_);
50695070 ASSERT (link_manager_add_link (
50705071 lm_.get (), reinterpret_cast <const uint8_t (*)[6 ]>(peer.data ())));
50715072
50725073 CheckExpiringConnection (handle);
50735074
5074- auto addr = incoming.GetSourceAddress ();
5075+ AclConnection& connection = connections_.GetAclConnection (handle);
5076+ auto bd_addr = incoming.GetSourceAddress ();
50755077 auto response = model::packets::PageResponseView::Create (incoming);
50765078 ASSERT (response.IsValid ());
5077- /* Role change event before connection complete is a quirk commonly exists in
5078- * Android-capatable Bluetooth controllers.
5079- * On the initiator side, only connection in peripheral role should be
5080- * accompanied with a role change event */
5081- // TODO(b/274476773): Add a config option for this quirk
5082- if (connections_.IsRoleSwitchAllowedForPendingConnection () &&
5083- response.GetTryRoleSwitch ()) {
5084- auto role = bluetooth::hci::Role::PERIPHERAL;
5085- connections_.SetAclRole (handle, role);
5086- if (IsEventUnmasked (EventCode::ROLE_CHANGE)) {
5087- send_event_ (bluetooth::hci::RoleChangeBuilder::Create (ErrorCode::SUCCESS,
5088- addr, role));
5089- }
5079+
5080+ bluetooth::hci::Role role =
5081+ connections_.IsRoleSwitchAllowedForPendingConnection () &&
5082+ response.GetTryRoleSwitch ()
5083+ ? bluetooth::hci::Role::PERIPHERAL
5084+ : bluetooth::hci::Role::CENTRAL;
5085+
5086+ connection.SetLinkPolicySettings (default_link_policy_settings_);
5087+ connection.SetRole (role);
5088+
5089+ // Role change event before connection complete generates an HCI Role Change
5090+ // event on the initiator side if accepted; the event is sent before the
5091+ // HCI Connection Complete event.
5092+ if (role == bluetooth::hci::Role::PERIPHERAL &&
5093+ IsEventUnmasked (EventCode::ROLE_CHANGE)) {
5094+ send_event_ (bluetooth::hci::RoleChangeBuilder::Create (ErrorCode::SUCCESS,
5095+ bd_addr, role));
50905096 }
5097+
50915098 if (IsEventUnmasked (EventCode::CONNECTION_COMPLETE)) {
50925099 send_event_ (bluetooth::hci::ConnectionCompleteBuilder::Create (
5093- ErrorCode::SUCCESS, handle, addr , bluetooth::hci::LinkType::ACL,
5100+ ErrorCode::SUCCESS, handle, bd_addr , bluetooth::hci::LinkType::ACL,
50945101 bluetooth::hci::Enable::DISABLED));
50955102 }
50965103}
@@ -5223,42 +5230,49 @@ ErrorCode LinkLayerController::AcceptConnectionRequest(const Address& bd_addr,
52235230 return ErrorCode::UNKNOWN_CONNECTION;
52245231}
52255232
5226- void LinkLayerController::MakePeripheralConnection (const Address& addr ,
5233+ void LinkLayerController::MakePeripheralConnection (const Address& bd_addr ,
52275234 bool try_role_switch) {
5228- INFO (id_, " Sending page response to {}" , addr );
5235+ INFO (id_, " Sending page response to {}" , bd_addr );
52295236 SendLinkLayerPacket (model::packets::PageResponseBuilder::Create (
5230- GetAddress (), addr , try_role_switch));
5237+ GetAddress (), bd_addr , try_role_switch));
52315238
5232- uint16_t handle = connections_.CreateConnection (addr, GetAddress ());
5233- if (handle == kReservedHandle ) {
5239+ uint16_t connection_handle =
5240+ connections_.CreateConnection (bd_addr, GetAddress ());
5241+ if (connection_handle == kReservedHandle ) {
52345242 INFO (id_, " CreateConnection failed" );
52355243 return ;
52365244 }
5245+
52375246 ASSERT (link_manager_add_link (
5238- lm_.get (), reinterpret_cast <const uint8_t (*)[6 ]>(addr .data ())));
5247+ lm_.get (), reinterpret_cast <const uint8_t (*)[6 ]>(bd_addr .data ())));
52395248
5240- CheckExpiringConnection (handle );
5249+ CheckExpiringConnection (connection_handle );
52415250
5242- /* Role change event before connection complete is a quirk commonly exists in
5243- * Android-capatable Bluetooth controllers.
5244- * On the responder side, any connection should be accompanied with a role
5245- * change event */
5246- // TODO(b/274476773): Add a config option for this quirk
5247- auto role =
5251+ bluetooth::hci::Role role =
52485252 try_role_switch && connections_.IsRoleSwitchAllowedForPendingConnection ()
52495253 ? bluetooth::hci::Role::CENTRAL
52505254 : bluetooth::hci::Role::PERIPHERAL;
5251- connections_.SetAclRole (handle, role);
5252- if (IsEventUnmasked (EventCode::ROLE_CHANGE)) {
5255+
5256+ AclConnection& connection = connections_.GetAclConnection (connection_handle);
5257+
5258+ connection.SetLinkPolicySettings (default_link_policy_settings_);
5259+ connection.SetRole (role);
5260+
5261+ // Role change event before connection complete generates an HCI Role Change
5262+ // event on the acceptor side if accepted; the event is sent before the
5263+ // HCI Connection Complete event.
5264+ if (role == bluetooth::hci::Role::CENTRAL &&
5265+ IsEventUnmasked (EventCode::ROLE_CHANGE)) {
5266+ INFO (id_, " Role at connection setup accepted" );
52535267 send_event_ (bluetooth::hci::RoleChangeBuilder::Create (ErrorCode::SUCCESS,
5254- addr , role));
5268+ bd_addr , role));
52555269 }
52565270
5257- INFO (id_, " CreateConnection returned handle 0x{:x}" , handle );
5271+ INFO (id_, " CreateConnection returned handle 0x{:x}" , connection_handle );
52585272 if (IsEventUnmasked (EventCode::CONNECTION_COMPLETE)) {
52595273 send_event_ (bluetooth::hci::ConnectionCompleteBuilder::Create (
5260- ErrorCode::SUCCESS, handle, addr, bluetooth::hci::LinkType::ACL ,
5261- bluetooth::hci::Enable::DISABLED));
5274+ ErrorCode::SUCCESS, connection_handle, bd_addr ,
5275+ bluetooth::hci::LinkType::ACL, bluetooth::hci:: Enable::DISABLED));
52625276 }
52635277}
52645278
@@ -5488,67 +5502,124 @@ ErrorCode LinkLayerController::RoleDiscovery(uint16_t handle,
54885502 if (!connections_.HasHandle (handle)) {
54895503 return ErrorCode::UNKNOWN_CONNECTION;
54905504 }
5505+
54915506 *role = connections_.GetAclRole (handle);
54925507 return ErrorCode::SUCCESS;
54935508}
54945509
5495- ErrorCode LinkLayerController::SwitchRole (Address addr ,
5510+ ErrorCode LinkLayerController::SwitchRole (Address bd_addr ,
54965511 bluetooth::hci::Role role) {
5497- auto handle = connections_.GetHandleOnlyAddress (addr);
5498- if (handle == rootcanal::kReservedHandle ) {
5512+ // The BD_ADDR command parameter indicates for which connection
5513+ // the role switch is to be performed and shall specify a BR/EDR Controller
5514+ // for which a connection already exists.
5515+ uint16_t connection_handle = connections_.GetHandleOnlyAddress (bd_addr);
5516+ if (connection_handle == kReservedHandle ) {
5517+ INFO (id_, " unknown connection address {}" , bd_addr);
54995518 return ErrorCode::UNKNOWN_CONNECTION;
55005519 }
5501- // TODO(b/274248798): Reject role switch if disabled in link policy
5502- SendLinkLayerPacket (model::packets::RoleSwitchRequestBuilder::Create (
5503- GetAddress (), addr, static_cast <uint8_t >(role)));
5520+
5521+ AclConnection& connection = connections_.GetAclConnection (connection_handle);
5522+
5523+ // If there is an (e)SCO connection between the local device and the device
5524+ // identified by the BD_ADDR parameter, an attempt to perform a role switch
5525+ // shall be rejected by the local device.
5526+ if (connections_.GetScoHandle (bd_addr) != kReservedHandle ) {
5527+ INFO (id_,
5528+ " role switch rejected because an Sco link is opened with"
5529+ " the target device" );
5530+ return ErrorCode::COMMAND_DISALLOWED;
5531+ }
5532+
5533+ // If the connection between the local device and the device identified by the
5534+ // BD_ADDR parameter is placed in Sniff mode, an attempt to perform a role
5535+ // switch shall be rejected by the local device.
5536+ if (connection.GetMode () == AclConnectionState::kSniffMode ) {
5537+ INFO (id_,
5538+ " role switch rejected because the acl connection is in sniff mode" );
5539+ return ErrorCode::COMMAND_DISALLOWED;
5540+ }
5541+
5542+ if (role != connection.GetRole ()) {
5543+ SendLinkLayerPacket (model::packets::RoleSwitchRequestBuilder::Create (
5544+ GetAddress (), bd_addr));
5545+ } else if (IsEventUnmasked (EventCode::ROLE_CHANGE)) {
5546+ // Note: the status is Success only if the role change procedure was
5547+ // actually performed, otherwise the status is >0.
5548+ ScheduleTask (kNoDelayMs , [this , bd_addr, role]() {
5549+ send_event_ (bluetooth::hci::RoleChangeBuilder::Create (
5550+ ErrorCode::ROLE_SWITCH_FAILED, bd_addr, role));
5551+ });
5552+ }
5553+
55045554 return ErrorCode::SUCCESS;
55055555}
55065556
55075557void LinkLayerController::IncomingRoleSwitchRequest (
55085558 model::packets::LinkLayerPacketView incoming) {
5509- auto addr = incoming.GetSourceAddress ();
5510- auto handle = connections_.GetHandleOnlyAddress (addr );
5511- auto request = model::packets::RoleSwitchRequestView::Create (incoming);
5512- ASSERT (request .IsValid ());
5559+ auto bd_addr = incoming.GetSourceAddress ();
5560+ auto connection_handle = connections_.GetHandleOnlyAddress (bd_addr );
5561+ auto switch_req = model::packets::RoleSwitchRequestView::Create (incoming);
5562+ ASSERT (switch_req .IsValid ());
55135563
5514- // TODO(b/274248798): Reject role switch if disabled in link policy
5515- Role remote_role = static_cast <Role>(request.GetInitiatorNewRole ());
5516- Role local_role =
5517- remote_role == Role::CENTRAL ? Role::PERIPHERAL : Role::CENTRAL;
5518- connections_.SetAclRole (handle, local_role);
5519- if (IsEventUnmasked (EventCode::ROLE_CHANGE)) {
5520- ScheduleTask (kNoDelayMs , [this , addr, local_role]() {
5521- send_event_ (bluetooth::hci::RoleChangeBuilder::Create (ErrorCode::SUCCESS,
5522- addr, local_role));
5523- });
5564+ if (connection_handle == kReservedHandle ) {
5565+ INFO (id_, " ignoring Switch Request received on unknown connection" );
5566+ return ;
55245567 }
5525- ScheduleTask (kNoDelayMs , [this , addr, remote_role]() {
5568+
5569+ AclConnection& connection = connections_.GetAclConnection (connection_handle);
5570+
5571+ if (!connection.IsRoleSwitchEnabled ()) {
5572+ INFO (id_, " role switch disabled by local link policy settings" );
55265573 SendLinkLayerPacket (model::packets::RoleSwitchResponseBuilder::Create (
5527- GetAddress (), addr, static_cast <uint8_t >(ErrorCode::SUCCESS),
5528- static_cast <uint8_t >(remote_role)));
5529- });
5574+ GetAddress (), bd_addr,
5575+ static_cast <uint8_t >(ErrorCode::ROLE_CHANGE_NOT_ALLOWED)));
5576+ } else {
5577+ INFO (id_, " role switch request accepted by local device" );
5578+ SendLinkLayerPacket (model::packets::RoleSwitchResponseBuilder::Create (
5579+ GetAddress (), bd_addr, static_cast <uint8_t >(ErrorCode::SUCCESS)));
5580+
5581+ bluetooth::hci::Role new_role =
5582+ connection.GetRole () == bluetooth::hci::Role::CENTRAL
5583+ ? bluetooth::hci::Role::PERIPHERAL
5584+ : bluetooth::hci::Role::CENTRAL;
5585+
5586+ connection.SetRole (new_role);
5587+
5588+ if (IsEventUnmasked (EventCode::ROLE_CHANGE)) {
5589+ ScheduleTask (kNoDelayMs , [this , bd_addr, new_role]() {
5590+ send_event_ (bluetooth::hci::RoleChangeBuilder::Create (
5591+ ErrorCode::SUCCESS, bd_addr, new_role));
5592+ });
5593+ }
5594+ }
55305595}
55315596
55325597void LinkLayerController::IncomingRoleSwitchResponse (
55335598 model::packets::LinkLayerPacketView incoming) {
5534- auto addr = incoming.GetSourceAddress ();
5535- auto handle = connections_.GetHandleOnlyAddress (addr );
5536- auto response = model::packets::RoleSwitchResponseView::Create (incoming);
5537- ASSERT (response .IsValid ());
5599+ auto bd_addr = incoming.GetSourceAddress ();
5600+ auto connection_handle = connections_.GetHandleOnlyAddress (bd_addr );
5601+ auto switch_rsp = model::packets::RoleSwitchResponseView::Create (incoming);
5602+ ASSERT (switch_rsp .IsValid ());
55385603
5539- // TODO(b/274248798): Reject role switch if disabled in link policy
5540- ErrorCode status = ErrorCode::SUCCESS;
5541- Role role = static_cast <Role>(response.GetInitiatorNewRole ());
5542- if (response.GetStatus () == static_cast <uint8_t >(ErrorCode::SUCCESS)) {
5543- connections_.SetAclRole (handle, role);
5544- } else {
5545- status = static_cast <ErrorCode>(response.GetStatus ());
5604+ if (connection_handle == kReservedHandle ) {
5605+ INFO (id_, " ignoring Switch Response received on unknown connection" );
5606+ return ;
55465607 }
55475608
5609+ AclConnection& connection = connections_.GetAclConnection (connection_handle);
5610+ ErrorCode status = ErrorCode (switch_rsp.GetStatus ());
5611+ bluetooth::hci::Role new_role =
5612+ status != ErrorCode::SUCCESS ? connection.GetRole ()
5613+ : connection.GetRole () == bluetooth::hci::Role::CENTRAL
5614+ ? bluetooth::hci::Role::PERIPHERAL
5615+ : bluetooth::hci::Role::CENTRAL;
5616+
5617+ connection.SetRole (new_role);
5618+
55485619 if (IsEventUnmasked (EventCode::ROLE_CHANGE)) {
5549- ScheduleTask (kNoDelayMs , [this , status, addr, role ]() {
5620+ ScheduleTask (kNoDelayMs , [this , status, bd_addr, new_role ]() {
55505621 send_event_ (
5551- bluetooth::hci::RoleChangeBuilder::Create (status, addr, role ));
5622+ bluetooth::hci::RoleChangeBuilder::Create (status, bd_addr, new_role ));
55525623 });
55535624 }
55545625}
@@ -5558,6 +5629,7 @@ ErrorCode LinkLayerController::ReadLinkPolicySettings(uint16_t handle,
55585629 if (!connections_.HasHandle (handle)) {
55595630 return ErrorCode::UNKNOWN_CONNECTION;
55605631 }
5632+
55615633 *settings = connections_.GetAclLinkPolicySettings (handle);
55625634 return ErrorCode::SUCCESS;
55635635}
@@ -5579,6 +5651,7 @@ ErrorCode LinkLayerController::WriteDefaultLinkPolicySettings(
55795651 if (settings > 7 /* Sniff + Hold + Role switch */ ) {
55805652 return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS;
55815653 }
5654+
55825655 default_link_policy_settings_ = settings;
55835656 return ErrorCode::SUCCESS;
55845657}
0 commit comments