Zephyr Project
3.6.0

Contents

  • Introduction
  • Developing with Zephyr
  • Kernel
  • OS Services
  • Build and Configuration Systems
  • Connectivity
    • Bluetooth
      • Overview
      • Bluetooth Stack Architecture
      • Bluetooth Low Energy Controller
      • Bluetooth Audio Architecture
      • Bluetooth Qualification
      • Bluetooth tools
      • Developing Bluetooth Applications
      • AutoPTS on Windows 10 with nRF52 board
      • AutoPTS on Linux
      • Bluetooth APIs
        • Attribute Protocol (ATT)
        • Bluetooth Audio
        • Basic Audio Profile
        • Common Audio Profile
        • Connection Management
        • Bluetooth Controller
        • Bluetooth Coordinated Sets
        • Cryptography
        • Data Buffers
        • Generic Access Profile (GAP)
        • Generic Attribute Profile (GATT)
        • HCI Drivers
        • HCI RAW channel
        • Hands Free Profile (HFP)
        • Logical Link Control and Adaptation Protocol (L2CAP)
        • Bluetooth Media
        • Bluetooth Mesh Profile
        • Bluetooth Microphone Control
        • Serial Port Emulation (RFCOMM)
        • Bluetooth standard services
        • Service Discovery Protocol (SDP)
        • Bluetooth Audio Volume Control
        • Universal Unique Identifiers (UUIDs)
        • Bluetooth: Basic Audio Profile
        • Bluetooth: Broadcast Audio Profile Broadcast Assistant
        • Bluetooth: Broadcast Audio Profile Scan Delegator
        • Bluetooth: Common Audio Profile Shell
        • Bluetooth: Call Control Profile
        • Bluetooth: Coordinated Set Identification Profile
        • Bluetooth: Gaming Audio Profile Shell
        • Bluetooth: Isochronous Channels
        • Media control for Generic Audio Content Control
        • Bluetooth: Telephone and Media Audio Profile Shell
        • Bluetooth: Public Broadcast Profile Shell
      • Bluetooth Shell
    • Controller Area Network (CAN) Bus Protocols
    • Networking
    • LoRa and LoRaWAN
    • USB
  • Hardware Support
  • Contributing to Zephyr
  • Project and Governance
  • Security
  • Safety
  • Samples and Demos
  • Supported Boards
  • Releases
Zephyr Project
  • Connectivity
  • Bluetooth
  • Bluetooth APIs
  • Logical Link Control and Adaptation Protocol (L2CAP)
  • View page source

Logical Link Control and Adaptation Protocol (L2CAP)

L2CAP layer enables connection-oriented channels which can be enable with the configuration option: CONFIG_BT_L2CAP_DYNAMIC_CHANNEL. This channels support segmentation and reassembly transparently, they also support credit based flow control making it suitable for data streams.

Channels instances are represented by the bt_l2cap_chan struct which contains the callbacks in the bt_l2cap_chan_ops struct to inform when the channel has been connected, disconnected or when the encryption has changed. In addition to that it also contains the recv callback which is called whenever an incoming data has been received. Data received this way can be marked as processed by returning 0 or using bt_l2cap_chan_recv_complete() API if processing is asynchronous.

Note

The recv callback is called directly from RX Thread thus it is not recommended to block for long periods of time.

For sending data the bt_l2cap_chan_send() API can be used noting that it may block if no credits are available, and resuming as soon as more credits are available.

Servers can be registered using bt_l2cap_server_register() API passing the bt_l2cap_server struct which informs what psm it should listen to, the required security level sec_level, and the callback accept which is called to authorize incoming connection requests and allocate channel instances.

Client channels can be initiated with use of bt_l2cap_chan_connect() API and can be disconnected with the bt_l2cap_chan_disconnect() API. Note that the later can also disconnect channel instances created by servers.

API Reference

group bt_l2cap

L2CAP.

Defines

BT_L2CAP_HDR_SIZE

L2CAP PDU header size, used for buffer size calculations.

BT_L2CAP_TX_MTU

Maximum Transmission Unit (MTU) for an outgoing L2CAP PDU.

BT_L2CAP_RX_MTU

Maximum Transmission Unit (MTU) for an incoming L2CAP PDU.

BT_L2CAP_BUF_SIZE(mtu)

Helper to calculate needed buffer size for L2CAP PDUs.

Useful for creating buffer pools.

Parameters:
  • mtu – Needed L2CAP PDU MTU.

Returns:

Needed buffer size to match the requested L2CAP PDU MTU.

BT_L2CAP_SDU_HDR_SIZE

L2CAP SDU header size, used for buffer size calculations.

BT_L2CAP_SDU_TX_MTU

Maximum Transmission Unit for an unsegmented outgoing L2CAP SDU.

The Maximum Transmission Unit for an outgoing L2CAP SDU when sent without segmentation, i.e. a single L2CAP SDU will fit inside a single L2CAP PDU.

The MTU for outgoing L2CAP SDUs with segmentation is defined by the size of the application buffer pool.

BT_L2CAP_SDU_RX_MTU

Maximum Transmission Unit for an unsegmented incoming L2CAP SDU.

The Maximum Transmission Unit for an incoming L2CAP SDU when sent without segmentation, i.e. a single L2CAP SDU will fit inside a single L2CAP PDU.

The MTU for incoming L2CAP SDUs with segmentation is defined by the size of the application buffer pool. The application will have to define an alloc_buf callback for the channel in order to support receiving segmented L2CAP SDUs.

BT_L2CAP_SDU_BUF_SIZE(mtu)

Helper to calculate needed buffer size for L2CAP SDUs.

Useful for creating buffer pools.

Parameters:
  • mtu – Required BT_L2CAP_*_SDU.

Returns:

Needed buffer size to match the requested L2CAP SDU MTU.

BT_L2CAP_LE_CHAN(_ch)

Helper macro getting container object of type bt_l2cap_le_chan address having the same container chan member address as object in question.

Parameters:
  • _ch – Address of object of bt_l2cap_chan type

Returns:

Address of in memory bt_l2cap_le_chan object type containing the address of in question object.

BT_L2CAP_CHAN_SEND_RESERVE

Headroom needed for outgoing L2CAP PDUs.

BT_L2CAP_SDU_CHAN_SEND_RESERVE

Headroom needed for outgoing L2CAP SDUs.

Typedefs

typedef void (*bt_l2cap_chan_destroy_t)(struct bt_l2cap_chan *chan)

Channel destroy callback.

Param chan:

Channel object.

typedef enum bt_l2cap_chan_state bt_l2cap_chan_state_t

Life-span states of L2CAP CoC channel.

Used only by internal APIs dealing with setting channel to proper state depending on operational context.

A channel enters the BT_L2CAP_CONNECTING state upon bt_l2cap_chan_connect, bt_l2cap_ecred_chan_connect or upon returning from bt_l2cap_server::accept.

When a channel leaves the BT_L2CAP_CONNECTING state, bt_l2cap_chan_ops::connected is called.

typedef enum bt_l2cap_chan_status bt_l2cap_chan_status_t

Status of L2CAP channel.

Enums

enum bt_l2cap_chan_state

Life-span states of L2CAP CoC channel.

Used only by internal APIs dealing with setting channel to proper state depending on operational context.

A channel enters the BT_L2CAP_CONNECTING state upon bt_l2cap_chan_connect, bt_l2cap_ecred_chan_connect or upon returning from bt_l2cap_server::accept.

When a channel leaves the BT_L2CAP_CONNECTING state, bt_l2cap_chan_ops::connected is called.

Values:

enumerator BT_L2CAP_DISCONNECTED

Channel disconnected.

enumerator BT_L2CAP_CONNECTING

Channel in connecting state.

enumerator BT_L2CAP_CONFIG

Channel in config state, BR/EDR specific.

enumerator BT_L2CAP_CONNECTED

Channel ready for upper layer traffic on it.

enumerator BT_L2CAP_DISCONNECTING

Channel in disconnecting state.

enum bt_l2cap_chan_status

Status of L2CAP channel.

Values:

enumerator BT_L2CAP_STATUS_OUT

Channel can send at least one PDU.

enumerator BT_L2CAP_STATUS_SHUTDOWN

Channel shutdown status.

   Once this status is notified it means the channel will no longer be
   able to transmit or receive data.
enumerator BT_L2CAP_STATUS_ENCRYPT_PENDING

Channel encryption pending status.

enumerator BT_L2CAP_NUM_STATUS

Functions

int bt_l2cap_server_register(struct bt_l2cap_server *server)

Register L2CAP server.

Register L2CAP server for a PSM, each new connection is authorized using the accept() callback which in case of success shall allocate the channel structure to be used by the new connection.

For fixed, SIG-assigned PSMs (in the range 0x0001-0x007f) the PSM should be assigned to server->psm before calling this API. For dynamic PSMs (in the range 0x0080-0x00ff) server->psm may be pre-set to a given value (this is however not recommended) or be left as 0, in which case upon return a newly allocated value will have been assigned to it. For dynamically allocated values the expectation is that it’s exposed through a GATT service, and that’s how L2CAP clients discover how to connect to the server.

Parameters:
  • server – Server structure.

Returns:

0 in case of success or negative value in case of error.

int bt_l2cap_br_server_register(struct bt_l2cap_server *server)

Register L2CAP server on BR/EDR oriented connection.

Register L2CAP server for a PSM, each new connection is authorized using the accept() callback which in case of success shall allocate the channel structure to be used by the new connection.

Parameters:
  • server – Server structure.

Returns:

0 in case of success or negative value in case of error.

int bt_l2cap_ecred_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan **chans, uint16_t psm)

Connect Enhanced Credit Based L2CAP channels.

Connect up to 5 L2CAP channels by PSM, once the connection is completed each channel connected() callback will be called. If the connection is rejected disconnected() callback is called instead.

Parameters:
  • conn – Connection object.

  • chans – Array of channel objects.

  • psm – Channel PSM to connect to.

Returns:

0 in case of success or negative value in case of error.

int bt_l2cap_ecred_chan_reconfigure(struct bt_l2cap_chan **chans, uint16_t mtu)

Reconfigure Enhanced Credit Based L2CAP channels.

Reconfigure up to 5 L2CAP channels. Channels must be from the same bt_conn. Once reconfiguration is completed each channel reconfigured() callback will be called. MTU cannot be decreased on any of provided channels.

Parameters:
  • chans – Array of channel objects. Null-terminated. Elements after the first 5 are silently ignored.

  • mtu – Channel MTU to reconfigure to.

Returns:

0 in case of success or negative value in case of error.

int bt_l2cap_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan, uint16_t psm)

Connect L2CAP channel.

Connect L2CAP channel by PSM, once the connection is completed channel connected() callback will be called. If the connection is rejected disconnected() callback is called instead. Channel object passed (over an address of it) as second parameter shouldn’t be instantiated in application as standalone. Instead of, application should create transport dedicated L2CAP objects, i.e. type of bt_l2cap_le_chan for LE and/or type of bt_l2cap_br_chan for BR/EDR. Then pass to this API the location (address) of bt_l2cap_chan type object which is a member of both transport dedicated objects.

Parameters:
  • conn – Connection object.

  • chan – Channel object.

  • psm – Channel PSM to connect to.

Returns:

0 in case of success or negative value in case of error.

int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan)

Disconnect L2CAP channel.

Disconnect L2CAP channel, if the connection is pending it will be canceled and as a result the channel disconnected() callback is called. Regarding to input parameter, to get details see reference description to bt_l2cap_chan_connect() API above.

Parameters:
  • chan – Channel object.

Returns:

0 in case of success or negative value in case of error.

int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf)

Send data to L2CAP channel.

Send data from buffer to the channel. If credits are not available, buf will be queued and sent as and when credits are received from peer. Regarding to first input parameter, to get details see reference description to bt_l2cap_chan_connect() API above.

When sending L2CAP data over an BR/EDR connection the application is sending L2CAP PDUs. The application is required to have reserved BT_L2CAP_CHAN_SEND_RESERVE bytes in the buffer before sending. The application should use the BT_L2CAP_BUF_SIZE() helper to correctly size the buffers for the for the outgoing buffer pool.

When sending L2CAP data over an LE connection the application is sending L2CAP SDUs. The application shall reserve BT_L2CAP_SDU_CHAN_SEND_RESERVE bytes in the buffer before sending.

The application can use the BT_L2CAP_SDU_BUF_SIZE() helper to correctly size the buffer to account for the reserved headroom.

When segmenting an L2CAP SDU into L2CAP PDUs the stack will first attempt to allocate buffers from the channel’s alloc_seg callback and will fallback on the stack’s global buffer pool (sized CONFIG_BT_L2CAP_TX_BUF_COUNT ).

Note

Buffer ownership is transferred to the stack in case of success, in case of an error the caller retains the ownership of the buffer.

Returns:

0 in case of success or negative value in case of error.

Returns:

-EINVAL if buf or chan is NULL.

Returns:

-EINVAL if chan is not either BR/EDR or LE credit-based.

Returns:

-EINVAL if buffer doesn’t have enough bytes reserved to fit header.

Returns:

-EMSGSIZE if buf is larger than chan’s MTU.

Returns:

-ENOTCONN if underlying conn is disconnected.

Returns:

-ESHUTDOWN if L2CAP channel is disconnected.

Returns:

-other (from lower layers) if chan is BR/EDR.

int bt_l2cap_chan_give_credits(struct bt_l2cap_chan *chan, uint16_t additional_credits)

Give credits to the remote.

Only available for channels using bt_l2cap_chan_ops::seg_recv. CONFIG_BT_L2CAP_SEG_RECV must be enabled to make this function available.

Each credit given allows the peer to send one segment.

This function depends on a valid chan object. Make sure to default-initialize or memset chan when allocating or reusing it for new connections.

Adding zero credits is not allowed.

Credits can be given before entering the BT_L2CAP_CONNECTING state. Doing so will adjust the ‘initial credits’ sent in the connection PDU.

Must not be called while the channel is in BT_L2CAP_CONNECTING state.

Returns:

0 in case of success or negative value in case of error.

int bt_l2cap_chan_recv_complete(struct bt_l2cap_chan *chan, struct net_buf *buf)

Complete receiving L2CAP channel data.

Complete the reception of incoming data. This shall only be called if the channel recv callback has returned -EINPROGRESS to process some incoming data. The buffer shall contain the original user_data as that is used for storing the credits/segments used by the packet.

Parameters:
  • chan – Channel object.

  • buf – Buffer containing the data.

Returns:

0 in case of success or negative value in case of error.

struct bt_l2cap_chan
#include <l2cap.h>

L2CAP Channel structure.

Public Members

struct bt_conn *conn

Channel connection reference.

const struct bt_l2cap_chan_ops *ops

Channel operations reference.

struct bt_l2cap_le_endpoint
#include <l2cap.h>

LE L2CAP Endpoint structure.

Public Members

uint16_t cid

Endpoint Channel Identifier (CID)

uint16_t mtu

Endpoint Maximum Transmission Unit.

uint16_t mps

Endpoint Maximum PDU payload Size.

uint16_t init_credits

Endpoint initial credits.

atomic_t credits

Endpoint credits.

struct bt_l2cap_le_chan
#include <l2cap.h>

LE L2CAP Channel structure.

Public Members

struct bt_l2cap_chan chan

Common L2CAP channel reference object.

struct bt_l2cap_le_endpoint rx

Channel Receiving Endpoint.

If the application has set an alloc_buf channel callback for the channel to support receiving segmented L2CAP SDUs the application should inititalize the MTU of the Receiving Endpoint. Otherwise the MTU of the receiving endpoint will be initialized to BT_L2CAP_SDU_RX_MTU by the stack.

This is the source of the MTU, MPS and credit values when sending L2CAP_LE_CREDIT_BASED_CONNECTION_REQ/RSP and L2CAP_CONFIGURATION_REQ.

uint16_t pending_rx_mtu

Pending RX MTU on ECFC reconfigure, used internally by stack.

struct bt_l2cap_le_endpoint tx

Channel Transmission Endpoint.

This is an image of the remote’s rx.

The MTU and MPS is controlled by the remote by L2CAP_LE_CREDIT_BASED_CONNECTION_REQ/RSP or L2CAP_CONFIGURATION_REQ.

struct bt_l2cap_br_endpoint
#include <l2cap.h>

BREDR L2CAP Endpoint structure.

Public Members

uint16_t cid

Endpoint Channel Identifier (CID)

uint16_t mtu

Endpoint Maximum Transmission Unit.

struct bt_l2cap_br_chan
#include <l2cap.h>

BREDR L2CAP Channel structure.

Public Members

struct bt_l2cap_chan chan

Common L2CAP channel reference object.

struct bt_l2cap_br_endpoint rx

Channel Receiving Endpoint.

struct bt_l2cap_br_endpoint tx

Channel Transmission Endpoint.

uint16_t psm

Remote PSM to be connected.

uint8_t ident

Helps match request context during CoC.

struct bt_l2cap_chan_ops
#include <l2cap.h>

L2CAP Channel operations structure.

Public Members

void (*connected)(struct bt_l2cap_chan *chan)

Channel connected callback.

If this callback is provided it will be called whenever the connection completes.

Param chan:

The channel that has been connected

void (*disconnected)(struct bt_l2cap_chan *chan)

Channel disconnected callback.

If this callback is provided it will be called whenever the channel is disconnected, including when a connection gets rejected.

Param chan:

The channel that has been Disconnected

void (*encrypt_change)(struct bt_l2cap_chan *chan, uint8_t hci_status)

Channel encrypt_change callback.

If this callback is provided it will be called whenever the security level changed (indirectly link encryption done) or authentication procedure fails. In both cases security initiator and responder got the final status (HCI status) passed by related to encryption and authentication events from local host’s controller.

Param chan:

The channel which has made encryption status changed.

Param status:

HCI status of performed security procedure caused by channel security requirements. The value is populated by HCI layer and set to 0 when success and to non-zero (reference to HCI Error Codes) when security/authentication failed.

struct net_buf *(*alloc_seg)(struct bt_l2cap_chan *chan)

Channel alloc_seg callback.

If this callback is provided the channel will use it to allocate buffers to store segments. This avoids wasting big SDU buffers with potentially much smaller PDUs. If this callback is supplied, it must return a valid buffer.

Param chan:

The channel requesting a buffer.

Return:

Allocated buffer.

struct net_buf *(*alloc_buf)(struct bt_l2cap_chan *chan)

Channel alloc_buf callback.

If this callback is provided the channel will use it to allocate buffers to store incoming data. Channels that requires segmentation must set this callback. If the application has not set a callback the L2CAP SDU MTU will be truncated to BT_L2CAP_SDU_RX_MTU.

Param chan:

The channel requesting a buffer.

Return:

Allocated buffer.

int (*recv)(struct bt_l2cap_chan *chan, struct net_buf *buf)

Channel recv callback.

Param chan:

The channel receiving data.

Param buf:

Buffer containing incoming data.

Return:

0 in case of success or negative value in case of error.

Return:

-EINPROGRESS in case where user has to confirm once the data has been processed by calling bt_l2cap_chan_recv_complete passing back the buffer received with its original user_data which contains the number of segments/credits used by the packet.

void (*sent)(struct bt_l2cap_chan *chan)

Channel sent callback.

This callback will be called once the controller marks the SDU as completed. When the controller does so is implementation dependent. It could be after the SDU is enqueued for transmission, or after it is sent on air.

Param chan:

The channel which has sent data.

void (*status)(struct bt_l2cap_chan *chan, atomic_t *status)

Channel status callback.

If this callback is provided it will be called whenever the channel status changes.

Param chan:

The channel which status changed

Param status:

The channel status

void (*reconfigured)(struct bt_l2cap_chan *chan)

Channel reconfigured callback.

If this callback is provided it will be called whenever peer or local device requested reconfiguration. Application may check updated MTU and MPS values by inspecting chan->le endpoints.

Param chan:

The channel which was reconfigured

void (*seg_recv)(struct bt_l2cap_chan *chan, size_t sdu_len, off_t seg_offset, struct net_buf_simple *seg)

Handle L2CAP segments directly.

This is an alternative to bt_l2cap_chan_ops::recv. They cannot be used together.

This is called immediately for each received segment.

Unlike with bt_l2cap_chan_ops::recv, flow control is explicit. Each time this handler is invoked, the remote has permanently used up one credit. Use bt_l2cap_chan_give_credits to give credits.

The start of an SDU is marked by seg_offset == 0. The end of an SDU is marked by seg_offset + seg->len == sdu_len.

The stack guarantees that:

  • The sender had the credit.

  • The SDU length does not exceed MTU.

  • The segment length does not exceed MPS.

Additionally, the L2CAP protocol is such that:

  • Segments come in order.

  • SDUs cannot be interleaved or aborted halfway.

Note

With this alternative API, the application is responsible for setting the RX MTU and MPS. The MPS must not exceed BT_L2CAP_RX_MTU.

Param chan:

The receiving channel.

Param sdu_len:

Byte length of the SDU this segment is part of.

Param seg_offset:

The byte offset of this segment in the SDU.

Param seg:

The segment payload.

struct bt_l2cap_server
#include <l2cap.h>

L2CAP Server structure.

Public Members

uint16_t psm

Server PSM.

Possible values: 0 A dynamic value will be auto-allocated when bt_l2cap_server_register() is called.

0x0001-0x007f Standard, Bluetooth SIG-assigned fixed values.

0x0080-0x00ff Dynamically allocated. May be pre-set by the application before server registration (not recommended however), or auto-allocated by the stack if the app gave 0 as the value.

bt_security_t sec_level

Required minimum security level.

int (*accept)(struct bt_conn *conn, struct bt_l2cap_server *server, struct bt_l2cap_chan **chan)

Server accept callback.

This callback is called whenever a new incoming connection requires authorization.

Param conn:

The connection that is requesting authorization

Param server:

Pointer to the server structure this callback relates to

Param chan:

Pointer to received the allocated channel

Return:

0 in case of success or negative value in case of error.

Return:

-ENOMEM if no available space for new channel.

Return:

-EACCES if application did not authorize the connection.

Return:

-EPERM if encryption key size is too short.

Next Previous

© Copyright 2015-2024 Zephyr Project members and individual contributors. Last updated on Aug 04, 2024.

Zephyr Project
Bridle
Bridle API
Zephyr Project API
Kconfig Reference
Devicetree Bindings