BLE L2CAP Frame Generation and Decoding

This example shows how to generate and decode Bluetooth® Low Energy L2CAP frames using the Communications Toolbox™ Library for the Bluetooth® Protocol.

Background

The Bluetooth Core Specification [ 1 ] includes a Low Energy (LE) version for low-rate wireless personal area networks, that is referred to as Bluetooth Low Energy (BLE) or Bluetooth Smart. The BLE stack consists of: Generic Attribute Profile (GATT), Attribute Protocol (ATT), Security Manager Protocol (SMP), Logical Link Control and Adaptation Protocol (L2CAP), Link layer and Physical layer. BLE was added to the standard for low energy devices generating small amounts of data, such as notification alerts used in such applications as home automation, health-care, fitness, and Internet of Things (IoT).

The L2CAP layer in BLE corresponds to the higher sub-layer i.e. Logical Link Control (LLC) of the Data Link Layer in the OSI reference model. The L2CAP is above the PHY and Link Layer of BLE. The BLE specification optimized and simplified the L2CAP when compared to classic Bluetooth.

L2CAP in BLE is responsible for: (i) logical connection establishment (ii) protocol multiplexing (iii) segmentation and reassembly (iv) flow control per 'dynamic' L2CAP channel.

The L2CAP layer adds an L2CAP basic header to the higher-layer payload and passes the Protocol Data Unit (PDU) to the Link Layer below it.

L2CAP Frames

L2CAP Frames consist of two sub-categories: Data frames and Signaling frames. There are different types of frames within these two categories of frames. The Data frames are again sub-categorized into B-frame (Basic information frame) and LE-frame (Low Energy information frame). Each frame type has its own format.

A channel identifier (CID) is the local name representing a logical channel endpoint on the device. For the protocols, such as the ATT and SMP, these channels are fixed by the Bluetooth Special Interest Group (SIG). For application specific profiles, such as Internet Protocol Support Profile (IPSP) and Object Transfer Profile (OTP), these channels are dynamically allocated.

Signaling frames are used with a fixed logical channel called signaling channel ('0005') and used for logical connection establishment between peer devices using the LE credit based flow control mechanism. These signaling frames are also used for updating the connection parameters (Slave latency, Connection timeout, Minimum connection interval and Maximum connection interval) when connection parameters request procedure is not supported in the Link Layer.

Data frames (B-frames and LE-frames) carry the upper-layer payload as 'Information Payload' in its frame format. B-Frames are used to carry fixed channels (ATT and SMP with fixed logical channels '0004' and '0006' respectively) payload. LE-frames are used to carry payload through dynamically created logical channels for application specific profiles, such as IPSP and OTP.

This example illustrates generation and decoding of the following frames. For a list of other signaling frames supported, see the CommandType property.

1. Flow control credit: This signaling frame is sent to create and configure an L2CAP logical channel between two devices.

2. B-frames over fixed channels (ATT, SMP, etc.): This frame is used for carrying fixed channels payload in basic L2CAP mode.

3. LE-frames over dynamic channels (profiles like IPSP, OTP, etc.): This frame is used for carrying dynamic channels payload in LE credit based flow control mode.

Check for Support Package Installation

% Check if the 'Communications Toolbox Library for the Bluetooth Protocol'
% support package is installed or not.
commSupportPackageCheck('BLUETOOTH');

L2CAP Frames Generation

You can use the bleL2CAPFrame function to generate an L2CAP frame. This function accepts a configuration object bleL2CAPFrameConfig. This object configures the fields required for generating an L2CAP frame.

Signaling frame generation

To generate a signaling frame, create a bleL2CAPFrameConfig object with ChannelIdentifier set to '0005'.

cfgL2CAP = bleL2CAPFrameConfig('ChannelIdentifier', '0005');

Configure the fields:

% Command type
cfgL2CAP.CommandType = 'Flow control credit';
% Source channel identifier
cfgL2CAP.SourceChannelIdentifier = '0041';
% LE credits
cfgL2CAP.Credits = 25
cfgL2CAP = 

  bleL2CAPFrameConfig with properties:

          ChannelIdentifier: '0005'
                CommandType: 'Flow control credit'
           SignalIdentifier: '01'
    SourceChannelIdentifier: '0041'
                    Credits: 25

Generate a 'Flow control credit' command.

sigFrame = bleL2CAPFrame(cfgL2CAP);

B-frame generation

To generate a B-frame (carrying ATT PDU), create a bleL2CAPFrameConfig object with ChannelIdentifier set to '0004' (ATT channel ID).

cfgL2CAP = bleL2CAPFrameConfig('ChannelIdentifier', '0004')
cfgL2CAP = 

  bleL2CAPFrameConfig with properties:

    ChannelIdentifier: '0004'

A B-frame is used to transmit payload from the ATT upper-layer. A 5-byte ATT PDU is used as payload in this example.

payload = ['04';'01';'00';'FF';'FF'];

Generate an L2CAP B-frame using the payload and configuration.

bFrame = bleL2CAPFrame(cfgL2CAP, payload);

LE-frame generation

To generate an LE-frame, create a bleL2CAPFrameConfig object with ChannelIdentifier set to '0035'.

cfgL2CAP = bleL2CAPFrameConfig('ChannelIdentifier', '0035')
cfgL2CAP = 

  bleL2CAPFrameConfig with properties:

    ChannelIdentifier: '0035'

An LE-frame is used to transmit the payload of dynamic channels. A 2-byte payload is used in this example.

payload = ['01';'02'];

Generate an L2CAP LE-frame using the payload and configuration.

leFrame = bleL2CAPFrame(cfgL2CAP, payload);

Decoding L2CAP Frames

You can use the bleL2CAPFrameDecode function to decode an L2CAP frame. This function outputs the following information:

  1. status: An enumeration of type blePacketDecodeStatus, which indicates whether or not the L2CAP decoding was successful.

  2. cfgL2CAP: An L2CAP frame configuration object of type bleL2CAPFrameConfig, which contains the decoded L2CAP properties.

This function accepts a BLE L2CAP frame as the input.

Decoding Signaling frame

[sigFrameDecodeStatus, cfgL2CAP] = bleL2CAPFrameDecode(sigFrame);

% Observe the outputs

% Decoding is successful
if strcmp(sigFrameDecodeStatus, 'Success')
    fprintf('L2CAP decoding status is: %s\n\n', sigFrameDecodeStatus);
    fprintf('Received L2CAP signaling frame configuration is:\n');
    cfgL2CAP
% Decoding failed
else
    fprintf('L2CAP decoding status is: %s\n', sigFrameDecodeStatus);
end
L2CAP decoding status is: Success

Received L2CAP signaling frame configuration is:

cfgL2CAP = 

  bleL2CAPFrameConfig with properties:

          ChannelIdentifier: '0005'
                CommandType: 'Flow control credit'
           SignalIdentifier: '01'
    SourceChannelIdentifier: '0041'
                    Credits: 25

Decoding B-frame

[bFrameDecodeStatus, cfgL2CAP, payload] = bleL2CAPFrameDecode(bFrame);

% Observe the outputs

% Decoding is successful
if strcmp(bFrameDecodeStatus, 'Success')
    fprintf('L2CAP decoding status is: %s\n\n', bFrameDecodeStatus);
    fprintf('Received L2CAP B-frame configuration is:\n');
    cfgL2CAP
    fprintf('Payload carried by L2CAP B-frame is:\n');
    payload
% Decoding failed
else
    fprintf('L2CAP decoding status is: %s\n', bFrameDecodeStatus);
end
L2CAP decoding status is: Success

Received L2CAP B-frame configuration is:

cfgL2CAP = 

  bleL2CAPFrameConfig with properties:

    ChannelIdentifier: '0004'

Payload carried by L2CAP B-frame is:

payload =

  5x2 char array

    '04'
    '01'
    '00'
    'FF'
    'FF'

Decoding LE-frame

[leFrameDecodeStatus, cfgL2CAP, payload] = bleL2CAPFrameDecode(leFrame);

% Observe the outputs

% Decoding is successful
if strcmp(leFrameDecodeStatus, 'Success')
    fprintf('L2CAP decoding status is: %s\n\n', leFrameDecodeStatus);
    fprintf('Received L2CAP LE-frame configuration is:\n');
    cfgL2CAP
    fprintf('Payload carried by L2CAP LE-frame is:\n');
    payload
% Decoding failed
else
    fprintf('L2CAP decoding status is: %s\n', leFrameDecodeStatus);
end
L2CAP decoding status is: Success

Received L2CAP LE-frame configuration is:

cfgL2CAP = 

  bleL2CAPFrameConfig with properties:

    ChannelIdentifier: '0035'

Payload carried by L2CAP LE-frame is:

payload =

  2x2 char array

    '01'
    '02'

Exporting to a PCAP File

The generated frames are exported to a PCAP file, which can be analyzed and visualized with a third party packet analyzer such as Wireshark [ 2 ]. The helper function helperBLEExportToPCAP generates a PCAP file containing the BLE L2CAP frames enclosed within a Link Layer packet.

The PCAP format expects L2CAP frame to be enclosed within Link Layer packet and also expects the generated packet to be prepended with the access address. The helper function helperBLEPrependAccessAddress prepends the access address to the generated packet. The following commands generate a PCAP file for the L2CAP frames generated in this example.

% Create a cell array of L2CAP frames
l2capFrames = {sigFrame, bFrame, leFrame};
llPackets = cell(1, numel(l2capFrames));
for i = 1:numel(llPackets)
    % Add Link Layer header to the generated L2CAP frame
    cfgLLData = bleLLDataChannelPDUConfig('LLID', 'Data (start fragment/complete)');
    llDataPDU = bleLLDataChannelPDU(cfgLLData, l2capFrames{i});
    % Prepend access address. A 4-byte access address is used in this example
    llPackets{i} = helperBLEPrependAccessAddress(llDataPDU, '01234567');
end

Create PCAP file for the generated Link Layer packets.

% Export generated frames to a PCAP format
helperBLEExportToPCAP(llPackets, 'BLEL2CAPFrames.pcap');

Visualization of the Generated L2CAP Frames

You can open the PCAP file containing the generated L2CAP frames in a packet analyzer. The L2CAP frames decoded by the packet analyzer match the standard compliant L2CAP frames generated by the Communications Toolbox™ Library for the Bluetooth Protocol. The captured analysis of the L2CAP frames is shown below.

  • Signaling frame (flow control credit)

  • B-frame (carrying ATT PDU)

  • LE-frame (carrying dynamic channel payload)

Conclusion

This example demonstrated generation and decoding of L2CAP frames specified in the Bluetooth [ 1 ] standard. You can use a packet analyzer to view the generated L2CAP frames.

Appendix

This example uses the following helper functions:

Selected Bibliography

  1. Bluetooth SIG, Bluetooth core specification v5.0: https://www.bluetooth.com/

  2. Wireshark software: https://www.wireshark.org/