Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4c8a8eaa authored by Archie Pusaka's avatar Archie Pusaka
Browse files

floss: hcidoc: Introduce the hcidoc_packets crate

The current pdl-compiler doesn't work well with l2cap_packets.pdl.
Therefore, we temporarily write our own l2cap_packets.pdl, which is a
stripped down version of the original pdl file, but works with the
pdl-compiler. This is put into it's own crate. If we found another
non-compatible pdl files, we can utilize this crate again.

Ideally this should be obsoleted once pdl-compiler is fixed.

Bug: 306108678
Test: m -j
Test: ./build.py --target=utils, verify l2cap_packets.rs is generated.

Change-Id: I56acff17e903d6ca435c638257c8784619d5bc47
parent d4c5236f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ edition = "2021"

[dependencies]
bt_packets = { path = "../../system/gd/rust/packets" }
hcidoc_packets = { path = "packets" }
clap = "4.0"
chrono = "0.4"
num-derive = "0.3"
+39 −0
Original line number Diff line number Diff line
#
#  Copyright 2023 Google, Inc.
#
#  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.

# This crate is a temporary package until we can parse l2cap_packets.pdl file
# properly. Until then, we fork the file to this crate so we get a workable
# l2cap_packets.rs to be used to speed up the development of hcidoc.
# The content of this crate mainly copies bt_packets, which is located in
# system/gd/rust/packets.

[package]
name = "hcidoc_packets"
version = "0.0.1"
edition = "2018"
build = "build.rs"

[dependencies]

bindgen = "0.64"
bytes = "1.0"
num-derive = "0.3"
num-traits = "0.2"
thiserror = "1.0"
walkdir = "2.2"

[lib]
path = "lib.rs"
crate-types = ["rlib"]
+45 −0
Original line number Diff line number Diff line
//
//  Copyright 2023 Google, Inc.
//
//  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.

use std::env;
use std::fs::File;
use std::path::PathBuf;
use std::process::{Command, Stdio};

fn main() {
    generate_packets();
}

fn generate_packets() {
    let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
    let out_file = File::create(out_dir.join("l2cap_packets.rs")).unwrap();
    let in_file = PathBuf::from("l2cap_packets.pdl");

    // Expect pdlc to be in the PATH
    println!("cargo:rerun-if-changed={}", in_file.display());
    let output = Command::new("pdlc")
        .arg("--output-format")
        .arg("rust")
        .arg(in_file)
        .stdout(Stdio::from(out_file))
        .output()
        .unwrap();

    println!(
        "Status: {}, stderr: {}",
        output.status,
        String::from_utf8_lossy(output.stderr.as_slice())
    );
}
+617 −0
Original line number Diff line number Diff line
little_endian_packets

packet BasicFrame {
  _size_(_payload_) : 16,
  channel_id : 16,
  _payload_,
}

enum Continuation : 1 {
  END = 0,
  CONTINUE = 1,
}

// ChannelId 2 is connectionless
packet GroupFrame : BasicFrame (channel_id = 0x02) {
  psm : 16,
  _payload_,
}

enum FrameType : 1 {
  I_FRAME = 0,
  S_FRAME = 1,
}

group FrameGroup {
  frame_type: FrameType
}

enum SupervisoryFunction : 2 {
  RECEIVER_READY = 0,
  REJECT = 1,
  RECEIVER_NOT_READY = 2,
  SELECT_REJECT = 3,
}

enum RetransmissionDisable : 1 {
  NORMAL = 0,
  DISABLE = 1,
}

enum SegmentationAndReassembly : 2 {
  UNSEGMENTED = 0,
  START = 1,
  END = 2,
  CONTINUATION = 3,
}

packet StandardFrame : BasicFrame {
  _payload_,
}

group StandardSupervisoryControl {
  FrameGroup {
    frame_type = S_FRAME
  },
  _fixed_ = 0 : 1,
  s : SupervisoryFunction,
  _reserved_ : 3,
  r : RetransmissionDisable,
  req_seq : 6,
  _reserved_ : 2,
}

group StandardInformationControl {
  FrameGroup {
    frame_type = I_FRAME
  },
  tx_seq : 6,
  r : RetransmissionDisable,
  req_seq : 6,
  sar : SegmentationAndReassembly,
}

packet StandardSupervisoryFrame : StandardFrame {
  StandardSupervisoryControl,
}

packet StandardInformationFrame : StandardFrame {
  StandardInformationControl,
  _payload_,
}

packet StandardInformationStartFrame : StandardInformationFrame (sar = START) {
  l2cap_sdu_length : 16,
  _payload_,
}

enum Poll : 1 {
  NOT_SET = 0,
  POLL = 1,
}

enum Final : 1 {
  NOT_SET = 0,
  POLL_RESPONSE = 1,
}

group EnhancedSupervisoryControl {
  FrameGroup {
    frame_type = S_FRAME
  },
  _fixed_ = 0 : 1,
  s : SupervisoryFunction,
  p : Poll,
  _reserved_ : 2,
  f : Final,
  req_seq : 6,
  _reserved_ : 2,
}

group EnhancedInformationControl {
  FrameGroup {
    frame_type = I_FRAME
  },
  tx_seq : 6,
  f : Final,
  req_seq : 6,
  sar : SegmentationAndReassembly,
}

packet EnhancedSupervisoryFrame : StandardFrame {
  EnhancedSupervisoryControl,
}

packet EnhancedInformationFrame : StandardFrame {
  EnhancedInformationControl,
  _payload_,
}

packet EnhancedInformationStartFrame : EnhancedInformationFrame (sar = START) {
  l2cap_sdu_length : 16,
  _payload_,
}

group ExtendedSupervisoryControl {
  FrameGroup {
    frame_type = S_FRAME
  },
  f : Final,
  req_seq : 14,
  s : SupervisoryFunction,
  p : Poll,
  _reserved_ : 5,
  _reserved_ : 8,
}

group ExtendedInformationControl {
  FrameGroup {
    frame_type = I_FRAME
  },
  f : Final,
  req_seq : 14,
  sar : SegmentationAndReassembly,
  tx_seq : 14,
}

packet ExtendedSupervisoryFrame : StandardFrame {
  ExtendedSupervisoryControl,
}

packet ExtendedInformationFrame : StandardFrame {
  ExtendedInformationControl,
  _payload_,
}

packet ExtendedInformationStartFrame : ExtendedInformationFrame (sar = START) {
  l2cap_sdu_length : 16,
  _payload_,
}

packet FirstLeInformationFrame : BasicFrame {
  l2cap_sdu_length : 16,
  _payload_,
}

enum CommandCode : 8 {
  COMMAND_REJECT = 0x01,
  CONNECTION_REQUEST = 0x02,
  CONNECTION_RESPONSE = 0x03,
  CONFIGURATION_REQUEST = 0x04,
  CONFIGURATION_RESPONSE = 0x05,
  DISCONNECTION_REQUEST = 0x06,
  DISCONNECTION_RESPONSE = 0x07,
  ECHO_REQUEST = 0x08,
  ECHO_RESPONSE = 0x09,
  INFORMATION_REQUEST = 0x0A,
  INFORMATION_RESPONSE = 0x0B,
  CREATE_CHANNEL_REQUEST = 0x0C,
  CREATE_CHANNEL_RESPONSE = 0x0D,
  MOVE_CHANNEL_REQUEST = 0x0E,
  MOVE_CHANNEL_RESPONSE = 0x0F,
  MOVE_CHANNEL_CONFIRMATION_REQUEST = 0x10,
  MOVE_CHANNEL_CONFIRMATION_RESPONSE = 0x11,
  FLOW_CONTROL_CREDIT = 0x16,  // Core 5.2 COC
  CREDIT_BASED_CONNECTION_REQUEST = 0x17,
  CREDIT_BASED_CONNECTION_RESPONSE = 0x18,
  CREDIT_BASED_RECONFIGURE_REQUEST = 0x19,
  CREDIT_BASED_RECONFIGURE_RESPONSE = 0x1A,
}

packet ControlFrame : BasicFrame (channel_id = 0x0001) {
  _payload_,
}

packet Control {
  code : CommandCode,
  identifier : 8,
  _size_(_payload_) : 16,
  _payload_,
}

enum CommandRejectReason : 16 {
  COMMAND_NOT_UNDERSTOOD = 0x0000,
  SIGNALING_MTU_EXCEEDED = 0x0001,
  INVALID_CID_IN_REQUEST = 0x0002,
}

packet CommandReject : Control (code = COMMAND_REJECT) {
  reason : CommandRejectReason,
  _body_,
}

packet CommandRejectNotUnderstood : CommandReject (reason = COMMAND_NOT_UNDERSTOOD) {
}

packet CommandRejectMtuExceeded : CommandReject (reason = SIGNALING_MTU_EXCEEDED) {
  actual_mtu : 16,
}

packet CommandRejectInvalidCid : CommandReject (reason = INVALID_CID_IN_REQUEST) {
  local_channel : 16, // Relative to the sender of the CommandReject
  remote_channel : 16,
}

packet ConnectionRequest : Control (code = CONNECTION_REQUEST) {
  psm : 16,
  source_cid : 16,
}

enum ConnectionResponseResult : 16 {
  SUCCESS = 0x0000,
  PENDING = 0x0001,
  PSM_NOT_SUPPORTED = 0x0002,
  SECURITY_BLOCK = 0x0003,
  NO_RESOURCES_AVAILABLE = 0x0004,
  INVALID_CID = 0x0006,
  SOURCE_CID_ALREADY_ALLOCATED = 0x0007,
}

enum ConnectionResponseStatus : 16 {
  NO_FURTHER_INFORMATION_AVAILABLE = 0x0000,
  AUTHENTICATION_PENDING = 0x0001,
  AUTHORIZATION_PENDING = 0x0002,
}

packet ConnectionResponse : Control (code = CONNECTION_RESPONSE) {
  destination_cid : 16,
  source_cid : 16,
  result : ConnectionResponseResult,
  status : ConnectionResponseStatus,
}

enum ConfigurationOptionType : 7 {
  MTU = 0x01,
  FLUSH_TIMEOUT = 0x02,
  QUALITY_OF_SERVICE = 0x03,
  RETRANSMISSION_AND_FLOW_CONTROL = 0x04,
  FRAME_CHECK_SEQUENCE = 0x05,
  EXTENDED_FLOW_SPECIFICATION = 0x06,
  EXTENDED_WINDOW_SIZE = 0x07,
}

enum ConfigurationOptionIsHint : 1 {
  OPTION_MUST_BE_RECOGNIZED = 0,
  OPTION_IS_A_HINT = 1,
}

enum QosServiceType : 8 {
  NO_TRAFFIC = 0x00,
  BEST_EFFORT = 0x01, // Default
  GUARANTEED = 0x02,
}

enum RetransmissionAndFlowControlModeOption : 8 {
  L2CAP_BASIC = 0x00,
  RETRANSMISSION = 0x01,
  FLOW_CONTROL = 0x02,
  ENHANCED_RETRANSMISSION = 0x03,
  STREAMING = 0x04,
}

enum FcsType : 8 {
  NO_FCS = 0,
  DEFAULT = 1,  // 16-bit FCS
}

enum ConfigurationResponseResult : 16 {
  SUCCESS = 0x0000,
  UNACCEPTABLE_PARAMETERS = 0x0001,
  REJECTED = 0x0002,
  UNKNOWN_OPTIONS = 0x0003,
  PENDING = 0x0004,
  FLOW_SPEC_REJECTED = 0x0005,
}

packet DisconnectionRequest : Control (code = DISCONNECTION_REQUEST) {
  destination_cid : 16,
  source_cid : 16,
}

packet DisconnectionResponse : Control (code = DISCONNECTION_RESPONSE) {
  destination_cid : 16,
  source_cid : 16,
}

packet EchoRequest : Control (code = ECHO_REQUEST) {
  _payload_, // Optional and implementation specific
}

packet EchoResponse : Control (code = ECHO_RESPONSE) {
  _payload_, // Optional and implementation specific
}

enum InformationRequestInfoType : 16 {
  CONNECTIONLESS_MTU = 0x0001,
  EXTENDED_FEATURES_SUPPORTED = 0x0002,
  FIXED_CHANNELS_SUPPORTED = 0x0003,
}

packet InformationRequest : Control (code = INFORMATION_REQUEST) {
  info_type : InformationRequestInfoType,
}

enum InformationRequestResult : 16 {
  SUCCESS = 0x0000,
  NOT_SUPPORTED = 0x0001,
}

packet InformationResponse : Control (code = INFORMATION_RESPONSE) {
  info_type : InformationRequestInfoType,
  result : InformationRequestResult,
  _body_,
}

packet InformationResponseConnectionlessMtu : InformationResponse (info_type = CONNECTIONLESS_MTU) {
  connectionless_mtu : 16,
}

packet InformationResponseExtendedFeatures : InformationResponse (info_type = EXTENDED_FEATURES_SUPPORTED) {
  // ExtendedFeatureMask : 32,
  flow_control_mode : 1,
  retransmission_mode : 1,
  bi_directional_qoS : 1,
  enhanced_retransmission_mode : 1,
  streaming_mode : 1,
  fcs_option : 1,
  extended_flow_specification_for_br_edr : 1,
  fixed_channels : 1,
  extended_window_size : 1,
  unicast_connectionless_data_reception : 1,
  enhanced_credit_based_flow_control_mode : 1,
  _reserved_ : 21,
}

packet InformationResponseFixedChannels : InformationResponse (info_type = FIXED_CHANNELS_SUPPORTED) {
  fixed_channels : 64, // bit 0 must be 0, bit 1 must be 1, all others 1 = supported
}

packet CreateChannelRequest : Control (code = CREATE_CHANNEL_REQUEST) {
  psm : 16,
  source_cid : 16,
  controller_id : 8,
}

enum CreateChannelResponseResult : 16 {
  SUCCESS = 0x0000,
  PENDING = 0x0001,
  PSM_NOT_SUPPORTED = 0x0002,
  SECURITY_BLOCK = 0x0003,
  NO_RESOURCES_AVAILABLE = 0x0004,
  CONTROLLER_ID_NOT_SUPPORTED = 0x0005,
  INVALID_CID = 0x0006,
  SOURCE_CID_ALREADY_ALLOCATED = 0x0007,
}

enum CreateChannelResponseStatus : 16 {
  NO_FURTHER_INFORMATION_AVAILABLE = 0x0000,
  AUTHENTICATION_PENDING = 0x0001,
  AUTHORIZATION_PENDING = 0x0002,
}

packet CreateChannelResponse : Control (code = CREATE_CHANNEL_RESPONSE) {
  destination_cid : 16,
  source_cid : 16,
  result : CreateChannelResponseResult,
  status : CreateChannelResponseStatus,
}

// AMP Only ?
packet MoveChannelRequest : Control (code = MOVE_CHANNEL_REQUEST) {
  initiator_cid : 16,
  dest_controller_id : 8,
}

enum MoveChannelResponseResult : 16 {
  SUCCESS = 0x0000,
  PENDING = 0x0001,
  CONTROLLER_ID_NOT_SUPPORTED = 0x0002,
  NEW_CONTROLLER_ID_IS_SAME = 0x0003,
  CONFIGURATION_NOT_SUPPORTED = 0x0004,
  CHANNEL_COLLISION = 0x0005,
  CHANNEL_NOT_ALLOWED_TO_BE_MOVED = 0x0006,
}

packet MoveChannelResponse : Control (code = MOVE_CHANNEL_RESPONSE) {
  initiator_cid : 16,
  result : MoveChannelResponseResult,
}

enum MoveChannelConfirmationResult : 16 {
  SUCCESS = 0x0000,
  FAILURE = 0x0001,
}

packet MoveChannelConfirmationRequest : Control (code = MOVE_CHANNEL_CONFIRMATION_REQUEST) {
  initiator_cid : 16,
  result : MoveChannelConfirmationResult,
}

packet MoveChannelConfirmationResponse : Control (code = MOVE_CHANNEL_CONFIRMATION_RESPONSE) {
  initiator_cid : 16,
}

// Core 5.2 COC

packet FlowControlCredit : Control (code = FLOW_CONTROL_CREDIT) {
  cid : 16, // Receiver's destination CID
  credits : 16,
}

packet CreditBasedConnectionRequest : Control (code = CREDIT_BASED_CONNECTION_REQUEST) {
  spsm : 16,
  mtu : 16,
  mps : 16,
  initial_credits : 16,
  source_cid : 16[],
}

enum CreditBasedConnectionResponseResult : 16 {
  SUCCESS = 0x0000,
  SPSM_NOT_SUPPORTED = 0x0002,
  SOME_REFUSED_NO_RESOURCES_AVAILABLE = 0x0004,
  ALL_REFUSED_INSUFFICIENT_AUTHENTICATION = 0x0005,
  ALL_REFUSED_INSUFFICIENT_AUTHORIZATION = 0x0006,
  ALL_REFUSED_INSUFFICIENT_ENCRYPTION_KEY_SIZE = 0x0007,
  ALL_REFUSED_INSUFFICIENT_ENCRYPTION = 0x0008,
  SOME_REFUSED_INVALID_SOURCE_CID = 0x0009,
  SOME_REFUSED_SOURCE_CID_ALREADY_ALLOCATED = 0x000A,
  ALL_REFUSED_UNACCEPTABLE_PARAMETERS = 0x000B,
  ALL_REFUSED_INVALID_PARAMETERS = 0x000C,
}

packet CreditBasedConnectionResponse : Control (code = CREDIT_BASED_CONNECTION_RESPONSE) {
  mtu : 16,
  mps : 16,
  initial_credits : 16,
  result : CreditBasedConnectionResponseResult,
  destination_cid : 16[],
}

packet CreditBasedReconfigureRequest : Control (code = CREDIT_BASED_RECONFIGURE_REQUEST) {
  mtu : 16,
  mps : 16,
  destination_cid : 16[],
}

enum CreditBasedReconfigureResponseResult : 16 {
  SUCCESS = 0x0000,
  MTU_NOT_ALLOWED = 0x01,
  MPS_NOT_ALLOWED = 0x02,
  INVALID_DESTINATION_CID = 0x03,
  UNACCEPTABLE_PARAMETERS = 0x04,
}

packet CreditBasedReconfigureResponse : Control (code = CREDIT_BASED_RECONFIGURE_RESPONSE) {
  result: CreditBasedReconfigureResponseResult,
}

enum LeCommandCode : 8 {
  COMMAND_REJECT = 0x01,
  DISCONNECTION_REQUEST = 0x06,
  DISCONNECTION_RESPONSE = 0x07,
  CONNECTION_PARAMETER_UPDATE_REQUEST = 0x12,
  CONNECTION_PARAMETER_UPDATE_RESPONSE = 0x13,
  LE_CREDIT_BASED_CONNECTION_REQUEST = 0x14,
  LE_CREDIT_BASED_CONNECTION_RESPONSE = 0x15,
  LE_FLOW_CONTROL_CREDIT = 0x16,
  CREDIT_BASED_CONNECTION_REQUEST = 0x17,  // Core 5.2 COC
  CREDIT_BASED_CONNECTION_RESPONSE = 0x18,
  CREDIT_BASED_RECONFIGURE_REQUEST = 0x19,
  CREDIT_BASED_RECONFIGURE_RESPONSE = 0x1A,
}

packet LeControlFrame : BasicFrame (channel_id = 0x0005) {
  _payload_,
}

packet LeControl {
  code : LeCommandCode,
  identifier : 8, // Must be non-zero
  _size_(_payload_) : 16,
  _payload_,
}


packet LeCommandReject : LeControl (code = COMMAND_REJECT) {
  reason : CommandRejectReason,
  _payload_,
}

packet LeCommandRejectNotUnderstood : LeCommandReject (reason = COMMAND_NOT_UNDERSTOOD) {
}

packet LeCommandRejectMtuExceeded : LeCommandReject (reason = SIGNALING_MTU_EXCEEDED) {
  actual_mtu : 16,
}

packet LeCommandRejectInvalidCid : LeCommandReject (reason = INVALID_CID_IN_REQUEST) {
  local_channel : 16, // Relative to the sender of the CommandReject
  remote_channel : 16,
}

packet LeDisconnectionRequest : LeControl (code = DISCONNECTION_REQUEST) {
  destination_cid : 16,
  source_cid : 16,
}

packet LeDisconnectionResponse : LeControl (code = DISCONNECTION_RESPONSE) {
  destination_cid : 16,
  source_cid : 16,
}

packet ConnectionParameterUpdateRequest : LeControl (code = CONNECTION_PARAMETER_UPDATE_REQUEST) {
  interval_min : 16,
  interval_max : 16,
  peripheral_latency : 16,
  timeout_multiplier : 16,
}

enum ConnectionParameterUpdateResponseResult : 16 {
  ACCEPTED = 0,
  REJECTED = 1,
}

packet ConnectionParameterUpdateResponse : LeControl (code = CONNECTION_PARAMETER_UPDATE_RESPONSE) {
  result : ConnectionParameterUpdateResponseResult,
}

packet LeCreditBasedConnectionRequest : LeControl (code = LE_CREDIT_BASED_CONNECTION_REQUEST) {
  le_psm : 16, // 0x0001-0x007F Fixed, 0x0080-0x00FF Dynamic
  source_cid : 16,
  mtu : 16,
  mps : 16,
  initial_credits : 16,
}

enum LeCreditBasedConnectionResponseResult : 16 {
  SUCCESS = 0x0000,
  LE_PSM_NOT_SUPPORTED = 0x0002,
  NO_RESOURCES_AVAILABLE = 0x0004,
  INSUFFICIENT_AUTHENTICATION = 0x0005,
  INSUFFICIENT_AUTHORIZATION = 0x0006,
  INSUFFICIENT_ENCRYPTION_KEY_SIZE = 0x0007,
  INSUFFICIENT_ENCRYPTION = 0x0008,
  INVALID_SOURCE_CID = 0x0009,
  SOURCE_CID_ALREADY_ALLOCATED = 0x000A,
  UNACCEPTABLE_PARAMETERS = 0x000B,
}

packet LeCreditBasedConnectionResponse : LeControl (code = LE_CREDIT_BASED_CONNECTION_RESPONSE) {
  destination_cid : 16,
  mtu : 16,
  mps : 16,
  initial_credits : 16,
  result : LeCreditBasedConnectionResponseResult,
}

packet LeFlowControlCredit : LeControl (code = LE_FLOW_CONTROL_CREDIT) {
  cid : 16, // Receiver's destination CID
  credits : 16,
}

packet LeEnhancedCreditBasedConnectionRequest : LeControl (code = CREDIT_BASED_CONNECTION_REQUEST) {
  spsm : 16,
  mtu : 16,
  mps : 16,
  initial_credits : 16,
  source_cid : 16[],
}

packet LeEnhancedCreditBasedConnectionResponse : LeControl (code = CREDIT_BASED_CONNECTION_RESPONSE) {
  mtu : 16,
  mps : 16,
  initial_credits : 16,
  result : CreditBasedConnectionResponseResult,
  destination_cid : 16[],
}

packet LeEnhancedCreditBasedReconfigureRequest : LeControl (code = CREDIT_BASED_RECONFIGURE_REQUEST) {
  mtu : 16,
  mps : 16,
  destination_cid : 16[],
}

packet LeEnhancedCreditBasedReconfigureResponse : LeControl (code = CREDIT_BASED_RECONFIGURE_RESPONSE) {
  result: CreditBasedReconfigureResponseResult,
}
+7 −0
Original line number Diff line number Diff line
#![allow(clippy::all)]
#![allow(unused)]
#![allow(missing_docs)]

pub mod l2cap {
    include!(concat!(env!("OUT_DIR"), "/l2cap_packets.rs"));
}