Anyone who considers protocol unimportant has never dealt with a cat.
—Robert A. Heinlein
The Logical Link Control and Adaptation Protocol (L2CAP) is a protocol multiplexing layer that enables Bluetooth low energy to multiplex three different channels. It also enables segmentation and reassembly of packets that are larger than the underlying radio can deliver. On a Bluetooth classic radio, the L2CAP layer also performs many additional, complicated operations.
One of the basic concepts for Bluetooth low energy is a radically different connectionless model; this means that you only have to create a connection when you need to send data, and the device can always disconnect at any time. To achieve this, the connectionless model must be extended up to the L2CAP layer; thus, only fixed channels are supported. Fixed channels don’t have any configuration parameters to negotiate, and they exist as soon as the lower layers have established a connection; consequently, there is no time wasted waiting for the channel to be created.
When Bluetooth low energy was first designed, it did not use L2CAP. Previously, a Protocol Adaptation Layer (PAL), was designed to be a highly optimized, and severely restrictive multiplexer between two protocols. The PAL looked like the Attribute Protocol and a signaling layer. This was bad for two reasons: flexibility and legacy implementations.
The PAL could only support two types of packet: a single higher-layer protocol or its own signaling layer. There was no segmentation or reassembly, nor was there the ability to separate different protocols. One of the basic design tenets of protocol design is that you layer protocols; each protocol is self-contained. This means that is possible to design, for example, the Security Manager with all the other parts of the system. At the point of implementation, each protocol is a separate layer that can be individually tested. Therefore, the PAL broke this simple rule. The part that killed this approach, however, was not the design, but the lack of flexibility.
Most multiplexing layers perform segmentation and reassembly. This means that a large protocol packet from a higher layer can be segmented into multiple smaller packets appropriately labeled so that they can be transmitted through a system that has packet length restrictions. A good example of this is an ATM network for which each packet is restricted to just a few bytes of data, allowing the rapid switching between different streams. This facilitates the delivery of low-latency audio traffic and bulk data at the same time.
The Host Controller Interface (HCI) supports segmentation and reassembly by using the “start” and “continuation” bits on each data packet. However, the PAL didn’t support such a basic feature. This meant that the maximum size of any application data in this layer would be limited to just 24 bytes of data. This severe restriction was the eventual downfall of the PAL.
When L2CAP was proposed as an alternative, the group designing Bluetooth low energy split down the middle: the companies that already had existing Bluetooth implementations and the companies that didn’t. In some standards bodies, this would have meant many months of acrimonious voting to attempt to force division; this is also typically associated with disruptive political actions like trying to stuff the room with voting members to try to sway the vote one way or the other. In Bluetooth, this is not the standard approach. Instead, a paper on the various costs of each approach was written showing the cost of adding L2CAP. The deciding argument was that the battery life of a device that reported something once a second was reduced from 3.3 years to 3.2 years. So L2CAP did reduce the battery life of the device, but compared with the 7 bytes before the payload of the packet, and the 3 bytes of cyclic redundancy check (CRC) on every single packet whether it was carrying data or not, it was not a significant reduction. This is another example of the attention to detail that the designers of Bluetooth low energy took to consider the system design issues of all the decisions.
L2CAP gives you the ability to plug Bluetooth low energy into an existing L2CAP implementation. It also supports the full segmentation and reassembly from Blue-tooth classic, effectively allowing packet sizes of up to 65,535 bytes in length; even though there are no protocols that support this packet size that can be run on Blue-tooth low energy. L2CAP also retains the channel model that Bluetooth classic uses.
In Bluetooth classic, the channels come in two different flavors: fixed and connection-oriented. A fixed channel exists for as long as the two devices are connected. These are used primarily for signaling channels, either for basic L2CAP signaling commands or, in v2.0 and later, an Alternate MAC/PHY signaling channel. Connection-oriented channels can be created at any time by sending a few L2CAP signaling commands to a peer device.
In Bluetooth classic, connection-oriented channels allow data from an individual pair of applications to be considered as separate from the data of other channels. For example, even though connection-oriented channels can add additional data integrity checking, they might have a different flow specification, or they might be a streaming channel rather than a best-effort channel. Connection-oriented channels are great when you have a complex system that has multiple, varied types of data being transmitted at the same time. For example, a phone and a car can have multiple different protocols running at the same time: one stream for the high-quality audio from the phone to the car stereo; one stream for the hands-free operation; another stream for the phone book; and perhaps another stream for an Internet connection.
Opening connection-oriented channels can be a complex operation. Each L2CAP channel has a large number of configuration parameters; seven in the latest specification. This means that in addition to the two messages that have to be exchanged to request a connection to be established, each of the configuration parameters has to be agreed upon before any data is allowed to be sent. This could be fairly quick—just another four messages—or it could be a fairly lengthy operation of proposed values and counter proposals. The other complexity that connection-oriented channels bring is that once they are all configured and data is flowing, a device can renegotiate different parameters. All this increases the latency of the data connection at the expense of more flexibility. For most Bluetooth classic protocols and profiles, this is an acceptable cost because these connections are kept alive for long periods of time.
In L2CAP, there is a simple concept of a channel. L2CAP, after all, is a multiplexing layer, and to do this, it has multiple channels. A channel is a single sequence of packets, from and to a single pair of services on a single device. Between two devices, there can be multiple channels active at the same time.
In Bluetooth low energy, only fixed channels are supported. A fixed channel is a channel that exists as soon as the two devices are connected; there is no configuration requirement for fixed channels. The future-proofed flexibility still exists to add connection-oriented channels if they are considered necessary.
Table 9–1 presents the L2CAP channel identifiers. Each channel identifier in Blue-tooth is a 16-bit number. The channel identifier 0x0000 is reserved and should never be used. Channel identifier 0x0001 is a fixed channel for Bluetooth classic signaling.
Channel identifier 0x0002 is a fixed channel used for “connectionless data,” although there is no profile that currently uses this. Channel identifier 0x0003 is used for the Alternate MAC/PHY protocol when sending data at high speed is required. Channel identifier 0x003F is used for a test channel for the Alternate MAC/PHY controllers.
There are three Bluetooth low energy channels: Channel identifier 0x0004 is used for the Attribute Protocol (for more information on this, go to Chapter 10, Attributes); Channel identifier 0x0005 is used for the Bluetooth low energy signaling channel; Channel identifier 0x0006 is used for the Security Manager (for more information on this, go to Chapter 11, Security). All the other channel identifiers from 0x0007 to 0x003E are reserved, and channel identifiers from 0x0040 to 0xFFFF can be used for connection-oriented channels.
Each L2CAP packet contains a 32-bit header followed by its payload. It is assumed that segmentation and reassembly is used; thus, the length of the packet must be included in the packet header so that the end of the packet can be determined. The segmentation and reassembly scheme used requires the marking of packets over the HCI interface (for more information on this, go to Chapter 8, The Host Controller Interface) as well as within each transmitted packet as either a start or continuation packet. There is no way to denote that a given L2CAP packet segment is the end of the current packet. This means that the only way to determine if the current packet is complete is to either send a new packet, assuming that one is ready to be sent, or to include the packet length in the very first packet sent.
As shown in Figure 9–1, the header contains a 2-byte length field followed by the 2-byte channel identifier. This is followed by length bytes of information payload. In Bluetooth classic, the information payload can also include additional headers and information, but in Bluetooth low energy, there are no other structures of significance at the L2CAP layer.
For all Bluetooth low energy channels, the information payload starts with a Maximum Transmission Unit (MTU) size of 23 bytes. MTU is the largest possible size for the information payload in a given L2CAP channel. This means that all Bluetooth low energy devices must support 27-byte packets over the air—4 bytes of the L2CAP header and 23 bytes for the information payload.
The LE signaling channel is used for signaling at the host level. As illustrated in Figure 9–2, each LE signaling channel packet contains a single opcode, followed by any parameters. The following command opcodes are supported on the LE signaling channel:
• Command Reject
• Connection Parameter Update Request
• Connection Parameter Update Response
Whenever a signaling command is sent, an identifier is included in the information payload. This identifier is just 1 byte in length and is used to match responses with requests. For example, if a request was sent with the identifier 0x35, any response that also had the same identifier 0x35 would be the response for that request. This allows multiple requests to be outstanding at the same time, with each request having a different identifier. Identifiers can’t be reused unless all other identifiers have been used. This leads implementations to use an increment operation to ensure this rule is met. There is just one exception to this: An identifier with the value 0x00 is never used. A side effect of the use of identifiers is that duplicate commands can be silently dropped. This would be useful if the command channels were unreliable, but they are always sent on a reliable bearer, so this rule is rarely invoked.
In Bluetooth low energy, because only one request has been defined, and because this request can only be sent when no other request is outstanding, the logic for identifiers is very simple.
The command reject command is used to reject any nonsupported message that was received by the device. This command is identical to the Bluetooth classic command reject command. It contains a reason code and can contain some data. The reason code can be either Command not understood or Signaling MTU exceeded.
The Command not understood reason code is used when a command was sent to the device that it does not support. This should be sent even for command codes that are not defined at the moment; this allows a device to be forward-compatible with future versions of the specifications.
The Signaling MTU exceeded reason code is used when a command is received that is longer than 23 bytes. The default MTU for the signaling channel is just 23 bytes, so if a command were received that was 24 bytes or more, the command reject would be sent in reply.
In Bluetooth classic, another reason code is defined, Invalid CID in request, but because no commands are defined that use a channel identifier in Bluetooth low energy, this reason code has never been used.
The connection parameter update request command provides the slave device with the ability to ask for the Link Layer connection parameters to be updated, as demonstrated in Figure 9–3. These parameters include how often the slave wants the master to allow the slave to transmit, the connection event interval, and often the slave wants to be able to ignore the master, the slave latency, and the supervision timeout.
This command would be used when the slave is in a connection for which it wants to modify current connection parameters. For example, the connection event interval might be too fast and therefore wasting too much power. This would not be a problem if the slave latency were reasonably high, but if this is not true, then the slave would have to listen very frequently. Sometimes this is useful, for example, when the devices are first bonding and sending many messages between one another, discovering the services and characteristics of the device. But many other times, having the ability to minimize the number of connection events when the slave has to listen is vitally important for efficient battery life.
This command is only usefully sent from the slave to the master; the master can always initiate a Link Layer connection parameter update control procedure at any time (see Section 7.10.1 in Chapter 7). If the command is sent by the master, the slave would consider it an error and would respond with a Command Reject command with the reason code Command not understood.
The slave can send this command at any time. If the master receives the message and can change the connection parameters, it will respond with a Connection Parameter Update Response with a result code set to accepted. The master will also initiate the Link Layer connection parameter update control procedure.
Of course, this is just a request, and if the master doesn’t like the parameters that the slave wanted, it can reject the request by sending a Connection Parameter Update Response with the result code set to rejected. The slave then has two options: accept that the master wants or needs the connection parameters that it is currently using, or terminate the connection. Terminating the connection might appear at first glance to be a fairly drastic approach, but if the slave would burn through its battery in a week with the current connection parameters but would last for years with its requested connection parameters, it might have only one logical choice available.
To reduce the probability of having the master reject the connection parameters from the slave, the slave can request a range of connection event intervals that would be acceptable. A well-designed slave would willingly accept a wide range of intervals. A master device might also be doing some other activities such as a low latency conversational audio connection or a high-quality audio connection and is therefore severely restricted in the range of connection intervals that it can accept. The set of intervals it can accept might be different depending on what it is currently doing, so it might not be the same as the last time the two devices connected.
Another way to increase the chance that the master will accept the connection parameters is to have a reasonably sized slave latency. The master can then choose the most suitable connection event interval, and the slave can then use a slave latency that gives it the best power consumption. For example, if the slave wants to synchronize every 600 milliseconds, it could request a connection interval range of between 100 milliseconds and 750 milliseconds, with a slave latency of 5. If the master chooses 100 milliseconds, the slave could synchronize every 6 connection events. If the master chooses 200 milliseconds, then the slave could ignore 2 out of every 3 connection events, achieving its desired synchronization interval of 600 milliseconds. If the master chooses 300 milliseconds, the slave could ignore every other connection event. If the master chooses 400 milliseconds, the slave could synchronize every 400 milliseconds.