diff options
| author | 2023-05-04 10:37:17 -0700 | |
|---|---|---|
| committer | 2023-05-06 01:04:14 +0000 | |
| commit | e0cf5f94f2087f87c02b7f95e49bb8818cb48bea (patch) | |
| tree | 395a2a7964833a83a1a7c962cb69d40970fa5e88 | |
| parent | e1e32a6f97660a33944adf2974cada9d517ed4d8 (diff) | |
RootCanal: Implement the LL phy update procedure
Implement the full semantic of the LE Set Phy and LE Set Default Phy
commands by performing the LL phy update procedure.
Bug: 275970864
Test: m root-canal
Change-Id: I144ec8c153e0f2a3d96bcc408a46f0d383077625
9 files changed, 247 insertions, 66 deletions
diff --git a/tools/rootcanal/model/controller/acl_connection.cc b/tools/rootcanal/model/controller/acl_connection.cc index 85915b7d09..2c47ad191d 100644 --- a/tools/rootcanal/model/controller/acl_connection.cc +++ b/tools/rootcanal/model/controller/acl_connection.cc @@ -33,22 +33,6 @@ void AclConnection::Encrypt() { encrypted_ = true; }; bool AclConnection::IsEncrypted() const { return encrypted_; }; -AddressWithType AclConnection::GetAddress() const { return address_; } - -void AclConnection::SetAddress(AddressWithType address) { address_ = address; } - -AddressWithType AclConnection::GetOwnAddress() const { return own_address_; } - -AddressWithType AclConnection::GetResolvedAddress() const { - return resolved_address_; -} - -void AclConnection::SetOwnAddress(AddressWithType address) { - own_address_ = address; -} - -Phy::Type AclConnection::GetPhyType() const { return type_; } - uint16_t AclConnection::GetLinkPolicySettings() const { return link_policy_settings_; }; diff --git a/tools/rootcanal/model/controller/acl_connection.h b/tools/rootcanal/model/controller/acl_connection.h index eed6a0540d..74bc9a700a 100644 --- a/tools/rootcanal/model/controller/acl_connection.h +++ b/tools/rootcanal/model/controller/acl_connection.h @@ -35,44 +35,39 @@ class AclConnection { virtual ~AclConnection() = default; - void Encrypt(); - - bool IsEncrypted() const; - - AddressWithType GetAddress() const; - - void SetAddress(AddressWithType address); - - AddressWithType GetOwnAddress() const; + Phy::Type GetPhyType() const { return type_; } - void SetOwnAddress(AddressWithType address); + AddressWithType GetAddress() const { return address_; } + AddressWithType GetOwnAddress() const { return own_address_; } + AddressWithType GetResolvedAddress() const { return resolved_address_; } - AddressWithType GetResolvedAddress() const; - - Phy::Type GetPhyType() const; + void Encrypt(); + bool IsEncrypted() const; uint16_t GetLinkPolicySettings() const; - void SetLinkPolicySettings(uint16_t settings); bluetooth::hci::Role GetRole() const; - void SetRole(bluetooth::hci::Role role); int8_t GetRssi() const; - void SetRssi(int8_t rssi); - void ResetLinkTimer(); - std::chrono::steady_clock::duration TimeUntilNearExpiring() const; - - bool IsNearExpiring() const; - std::chrono::steady_clock::duration TimeUntilExpired() const; - + void ResetLinkTimer(); + bool IsNearExpiring() const; bool HasExpired() const; + // LE-ACL state. + void InitiatePhyUpdate() { initiated_phy_update_ = true; } + void PhyUpdateComplete() { initiated_phy_update_ = false; } + bool InitiatedPhyUpdate() const { return initiated_phy_update_; } + bluetooth::hci::PhyType GetTxPhy() const { return tx_phy_; } + bluetooth::hci::PhyType GetRxPhy() const { return rx_phy_; } + void SetTxPhy(bluetooth::hci::PhyType phy) { tx_phy_ = phy; } + void SetRxPhy(bluetooth::hci::PhyType phy) { rx_phy_ = phy; } + private: AddressWithType address_; AddressWithType own_address_; @@ -89,6 +84,11 @@ class AclConnection { bluetooth::hci::Role role_{bluetooth::hci::Role::CENTRAL}; std::chrono::steady_clock::time_point last_packet_timestamp_; std::chrono::steady_clock::duration timeout_; + + // LE-ACL state. + bluetooth::hci::PhyType tx_phy_{bluetooth::hci::PhyType::LE_1M}; + bluetooth::hci::PhyType rx_phy_{bluetooth::hci::PhyType::LE_1M}; + bool initiated_phy_update_{false}; }; } // namespace rootcanal diff --git a/tools/rootcanal/model/controller/acl_connection_handler.cc b/tools/rootcanal/model/controller/acl_connection_handler.cc index 2e3bd5a2a0..d310450b10 100644 --- a/tools/rootcanal/model/controller/acl_connection_handler.cc +++ b/tools/rootcanal/model/controller/acl_connection_handler.cc @@ -197,6 +197,11 @@ uint16_t AclConnectionHandler::GetHandleOnlyAddress( return kReservedHandle; } +AclConnection& AclConnectionHandler::GetAclConnection(uint16_t handle) { + ASSERT_LOG(HasHandle(handle), "Unknown handle %d", handle); + return acl_connections_.at(handle); +} + AddressWithType AclConnectionHandler::GetAddress(uint16_t handle) const { ASSERT_LOG(HasHandle(handle), "Unknown handle %hd", handle); return acl_connections_.at(handle).GetAddress(); diff --git a/tools/rootcanal/model/controller/acl_connection_handler.h b/tools/rootcanal/model/controller/acl_connection_handler.h index 1534fe17bb..c9bf92aaec 100644 --- a/tools/rootcanal/model/controller/acl_connection_handler.h +++ b/tools/rootcanal/model/controller/acl_connection_handler.h @@ -91,6 +91,10 @@ class AclConnectionHandler { bluetooth::hci::AddressWithType GetOwnAddress(uint16_t handle) const; bluetooth::hci::AddressWithType GetResolvedAddress(uint16_t handle) const; + // Return the AclConnection for the selected connection handle, asserts + // if the handle is not currently used. + AclConnection& GetAclConnection(uint16_t handle); + void Encrypt(uint16_t handle); bool IsEncrypted(uint16_t handle) const; diff --git a/tools/rootcanal/model/controller/dual_mode_controller.cc b/tools/rootcanal/model/controller/dual_mode_controller.cc index 97da8504b0..b6efbd4510 100644 --- a/tools/rootcanal/model/controller/dual_mode_controller.cc +++ b/tools/rootcanal/model/controller/dual_mode_controller.cc @@ -1824,8 +1824,8 @@ void DualModeController::LeSetDefaultPhy(CommandView command) { ASSERT(command_view.IsValid()); ErrorCode status = link_layer_controller_.LeSetDefaultPhy( command_view.GetAllPhysNoTransmitPreference(), - command_view.GetAllPhysNoReceivePreference(), - command_view.GetTxPhysBitmask(), command_view.GetRxPhysBitmask()); + command_view.GetAllPhysNoReceivePreference(), command_view.GetTxPhys(), + command_view.GetRxPhys()); send_event_(bluetooth::hci::LeSetDefaultPhyCompleteBuilder::Create( kNumCommandPackets, status)); } @@ -1836,9 +1836,8 @@ void DualModeController::LeSetPhy(CommandView command) { ErrorCode status = link_layer_controller_.LeSetPhy( command_view.GetConnectionHandle(), command_view.GetAllPhysNoTransmitPreference(), - command_view.GetAllPhysNoReceivePreference(), - command_view.GetTxPhysBitmask(), command_view.GetRxPhysBitmask(), - command_view.GetPhyOptions()); + command_view.GetAllPhysNoReceivePreference(), command_view.GetTxPhys(), + command_view.GetRxPhys(), command_view.GetPhyOptions()); send_event_(bluetooth::hci::LeSetPhyStatusBuilder::Create( status, kNumCommandPackets)); } diff --git a/tools/rootcanal/model/controller/link_layer_controller.cc b/tools/rootcanal/model/controller/link_layer_controller.cc index d428eb5a31..00eb1b0c42 100644 --- a/tools/rootcanal/model/controller/link_layer_controller.cc +++ b/tools/rootcanal/model/controller/link_layer_controller.cc @@ -319,9 +319,10 @@ ErrorCode LinkLayerController::LeReadPhy(uint16_t connection_handle, return ErrorCode::UNKNOWN_CONNECTION; } - // TODO(b/275970864) save the phy in the connection state. - *tx_phy = bluetooth::hci::PhyType::LE_1M; - *rx_phy = bluetooth::hci::PhyType::LE_1M; + AclConnection const& connection = + connections_.GetAclConnection(connection_handle); + *tx_phy = connection.GetTxPhy(); + *rx_phy = connection.GetRxPhy(); return ErrorCode::SUCCESS; } @@ -335,7 +336,7 @@ ErrorCode LinkLayerController::LeSetDefaultPhy( // the TX_PHYs parameter shall be ignored; otherwise at least one bit shall // be set to 1. if (all_phys_no_transmit_preference) { - tx_phys = 0x1; // LE_1M_PHY by default. + tx_phys = supported_phys; } if (tx_phys == 0) { LOG_INFO("TX_Phys does not configure any bit"); @@ -346,7 +347,7 @@ ErrorCode LinkLayerController::LeSetDefaultPhy( // the RX_PHYs parameter shall be ignored; otherwise at least one bit shall // be set to 1. if (all_phys_no_receive_preference) { - rx_phys = 0x1; // LE_1M_PHY by default. + rx_phys = supported_phys; } if (rx_phys == 0) { LOG_INFO("RX_Phys does not configure any bit"); @@ -366,7 +367,8 @@ ErrorCode LinkLayerController::LeSetDefaultPhy( return ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; } - // TODO(b/275970864) save the phy default preference. + default_tx_phys_ = tx_phys; + default_rx_phys_ = rx_phys; return ErrorCode::SUCCESS; } @@ -374,7 +376,7 @@ ErrorCode LinkLayerController::LeSetDefaultPhy( ErrorCode LinkLayerController::LeSetPhy( uint16_t connection_handle, bool all_phys_no_transmit_preference, bool all_phys_no_receive_preference, uint8_t tx_phys, uint8_t rx_phys, - bluetooth::hci::PhyOptions phy_options) { + bluetooth::hci::PhyOptions /*phy_options*/) { uint8_t supported_phys = properties_.LeSupportedPhys(); // Note: no documented status code for this case. @@ -388,7 +390,7 @@ ErrorCode LinkLayerController::LeSetPhy( // the TX_PHYs parameter shall be ignored; otherwise at least one bit shall // be set to 1. if (all_phys_no_transmit_preference) { - tx_phys = 0x1; // LE_1M_PHY by default. + tx_phys = supported_phys; } if (tx_phys == 0) { LOG_INFO("TX_Phys does not configure any bit"); @@ -399,7 +401,7 @@ ErrorCode LinkLayerController::LeSetPhy( // the RX_PHYs parameter shall be ignored; otherwise at least one bit shall // be set to 1. if (all_phys_no_receive_preference) { - rx_phys = 0x1; // LE_1M_PHY by default. + rx_phys = supported_phys; } if (rx_phys == 0) { LOG_INFO("RX_Phys does not configure any bit"); @@ -422,18 +424,164 @@ ErrorCode LinkLayerController::LeSetPhy( // The HCI_LE_PHY_Update_Complete event shall be generated either when one // or both PHY changes or when the Controller determines that neither PHY // will change immediately. - // TODO(b/275970864) send LL_PHY_REQ to the peer. - ScheduleTask(0ms, [this, connection_handle] { - send_event_(bluetooth::hci::LePhyUpdateCompleteBuilder::Create( - ErrorCode::SUCCESS, connection_handle, - static_cast<uint8_t>(bluetooth::hci::PhyType::LE_1M), - static_cast<uint8_t>(bluetooth::hci::PhyType::LE_1M))); - }); + SendLeLinkLayerPacket(model::packets::LlPhyReqBuilder::Create( + connections_.GetOwnAddress(connection_handle).GetAddress(), + connections_.GetAddress(connection_handle).GetAddress(), tx_phys, + rx_phys)); - // TODO(b/275970864) save the phy preference. + connections_.GetAclConnection(connection_handle).InitiatePhyUpdate(); + requested_tx_phys_ = tx_phys; + requested_rx_phys_ = rx_phys; return ErrorCode::SUCCESS; } +// Helper to pick one phy in enabled phys. +static bluetooth::hci::PhyType select_phy(uint8_t phys, + bluetooth::hci::PhyType current) { + return (phys & 0x4) ? bluetooth::hci::PhyType::LE_CODED + : (phys & 0x2) ? bluetooth::hci::PhyType::LE_2M + : (phys & 0x1) ? bluetooth::hci::PhyType::LE_1M + : current; +} + +// Helper to generate the LL_PHY_UPDATE_IND mask for the selected phy. +// The mask is non zero only if the phy has changed. +static uint8_t indicate_phy(bluetooth::hci::PhyType selected, + bluetooth::hci::PhyType current) { + return selected == current ? 0x0 + : selected == bluetooth::hci::PhyType::LE_CODED ? 0x4 + : selected == bluetooth::hci::PhyType::LE_2M ? 0x2 + : 0x1; +} + +void LinkLayerController::IncomingLlPhyReq( + model::packets::LinkLayerPacketView incoming) { + auto phy_req = model::packets::LlPhyReqView::Create(incoming); + ASSERT(phy_req.IsValid()); + uint16_t connection_handle = + connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); + AclConnection& connection = connections_.GetAclConnection(connection_handle); + + if (connection.GetRole() == bluetooth::hci::Role::PERIPHERAL) { + // Peripheral receives the request: respond with local phy preferences + // in LL_PHY_RSP pdu. + SendLeLinkLayerPacket(model::packets::LlPhyRspBuilder::Create( + incoming.GetDestinationAddress(), incoming.GetSourceAddress(), + default_tx_phys_, default_rx_phys_)); + } else { + // Central receives the request: respond with LL_PHY_UPDATE_IND and + // the selected phys. + + // Intersect phy preferences with local preferences. + uint8_t tx_phys = phy_req.GetRxPhys() & default_tx_phys_; + uint8_t rx_phys = phy_req.GetTxPhys() & default_rx_phys_; + + // Select valid TX and RX phys from preferences. + bluetooth::hci::PhyType phy_c_to_p = + select_phy(tx_phys, connection.GetTxPhy()); + bluetooth::hci::PhyType phy_p_to_c = + select_phy(rx_phys, connection.GetRxPhy()); + + // Send LL_PHY_UPDATE_IND to notify selected phys. + // + // PHY_C_TO_P shall be set to indicate the PHY that shall be used for + // packets sent from the Central to the Peripheral. These fields each + // consist of 8 bits. If a PHY is changing, the bit corresponding to the new + // PHY shall be set to 1 and the remaining bits to 0; if a PHY is remaining + // unchanged, then the corresponding field shall be set to the value 0. + SendLeLinkLayerPacket(model::packets::LlPhyUpdateIndBuilder::Create( + incoming.GetDestinationAddress(), incoming.GetSourceAddress(), + indicate_phy(phy_c_to_p, connection.GetTxPhy()), + indicate_phy(phy_p_to_c, connection.GetRxPhy()), 0)); + + // Notify the host when the phy selection has changed + // (responder in this case). + if ((phy_c_to_p != connection.GetTxPhy() || + phy_p_to_c != connection.GetRxPhy()) && + IsLeEventUnmasked(SubeventCode::PHY_UPDATE_COMPLETE)) { + send_event_(bluetooth::hci::LePhyUpdateCompleteBuilder::Create( + ErrorCode::SUCCESS, connection_handle, phy_c_to_p, phy_p_to_c)); + } + + // Update local state. + connection.SetTxPhy(phy_c_to_p); + connection.SetRxPhy(phy_p_to_c); + } +} + +void LinkLayerController::IncomingLlPhyRsp( + model::packets::LinkLayerPacketView incoming) { + auto phy_rsp = model::packets::LlPhyRspView::Create(incoming); + ASSERT(phy_rsp.IsValid()); + uint16_t connection_handle = + connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); + AclConnection& connection = connections_.GetAclConnection(connection_handle); + ASSERT(connection.GetRole() == bluetooth::hci::Role::CENTRAL); + + // Intersect phy preferences with local preferences. + uint8_t tx_phys = phy_rsp.GetRxPhys() & requested_tx_phys_; + uint8_t rx_phys = phy_rsp.GetTxPhys() & requested_rx_phys_; + + // Select valid TX and RX phys from preferences. + bluetooth::hci::PhyType phy_c_to_p = + select_phy(tx_phys, connection.GetTxPhy()); + bluetooth::hci::PhyType phy_p_to_c = + select_phy(rx_phys, connection.GetRxPhy()); + + // Send LL_PHY_UPDATE_IND to notify selected phys. + // + // PHY_C_TO_P shall be set to indicate the PHY that shall be used for + // packets sent from the Central to the Peripheral. These fields each + // consist of 8 bits. If a PHY is changing, the bit corresponding to the new + // PHY shall be set to 1 and the remaining bits to 0; if a PHY is remaining + // unchanged, then the corresponding field shall be set to the value 0. + SendLeLinkLayerPacket(model::packets::LlPhyUpdateIndBuilder::Create( + incoming.GetDestinationAddress(), incoming.GetSourceAddress(), + indicate_phy(phy_c_to_p, connection.GetTxPhy()), + indicate_phy(phy_p_to_c, connection.GetRxPhy()), 0)); + + // Always notify the host, even if the phy selection has not changed + // (initiator in this case). + if (IsLeEventUnmasked(SubeventCode::PHY_UPDATE_COMPLETE)) { + send_event_(bluetooth::hci::LePhyUpdateCompleteBuilder::Create( + ErrorCode::SUCCESS, connection_handle, phy_c_to_p, phy_p_to_c)); + } + + // Update local state. + connection.PhyUpdateComplete(); + connection.SetTxPhy(phy_c_to_p); + connection.SetRxPhy(phy_p_to_c); +} + +void LinkLayerController::IncomingLlPhyUpdateInd( + model::packets::LinkLayerPacketView incoming) { + auto phy_update_ind = model::packets::LlPhyUpdateIndView::Create(incoming); + ASSERT(phy_update_ind.IsValid()); + uint16_t connection_handle = + connections_.GetHandleOnlyAddress(incoming.GetSourceAddress()); + AclConnection& connection = connections_.GetAclConnection(connection_handle); + ASSERT(connection.GetRole() == bluetooth::hci::Role::PERIPHERAL); + + bluetooth::hci::PhyType tx_phy = + select_phy(phy_update_ind.GetPhyPToC(), connection.GetTxPhy()); + bluetooth::hci::PhyType rx_phy = + select_phy(phy_update_ind.GetPhyCToP(), connection.GetRxPhy()); + + // Update local state, and notify the host. + // The notification is sent only when the local host is initiator + // of the Phy update procedure or the phy selection has changed. + if (IsLeEventUnmasked(SubeventCode::PHY_UPDATE_COMPLETE) && + (tx_phy != connection.GetTxPhy() || rx_phy != connection.GetRxPhy() || + connection.InitiatedPhyUpdate())) { + send_event_(bluetooth::hci::LePhyUpdateCompleteBuilder::Create( + ErrorCode::SUCCESS, connection_handle, tx_phy, rx_phy)); + } + + connection.PhyUpdateComplete(); + connection.SetTxPhy(tx_phy); + connection.SetRxPhy(rx_phy); +} + // HCI LE Set Host Feature command (Vol 4, Part E ยง 7.8.115). ErrorCode LinkLayerController::LeSetHostFeature(uint8_t bit_number, uint8_t bit_value) { @@ -2209,6 +2357,15 @@ void LinkLayerController::IncomingPacket( case model::packets::PacketType::ROLE_SWITCH_RESPONSE: IncomingRoleSwitchResponse(incoming); break; + case model::packets::PacketType::LL_PHY_REQ: + IncomingLlPhyReq(incoming); + break; + case model::packets::PacketType::LL_PHY_RSP: + IncomingLlPhyRsp(incoming); + break; + case model::packets::PacketType::LL_PHY_UPDATE_IND: + IncomingLlPhyUpdateInd(incoming); + break; default: LOG_WARN("Dropping unhandled packet of type %s", model::packets::PacketTypeText(incoming.GetType()).c_str()); @@ -5975,6 +6132,8 @@ void LinkLayerController::Reset() { inquiry_mode_ = InquiryType::STANDARD; inquiry_lap_ = 0; inquiry_max_responses_ = 0; + default_tx_phys_ = properties_.LeSupportedPhys(); + default_rx_phys_ = properties_.LeSupportedPhys(); bluetooth::hci::Lap general_iac; general_iac.lap_ = 0x33; // 0x9E8B33 diff --git a/tools/rootcanal/model/controller/link_layer_controller.h b/tools/rootcanal/model/controller/link_layer_controller.h index cf89e6ae14..f7300747ee 100644 --- a/tools/rootcanal/model/controller/link_layer_controller.h +++ b/tools/rootcanal/model/controller/link_layer_controller.h @@ -709,6 +709,10 @@ class LinkLayerController { void IncomingRoleSwitchRequest(model::packets::LinkLayerPacketView incoming); void IncomingRoleSwitchResponse(model::packets::LinkLayerPacketView incoming); + void IncomingLlPhyReq(model::packets::LinkLayerPacketView incoming); + void IncomingLlPhyRsp(model::packets::LinkLayerPacketView incoming); + void IncomingLlPhyUpdateInd(model::packets::LinkLayerPacketView incoming); + public: bool IsEventUnmasked(bluetooth::hci::EventCode event) const; bool IsLeEventUnmasked(bluetooth::hci::SubeventCode subevent) const; @@ -991,6 +995,12 @@ class LinkLayerController { // Extended advertising sets. std::unordered_map<uint8_t, ExtendedAdvertiser> extended_advertisers_{}; + // Local phy preferences, defaults to LE 1M Phy. + uint8_t default_tx_phys_{0x1}; + uint8_t default_rx_phys_{0x1}; + uint8_t requested_tx_phys_{0x1}; + uint8_t requested_rx_phys_{0x1}; + struct PeriodicAdvertiserListEntry { bluetooth::hci::AdvertiserAddressType advertiser_address_type; Address advertiser_address; diff --git a/tools/rootcanal/packets/hci/hci_packets.pdl b/tools/rootcanal/packets/hci/hci_packets.pdl index f4c9766c0e..2eb4e5ea5a 100644 --- a/tools/rootcanal/packets/hci/hci_packets.pdl +++ b/tools/rootcanal/packets/hci/hci_packets.pdl @@ -3718,9 +3718,9 @@ packet LeSetDefaultPhy : Command (op_code = LE_SET_DEFAULT_PHY) { all_phys_no_transmit_preference : 1, all_phys_no_receive_preference : 1, _reserved_ : 6, - tx_phys_bitmask : 3, + tx_phys : 3, _reserved_ : 5, - rx_phys_bitmask : 3, + rx_phys : 3, _reserved_ : 5, } @@ -3740,9 +3740,9 @@ packet LeSetPhy : Command (op_code = LE_SET_PHY) { all_phys_no_transmit_preference : 1, all_phys_no_receive_preference : 1, _reserved_ : 6, - tx_phys_bitmask : 3, + tx_phys : 3, _reserved_ : 5, - rx_phys_bitmask : 3, + rx_phys : 3, _reserved_ : 5, phy_options : PhyOptions, } @@ -5871,8 +5871,8 @@ packet LePhyUpdateComplete : LeMetaEvent (subevent_code = PHY_UPDATE_COMPLETE) { status : ErrorCode, connection_handle : 12, _reserved_ : 4, - tx_phy : 8, - rx_phy : 8, + tx_phy : PhyType, + rx_phy : PhyType, } enum DataStatus : 2 { diff --git a/tools/rootcanal/packets/link_layer_packets.pdl b/tools/rootcanal/packets/link_layer_packets.pdl index f168de24c0..3a92e39f08 100644 --- a/tools/rootcanal/packets/link_layer_packets.pdl +++ b/tools/rootcanal/packets/link_layer_packets.pdl @@ -52,6 +52,10 @@ enum PacketType : 8 { PING_RESPONSE = 0x36, ROLE_SWITCH_REQUEST = 0x38, ROLE_SWITCH_RESPONSE = 0x39, + + LL_PHY_REQ = 0x50, + LL_PHY_RSP = 0x51, + LL_PHY_UPDATE_IND = 0x52, } packet LinkLayerPacket { @@ -404,3 +408,19 @@ packet RoleSwitchResponse : LinkLayerPacket (type = ROLE_SWITCH_RESPONSE) { status: 8, initiator_new_role: 8, } + +packet LlPhyReq : LinkLayerPacket (type = LL_PHY_REQ) { + tx_phys: 8, + rx_phys: 8, +} + +packet LlPhyRsp : LinkLayerPacket (type = LL_PHY_RSP) { + tx_phys: 8, + rx_phys: 8, +} + +packet LlPhyUpdateInd : LinkLayerPacket (type = LL_PHY_UPDATE_IND) { + phy_c_to_p: 8, + phy_p_to_c: 8, + instant: 16, +} |