Skip to content

Commit 33825a7

Browse files
committed
RootCanal: Implement all Role Change configurations
Reland original change Idf251f4e8234c015fc43863cd3d7f7928a510c2d. Bug: 274248798 Test: atest --host rootcanal_ll_test Change-Id: I6b3ab4ff9f6636a8fe4ddd9b0e9c71832ebe7783
1 parent 77d70fa commit 33825a7

File tree

16 files changed

+622
-87
lines changed

16 files changed

+622
-87
lines changed

config.proto

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,8 @@ message ControllerQuirks {
2929
optional bool send_acl_data_before_connection_complete = 1;
3030
// Configure a default value for the LE random address.
3131
optional bool has_default_random_address = 2;
32-
// Send the Role Change event before the Connection Complete event
33-
// in the case where a role switch is initiated at connection establishment.
34-
optional bool send_role_change_before_connection_complete = 3;
3532
// Send an Hardware Error event if any command is called before HCI Reset.
36-
optional bool hardware_error_before_reset = 4;
33+
optional bool hardware_error_before_reset = 3;
3734
}
3835

3936
message Controller {

model/controller/acl_connection.cc

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ void AclConnection::Encrypt() { encrypted_ = true; };
3333

3434
bool AclConnection::IsEncrypted() const { return encrypted_; };
3535

36-
uint16_t AclConnection::GetLinkPolicySettings() const {
37-
return link_policy_settings_;
38-
};
39-
4036
void AclConnection::SetLinkPolicySettings(uint16_t settings) {
4137
link_policy_settings_ = settings;
4238
}

model/controller/acl_connection.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ namespace rootcanal {
2626

2727
using ::bluetooth::hci::AddressWithType;
2828

29+
enum AclConnectionState {
30+
kActiveMode,
31+
kHoldMode,
32+
kSniffMode,
33+
};
34+
2935
// Model the connection of a device to the controller.
3036
class AclConnection {
3137
public:
@@ -44,8 +50,15 @@ class AclConnection {
4450
void Encrypt();
4551
bool IsEncrypted() const;
4652

47-
uint16_t GetLinkPolicySettings() const;
4853
void SetLinkPolicySettings(uint16_t settings);
54+
uint16_t GetLinkPolicySettings() const { return link_policy_settings_; }
55+
bool IsRoleSwitchEnabled() const {
56+
return (link_policy_settings_ & 0x1) != 0;
57+
}
58+
bool IsHoldModeEnabled() const { return (link_policy_settings_ & 0x2) != 0; }
59+
bool IsSniffModeEnabled() const { return (link_policy_settings_ & 0x4) != 0; }
60+
61+
AclConnectionState GetMode() const { return state_; }
4962

5063
bluetooth::hci::Role GetRole() const;
5164
void SetRole(bluetooth::hci::Role role);
@@ -81,6 +94,7 @@ class AclConnection {
8194
// State variables
8295
bool encrypted_{false};
8396
uint16_t link_policy_settings_{0};
97+
AclConnectionState state_{kActiveMode};
8498
bluetooth::hci::Role role_{bluetooth::hci::Role::CENTRAL};
8599
std::chrono::steady_clock::time_point last_packet_timestamp_;
86100
std::chrono::steady_clock::duration timeout_;

model/controller/controller_properties.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1963,7 +1963,6 @@ ControllerProperties::ControllerProperties(
19631963
config.quirks().hardware_error_before_reset();
19641964
}
19651965
// TODO(b/270606199): support send_acl_data_before_connection_complete
1966-
// TODO(b/274476773): support send_role_change_before_connection_complete
19671966
}
19681967

19691968
if (!CheckSupportedFeatures()) {

model/controller/link_layer_controller.cc

Lines changed: 144 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -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

55075557
void 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

55325597
void 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
}

packets/link_layer_packets.pdl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,12 +356,10 @@ packet PingResponse : LinkLayerPacket (type = PING_RESPONSE) {
356356
}
357357

358358
packet RoleSwitchRequest : LinkLayerPacket (type = ROLE_SWITCH_REQUEST) {
359-
initiator_new_role: 8,
360359
}
361360

362361
packet RoleSwitchResponse : LinkLayerPacket (type = ROLE_SWITCH_RESPONSE) {
363362
status: 8,
364-
initiator_new_role: 8,
365363
}
366364

367365
packet LlPhyReq : LinkLayerPacket (type = LL_PHY_REQ) {

0 commit comments

Comments
 (0)