blob: 7f3247c46942326365956aa3d66496b689c1939b [file] [log] [blame]
# Copyright 2024 The Pigweed Authors
#
# 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
#
# https://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 file contains Emboss definitions for the logical link control and
# adaptation protocol (l2cap) frames found in the Bluetooth core specification.
# The Emboss compiler is used to generate a C++ header from this file.
[$default byte_order: "LittleEndian"]
[(cpp) namespace: "pw::bluetooth::emboss"]
# ========================= Data Packet Format =================================
# Core Spec v6.0 Vol 3, Part A, Section 3
struct BasicL2capHeader:
0 [+2] UInt pdu_length
-- For B-frames, the PDU Length equals the payload size.
$next [+2] UInt channel_id
-- The channel ID (CID) identifies the destination channel endpoint of the
-- packet.
[requires: this != 0]
struct BFrame:
-- Defined in Core Spec v6.0 Vol 3, Part A, Section 3.1.
0 [+BasicL2capHeader.$size_in_bytes] BasicL2capHeader header
let pdu_length = header.pdu_length
let channel_id = header.channel_id
$next [+pdu_length] UInt:8[pdu_length] payload
struct BFrameHeader:
# TODO: b/364711772 - Migrate clients to `BFrame` & delete.
-- 3.1
-- A frame header for a B-Frame.
-- In basic L2CAP mode, the L2CAP PDU on a connection-oriented channel is also
-- referred to as a "B-frame".
0 [+2] UInt pdu_length
-- For B-frames, the PDU Length equals the payload size.
$next [+2] UInt channel_id
-- The channel ID (CID) identifies the destination channel endpoint of the
-- packet.
struct FirstKFrame:
-- Defined in Core Spec v6.0 Vol 3, Part A, Section 3.4.
[requires: 0 <= payload_size <= 65533]
0 [+BasicL2capHeader.$size_in_bytes] BasicL2capHeader header
let pdu_length = header.pdu_length
let channel_id = header.channel_id
let payload_size = pdu_length-2
$next [+2] UInt sdu_length
-- The first K-Frame of an SDU contains an SDU length field following the
-- L2CAP header. Subsequent frames that are part of the same SDU do not
-- contain the SDU length field.
$next [+payload_size] UInt:8[payload_size] payload
struct SubsequentKFrame:
-- Defined in Core Spec v6.0 Vol 3, Part A, Section 3.4.
[requires: 0 <= payload_size <= 65533]
0 [+BasicL2capHeader.$size_in_bytes] BasicL2capHeader header
let pdu_length = header.pdu_length
let channel_id = header.channel_id
let payload_size = pdu_length
$next [+payload_size] UInt:8[payload_size] payload
struct KFrameSduHeader:
# TODO: b/364711772 - Migrate clients to `FirstKFrame` & delete.
-- 3.4.2
-- A frame header for a K-Frame (credit based flow control) SDU.
0 [+2] UInt sdu_length
struct KFramePduHeader:
# TODO: b/364711772 - Migrate clients to `SubsequentKFrame` & delete.
-- 3.4.1
-- A frame header for a K-Frame (credit based flow control) PDU.
0 [+2] UInt pdu_length
$next [+2] UInt channel_id
# ====================== Signaling Packet Formats ==============================
# Core Spec v6.0 Vol 3, Part A, Section 4
enum L2capSignalingPacketCode:
-- Possible values for the Code field of an L2CAP C-frame. See Core Spec v5.4,
-- Vol 3, Part A, Table 4.2 for a list of the codes.
[maximum_bits: 8]
COMMAND_REJECT_RSP = 0x01
CONNECTION_REQ = 0x02
CONNECTION_RSP = 0x03
CONFIGURATION_REQ = 0x04
CONFIGURATION_RSP = 0x05
DISCONNECTION_REQ = 0x06
DISCONNECTION_RSP = 0x07
ECHO_REQ = 0x08
ECHO_RSP = 0x09
INFORMATION_REQ = 0x0A
INFORMATION_RSP = 0x0B
CONNECTION_PARAMETER_UPDATE_REQ = 0x12
CONNECTION_PARAMETER_UPDATE_RSP = 0x13
LE_CREDIT_BASED_CONNECTION_REQ = 0x14
LE_CREDIT_BASED_CONNECTION_RSP = 0x15
FLOW_CONTROL_CREDIT_IND = 0x16
CREDIT_BASED_CONNECTION_REQ = 0x17
CREDIT_BASED_CONNECTION_RSP = 0x18
CREDIT_BASED_RECONFIGURE_REQ = 0x19
CREDIT_BASED_RECONFIGURE_RSP = 0x1A
enum L2capFixedCid:
-- Possible fixed values for L2CAP channel ID. See Core Spec v6.0, Vol 3,
-- Part A, Table 2.1
[maximum_bits: 16]
ACL_U_SIGNALING = 0x0001
CONNECTIONLESS = 0x0002 # Applicable to ACL-U and APB-U
ACL_U_SECURITY_MANAGER = 0x0007
LE_U_ATTRIBUTE_PROTOCOL = 0x0004
LE_U_SIGNALING = 0x0005
LE_U_SECURITY_MANAGER = 0x0006
enum L2capFixedPsmCode:
-- Possible fixed values for PSM or SPSM as assigned by Bluetooth SIG. See
-- Core Spec v5.4, Vol 3, Part A, Section 4.2 and Assigned_Numbers Section 2.5
[maximum_bits: 16]
SDP = 0x0001 # PSM
RFCOMM = 0x0003 # PSM
ATT = 0x001F # PSM
EATT = 0x0027 # PSM or SPSM
enum L2capCommandRejectReasonCode:
-- Reported in L2CAP_COMMAND_REJECT_RSP packets.
[maximum_bits: 16]
NOT_UNDERSTOOD = 0x0000
SIG_MTU_EXCEEDED = 0x0001
INVALID_CID = 0x0002
-- Typically a channel is invalid because it does not exist.
struct CFrame:
-- A Control Frame (C-frame) contains L2CAP signaling commands exchanged
-- between peer L2CAP entities. C-frames are exclusively used on the L2CAP
-- signaling channels.
0 [+BasicL2capHeader.$size_in_bytes] BasicL2capHeader header
let pdu_length = header.pdu_length
let channel_id = header.channel_id
$next [+pdu_length] UInt:8[pdu_length] payload
struct L2capSignalingCommandHeader:
-- C-frame refers to an L2CAP PDU payload containing one or more signaling
-- commands.
0 [+1] L2capSignalingPacketCode code
$next [+1] UInt identifier
-- Matches responses with requests.
$next [+2] UInt data_length
struct L2capSignalingCommand:
-- Generic L2CAP signaling command.
0 [+L2capSignalingCommandHeader.$size_in_bytes] L2capSignalingCommandHeader command_header
let data_length = command_header.data_length
$next [+data_length] UInt:8[data_length] payload
struct L2capCommandRejectRsp:
-- Section 4.1
-- An L2CAP_COMMAND_REJECT_RSP packet shall be sent in response to a command
-- packet with an unknown command code or when sending the corresponding
-- response is inappropriate.
[requires: command_header.code == L2capSignalingPacketCode.COMMAND_REJECT_RSP]
0 [+L2capSignalingCommandHeader.$size_in_bytes] L2capSignalingCommandHeader command_header
$next [+2] L2capCommandRejectReasonCode reason
-- Describes why the request packet was rejected.
if reason == L2capCommandRejectReasonCode.SIG_MTU_EXCEEDED:
6 [+2] UInt actual_sig_mtu
if reason == L2capCommandRejectReasonCode.INVALID_CID:
# The local and remote endpoints of the disputed channel relative to the
# sender of this L2CAP_COMMAND_REJECT_RSP packet. If the rejected command
# contains only one of the channel endpoints, the other one shall be
# replaced by the null CID 0x0000.
6 [+2] UInt local_endpoint
-- The destination CID from the rejected command.
8 [+2] UInt remote_endpoint
-- The source CID from the rejected command.
struct L2capConnectionReq:
-- Section 4.2
-- L2CAP_CONNECTION_REQ packets are sent to create an L2CAP channel between
-- two devices.
[requires: command_header.code == L2capSignalingPacketCode.CONNECTION_REQ]
0 [+L2capSignalingCommandHeader.$size_in_bytes] L2capSignalingCommandHeader command_header
$next [+2] UInt psm
-- Protocol/Service Multiplexer.
$next [+2] UInt source_cid
-- The channel endpoint on the device sending the request.
enum L2capConnectionRspResultCode:
-- Reported in L2CAP_CONNECTION_RSP packets.
[maximum_bits: 16]
SUCCESSFUL = 0x0000
PENDING = 0x0001
PSM_NOT_SUPPORTED = 0x0002
SECURITY_BLOCK = 0x0003
NO_RESOURCES_AVAILABLE = 0x0004
INVALID_SOURCE_CID = 0x0005
SOURCE_CID_ALREADY_ALLOCATED = 0x0006
enum L2capConnectionRspStatusCode:
-- Reported in L2CAP_CONNECTION_RSP packets if result is PENDING.
[maximum_bits: 16]
NO_INFORMATION = 0x0000
AUTHENTICATION_PENDING = 0x0001
AUTHORIZATION_PENDING = 0x0002
struct L2capConnectionRsp:
-- Section 4.3
-- L2CAP_CONNECTION_RSP packets are sent in response to a L2CAP_CONNECTION_REQ
-- packet.
[requires: command_header.code == L2capSignalingPacketCode.CONNECTION_RSP]
0 [+L2capSignalingCommandHeader.$size_in_bytes] L2capSignalingCommandHeader command_header
$next [+2] UInt destination_cid
-- The channel endpoint on the device sending this response packet.
$next [+2] UInt source_cid
-- The channel endpoint on the device receiving the packet.
$next [+2] L2capConnectionRspResultCode result
-- The outcome of the connection request.
if result == L2capConnectionRspResultCode.PENDING:
$next [+2] L2capConnectionRspStatusCode status
-- The status of the connection.
struct L2capDisconnectionReq:
-- Section 4.6
-- Once an L2CAP_DISCONNECTION_REQ packet is issued, all incoming data in
-- transit on this L2CAP channel shall be discarded and any new additional
-- outgoing data shall be discarded.
[requires: command_header.code == L2capSignalingPacketCode.DISCONNECTION_REQ]
0 [+L2capSignalingCommandHeader.$size_in_bytes] L2capSignalingCommandHeader command_header
$next [+2] UInt destination_cid
-- The endpoint of the channel to be disconnected on the device receiving
-- this request.
$next [+2] UInt source_cid
-- The endpoint of the channel to be disconnected on the device sending this
-- request.
struct L2capDisconnectionRsp:
-- Section 4.7
-- L2CAP_DISCONNECTION_RSP packets shall be sent in response to each valid
-- L2CAP_DISCONNECTION_REQ packet.
[requires: command_header.code == L2capSignalingPacketCode.DISCONNECTION_RSP]
0 [+L2capSignalingCommandHeader.$size_in_bytes] L2capSignalingCommandHeader command_header
$next [+2] UInt destination_cid
-- The channel endpoint on the device sending the packet.
$next [+2] UInt source_cid
-- The channel endpoint on the device receiving the packet.
struct L2capLeCreditBasedConnectionReq:
-- Section 4.22
-- L2CAP_LE_CREDIT_BASED_CONNECTION_REQ packets are sent to create and
-- configure an L2CAP channel between two devices using LE Credit Based Flow
-- Control mode.
[requires: command_header.code == L2capSignalingPacketCode.LE_CREDIT_BASED_CONNECTION_REQ]
0 [+L2capSignalingCommandHeader.$size_in_bytes] L2capSignalingCommandHeader command_header
-- `code` is expected to be LE_CREDIT_BASED_CONNECTION_REQ
$next [+2] UInt spsm
-- Simplified Protocol/Service Multiplexer.
$next [+2] UInt source_cid
-- Channel endpoint on the device sending the request.
let min_mtu = 23
$next [+2] UInt mtu
-- Maximum Transmission Unit
[requires: this >= L2capLeCreditBasedConnectionReq.min_mtu]
let min_mps = 23
let max_mps = 65533
$next [+2] UInt mps
-- Maximum PDU Payload Size
[requires: L2capLeCreditBasedConnectionReq.min_mps <= this <= L2capLeCreditBasedConnectionReq.max_mps]
let max_credit_value = 65535
$next [+2] UInt initial_credits
[requires: this <= L2capLeCreditBasedConnectionReq.max_credit_value]
struct L2capFlowControlCreditInd:
-- Section 4.24
-- A device shall send an L2CAP_FLOW_CONTROL_CREDIT_IND packet when it is
-- capable of receiving additional K-frames (for example after it has
-- processed one or more K-frames) in LE Credit Based Flow Control mode and
-- Enhanced Credit Based Flow Control mode.
[requires: command_header.code == L2capSignalingPacketCode.FLOW_CONTROL_CREDIT_IND]
0 [+L2capSignalingCommandHeader.$size_in_bytes] L2capSignalingCommandHeader command_header
$next [+2] UInt cid
-- The source channel endpoint of the device sending the packet.
$next [+2] UInt credits
-- The credit value field represents number of credits the receiving device
-- can increment.
[requires: 1 <= this <= 65535]