The L2CAP layer of the BLE Host Stack performs data multiplexing through the use of a Channel ID (CID), which is a 2-byte value contained by the L2CAP Basic Header, as seen in the general L2CAP packet format:
Several CIDs are reserved. For instance, 0x0004 is used by the ATT, 0x0006 by the SMP, 0x0005 is the Signaling Channel. The 0x0040-0x007F range is assigned for the Connection-Oriented Channels.
The LE Credit-Based Flow Control is an L2CAP mode of operation for Connection-Oriented Channels in which an endpoint device has complete control over how many packets the peer device may send at any time through the use of credits.
One credit represents the permission to send one LE-frame over the established channel. The receiving device gives a fixed number of credits to the sending device, so that the latter knows exactly how many LE-frames it may send. The attempt to send more frames than permitted results in the receiving device closing the channel.
An initial number of credits are given by each device to the peer when the connection is created. Subsequently, each device can give more credits as it deems necessary; if a device wants to send more data than it is allowed, there’s nothing it can do but wait until it receives more credits from the peer.
A Protocol Service Multiplexer must be associated with any credit-based connection. It is abbreviated as LE_PSM and is a two-byte value identifying the protocol that uses the credit-based connection. The specification defined the ranges for allowed LE_PSMs; some are reserved by specific profiles (e.g. IPSP) and others may be dynamically used by custom application profiles.
An LE Credit-Based connection is created and managed on the L2CAP Signaling Channel, with the following commands and parameters.
- LE Credit-Based Connection Request, with the parameters:
- Source Channel ID (SCID)
- Maximum Transmission Unit (MTU)
- Maximum Payload Size (MPS)
- Initial Credits
- LE Credit-Based Connection Response
- Destination CID (DCID)
- Initial Credits
- LE Flow Control Credit
The requesting device must specify the LE_PSM for which the connection is opened, the CID to which the responder will send data (SCID), the supported MTU and MPS and the initial number of credits given to the responder.
In turn, the responding device can reject the request (reason is found in the Result parameter) or can accept it (Result is 0) and also provide the CID where the requesting device can send data (DCID), initial credits for this CID and its own MTU and MPS.
The minimum values between the two devices’ MTU and MPS are used. MTU is the maximum transmission unit, i.e. the maximum size of data (an SDU – Service Data Unit) to be transmitted. MPS is the maximum payload size, i.e. the maximum size of a single L2CAP packet, which is an LE-frame and “eats” one credit when is transmitted.
At any moment, any of the two devices can send a Flow Control Credit command to increase the credits of the peer on the given CID.
The data packets - example
Let’s assume device A sends an LE Credit-Based Connection Request with:
- LE_PSM = 0x0080
- SCID = 0x004a
- MTU = 100
- MPS = 40
- I.C. = 5
Device B answers with an LE Credit-Based Connection Response:
- DCID = 0x004b
- MTU =260
- MPS = 60
- I.C. = 10
So MTU becomes 100 and MPS becomes 40. This means that a device can send SDUs of maximum 100 bytes, but these 100 bytes will be fragmented to fit into LE-frames of maximum 40 bytes payload.
An LE-frame contains:
- The basic L2CAP header: Length (2 bytes) and CID (2 bytes)
- Payload (length maximum equal to MPS)
When a large SDU is sent, the first LE-frame Payload starts with 2 bytes of SDU Length then follow the first MPS-2 bytes of SDU. Subsequent LE-frames each contain MPS bytes of SDU, while the last one may contain less than MPS bytes.
If device A from our example wants to send an SDU of 90 bytes, it would need 3 credits because the 90 bytes can be split in 3 LE-frames: