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