haiku/headers/private/bluetooth/l2cap.h
Augustin Cavalier bb83316a58 L2CAP: Major refactor of the whole component.
(And surrounding portions of the "btCoreData" module.)

 * Rewrote the main "l2cap.h" header representing protocol constants
   and structures. Now conforms to general Haiku naming conventions
   rather than BSD ones. Some more constants added/removed based
   on the most recent Bluetooth specification.

 * Rewrote all code derived from the BSDs to match Haiku conventions
   and structures in the driver.

 * Dropped the "channel" and "frame" structures from "btCoreData".
   Channels are now managed by L2capEndpoints, and "frames" are
   now just plain net_buffers without surrounding structures.
   This also makes state management much simpler.

 * Made it so that actual net_buffers are passed through to the
   l2cap_receive function rather than another data structure.
   A fake interface address is used to communicate connection
   information. (This probably ought to be changed, though.)

 * Get rid of l2cap_lower and l2cap_upper abstractions.
   Everything related to channel/endpoint management is now
   done in L2capEndpoint, while buffer reception is handled
   directly in l2cap_receive and elsewhere, same as other drivers.

 * Wire up more hooks and fix module flags (needed to be able to
   get the module loaded and opening sockets at all.)

 * Implement an actual locking strategy in L2capEndpoint
   and HciConnection. There's still problems with lifetime
   management, but at least thread-safety is mostly handled.

 * Create an L2capEndpointManager and use it to manage
   the endpoints, rather than having a single (unsafe)
   linked-list.

And plenty of other refactorings and cleanups besides.
There's still more to be done for Bluetooth overall, though:

 * The "btCoreData" and "hci" modules also badly need a major
   overhaul, and should be merged into a single "bluetooth"
   bus_manager. They also shouldn't be passing around pointers
   to other modules like this.

 * There's a number of TODOs/FIXMEs in the L2CAP module, most
   notably around timeouts (especially command timeouts) and
   parameter validation/specification.

Tested by myself with kallisti5's help. Incoming connections
(on the PSM for SDP) get all the way to the latter half
of the Configuration step before hanging.
2024-05-01 00:25:43 -04:00

229 lines
6.2 KiB
C

/*
* Copyright 2024, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _L2CAP_H_
#define _L2CAP_H_
#include <bluetooth/bluetooth.h>
/* Channel IDs */
/*! These are unique for a unit. Thus the total number of channels that a unit
* can have open simultaneously is (L2CAP_LAST_CID - L2CAP_FIRST_CID) = 65471.
* (This does not depend on the number of connections.) */
#define L2CAP_NULL_CID 0x0000
#define L2CAP_SIGNALING_CID 0x0001
#define L2CAP_CONNECTIONLESS_CID 0x0002
/* 0x0003-0x003f: reserved */
#define L2CAP_FIRST_CID 0x0040
#define L2CAP_LAST_CID 0xffff
/* Idents */
/*! Command idents are unique within a connection, since there is only one
* L2CAP_SIGNALING_CID. Thus only (L2CAP_LAST_IDENT - L2CAP_FIRST_IDENT),
* i.e. 254, commands can be pending simultaneously for a connection. */
#define L2CAP_NULL_IDENT 0x00
#define L2CAP_FIRST_IDENT 0x01
#define L2CAP_LAST_IDENT 0xff
/* MTU */
#define L2CAP_MTU_MINIMUM 48
#define L2CAP_MTU_DEFAULT 672
#define L2CAP_MTU_MAXIMUM 0xffff
/* Timeouts */
#define L2CAP_FLUSH_TIMEOUT_DEFAULT 0xffff /* always retransmit */
#define L2CAP_LINK_TIMEOUT_DEFAULT 0xffff
/* Protocol/Service Multiplexer (PSM) values */
#define L2CAP_PSM_ANY 0x0000 /* Any/Invalid PSM */
#define L2CAP_PSM_SDP 0x0001 /* Service Discovery Protocol */
#define L2CAP_PSM_RFCOMM 0x0003 /* RFCOMM protocol */
#define L2CAP_PSM_TCS_BIN 0x0005 /* Telephony Control Protocol */
#define L2CAP_PSM_TCS_BIN_CORDLESS 0x0007 /* TCS cordless */
#define L2CAP_PSM_BNEP 0x000F /* BNEP */
#define L2CAP_PSM_HID_CTRL 0x0011 /* HID control */
#define L2CAP_PSM_HID_INT 0x0013 /* HID interrupt */
#define L2CAP_PSM_UPnP 0x0015 /* UPnP (ESDP) */
#define L2CAP_PSM_AVCTP 0x0017 /* AVCTP */
#define L2CAP_PSM_AVDTP 0x0019 /* AVDTP */
/* < 0x1000: reserved */
/* >= 0x1000: dynamically assigned */
typedef struct {
uint16 length; /* payload size */
uint16 dcid; /* destination channel ID */
} _PACKED l2cap_basic_header;
/* Connectionless traffic ("CLT") */
typedef struct {
/* dcid == L2CAP_CONNECTIONLESS_CID (0x2) */
uint16 psm;
} _PACKED l2cap_connectionless_header;
#define L2CAP_CONNECTIONLESS_MTU_MAXIMUM (L2CAP_MTU_MAXIMUM - sizeof(l2cap_connectionless_header))
typedef struct {
uint8 code; /* command opcode */
#define L2CAP_IS_SIGNAL_REQ(code) (((code) & 1) == 0)
#define L2CAP_IS_SIGNAL_RSP(code) (((code) & 1) == 1)
uint8 ident; /* identifier to match request and response */
uint16 length; /* command parameters length */
} _PACKED l2cap_command_header;
#define L2CAP_COMMAND_REJECT_RSP 0x01
typedef struct {
enum : uint16 {
REJECTED_NOT_UNDERSTOOD = 0x0000,
REJECTED_MTU_EXCEEDED = 0x0001,
REJECTED_INVALID_CID = 0x0002,
/* 0x0003-0xffff: reserved */
}; uint16 reason;
/* data may follow */
} _PACKED l2cap_command_reject;
typedef union {
struct {
uint16 mtu; /* actual signaling MTU */
} _PACKED mtu_exceeded;
struct {
uint16 scid; /* source (local) CID */
uint16 dcid; /* destination (remote) CID */
} _PACKED invalid_cid;
} l2cap_command_reject_data;
#define L2CAP_CONNECTION_REQ 0x02
typedef struct {
uint16 psm;
uint16 scid; /* source channel ID */
} _PACKED l2cap_connection_req;
#define L2CAP_CONNECTION_RSP 0x03
typedef struct {
uint16 dcid; /* destination channel ID */
uint16 scid; /* source channel ID */
enum : uint16 {
RESULT_SUCCESS = 0x0000,
RESULT_PENDING = 0x0001,
RESULT_PSM_NOT_SUPPORTED = 0x0002,
RESULT_SECURITY_BLOCK = 0x0003,
RESULT_NO_RESOURCES = 0x0004,
RESULT_INVALID_SCID = 0x0005,
RESULT_SCID_ALREADY_ALLOCATED = 0x0006,
/* 0x0007-0xffff: reserved */
}; uint16 result;
enum : uint16 {
NO_STATUS_INFO = 0x0000,
STATUS_AUTHENTICATION_PENDING = 0x0001,
STATUS_AUTHORIZATION_PENDING = 0x0002,
/* 0x0003-0xffff: reserved */
}; uint16 status; /* only defined if result = pending */
} _PACKED l2cap_connection_rsp;
#define L2CAP_CONFIGURATION_REQ 0x04
typedef struct {
uint16 dcid; /* destination channel ID */
uint16 flags;
/* options may follow */
} _PACKED l2cap_configuration_req;
#define L2CAP_CONFIGURATION_RSP 0x05
typedef struct {
uint16 scid; /* source channel ID */
uint16 flags;
#define L2CAP_CFG_FLAG_CONTINUATION 0x0001
enum : uint16 {
RESULT_SUCCESS = 0x0000,
RESULT_UNACCEPTABLE_PARAMS = 0x0001,
RESULT_REJECTED = 0x0002,
RESULT_UNKNOWN_OPTION = 0x0003,
RESULT_PENDING = 0x0004,
RESULT_FLOW_SPEC_REJECTED = 0x0005,
/* 0x0006-0xffff: reserved */
}; uint16 result;
/* options may follow */
} _PACKED l2cap_configuration_rsp;
typedef struct {
enum : uint8 {
OPTION_MTU = 0x01,
OPTION_FLUSH_TIMEOUT = 0x02,
OPTION_QOS = 0x03,
OPTION_HINT_BIT = 0x80,
}; uint8 type;
uint8 length;
/* value follows */
} _PACKED l2cap_configuration_option;
typedef struct {
uint8 flags; /* reserved for future use */
uint8 service_type; /* 1 = best effort */
uint32 token_rate; /* average bytes per second */
uint32 token_bucket_size; /* max burst bytes */
uint32 peak_bandwidth; /* bytes per second */
uint32 access_latency; /* microseconds */
uint32 delay_variation; /* microseconds */
} _PACKED l2cap_qos;
typedef union {
uint16 mtu;
uint16 flush_timeout;
l2cap_qos qos;
} l2cap_configuration_option_value;
#define L2CAP_DISCONNECTION_REQ 0x06
typedef struct {
uint16 dcid; /* destination channel ID */
uint16 scid; /* source channel ID */
} _PACKED l2cap_disconnection_req;
#define L2CAP_DISCONNECTION_RSP 0x07
typedef l2cap_disconnection_req l2cap_disconnection_rsp;
#define L2CAP_ECHO_REQ 0x08
#define L2CAP_ECHO_RSP 0x09
#define L2CAP_MAX_ECHO_SIZE \
(L2CAP_MTU_MAXIMUM - sizeof(l2cap_command_header))
#define L2CAP_INFORMATION_REQ 0x0a
typedef struct {
enum : uint16 {
TYPE_CONNECTIONLESS_MTU = 0x0001,
TYPE_EXTENDED_FEATURES = 0x0002,
TYPE_FIXED_CHANNELS = 0x0003,
/* 0x0004-0xffff: reserved */
}; uint16 type;
} _PACKED l2cap_information_req;
#define L2CAP_INFORMATION_RSP 0x0b
typedef struct {
uint16 type;
enum : uint16 {
RESULT_SUCCESS = 0x0000,
RESULT_NOT_SUPPORTED = 0x0001,
}; uint16 result;
/* data may follow */
} _PACKED l2cap_information_rsp;
typedef union {
uint16 mtu;
uint32 extended_features;
} _PACKED l2cap_information_rsp_data;
#endif /* _L2CAP_H_ */