7 /* Protocol and service multiplexor */
8 #define HIDP_PSM 0x0011
9 #define INTR_PSM 0x0013
11 /* Packet header lengths */
12 #define L2CAP_HDR_LEN 4
13 #define L2CAP_SIGHDR_LEN 4
14 #define L2CAP_CFGOPTHDR_LEN 2
17 #define L2CAP_CONN_REQ_SIZE 4
18 #define L2CAP_CONN_RSP_SIZE 8
19 #define L2CAP_CFG_RSP_SIZE 6
20 #define L2CAP_DISCONN_RSP_SIZE 4
22 #define L2CAP_CFG_REQ_SIZE 4
24 #define L2CAP_DISCONN_REQ_SIZE 4
25 #define L2CAP_CMD_REJ_SIZE 2
28 #define L2CAP_CMD_REJ 0x01
29 #define L2CAP_CONN_REQ 0x02
30 #define L2CAP_CONN_RSP 0x03
31 #define L2CAP_CFG_REQ 0x04
32 #define L2CAP_CFG_RSP 0x05
33 #define L2CAP_DISCONN_REQ 0x06
34 #define L2CAP_DISCONN_RSP 0x07
35 #define L2CAP_ECHO_REQ 0x08
36 #define L2CAP_ECHO_RSP 0x09
37 #define L2CAP_INFO_REQ 0x0A
38 #define L2CAP_INFO_RSP 0x0B
40 /* Permanent channel identifiers */
41 #define L2CAP_NULL_CID 0x0000
42 #define L2CAP_SIG_CID 0x0001
43 #define L2CAP_CONNLESS_CID 0x0002
45 /* Channel identifiers values */
46 #define L2CAP_MIN_CID 0x0040
47 #define L2CAP_MAX_CID 0xFFFF
49 /* Configuration types */
50 #define L2CAP_CFG_MTU 0x01
51 #define L2CAP_FLUSHTO 0x02
52 #define L2CAP_QOS 0x03
54 /* Configuration types length */
55 #define L2CAP_MTU_LEN 2
56 #define L2CAP_FLUSHTO_LEN 2
57 #define L2CAP_QOS_LEN 22
59 /* Configuration response types */
60 #define L2CAP_CFG_SUCCESS 0x0000
61 #define L2CAP_CFG_UNACCEPT 0x0001
62 #define L2CAP_CFG_REJ 0x0002
63 #define L2CAP_CFG_UNKNOWN 0x0003
64 #define L2CAP_CFG_TIMEOUT 0xEEEE
67 #define L2CAP_QOS_NO_TRAFFIC 0x00
68 #define L2CAP_QOS_BEST_EFFORT 0x01
69 #define L2CAP_QOS_GUARANTEED 0x02
71 /* Command reject reasons */
72 #define L2CAP_CMD_NOT_UNDERSTOOD 0x0000
73 #define L2CAP_MTU_EXCEEDED 0x0001
74 #define L2CAP_INVALID_CID 0x0002
76 /* Connection response results */
77 #define L2CAP_CONN_SUCCESS 0x0000
78 #define L2CAP_CONN_PND 0x0001
79 #define L2CAP_CONN_REF_PSM 0x0002
80 #define L2CAP_CONN_REF_SEC 0x0003
81 #define L2CAP_CONN_REF_RES 0x0004
82 #define L2CAP_CONN_CFG_TO 0x0005 /* Implementation specific result */
84 /* Echo response results */
85 #define L2CAP_ECHO_RCVD 0x00
86 #define L2CAP_ECHO_TO 0x01
88 /* L2CAP segmentation */
89 #define L2CAP_ACL_START 0x02
90 #define L2CAP_ACL_CONT 0x01
92 /* L2CAP config default parameters */
93 #define L2CAP_CFG_DEFAULT_INMTU 672 /* Two Baseband DH5 packets (2*341=682) minus the Baseband ACL
94 headers (2*2=4) and L2CAP header (6) */
95 #define L2CAP_CFG_DEFAULT_OUTFLUSHTO 0xFFFF
97 /* L2CAP configuration parameter masks */
98 #define L2CAP_CFG_IR 0x01
99 #define L2CAP_CFG_IN_SUCCESS 0x02
100 #define L2CAP_CFG_OUT_SUCCESS 0x04
101 #define L2CAP_CFG_OUT_REQ 0x08
104 L2CAP_CLOSED
, L2CAP_LISTEN
, W4_L2CAP_CONNECT_RSP
, W4_L2CA_CONNECT_RSP
, L2CAP_CONFIG
,
105 L2CAP_OPEN
, W4_L2CAP_DISCONNECT_RSP
, W4_L2CA_DISCONNECT_RSP
121 struct l2cap_cfgopt_hdr
127 /* This structure is used to represent L2CAP signals. */
129 struct l2cap_sig
*next
; /* for the linked list, used when putting signals
131 struct pbuf
*p
; /* buffer containing data + L2CAP header */
132 u16_t sigid
; /* Identification */
133 u16_t ertx
; /* extended response timeout expired */
134 u8_t rtx
; /* response timeout expired */
135 u8_t nrtx
; /* number of retransmissions */
153 struct l2cap_seg
*next
;
154 struct bd_addr bdaddr
;
157 struct l2cap_hdr
*l2caphdr
;
158 struct l2cap_pcb
*pcb
; /* The L2CAP Protocol Control Block */
162 struct l2cap_pcb
*next
; /* For the linked list */
164 enum l2cap_state state
; /* L2CAP state */
168 u16_t scid
; /* Source CID */
169 u16_t dcid
; /* Destination CID */
171 u16_t psm
; /* Protocol/Service Multiplexer */
173 u16_t ursp_id
; /* Signal id to respond to */
174 u8_t encrypt
; /* encryption mode */
176 struct l2cap_sig
*unrsp_sigs
; /* List of sent but unresponded signals */
178 struct bd_addr remote_bdaddr
;
180 struct l2cap_cfg cfg
; /* Configuration parameters */
182 /* Upper layer to L2CAP confirmation functions */
184 /* Function to be called when a connection has been set up */
185 err_t (* l2ca_connect_cfm
)(void *arg
, struct l2cap_pcb
*pcb
, u16_t result
, u16_t status
);
186 /* Function to be called when a connection has been closed */
187 err_t (* l2ca_disconnect_cfm
)(void *arg
, struct l2cap_pcb
*pcb
);
188 /* Function to be called when a echo reply has been received */
189 err_t (* l2ca_pong
)(void *arg
, struct l2cap_pcb
*pcb
, u8_t result
);
191 /* L2CAP to upper layer indication functions */
193 /* Function to be called when a connection indication event occurs */
194 err_t (* l2ca_connect_ind
)(void *arg
, struct l2cap_pcb
*pcb
, err_t err
);
195 /* Function to be called when a disconnection indication event occurs */
196 err_t (* l2ca_disconnect_ind
)(void *arg
, struct l2cap_pcb
*pcb
, err_t err
);
197 /* Function to be called when a timeout indication event occurs */
198 err_t (* l2ca_timeout_ind
)(void *arg
, struct l2cap_pcb
*newpcb
, err_t err
);
199 /* Function to be called when a L2CAP connection receives data */
200 err_t (* l2ca_recv
)(void *arg
, struct l2cap_pcb
*pcb
, struct pbuf
*p
, err_t err
);
203 struct l2cap_pcb_listen
{
204 struct l2cap_pcb_listen
*next
; /* for the linked list */
206 enum l2cap_state state
; /* L2CAP state */
210 u16_t psm
; /* Protocol/Service Multiplexer */
211 struct bd_addr bdaddr
; /* Device Address */
213 /* Function to call when a connection request has been received
214 from a remote device. */
215 err_t (* l2ca_connect_ind
)(void *arg
, struct l2cap_pcb
*pcb
, err_t err
);
218 #define l2cap_psm(pcb) ((pcb)->psm)
221 struct l2cap_pcb
* l2cap_new(void);
223 void lp_connect_ind(struct bd_addr
*bdaddr
);
224 void lp_connect_cfm(struct bd_addr
*bdaddr
, u8_t encrypt_mode
, err_t err
);
225 void lp_disconnect_ind(struct bd_addr
*bdaddr
,u8_t reason
);
227 err_t
l2ca_config_req(struct l2cap_pcb
*pcb
);
228 err_t
l2ca_disconnect_req(struct l2cap_pcb
*pcb
, err_t (* l2ca_disconnect_cfm
)(void *arg
, struct l2cap_pcb
*pcb
));
229 err_t
l2ca_datawrite(struct l2cap_pcb
*pcb
, struct pbuf
*p
);
230 err_t
l2ca_ping(struct bd_addr
*bdaddr
, struct l2cap_pcb
*tpcb
,err_t (* l2ca_pong
)(void *arg
, struct l2cap_pcb
*pcb
, u8_t result
));
231 err_t
l2ca_connect_req(struct l2cap_pcb
*pcb
, struct bd_addr
*bdaddr
, u16_t psm
, u8_t role_switch
, err_t (* l2ca_connect_cfm
)(void *arg
, struct l2cap_pcb
*lpcb
,u16_t result
, u16_t status
));
234 void l2cap_input(struct pbuf
*p
, struct bd_addr
*bdaddr
);
235 err_t
l2cap_close(struct l2cap_pcb
*pcb
);
236 void l2cap_reset_all(void);
237 u8_t
l2cap_next_sigid(void);
238 err_t
l2cap_write(struct bd_addr
*bdaddr
, struct pbuf
*p
, u16_t len
);
239 void l2cap_arg(struct l2cap_pcb
*pcb
, void *arg
);
240 void l2cap_disconnect_ind(struct l2cap_pcb
*pcb
, err_t (* l2ca_disconnect_ind
)(void *arg
, struct l2cap_pcb
*newpcb
, err_t err
));
241 void l2cap_timeout_ind(struct l2cap_pcb
*pcb
,err_t (* l2ca_timeout_ind
)(void *arg
, struct l2cap_pcb
*newpcb
, err_t err
));
242 void l2cap_recv(struct l2cap_pcb
*pcb
, err_t (* l2ca_recv
)(void *arg
, struct l2cap_pcb
*pcb
, struct pbuf
*p
, err_t err
));
243 err_t
l2cap_signal(struct l2cap_pcb
*pcb
, u8_t code
, u16_t ursp_id
, struct bd_addr
*remote_bdaddr
, struct pbuf
*data
);
244 void l2cap_process_sig(struct pbuf
*q
, struct l2cap_hdr
*l2caphdr
, struct bd_addr
*bdaddr
);
246 err_t
l2cap_rexmit_signal(struct l2cap_pcb
*pcb
, struct l2cap_sig
*sig
);
247 err_t
l2cap_connect_ind(struct l2cap_pcb
*npcb
, struct bd_addr
*bdaddr
, u16_t psm
,err_t (* l2ca_connect_ind
)(void *arg
, struct l2cap_pcb
*pcb
, err_t err
));
249 void (*l2cap_disconnect_bb(void (*l2ca_disconnect_bb
)(struct bd_addr
*bdaddr
,u8_t reason
)))(struct bd_addr
*bdaddr
,u8_t reason
);
251 /* Internal functions and global variables */
252 #define L2CA_ACTION_CONN_CFM(pcb,result,status,ret) if((pcb)->l2ca_connect_cfm != NULL) (ret = (pcb)->l2ca_connect_cfm((pcb)->callback_arg,(pcb),(result),(status)))
253 #define L2CA_ACTION_DISCONN_CFM(pcb,ret) if((pcb)->l2ca_disconnect_cfm != NULL) (ret = (pcb)->l2ca_disconnect_cfm((pcb)->callback_arg,(pcb)))
254 #define L2CA_ACTION_PING_CFM(pcb,result,ret) if((pcb)->l2ca_pong != NULL) (ret = (pcb)->l2ca_pong((pcb)->callback_arg,(pcb),(result)))
256 #define L2CA_ACTION_CONN_IND(pcb,err,ret) if((pcb)->l2ca_connect_ind != NULL) (ret = (pcb)->l2ca_connect_ind((pcb)->callback_arg,(pcb),(err)))
257 #define L2CA_ACTION_DISCONN_IND(pcb,err,ret) \
258 if((pcb)->l2ca_disconnect_ind != NULL) { \
259 LOG("l2cap_disconnect_ind called\n"); \
260 (ret = (pcb)->l2ca_disconnect_ind((pcb)->callback_arg,(pcb),(err))); \
264 #define L2CA_ACTION_TO_IND(pcb,err,ret) if((pcb)->l2ca_timeout_ind != NULL) (ret = (pcb)->l2ca_timeout_ind((pcb)->callback_arg,(pcb),(err)))
265 #define L2CA_ACTION_RECV(pcb,p,err,ret) \
266 if((pcb)->l2ca_recv != NULL) { \
267 (ret = (pcb)->l2ca_recv((pcb)->callback_arg,(pcb),(p),(err))); \
272 #define L2CAP_OPTH_TYPE(hdr) (((hdr)->type) & 0x7f)
273 #define L2CAP_OPTH_TOA(hdr) (((hdr)->type) >> 7)
275 /* The L2CAP PCB lists. */
276 extern struct l2cap_pcb_listen
*l2cap_listen_pcbs
; /* List of all L2CAP PCBs in CLOSED state
277 but awaing an incoming conn req. */
278 extern struct l2cap_pcb
*l2cap_active_pcbs
; /* List of all L2CAP PCBs that has
279 established or is about to establish
282 extern struct l2cap_pcb
*l2cap_tmp_pcb
; /* Only used for temporary storage. */
284 #define L2CAP_REG(pcbs, npcb) do { \
286 _CPU_ISR_Disable(level); \
287 npcb->next = *pcbs; \
289 _CPU_ISR_Restore(level); \
291 #define L2CAP_RMV(pcbs, npcb) do { \
293 _CPU_ISR_Disable(level); \
294 if(*pcbs == npcb) { \
295 *pcbs = (*pcbs)->next; \
296 } else for(l2cap_tmp_pcb = *pcbs; l2cap_tmp_pcb != NULL; l2cap_tmp_pcb = l2cap_tmp_pcb->next) { \
297 if(l2cap_tmp_pcb->next != NULL && l2cap_tmp_pcb->next == npcb) { \
298 l2cap_tmp_pcb->next = npcb->next; \
303 _CPU_ISR_Restore(level); \
306 /* The L2CAP SIG list macros */
307 extern struct l2cap_sig
*l2cap_tmp_sig
; /* Only used for temporary storage. */
309 #define L2CAP_SIG_REG(ursp_sigs, nsig) do { \
311 _CPU_ISR_Disable(level); \
312 nsig->next = *ursp_sigs; \
314 _CPU_ISR_Restore(level); \
316 #define L2CAP_SIG_RMV(ursp_sigs, nsig) do { \
318 _CPU_ISR_Disable(level); \
319 if(*ursp_sigs == nsig) { \
320 *ursp_sigs = (*ursp_sigs)->next; \
321 } else for(l2cap_tmp_sig = *ursp_sigs; l2cap_tmp_sig != NULL; l2cap_tmp_sig = l2cap_tmp_sig->next) { \
322 if(l2cap_tmp_sig->next != NULL && l2cap_tmp_sig->next == nsig) { \
323 l2cap_tmp_sig->next = nsig->next; \
328 _CPU_ISR_Restore(level); \
331 /* The L2CAP incoming segments list macros */
332 extern struct l2cap_seg
*l2cap_tmp_inseg
; /* Only used for temporary storage. */
334 #define L2CAP_SEG_REG(segs, nseg) do { \
336 _CPU_ISR_Disable(level); \
337 nseg->next = *segs; \
339 _CPU_ISR_Restore(level); \
341 #define L2CAP_SEG_RMV(segs, nseg) do { \
343 _CPU_ISR_Disable(level); \
344 if(*segs == nseg) { \
345 *segs = (*segs)->next; \
346 } else for(l2cap_tmp_inseg = *segs; l2cap_tmp_inseg != NULL; l2cap_tmp_inseg = l2cap_tmp_inseg->next) { \
347 if(l2cap_tmp_inseg->next != NULL && l2cap_tmp_inseg->next == nseg) { \
348 l2cap_tmp_inseg->next = nseg->next; \
353 _CPU_ISR_Restore(level); \