⛏️ index : haiku.git

/*
 * 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_ */