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.
This commit is contained in:
Augustin Cavalier
2024-05-01 00:25:43 -04:00
parent d3e2c76409
commit bb83316a58
29 changed files with 2027 additions and 3466 deletions
+24 -118
View File
@@ -9,6 +9,10 @@
#include <module.h>
#include <lock.h>
#include <util/DoublyLinkedList.h>
#include <util/VectorMap.h>
#include <net_datalink.h>
#include <net/if_dl.h>
#include <net_buffer.h>
#include <net_device.h>
@@ -22,10 +26,6 @@
#define BT_CORE_DATA_MODULE_NAME "bluetooth/btCoreData/v1"
struct L2capChannel;
struct L2capFrame;
struct L2capEndpoint;
typedef enum _connection_status {
HCI_CONN_CLOSED,
HCI_CONN_OPEN,
@@ -35,25 +35,30 @@ typedef enum _connection_status {
#ifdef __cplusplus
struct HciConnection : DoublyLinkedListLinkImpl<HciConnection> {
HciConnection();
HciConnection(hci_id hid);
virtual ~HciConnection();
hci_id Hid;
bluetooth_device* ndevice;
net_buffer* currentRxPacket;
ssize_t currentRxExpectedLength;
bdaddr_t destination;
uint16 handle;
int type;
uint16 mtu;
connection_status status;
uint16 lastCid;
uint8 lastIdent;
DoublyLinkedList<L2capChannel> ChannelList;
DoublyLinkedList<L2capFrame> ExpectedResponses;
DoublyLinkedList<L2capFrame> OutGoingFrames;
mutex fLock;
mutex fLockExpected;
net_buffer* currentRxPacket;
ssize_t currentRxExpectedLength;
struct net_interface_address interface_address;
struct sockaddr_dl address_dl;
struct sockaddr_storage address_dest;
void (*disconnect_hook)(HciConnection*);
public:
mutex fLock;
uint8 fNextIdent;
VectorMap<uint8, void*> fInUseIdents;
};
#else
@@ -62,84 +67,14 @@ struct HciConnection;
#endif
typedef enum _channel_status {
L2CAP_CHAN_CLOSED, /* channel closed */
L2CAP_CHAN_W4_L2CAP_CON_RSP, /* wait for L2CAP resp. */
L2CAP_CHAN_W4_L2CA_CON_RSP, /* wait for upper resp. */
L2CAP_CHAN_CONFIG, /* L2CAP configuration */
L2CAP_CHAN_OPEN, /* channel open */
L2CAP_CHAN_W4_L2CAP_DISCON_RSP, /* wait for L2CAP discon. */
L2CAP_CHAN_W4_L2CA_DISCON_RSP /* wait for upper discon. */
} channel_status;
#ifdef __cplusplus
typedef struct _ChannelConfiguration {
uint16 imtu; /* incoming channel MTU */
l2cap_flow_t iflow; /* incoming flow control */
uint16 omtu; /* outgoing channel MTU */
l2cap_flow_t oflow; /* outgoing flow control */
uint16 flush_timo; /* flush timeout */
uint16 link_timo; /* link timeout */
} ChannelConfiguration;
struct L2capChannel : DoublyLinkedListLinkImpl<L2capChannel> {
HciConnection* conn;
uint16 scid;
uint16 dcid;
uint16 psm;
uint8 ident;
uint8 cfgState;
channel_status state;
ChannelConfiguration* configuration;
L2capEndpoint* endpoint;
};
#endif
typedef enum _frametype {
L2CAP_C_FRAME, // signals
L2CAP_G_FRAME, // CL packets
L2CAP_B_FRAME, // CO packets
L2CAP_I_FRAME,
L2CAP_S_FRAME
} frame_type;
#ifdef __cplusplus
struct L2capFrame : DoublyLinkedListLinkImpl<L2capFrame> {
HciConnection* conn;
L2capChannel* channel;
uint16 flags; /* command flags */
#define L2CAP_CMD_PENDING (1 << 0) /* command is pending */
uint8 code; /* L2CAP command opcode */
uint8 ident; /* L2CAP command ident */
frame_type type;
net_buffer* buffer; // contains 1 l2cap / mutliple acls
// TODO :struct callout timo; /* RTX/ERTX timeout */
};
#endif
struct bluetooth_core_data_module_info {
module_info info;
status_t (*PostEvent)(bluetooth_device* ndev, void* event,
size_t size);
// FIXME: We really shouldn't be passing out connection pointers at all...
struct HciConnection* (*AddConnection)(uint16 handle, int type,
const bdaddr_t& dst, hci_id hid);
@@ -148,42 +83,13 @@ struct bluetooth_core_data_module_info {
hci_id (*RouteConnection)(const bdaddr_t& destination);
void (*SetAclBuffer)(struct HciConnection* conn,
net_buffer* nbuf);
void (*SetAclExpectedSize)(struct HciConnection* conn,
size_t size);
void (*AclPutting)(struct HciConnection* conn,
size_t size);
bool (*AclComplete)(struct HciConnection* conn);
bool (*AclOverFlowed)(struct HciConnection* conn);
struct HciConnection* (*ConnectionByHandle)(uint16 handle, hci_id hid);
struct HciConnection* (*ConnectionByDestination)(
const bdaddr_t& destination, hci_id hid);
struct L2capChannel* (*AddChannel)(struct HciConnection* conn,
uint16 psm);
void (*RemoveChannel)(struct HciConnection* conn,
uint16 scid);
struct L2capChannel* (*ChannelBySourceID)(struct HciConnection* conn,
uint16 sid);
uint16 (*ChannelAllocateCid)(struct HciConnection* conn);
uint16 (*ChannelAllocateIdent)(struct HciConnection* conn);
struct L2capFrame* (*SignalByIdent)(struct HciConnection* conn,
uint8 ident);
status_t (*TimeoutSignal)(struct L2capFrame* frame,
uint32 timeo);
status_t (*UnTimeoutSignal)(struct L2capFrame* frame);
struct L2capFrame* (*SpawnFrame)(struct HciConnection* conn,
struct L2capChannel* channel,
net_buffer* buffer, frame_type frame);
struct L2capFrame* (*SpawnSignal)(struct HciConnection* conn,
struct L2capChannel* channel,
net_buffer* buffer, uint8 ident, uint8 code);
status_t (*AcknowledgeSignal)(struct L2capFrame* frame);
status_t (*QueueSignal)(struct L2capFrame* frame);
uint8 (*allocate_command_ident)(struct HciConnection* conn, void* associated);
void* (*lookup_command_ident)(struct HciConnection* conn, uint8 ident);
void (*free_command_ident)(struct HciConnection* conn, uint8 ident);
};
+151 -234
View File
@@ -1,311 +1,228 @@
/*
* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*
* Copyright 2024, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
/*-
* Copyright (c) Maksim Yevmenkin <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*/
/**************************************************************************
**************************************************************************
** Common defines and types (L2CAP)
**************************************************************************
**************************************************************************/
#ifndef _L2CAP_
#define _L2CAP_
#ifndef _L2CAP_H_
#define _L2CAP_H_
#include <bluetooth/bluetooth.h>
// TODO: from BSD compatibility layer
#define htole16(x) (x)
#define le16toh(x) (x)
#define le32toh(x) (x)
#define htole32(x) (x)
#define HZ 1000000 // us per second TODO: move somewhere more generic
#define bluetooth_l2cap_ertx_timeout (60 * HZ)
#define bluetooth_l2cap_rtx_timeout (300 * HZ)
/*
* Channel IDs are assigned relative to the instance of L2CAP node, i.e.
* relative to the unit. So the total number of channels that unit can have
* open at the same time is 0xffff - 0x0040 = 0xffbf (65471). This number
* does not depend on number of connections.
*/
#define L2CAP_NULL_CID 0x0000 /* DO NOT USE THIS CID */
#define L2CAP_SIGNAL_CID 0x0001 /* signaling channel ID */
#define L2CAP_CLT_CID 0x0002 /* connectionless channel ID */
/* 0x0003 - 0x003f Reserved */
#define L2CAP_FIRST_CID 0x0040 /* dynamically alloc. (start) */
#define L2CAP_LAST_CID 0xffff /* dynamically alloc. (end) */
/* 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
/*
* L2CAP signaling command ident's are assigned relative to the connection,
* because there is only one signaling channel (cid == 0x01) for every
* connection. So up to 254 (0xff - 0x01) L2CAP commands can be pending at the
* same time for the same connection.
*/
#define L2CAP_NULL_IDENT 0x00 /* DO NOT USE THIS IDENT */
#define L2CAP_FIRST_IDENT 0x01 /* dynamically alloc. (start) */
#define L2CAP_LAST_IDENT 0xff /* dynamically alloc. (end) */
/* 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
/* L2CAP MTU */
/* MTU */
#define L2CAP_MTU_MINIMUM 48
#define L2CAP_MTU_DEFAULT 672
#define L2CAP_MTU_MAXIMUM 0xffff
/* L2CAP flush and link timeouts */
#define L2CAP_FLUSH_TIMO_DEFAULT 0xffff /* always retransmit */
#define L2CAP_LINK_TIMO_DEFAULT 0xffff
/* L2CAP Command Reject reasons */
#define L2CAP_REJ_NOT_UNDERSTOOD 0x0000
#define L2CAP_REJ_MTU_EXCEEDED 0x0001
#define L2CAP_REJ_INVALID_CID 0x0002
/* 0x0003 - 0xffff - reserved for future use */
/* Timeouts */
#define L2CAP_FLUSH_TIMEOUT_DEFAULT 0xffff /* always retransmit */
#define L2CAP_LINK_TIMEOUT_DEFAULT 0xffff
/* Protocol/Service Multioplexor (PSM) values */
/* 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_TCP 0x0005 /* Telephony Control Protocol */
#define L2CAP_PSM_TCS 0x0007 /* TCS cordless */
#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_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 for future use */
/* 0x1001 < x < 0xFFFF dinamically assigned */
/* L2CAP Connection response command result codes */
#define L2CAP_SUCCESS 0x0000
#define L2CAP_PENDING 0x0001
#define L2CAP_PSM_NOT_SUPPORTED 0x0002
#define L2CAP_SEQUIRY_BLOCK 0x0003
#define L2CAP_NO_RESOURCES 0x0004
#define L2CAP_TIMEOUT 0xeeee
#define L2CAP_UNKNOWN 0xffff
/* 0x0005 - 0xffff - reserved for future use */
/* L2CAP Connection response status codes */
#define L2CAP_NO_INFO 0x0000
#define L2CAP_AUTH_PENDING 0x0001
#define L2CAP_AUTZ_PENDING 0x0002
/* 0x0003 - 0xffff - reserved for future use */
/* L2CAP Configuration response result codes */
#define L2CAP_UNACCEPTABLE_PARAMS 0x0001
#define L2CAP_REJECT 0x0002
#define L2CAP_UNKNOWN_OPTION 0x0003
/* 0x0003 - 0xffff - reserved for future use */
/* L2CAP Configuration options */
#define L2CAP_OPT_CFLAG_BIT 0x0001
#define L2CAP_OPT_CFLAG(flags) ((flags) & L2CAP_OPT_CFLAG_BIT)
#define L2CAP_OPT_HINT_BIT 0x80
#define L2CAP_OPT_HINT(type) ((type) & L2CAP_OPT_HINT_BIT)
#define L2CAP_OPT_HINT_MASK 0x7f
#define L2CAP_OPT_MTU 0x01
#define L2CAP_OPT_MTU_SIZE sizeof(uint16)
#define L2CAP_OPT_FLUSH_TIMO 0x02
#define L2CAP_OPT_FLUSH_TIMO_SIZE sizeof(uint16)
#define L2CAP_OPT_QOS 0x03
#define L2CAP_OPT_QOS_SIZE sizeof(l2cap_flow_t)
/* 0x4 - 0xff - reserved for future use */
#define L2CAP_CFG_IN (1 << 0) /* incoming path done */
#define L2CAP_CFG_OUT (1 << 1) /* outgoing path done */
#define L2CAP_CFG_BOTH (L2CAP_CFG_IN | L2CAP_CFG_OUT)
#define L2CAP_CFG_IN_SENT (1 << 2) /* L2CAP ConfigReq sent */
#define L2CAP_CFG_OUT_SENT (1 << 3) /* ---/--- */
/* L2CAP Information request type codes */
#define L2CAP_CONNLESS_MTU 0x0001
#define L2CAP_EXTENDED_MASK 0x0002
/* 0x0003 - 0xffff - reserved for future use */
/* L2CAP Information response codes */
#define L2CAP_NOT_SUPPORTED 0x0001
/* 0x0002 - 0xffff - reserved for future use */
/* L2CAP flow (QoS) */
typedef struct {
uint8 flags; /* reserved for future use */
uint8 service_type; /* service type */
uint32 token_rate; /* bytes per second */
uint32 token_bucket_size; /* bytes */
uint32 peak_bandwidth; /* bytes per second */
uint32 latency; /* microseconds */
uint32 delay_variation; /* microseconds */
} __attribute__ ((packed)) l2cap_flow_t;
/* < 0x1000: reserved */
/* >= 0x1000: dynamically assigned */
/**************************************************************************
**************************************************************************
** Link level defines, headers and types
**************************************************************************
**************************************************************************/
/* L2CAP header */
typedef struct {
uint16 length; /* payload size */
uint16 dcid; /* destination channel ID */
} __attribute__ ((packed)) l2cap_hdr_t;
} _PACKED l2cap_basic_header;
/* L2CAP ConnectionLess Traffic (CLT) (if destination cid == 0x2) */
/* Connectionless traffic ("CLT") */
typedef struct {
uint16 psm; /* Protocol/Service Multiplexor */
} __attribute__ ((packed)) l2cap_clt_hdr_t;
/* dcid == L2CAP_CONNECTIONLESS_CID (0x2) */
uint16 psm;
} _PACKED l2cap_connectionless_header;
#define L2CAP_CONNECTIONLESS_MTU_MAXIMUM (L2CAP_MTU_MAXIMUM - sizeof(l2cap_connectionless_header))
#define L2CAP_CLT_MTU_MAXIMUM (L2CAP_MTU_MAXIMUM - sizeof(l2cap_clt_hdr_t))
/* L2CAP command header */
typedef struct {
uint8 code; /* command OpCode */
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 */
} __attribute__ ((packed)) l2cap_cmd_hdr_t;
} _PACKED l2cap_command_header;
/* L2CAP Command Reject */
#define L2CAP_CMD_REJ 0x01
#define L2CAP_COMMAND_REJECT_RSP 0x01
typedef struct {
uint16 reason; /* reason to reject command */
/* uint8 data[]; -- optional data (depends on reason) */
} __attribute__ ((packed)) l2cap_cmd_rej_cp;
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;
/* CommandReject data */
typedef union {
/* L2CAP_REJ_MTU_EXCEEDED */
struct {
uint16 mtu; /* actual signaling MTU */
} __attribute__ ((packed)) mtu;
/* L2CAP_REJ_INVALID_CID */
} _PACKED mtu_exceeded;
struct {
uint16 scid; /* local CID */
uint16 dcid; /* remote CID */
} __attribute__ ((packed)) cid;
} l2cap_cmd_rej_data_t;
typedef l2cap_cmd_rej_data_t * l2cap_cmd_rej_data_p;
uint16 scid; /* source (local) CID */
uint16 dcid; /* destination (remote) CID */
} _PACKED invalid_cid;
} l2cap_command_reject_data;
/* L2CAP Connection Request */
#define L2CAP_CON_REQ 0x02
#define L2CAP_CONNECTION_REQ 0x02
typedef struct {
uint16 psm; /* Protocol/Service Multiplexor (PSM) */
uint16 psm;
uint16 scid; /* source channel ID */
} __attribute__ ((packed)) l2cap_con_req_cp;
} _PACKED l2cap_connection_req;
/* L2CAP Connection Response */
#define L2CAP_CON_RSP 0x03
#define L2CAP_CONNECTION_RSP 0x03
typedef struct {
uint16 dcid; /* destination channel ID */
uint16 scid; /* source channel ID */
uint16 result; /* 0x00 - success */
uint16 status; /* more info if result != 0x00 */
} __attribute__ ((packed)) l2cap_con_rsp_cp;
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;
/* L2CAP Configuration Request */
#define L2CAP_CFG_REQ 0x04
#define L2CAP_CONFIGURATION_REQ 0x04
typedef struct {
uint16 dcid; /* destination channel ID */
uint16 flags; /* flags */
/* uint8 options[] -- options */
} __attribute__ ((packed)) l2cap_cfg_req_cp;
uint16 flags;
/* options may follow */
} _PACKED l2cap_configuration_req;
/* L2CAP Configuration Response */
#define L2CAP_CFG_RSP 0x05
#define L2CAP_CONFIGURATION_RSP 0x05
typedef struct {
uint16 scid; /* source channel ID */
uint16 flags; /* flags */
uint16 result; /* 0x00 - success */
/* uint8 options[] -- options */
} __attribute__ ((packed)) l2cap_cfg_rsp_cp;
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;
/* L2CAP configuration option */
typedef struct {
uint8 type;
uint8 length;
/* uint8 value[] -- option value (depends on type) */
} __attribute__ ((packed)) l2cap_cfg_opt_t;
typedef l2cap_cfg_opt_t * l2cap_cfg_opt_p;
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;
/* L2CAP configuration option value */
typedef union {
uint16 mtu; /* L2CAP_OPT_MTU */
uint16 flush_timo; /* L2CAP_OPT_FLUSH_TIMO */
l2cap_flow_t flow; /* L2CAP_OPT_QOS */
} l2cap_cfg_opt_val_t;
typedef l2cap_cfg_opt_val_t * l2cap_cfg_opt_val_p;
uint16 mtu;
uint16 flush_timeout;
l2cap_qos qos;
} l2cap_configuration_option_value;
/* L2CAP Disconnect Request */
#define L2CAP_DISCON_REQ 0x06
#define L2CAP_DISCONNECTION_REQ 0x06
typedef struct {
uint16 dcid; /* destination channel ID */
uint16 scid; /* source channel ID */
} __attribute__ ((packed)) l2cap_discon_req_cp;
} _PACKED l2cap_disconnection_req;
#define L2CAP_DISCONNECTION_RSP 0x07
typedef l2cap_disconnection_req l2cap_disconnection_rsp;
/* L2CAP Disconnect Response */
#define L2CAP_DISCON_RSP 0x07
typedef l2cap_discon_req_cp l2cap_discon_rsp_cp;
/* L2CAP Echo Request */
#define L2CAP_ECHO_REQ 0x08
/* No command parameters, only optional data */
/* L2CAP Echo Response */
#define L2CAP_ECHO_RSP 0x09
#define L2CAP_MAX_ECHO_SIZE \
(L2CAP_MTU_MAXIMUM - sizeof(l2cap_cmd_hdr_t))
/* No command parameters, only optional data */
(L2CAP_MTU_MAXIMUM - sizeof(l2cap_command_header))
/* L2CAP Information Request */
#define L2CAP_INFO_REQ 0x0a
#define L2CAP_INFORMATION_REQ 0x0a
typedef struct {
uint16 type; /* requested information type */
} __attribute__ ((packed)) l2cap_info_req_cp;
enum : uint16 {
TYPE_CONNECTIONLESS_MTU = 0x0001,
TYPE_EXTENDED_FEATURES = 0x0002,
TYPE_FIXED_CHANNELS = 0x0003,
/* 0x0004-0xffff: reserved */
}; uint16 type;
} _PACKED l2cap_information_req;
/* L2CAP Information Response */
#define L2CAP_INFO_RSP 0x0b
#define L2CAP_INFORMATION_RSP 0x0b
typedef struct {
uint16 type; /* requested information type */
uint16 result; /* 0x00 - success */
/* uint8 info[] -- info data (depends on type)
*
* L2CAP_CONNLESS_MTU - 2 bytes connectionless MTU
*/
} __attribute__ ((packed)) l2cap_info_rsp_cp;
#define IS_SIGNAL_REQ(code) ((code & 1) == 0)
#define IS_SIGNAL_RSP(code) ((code & 1) == 1)
uint16 type;
enum : uint16 {
RESULT_SUCCESS = 0x0000,
RESULT_NOT_SUPPORTED = 0x0001,
}; uint16 result;
/* data may follow */
} _PACKED l2cap_information_rsp;
typedef union {
/* L2CAP_CONNLESS_MTU */
struct {
uint16 mtu;
} __attribute__ ((packed)) mtu;
} l2cap_info_rsp_data_t;
typedef l2cap_info_rsp_data_t * l2cap_info_rsp_data_p;
uint16 mtu;
uint32 extended_features;
} _PACKED l2cap_information_rsp_data;
#endif
#endif /* _L2CAP_H_ */