xref: /haiku/headers/private/bluetooth/l2cap.h (revision bb83316a5811a550c4f850d07fa8e328e7ac0a94)
1696b8e46SOliver Ruiz Dorantes /*
2*bb83316aSAugustin Cavalier  * Copyright 2024, Haiku, Inc. All rights reserved.
3*bb83316aSAugustin Cavalier  * Distributed under the terms of the MIT License.
4696b8e46SOliver Ruiz Dorantes  */
5*bb83316aSAugustin Cavalier #ifndef _L2CAP_H_
6*bb83316aSAugustin Cavalier #define _L2CAP_H_
7696b8e46SOliver Ruiz Dorantes 
8696b8e46SOliver Ruiz Dorantes #include <bluetooth/bluetooth.h>
9696b8e46SOliver Ruiz Dorantes 
10696b8e46SOliver Ruiz Dorantes 
11*bb83316aSAugustin Cavalier /* Channel IDs */
12*bb83316aSAugustin Cavalier /*! These are unique for a unit. Thus the total number of channels that a unit
13*bb83316aSAugustin Cavalier  * can have open simultaneously is (L2CAP_LAST_CID - L2CAP_FIRST_CID) = 65471.
14*bb83316aSAugustin Cavalier  * (This does not depend on the number of connections.) */
15*bb83316aSAugustin Cavalier #define L2CAP_NULL_CID		0x0000
16*bb83316aSAugustin Cavalier #define L2CAP_SIGNALING_CID	0x0001
17*bb83316aSAugustin Cavalier #define L2CAP_CONNECTIONLESS_CID 0x0002
18*bb83316aSAugustin Cavalier 	/* 0x0003-0x003f: reserved */
19*bb83316aSAugustin Cavalier #define L2CAP_FIRST_CID		0x0040
20*bb83316aSAugustin Cavalier #define L2CAP_LAST_CID		0xffff
21696b8e46SOliver Ruiz Dorantes 
22696b8e46SOliver Ruiz Dorantes 
23*bb83316aSAugustin Cavalier /* Idents */
24*bb83316aSAugustin Cavalier /*! Command idents are unique within a connection, since there is only one
25*bb83316aSAugustin Cavalier  * L2CAP_SIGNALING_CID. Thus only (L2CAP_LAST_IDENT - L2CAP_FIRST_IDENT),
26*bb83316aSAugustin Cavalier  * i.e. 254, commands can be pending simultaneously for a connection. */
27*bb83316aSAugustin Cavalier #define L2CAP_NULL_IDENT		0x00
28*bb83316aSAugustin Cavalier #define L2CAP_FIRST_IDENT		0x01
29*bb83316aSAugustin Cavalier #define L2CAP_LAST_IDENT		0xff
30696b8e46SOliver Ruiz Dorantes 
31696b8e46SOliver Ruiz Dorantes 
32*bb83316aSAugustin Cavalier /* MTU */
33696b8e46SOliver Ruiz Dorantes #define L2CAP_MTU_MINIMUM		48
34696b8e46SOliver Ruiz Dorantes #define L2CAP_MTU_DEFAULT		672
35696b8e46SOliver Ruiz Dorantes #define L2CAP_MTU_MAXIMUM		0xffff
36696b8e46SOliver Ruiz Dorantes 
37696b8e46SOliver Ruiz Dorantes 
38*bb83316aSAugustin Cavalier /* Timeouts */
39*bb83316aSAugustin Cavalier #define L2CAP_FLUSH_TIMEOUT_DEFAULT	0xffff /* always retransmit */
40*bb83316aSAugustin Cavalier #define L2CAP_LINK_TIMEOUT_DEFAULT	0xffff
41696b8e46SOliver Ruiz Dorantes 
42*bb83316aSAugustin Cavalier 
43*bb83316aSAugustin Cavalier /* Protocol/Service Multiplexer (PSM) values */
44696b8e46SOliver Ruiz Dorantes #define L2CAP_PSM_ANY		0x0000	/* Any/Invalid PSM */
45696b8e46SOliver Ruiz Dorantes #define L2CAP_PSM_SDP		0x0001	/* Service Discovery Protocol */
46696b8e46SOliver Ruiz Dorantes #define L2CAP_PSM_RFCOMM	0x0003	/* RFCOMM protocol */
47*bb83316aSAugustin Cavalier #define L2CAP_PSM_TCS_BIN	0x0005	/* Telephony Control Protocol */
48*bb83316aSAugustin Cavalier #define L2CAP_PSM_TCS_BIN_CORDLESS 0x0007 /* TCS cordless */
49696b8e46SOliver Ruiz Dorantes #define L2CAP_PSM_BNEP		0x000F	/* BNEP */
50*bb83316aSAugustin Cavalier #define L2CAP_PSM_HID_CTRL	0x0011	/* HID control */
51*bb83316aSAugustin Cavalier #define L2CAP_PSM_HID_INT	0x0013	/* HID interrupt */
52696b8e46SOliver Ruiz Dorantes #define L2CAP_PSM_UPnP		0x0015	/* UPnP (ESDP) */
53696b8e46SOliver Ruiz Dorantes #define L2CAP_PSM_AVCTP		0x0017	/* AVCTP */
54696b8e46SOliver Ruiz Dorantes #define L2CAP_PSM_AVDTP		0x0019	/* AVDTP */
55*bb83316aSAugustin Cavalier 	/* < 0x1000: reserved */
56*bb83316aSAugustin Cavalier 	/* >= 0x1000: dynamically assigned */
57696b8e46SOliver Ruiz Dorantes 
58696b8e46SOliver Ruiz Dorantes 
59696b8e46SOliver Ruiz Dorantes typedef struct {
60696b8e46SOliver Ruiz Dorantes 	uint16	length;	/* payload size */
61696b8e46SOliver Ruiz Dorantes 	uint16	dcid;	/* destination channel ID */
62*bb83316aSAugustin Cavalier } _PACKED l2cap_basic_header;
63696b8e46SOliver Ruiz Dorantes 
64696b8e46SOliver Ruiz Dorantes 
65*bb83316aSAugustin Cavalier /* Connectionless traffic ("CLT") */
66696b8e46SOliver Ruiz Dorantes typedef struct {
67*bb83316aSAugustin Cavalier 	/* dcid == L2CAP_CONNECTIONLESS_CID (0x2) */
68*bb83316aSAugustin Cavalier 	uint16	psm;
69*bb83316aSAugustin Cavalier } _PACKED l2cap_connectionless_header;
70*bb83316aSAugustin Cavalier #define L2CAP_CONNECTIONLESS_MTU_MAXIMUM (L2CAP_MTU_MAXIMUM - sizeof(l2cap_connectionless_header))
71696b8e46SOliver Ruiz Dorantes 
72696b8e46SOliver Ruiz Dorantes 
73696b8e46SOliver Ruiz Dorantes typedef struct {
74*bb83316aSAugustin Cavalier 	uint8	code;   /* command opcode */
75*bb83316aSAugustin Cavalier #define L2CAP_IS_SIGNAL_REQ(code) (((code) & 1) == 0)
76*bb83316aSAugustin Cavalier #define L2CAP_IS_SIGNAL_RSP(code) (((code) & 1) == 1)
77696b8e46SOliver Ruiz Dorantes 	uint8	ident;  /* identifier to match request and response */
78696b8e46SOliver Ruiz Dorantes 	uint16	length; /* command parameters length */
79*bb83316aSAugustin Cavalier } _PACKED l2cap_command_header;
80696b8e46SOliver Ruiz Dorantes 
81*bb83316aSAugustin Cavalier #define L2CAP_COMMAND_REJECT_RSP	0x01
82696b8e46SOliver Ruiz Dorantes typedef struct {
83*bb83316aSAugustin Cavalier 	enum : uint16 {
84*bb83316aSAugustin Cavalier 		REJECTED_NOT_UNDERSTOOD	= 0x0000,
85*bb83316aSAugustin Cavalier 		REJECTED_MTU_EXCEEDED	= 0x0001,
86*bb83316aSAugustin Cavalier 		REJECTED_INVALID_CID	= 0x0002,
87*bb83316aSAugustin Cavalier 		/* 0x0003-0xffff: reserved */
88*bb83316aSAugustin Cavalier 	}; uint16 reason;
89*bb83316aSAugustin Cavalier 	/* data may follow */
90*bb83316aSAugustin Cavalier } _PACKED l2cap_command_reject;
91696b8e46SOliver Ruiz Dorantes 
92696b8e46SOliver Ruiz Dorantes typedef union {
93696b8e46SOliver Ruiz Dorantes 	struct {
94696b8e46SOliver Ruiz Dorantes 		uint16	mtu; /* actual signaling MTU */
95*bb83316aSAugustin Cavalier 	} _PACKED mtu_exceeded;
96696b8e46SOliver Ruiz Dorantes 	struct {
97*bb83316aSAugustin Cavalier 		uint16	scid; /* source (local) CID */
98*bb83316aSAugustin Cavalier 		uint16	dcid; /* destination (remote) CID */
99*bb83316aSAugustin Cavalier 	} _PACKED invalid_cid;
100*bb83316aSAugustin Cavalier } l2cap_command_reject_data;
101696b8e46SOliver Ruiz Dorantes 
102*bb83316aSAugustin Cavalier 
103*bb83316aSAugustin Cavalier #define L2CAP_CONNECTION_REQ	0x02
104696b8e46SOliver Ruiz Dorantes typedef struct {
105*bb83316aSAugustin Cavalier 	uint16	psm;
106696b8e46SOliver Ruiz Dorantes 	uint16	scid; /* source channel ID */
107*bb83316aSAugustin Cavalier } _PACKED l2cap_connection_req;
108696b8e46SOliver Ruiz Dorantes 
109*bb83316aSAugustin Cavalier #define L2CAP_CONNECTION_RSP	0x03
110696b8e46SOliver Ruiz Dorantes typedef struct {
111696b8e46SOliver Ruiz Dorantes 	uint16	dcid;   /* destination channel ID */
112696b8e46SOliver Ruiz Dorantes 	uint16	scid;   /* source channel ID */
113*bb83316aSAugustin Cavalier 	enum : uint16 {
114*bb83316aSAugustin Cavalier 		RESULT_SUCCESS					= 0x0000,
115*bb83316aSAugustin Cavalier 		RESULT_PENDING					= 0x0001,
116*bb83316aSAugustin Cavalier 		RESULT_PSM_NOT_SUPPORTED		= 0x0002,
117*bb83316aSAugustin Cavalier 		RESULT_SECURITY_BLOCK			= 0x0003,
118*bb83316aSAugustin Cavalier 		RESULT_NO_RESOURCES				= 0x0004,
119*bb83316aSAugustin Cavalier 		RESULT_INVALID_SCID				= 0x0005,
120*bb83316aSAugustin Cavalier 		RESULT_SCID_ALREADY_ALLOCATED	= 0x0006,
121*bb83316aSAugustin Cavalier 		/* 0x0007-0xffff: reserved */
122*bb83316aSAugustin Cavalier 	}; uint16 result;
123*bb83316aSAugustin Cavalier 	enum : uint16 {
124*bb83316aSAugustin Cavalier 		NO_STATUS_INFO					= 0x0000,
125*bb83316aSAugustin Cavalier 		STATUS_AUTHENTICATION_PENDING	= 0x0001,
126*bb83316aSAugustin Cavalier 		STATUS_AUTHORIZATION_PENDING	= 0x0002,
127*bb83316aSAugustin Cavalier 		/* 0x0003-0xffff: reserved */
128*bb83316aSAugustin Cavalier 	}; uint16 status; /* only defined if result = pending */
129*bb83316aSAugustin Cavalier } _PACKED l2cap_connection_rsp;
130696b8e46SOliver Ruiz Dorantes 
131*bb83316aSAugustin Cavalier 
132*bb83316aSAugustin Cavalier #define L2CAP_CONFIGURATION_REQ	0x04
133696b8e46SOliver Ruiz Dorantes typedef struct {
134696b8e46SOliver Ruiz Dorantes 	uint16	dcid;  /* destination channel ID */
135*bb83316aSAugustin Cavalier 	uint16	flags;
136*bb83316aSAugustin Cavalier 	/* options may follow */
137*bb83316aSAugustin Cavalier } _PACKED l2cap_configuration_req;
138696b8e46SOliver Ruiz Dorantes 
139*bb83316aSAugustin Cavalier #define L2CAP_CONFIGURATION_RSP	0x05
140696b8e46SOliver Ruiz Dorantes typedef struct {
141696b8e46SOliver Ruiz Dorantes 	uint16	scid;   /* source channel ID */
142*bb83316aSAugustin Cavalier 	uint16	flags;
143*bb83316aSAugustin Cavalier #define L2CAP_CFG_FLAG_CONTINUATION		0x0001
144*bb83316aSAugustin Cavalier 	enum : uint16 {
145*bb83316aSAugustin Cavalier 		RESULT_SUCCESS				= 0x0000,
146*bb83316aSAugustin Cavalier 		RESULT_UNACCEPTABLE_PARAMS	= 0x0001,
147*bb83316aSAugustin Cavalier 		RESULT_REJECTED				= 0x0002,
148*bb83316aSAugustin Cavalier 		RESULT_UNKNOWN_OPTION		= 0x0003,
149*bb83316aSAugustin Cavalier 		RESULT_PENDING				= 0x0004,
150*bb83316aSAugustin Cavalier 		RESULT_FLOW_SPEC_REJECTED	= 0x0005,
151*bb83316aSAugustin Cavalier 		/* 0x0006-0xffff: reserved */
152*bb83316aSAugustin Cavalier 	}; uint16 result;
153*bb83316aSAugustin Cavalier 	/* options may follow */
154*bb83316aSAugustin Cavalier } _PACKED l2cap_configuration_rsp;
155696b8e46SOliver Ruiz Dorantes 
156696b8e46SOliver Ruiz Dorantes typedef struct {
157*bb83316aSAugustin Cavalier 	enum : uint8 {
158*bb83316aSAugustin Cavalier 		OPTION_MTU				= 0x01,
159*bb83316aSAugustin Cavalier 		OPTION_FLUSH_TIMEOUT	= 0x02,
160*bb83316aSAugustin Cavalier 		OPTION_QOS				= 0x03,
161*bb83316aSAugustin Cavalier 
162*bb83316aSAugustin Cavalier 		OPTION_HINT_BIT			= 0x80,
163*bb83316aSAugustin Cavalier 	}; uint8 type;
164696b8e46SOliver Ruiz Dorantes 	uint8 length;
165*bb83316aSAugustin Cavalier 	/* value follows */
166*bb83316aSAugustin Cavalier } _PACKED l2cap_configuration_option;
167696b8e46SOliver Ruiz Dorantes 
168*bb83316aSAugustin Cavalier typedef struct {
169*bb83316aSAugustin Cavalier 	uint8 flags;				/* reserved for future use */
170*bb83316aSAugustin Cavalier 	uint8 service_type;			/* 1 = best effort */
171*bb83316aSAugustin Cavalier 	uint32 token_rate;			/* average bytes per second */
172*bb83316aSAugustin Cavalier 	uint32 token_bucket_size;	/* max burst bytes */
173*bb83316aSAugustin Cavalier 	uint32 peak_bandwidth;		/* bytes per second */
174*bb83316aSAugustin Cavalier 	uint32 access_latency;		/* microseconds */
175*bb83316aSAugustin Cavalier 	uint32 delay_variation;		/* microseconds */
176*bb83316aSAugustin Cavalier } _PACKED l2cap_qos;
177*bb83316aSAugustin Cavalier 
178696b8e46SOliver Ruiz Dorantes typedef union {
179*bb83316aSAugustin Cavalier 	uint16		mtu;
180*bb83316aSAugustin Cavalier 	uint16		flush_timeout;
181*bb83316aSAugustin Cavalier 	l2cap_qos	qos;
182*bb83316aSAugustin Cavalier } l2cap_configuration_option_value;
183696b8e46SOliver Ruiz Dorantes 
184*bb83316aSAugustin Cavalier 
185*bb83316aSAugustin Cavalier #define L2CAP_DISCONNECTION_REQ	0x06
186696b8e46SOliver Ruiz Dorantes typedef struct {
187696b8e46SOliver Ruiz Dorantes 	uint16	dcid; /* destination channel ID */
188696b8e46SOliver Ruiz Dorantes 	uint16	scid; /* source channel ID */
189*bb83316aSAugustin Cavalier } _PACKED l2cap_disconnection_req;
190696b8e46SOliver Ruiz Dorantes 
191*bb83316aSAugustin Cavalier #define L2CAP_DISCONNECTION_RSP	0x07
192*bb83316aSAugustin Cavalier typedef l2cap_disconnection_req l2cap_disconnection_rsp;
193696b8e46SOliver Ruiz Dorantes 
194*bb83316aSAugustin Cavalier 
195696b8e46SOliver Ruiz Dorantes #define L2CAP_ECHO_REQ	0x08
196696b8e46SOliver Ruiz Dorantes #define L2CAP_ECHO_RSP	0x09
197*bb83316aSAugustin Cavalier 
198696b8e46SOliver Ruiz Dorantes #define L2CAP_MAX_ECHO_SIZE \
199*bb83316aSAugustin Cavalier 	(L2CAP_MTU_MAXIMUM - sizeof(l2cap_command_header))
200696b8e46SOliver Ruiz Dorantes 
201*bb83316aSAugustin Cavalier 
202*bb83316aSAugustin Cavalier #define L2CAP_INFORMATION_REQ	0x0a
203696b8e46SOliver Ruiz Dorantes typedef struct {
204*bb83316aSAugustin Cavalier 	enum : uint16 {
205*bb83316aSAugustin Cavalier 		TYPE_CONNECTIONLESS_MTU	= 0x0001,
206*bb83316aSAugustin Cavalier 		TYPE_EXTENDED_FEATURES	= 0x0002,
207*bb83316aSAugustin Cavalier 		TYPE_FIXED_CHANNELS		= 0x0003,
208*bb83316aSAugustin Cavalier 			/* 0x0004-0xffff: reserved */
209*bb83316aSAugustin Cavalier 	}; uint16 type;
210*bb83316aSAugustin Cavalier } _PACKED l2cap_information_req;
211696b8e46SOliver Ruiz Dorantes 
212*bb83316aSAugustin Cavalier #define L2CAP_INFORMATION_RSP	0x0b
213696b8e46SOliver Ruiz Dorantes typedef struct {
214*bb83316aSAugustin Cavalier 	uint16	type;
215*bb83316aSAugustin Cavalier 	enum : uint16 {
216*bb83316aSAugustin Cavalier 		RESULT_SUCCESS			= 0x0000,
217*bb83316aSAugustin Cavalier 		RESULT_NOT_SUPPORTED	= 0x0001,
218*bb83316aSAugustin Cavalier 	}; uint16 result;
219*bb83316aSAugustin Cavalier 	/* data may follow */
220*bb83316aSAugustin Cavalier } _PACKED l2cap_information_rsp;
221696b8e46SOliver Ruiz Dorantes 
222696b8e46SOliver Ruiz Dorantes typedef union {
223696b8e46SOliver Ruiz Dorantes 	uint16 mtu;
224*bb83316aSAugustin Cavalier 	uint32 extended_features;
225*bb83316aSAugustin Cavalier } _PACKED l2cap_information_rsp_data;
226696b8e46SOliver Ruiz Dorantes 
227696b8e46SOliver Ruiz Dorantes 
228*bb83316aSAugustin Cavalier #endif /* _L2CAP_H_ */
229