1 /******************************************************************************
2 *
3 * Copyright (C) 2009-2013 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #include <string.h>
20 #include "bt_target.h"
21 #include "bt_utils.h"
22 #include "btu.h"
23 #include "gap_int.h"
24 #include "l2c_int.h"
25 #include "l2cdefs.h"
26 #include "osi/include/mutex.h"
27 #include "osi/include/osi.h"
28 #if (GAP_CONN_INCLUDED == TRUE)
29 #include "btm_int.h"
30
31 /******************************************************************************/
32 /* L O C A L F U N C T I O N P R O T O T Y P E S */
33 /******************************************************************************/
34 static void gap_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid, uint16_t psm,
35 uint8_t l2cap_id);
36 static void gap_connect_cfm(uint16_t l2cap_cid, uint16_t result);
37 static void gap_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
38 static void gap_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
39 static void gap_disconnect_ind(uint16_t l2cap_cid, bool ack_needed);
40 static void gap_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg);
41 static void gap_congestion_ind(uint16_t lcid, bool is_congested);
42 static void gap_tx_complete_ind(uint16_t l2cap_cid, uint16_t sdu_sent);
43
44 static tGAP_CCB* gap_find_ccb_by_cid(uint16_t cid);
45 static tGAP_CCB* gap_find_ccb_by_handle(uint16_t handle);
46 static tGAP_CCB* gap_allocate_ccb(void);
47 static void gap_release_ccb(tGAP_CCB* p_ccb);
48 static void gap_checks_con_flags(tGAP_CCB* p_ccb);
49
50 /*******************************************************************************
51 *
52 * Function gap_conn_init
53 *
54 * Description This function is called to initialize GAP connection
55 * management
56 *
57 * Returns void
58 *
59 ******************************************************************************/
gap_conn_init(void)60 void gap_conn_init(void) {
61 #if (AMP_INCLUDED == TRUE)
62 gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = gap_connect_ind;
63 gap_cb.conn.reg_info.pAMP_ConnectCfm_Cb = gap_connect_cfm;
64 gap_cb.conn.reg_info.pAMP_ConnectPnd_Cb = NULL;
65 gap_cb.conn.reg_info.pAMP_ConfigInd_Cb = gap_config_ind;
66 gap_cb.conn.reg_info.pAMP_ConfigCfm_Cb = gap_config_cfm;
67 gap_cb.conn.reg_info.pAMP_DisconnectInd_Cb = gap_disconnect_ind;
68 gap_cb.conn.reg_info.pAMP_DisconnectCfm_Cb = NULL;
69 gap_cb.conn.reg_info.pAMP_QoSViolationInd_Cb = NULL;
70 gap_cb.conn.reg_info.pAMP_DataInd_Cb = gap_data_ind;
71 gap_cb.conn.reg_info.pAMP_CongestionStatus_Cb = gap_congestion_ind;
72 gap_cb.conn.reg_info.pAMP_TxComplete_Cb = NULL;
73 gap_cb.conn.reg_info.pAMP_MoveInd_Cb = NULL;
74 gap_cb.conn.reg_info.pAMP_MoveRsp_Cb = NULL;
75 gap_cb.conn.reg_info.pAMP_MoveCfm_Cb = NULL; // gap_move_cfm
76 gap_cb.conn.reg_info.pAMP_MoveCfmRsp_Cb = NULL; // gap_move_cfm_rsp
77
78 #else
79 gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind;
80 gap_cb.conn.reg_info.pL2CA_ConnectCfm_Cb = gap_connect_cfm;
81 gap_cb.conn.reg_info.pL2CA_ConnectPnd_Cb = NULL;
82 gap_cb.conn.reg_info.pL2CA_ConfigInd_Cb = gap_config_ind;
83 gap_cb.conn.reg_info.pL2CA_ConfigCfm_Cb = gap_config_cfm;
84 gap_cb.conn.reg_info.pL2CA_DisconnectInd_Cb = gap_disconnect_ind;
85 gap_cb.conn.reg_info.pL2CA_DisconnectCfm_Cb = NULL;
86 gap_cb.conn.reg_info.pL2CA_QoSViolationInd_Cb = NULL;
87 gap_cb.conn.reg_info.pL2CA_DataInd_Cb = gap_data_ind;
88 gap_cb.conn.reg_info.pL2CA_CongestionStatus_Cb = gap_congestion_ind;
89 gap_cb.conn.reg_info.pL2CA_TxComplete_Cb = gap_tx_complete_ind;
90 #endif
91 }
92
93 /*******************************************************************************
94 *
95 * Function GAP_ConnOpen
96 *
97 * Description This function is called to open an L2CAP connection.
98 *
99 * Parameters: is_server - If true, the connection is not created
100 * but put into a "listen" mode waiting for
101 * the remote side to connect.
102 *
103 * service_id - Unique service ID from
104 * BTM_SEC_SERVICE_FIRST_EMPTY (6)
105 * to BTM_SEC_MAX_SERVICE_RECORDS (32)
106 *
107 * p_rem_bda - Pointer to remote BD Address.
108 * If a server, and we don't care about the
109 * remote BD Address, then NULL should be passed.
110 *
111 * psm - the PSM used for the connection
112 *
113 * p_config - Optional pointer to configuration structure.
114 * If NULL, the default GAP configuration will
115 * be used.
116 *
117 * security - security flags
118 * chan_mode_mask - (GAP_FCR_CHAN_OPT_BASIC,
119 * GAP_FCR_CHAN_OPT_ERTM,
120 * GAP_FCR_CHAN_OPT_STREAM)
121 *
122 * p_cb - Pointer to callback function for events.
123 *
124 * Returns handle of the connection if successful, else
125 * GAP_INVALID_HANDLE
126 *
127 ******************************************************************************/
GAP_ConnOpen(const char * p_serv_name,uint8_t service_id,bool is_server,BD_ADDR p_rem_bda,uint16_t psm,tL2CAP_CFG_INFO * p_cfg,tL2CAP_ERTM_INFO * ertm_info,uint16_t security,uint8_t chan_mode_mask,tGAP_CONN_CALLBACK * p_cb,tBT_TRANSPORT transport)128 uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id,
129 bool is_server, BD_ADDR p_rem_bda, uint16_t psm,
130 tL2CAP_CFG_INFO* p_cfg, tL2CAP_ERTM_INFO* ertm_info,
131 uint16_t security, uint8_t chan_mode_mask,
132 tGAP_CONN_CALLBACK* p_cb, tBT_TRANSPORT transport) {
133 tGAP_CCB* p_ccb;
134 uint16_t cid;
135
136 GAP_TRACE_EVENT("GAP_CONN - Open Request");
137
138 /* Allocate a new CCB. Return if none available. */
139 p_ccb = gap_allocate_ccb();
140 if (p_ccb == NULL) return (GAP_INVALID_HANDLE);
141
142 /* update the transport */
143 p_ccb->transport = transport;
144
145 /* The service_id must be set before calling gap_release_ccb(). */
146 p_ccb->service_id = service_id;
147
148 /* If caller specified a BD address, save it */
149 if (p_rem_bda) {
150 /* the bd addr is not BT_BD_ANY, then a bd address was specified */
151 if (memcmp(p_rem_bda, BT_BD_ANY, BD_ADDR_LEN))
152 p_ccb->rem_addr_specified = true;
153
154 memcpy(&p_ccb->rem_dev_address[0], p_rem_bda, BD_ADDR_LEN);
155 } else if (!is_server) {
156 /* remore addr is not specified and is not a server -> bad */
157 return (GAP_INVALID_HANDLE);
158 }
159
160 /* A client MUST have specified a bd addr to connect with */
161 if (!p_ccb->rem_addr_specified && !is_server) {
162 gap_release_ccb(p_ccb);
163 GAP_TRACE_ERROR(
164 "GAP ERROR: Client must specify a remote BD ADDR to connect to!");
165 return (GAP_INVALID_HANDLE);
166 }
167
168 /* Check if configuration was specified */
169 if (p_cfg) p_ccb->cfg = *p_cfg;
170
171 /* Configure L2CAP COC, if transport is LE */
172 if (transport == BT_TRANSPORT_LE) {
173 p_ccb->local_coc_cfg.credits = L2CAP_LE_DEFAULT_CREDIT;
174 p_ccb->local_coc_cfg.mtu = p_cfg->mtu;
175 p_ccb->local_coc_cfg.mps = L2CAP_LE_DEFAULT_MPS;
176 }
177
178 p_ccb->p_callback = p_cb;
179
180 /* If originator, use a dynamic PSM */
181 #if (AMP_INCLUDED == TRUE)
182 if (!is_server)
183 gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = NULL;
184 else
185 gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = gap_connect_ind;
186 #else
187 if (!is_server)
188 gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = NULL;
189 else
190 gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind;
191 #endif
192
193 /* Register the PSM with L2CAP */
194 if (transport == BT_TRANSPORT_BR_EDR) {
195 p_ccb->psm =
196 L2CA_REGISTER(psm, &gap_cb.conn.reg_info,
197 AMP_AUTOSWITCH_ALLOWED | AMP_USE_AMP_IF_POSSIBLE);
198 if (p_ccb->psm == 0) {
199 GAP_TRACE_ERROR("%s: Failure registering PSM 0x%04x", __func__, psm);
200 gap_release_ccb(p_ccb);
201 return (GAP_INVALID_HANDLE);
202 }
203 }
204
205 if (transport == BT_TRANSPORT_LE) {
206 p_ccb->psm =
207 L2CA_REGISTER_COC(psm, &gap_cb.conn.reg_info,
208 AMP_AUTOSWITCH_ALLOWED | AMP_USE_AMP_IF_POSSIBLE);
209 if (p_ccb->psm == 0) {
210 GAP_TRACE_ERROR("%s: Failure registering PSM 0x%04x", __func__, psm);
211 gap_release_ccb(p_ccb);
212 return (GAP_INVALID_HANDLE);
213 }
214 }
215
216 /* Register with Security Manager for the specific security level */
217 if (!BTM_SetSecurityLevel((uint8_t)!is_server, p_serv_name, p_ccb->service_id,
218 security, p_ccb->psm, 0, 0)) {
219 GAP_TRACE_ERROR("GAP_CONN - Security Error");
220 gap_release_ccb(p_ccb);
221 return (GAP_INVALID_HANDLE);
222 }
223
224 /* Fill in eL2CAP parameter data */
225 if (p_ccb->cfg.fcr_present) {
226 if (ertm_info == NULL) {
227 p_ccb->ertm_info.preferred_mode = p_ccb->cfg.fcr.mode;
228 p_ccb->ertm_info.user_rx_buf_size = GAP_DATA_BUF_SIZE;
229 p_ccb->ertm_info.user_tx_buf_size = GAP_DATA_BUF_SIZE;
230 p_ccb->ertm_info.fcr_rx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
231 p_ccb->ertm_info.fcr_tx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
232 } else {
233 p_ccb->ertm_info = *ertm_info;
234 }
235 }
236
237 /* optional FCR channel modes */
238 if (ertm_info != NULL) {
239 p_ccb->ertm_info.allowed_modes =
240 (chan_mode_mask) ? chan_mode_mask : (uint8_t)L2CAP_FCR_CHAN_OPT_BASIC;
241 }
242
243 if (is_server) {
244 p_ccb->con_flags |=
245 GAP_CCB_FLAGS_SEC_DONE; /* assume btm/l2cap would handle it */
246 p_ccb->con_state = GAP_CCB_STATE_LISTENING;
247 return (p_ccb->gap_handle);
248 } else {
249 /* We are the originator of this connection */
250 p_ccb->con_flags = GAP_CCB_FLAGS_IS_ORIG;
251
252 /* Transition to the next appropriate state, waiting for connection confirm.
253 */
254 p_ccb->con_state = GAP_CCB_STATE_CONN_SETUP;
255
256 /* mark security done flag, when security is not required */
257 if ((security & (BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_AUTHENTICATE |
258 BTM_SEC_OUT_ENCRYPT)) == 0)
259 p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
260
261 /* Check if L2CAP started the connection process */
262 if (p_rem_bda && (transport == BT_TRANSPORT_BR_EDR)) {
263 cid = L2CA_CONNECT_REQ(p_ccb->psm, p_rem_bda, &p_ccb->ertm_info);
264 if (cid != 0) {
265 p_ccb->connection_id = cid;
266 return (p_ccb->gap_handle);
267 }
268 }
269
270 if (p_rem_bda && (transport == BT_TRANSPORT_LE)) {
271 cid = L2CA_CONNECT_COC_REQ(p_ccb->psm, p_rem_bda, &p_ccb->local_coc_cfg);
272 if (cid != 0) {
273 p_ccb->connection_id = cid;
274 return (p_ccb->gap_handle);
275 }
276 }
277
278 gap_release_ccb(p_ccb);
279 return (GAP_INVALID_HANDLE);
280 }
281 }
282
283 /*******************************************************************************
284 *
285 * Function GAP_ConnClose
286 *
287 * Description This function is called to close a connection.
288 *
289 * Parameters: handle - Handle of the connection returned by GAP_ConnOpen
290 *
291 * Returns BT_PASS - closed OK
292 * GAP_ERR_BAD_HANDLE - invalid handle
293 *
294 ******************************************************************************/
GAP_ConnClose(uint16_t gap_handle)295 uint16_t GAP_ConnClose(uint16_t gap_handle) {
296 tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
297
298 GAP_TRACE_EVENT("GAP_CONN - close handle: 0x%x", gap_handle);
299
300 if (p_ccb) {
301 /* Check if we have a connection ID */
302 if (p_ccb->con_state != GAP_CCB_STATE_LISTENING)
303 L2CA_DISCONNECT_REQ(p_ccb->connection_id);
304
305 gap_release_ccb(p_ccb);
306
307 return (BT_PASS);
308 }
309
310 return (GAP_ERR_BAD_HANDLE);
311 }
312
313 /*******************************************************************************
314 *
315 * Function GAP_ConnReadData
316 *
317 * Description Normally not GKI aware application will call this function
318 * after receiving GAP_EVT_RXDATA event.
319 *
320 * Parameters: handle - Handle of the connection returned in the Open
321 * p_data - Data area
322 * max_len - Byte count requested
323 * p_len - Byte count received
324 *
325 * Returns BT_PASS - data read
326 * GAP_ERR_BAD_HANDLE - invalid handle
327 * GAP_NO_DATA_AVAIL - no data available
328 *
329 ******************************************************************************/
GAP_ConnReadData(uint16_t gap_handle,uint8_t * p_data,uint16_t max_len,uint16_t * p_len)330 uint16_t GAP_ConnReadData(uint16_t gap_handle, uint8_t* p_data,
331 uint16_t max_len, uint16_t* p_len) {
332 tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
333 uint16_t copy_len;
334
335 if (!p_ccb) return (GAP_ERR_BAD_HANDLE);
336
337 *p_len = 0;
338
339 if (fixed_queue_is_empty(p_ccb->rx_queue)) return (GAP_NO_DATA_AVAIL);
340
341 mutex_global_lock();
342
343 while (max_len) {
344 BT_HDR* p_buf =
345 static_cast<BT_HDR*>(fixed_queue_try_peek_first(p_ccb->rx_queue));
346 if (p_buf == NULL) break;
347
348 copy_len = (p_buf->len > max_len) ? max_len : p_buf->len;
349 max_len -= copy_len;
350 *p_len += copy_len;
351 if (p_data) {
352 memcpy(p_data, (uint8_t*)(p_buf + 1) + p_buf->offset, copy_len);
353 p_data += copy_len;
354 }
355
356 if (p_buf->len > copy_len) {
357 p_buf->offset += copy_len;
358 p_buf->len -= copy_len;
359 break;
360 }
361 osi_free(fixed_queue_try_dequeue(p_ccb->rx_queue));
362 }
363
364 p_ccb->rx_queue_size -= *p_len;
365
366 mutex_global_unlock();
367
368 GAP_TRACE_EVENT("GAP_ConnReadData - rx_queue_size left=%d, *p_len=%d",
369 p_ccb->rx_queue_size, *p_len);
370
371 return (BT_PASS);
372 }
373
374 /*******************************************************************************
375 *
376 * Function GAP_GetRxQueueCnt
377 *
378 * Description This function return number of bytes on the rx queue.
379 *
380 * Parameters: handle - Handle returned in the GAP_ConnOpen
381 * p_rx_queue_count - Pointer to return queue count in.
382 *
383 *
384 ******************************************************************************/
GAP_GetRxQueueCnt(uint16_t handle,uint32_t * p_rx_queue_count)385 int GAP_GetRxQueueCnt(uint16_t handle, uint32_t* p_rx_queue_count) {
386 tGAP_CCB* p_ccb;
387 int rc = BT_PASS;
388
389 /* Check that handle is valid */
390 if (handle < GAP_MAX_CONNECTIONS) {
391 p_ccb = &gap_cb.conn.ccb_pool[handle];
392
393 if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) {
394 *p_rx_queue_count = p_ccb->rx_queue_size;
395 } else
396 rc = GAP_INVALID_HANDLE;
397 } else
398 rc = GAP_INVALID_HANDLE;
399
400 GAP_TRACE_EVENT("GAP_GetRxQueueCnt - rc = 0x%04x, rx_queue_count=%d", rc,
401 *p_rx_queue_count);
402
403 return (rc);
404 }
405
406 /*******************************************************************************
407 *
408 * Function GAP_ConnBTRead
409 *
410 * Description Bluetooth-aware applications will call this function after
411 * receiving GAP_EVT_RXDATA event.
412 *
413 * Parameters: handle - Handle of the connection returned in the Open
414 * pp_buf - pointer to address of buffer with data,
415 *
416 * Returns BT_PASS - data read
417 * GAP_ERR_BAD_HANDLE - invalid handle
418 * GAP_NO_DATA_AVAIL - no data available
419 *
420 ******************************************************************************/
GAP_ConnBTRead(uint16_t gap_handle,BT_HDR ** pp_buf)421 uint16_t GAP_ConnBTRead(uint16_t gap_handle, BT_HDR** pp_buf) {
422 tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
423 BT_HDR* p_buf;
424
425 if (!p_ccb) return (GAP_ERR_BAD_HANDLE);
426
427 p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->rx_queue);
428
429 if (p_buf) {
430 *pp_buf = p_buf;
431
432 p_ccb->rx_queue_size -= p_buf->len;
433 return (BT_PASS);
434 } else {
435 *pp_buf = NULL;
436 return (GAP_NO_DATA_AVAIL);
437 }
438 }
439
440 /*******************************************************************************
441 *
442 * Function GAP_ConnWriteData
443 *
444 * Description Normally not GKI aware application will call this function
445 * to send data to the connection.
446 *
447 * Parameters: handle - Handle of the connection returned in the Open
448 * p_data - Data area
449 * max_len - Byte count requested
450 * p_len - Byte count received
451 *
452 * Returns BT_PASS - data read
453 * GAP_ERR_BAD_HANDLE - invalid handle
454 * GAP_ERR_BAD_STATE - connection not established
455 * GAP_CONGESTION - system is congested
456 *
457 ******************************************************************************/
GAP_ConnWriteData(uint16_t gap_handle,uint8_t * p_data,uint16_t max_len,uint16_t * p_len)458 uint16_t GAP_ConnWriteData(uint16_t gap_handle, uint8_t* p_data,
459 uint16_t max_len, uint16_t* p_len) {
460 tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
461 BT_HDR* p_buf;
462
463 *p_len = 0;
464
465 if (!p_ccb) return (GAP_ERR_BAD_HANDLE);
466
467 if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED) return (GAP_ERR_BAD_STATE);
468
469 while (max_len) {
470 if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
471 p_buf = (BT_HDR*)osi_malloc(L2CAP_FCR_ERTM_BUF_SIZE);
472 else
473 p_buf = (BT_HDR*)osi_malloc(GAP_DATA_BUF_SIZE);
474
475 p_buf->offset = L2CAP_MIN_OFFSET;
476 p_buf->len =
477 (p_ccb->rem_mtu_size < max_len) ? p_ccb->rem_mtu_size : max_len;
478 p_buf->event = BT_EVT_TO_BTU_SP_DATA;
479
480 memcpy((uint8_t*)(p_buf + 1) + p_buf->offset, p_data, p_buf->len);
481
482 *p_len += p_buf->len;
483 max_len -= p_buf->len;
484 p_data += p_buf->len;
485
486 GAP_TRACE_EVENT("GAP_WriteData %d bytes", p_buf->len);
487
488 fixed_queue_enqueue(p_ccb->tx_queue, p_buf);
489 }
490
491 if (p_ccb->is_congested) {
492 return (BT_PASS);
493 }
494
495 /* Send the buffer through L2CAP */
496 while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->tx_queue)) != NULL) {
497 uint8_t status = L2CA_DATA_WRITE(p_ccb->connection_id, p_buf);
498
499 if (status == L2CAP_DW_CONGESTED) {
500 p_ccb->is_congested = true;
501 break;
502 } else if (status != L2CAP_DW_SUCCESS)
503 return (GAP_ERR_BAD_STATE);
504 }
505
506 return (BT_PASS);
507 }
508
509 /*******************************************************************************
510 *
511 * Function GAP_ConnReconfig
512 *
513 * Description Applications can call this function to reconfigure the
514 * connection.
515 *
516 * Parameters: handle - Handle of the connection
517 * p_cfg - Pointer to new configuration
518 *
519 * Returns BT_PASS - config process started
520 * GAP_ERR_BAD_HANDLE - invalid handle
521 *
522 ******************************************************************************/
GAP_ConnReconfig(uint16_t gap_handle,tL2CAP_CFG_INFO * p_cfg)523 uint16_t GAP_ConnReconfig(uint16_t gap_handle, tL2CAP_CFG_INFO* p_cfg) {
524 tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
525
526 if (!p_ccb) return (GAP_ERR_BAD_HANDLE);
527
528 p_ccb->cfg = *p_cfg;
529
530 if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED)
531 L2CA_CONFIG_REQ(p_ccb->connection_id, p_cfg);
532
533 return (BT_PASS);
534 }
535
536 /*******************************************************************************
537 *
538 * Function GAP_ConnSetIdleTimeout
539 *
540 * Description Higher layers call this function to set the idle timeout for
541 * a connection, or for all future connections. The "idle
542 * timeout" is the amount of time that a connection can remain
543 * up with no L2CAP channels on it. A timeout of zero means
544 * that the connection will be torn down immediately when the
545 * last channel is removed. A timeout of 0xFFFF means no
546 * timeout. Values are in seconds.
547 *
548 * Parameters: handle - Handle of the connection
549 * timeout - in secs
550 * 0 = immediate disconnect when last channel is
551 * removed
552 * 0xFFFF = no idle timeout
553 *
554 * Returns BT_PASS - config process started
555 * GAP_ERR_BAD_HANDLE - invalid handle
556 *
557 ******************************************************************************/
GAP_ConnSetIdleTimeout(uint16_t gap_handle,uint16_t timeout)558 uint16_t GAP_ConnSetIdleTimeout(uint16_t gap_handle, uint16_t timeout) {
559 tGAP_CCB* p_ccb;
560
561 p_ccb = gap_find_ccb_by_handle(gap_handle);
562 if (p_ccb == NULL) return (GAP_ERR_BAD_HANDLE);
563
564 if (L2CA_SetIdleTimeout(p_ccb->connection_id, timeout, false))
565 return (BT_PASS);
566 else
567 return (GAP_ERR_BAD_HANDLE);
568 }
569
570 /*******************************************************************************
571 *
572 * Function GAP_ConnGetRemoteAddr
573 *
574 * Description This function is called to get the remote BD address
575 * of a connection.
576 *
577 * Parameters: handle - Handle of the connection returned by GAP_ConnOpen
578 *
579 * Returns BT_PASS - closed OK
580 * GAP_ERR_BAD_HANDLE - invalid handle
581 *
582 ******************************************************************************/
GAP_ConnGetRemoteAddr(uint16_t gap_handle)583 uint8_t* GAP_ConnGetRemoteAddr(uint16_t gap_handle) {
584 tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
585
586 GAP_TRACE_EVENT("GAP_ConnGetRemoteAddr gap_handle = %d", gap_handle);
587
588 if ((p_ccb) && (p_ccb->con_state > GAP_CCB_STATE_LISTENING)) {
589 GAP_TRACE_EVENT(
590 "GAP_ConnGetRemoteAddr bda "
591 ":0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
592 p_ccb->rem_dev_address[0], p_ccb->rem_dev_address[1],
593 p_ccb->rem_dev_address[2], p_ccb->rem_dev_address[3],
594 p_ccb->rem_dev_address[4], p_ccb->rem_dev_address[5]);
595 return (p_ccb->rem_dev_address);
596 } else {
597 GAP_TRACE_EVENT("GAP_ConnGetRemoteAddr return Error ");
598 return (NULL);
599 }
600 }
601
602 /*******************************************************************************
603 *
604 * Function GAP_ConnGetRemMtuSize
605 *
606 * Description Returns the remote device's MTU size
607 *
608 * Parameters: handle - Handle of the connection
609 *
610 * Returns uint16_t - maximum size buffer that can be transmitted to
611 * the peer
612 *
613 ******************************************************************************/
GAP_ConnGetRemMtuSize(uint16_t gap_handle)614 uint16_t GAP_ConnGetRemMtuSize(uint16_t gap_handle) {
615 tGAP_CCB* p_ccb;
616
617 p_ccb = gap_find_ccb_by_handle(gap_handle);
618 if (p_ccb == NULL) return (0);
619
620 return (p_ccb->rem_mtu_size);
621 }
622
623 /*******************************************************************************
624 *
625 * Function GAP_ConnGetL2CAPCid
626 *
627 * Description Returns the L2CAP channel id
628 *
629 * Parameters: handle - Handle of the connection
630 *
631 * Returns uint16_t - The L2CAP channel id
632 * 0, if error
633 *
634 ******************************************************************************/
GAP_ConnGetL2CAPCid(uint16_t gap_handle)635 uint16_t GAP_ConnGetL2CAPCid(uint16_t gap_handle) {
636 tGAP_CCB* p_ccb;
637
638 p_ccb = gap_find_ccb_by_handle(gap_handle);
639 if (p_ccb == NULL) return (0);
640
641 return (p_ccb->connection_id);
642 }
643
644 /*******************************************************************************
645 *
646 * Function gap_tx_connect_ind
647 *
648 * Description Sends out GAP_EVT_TX_EMPTY when transmission has been
649 * completed.
650 *
651 * Returns void
652 *
653 ******************************************************************************/
gap_tx_complete_ind(uint16_t l2cap_cid,uint16_t sdu_sent)654 void gap_tx_complete_ind(uint16_t l2cap_cid, uint16_t sdu_sent) {
655 tGAP_CCB* p_ccb = gap_find_ccb_by_cid(l2cap_cid);
656 if (p_ccb == NULL) return;
657
658 if ((p_ccb->con_state == GAP_CCB_STATE_CONNECTED) && (sdu_sent == 0xFFFF)) {
659 GAP_TRACE_EVENT("%s: GAP_EVT_TX_EMPTY", __func__);
660 p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_TX_EMPTY);
661 }
662 }
663
664 /*******************************************************************************
665 *
666 * Function gap_connect_ind
667 *
668 * Description This function handles an inbound connection indication
669 * from L2CAP. This is the case where we are acting as a
670 * server.
671 *
672 * Returns void
673 *
674 ******************************************************************************/
gap_connect_ind(BD_ADDR bd_addr,uint16_t l2cap_cid,uint16_t psm,uint8_t l2cap_id)675 static void gap_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid, uint16_t psm,
676 uint8_t l2cap_id) {
677 uint16_t xx;
678 tGAP_CCB* p_ccb;
679
680 /* See if we have a CCB listening for the connection */
681 for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS;
682 xx++, p_ccb++) {
683 if ((p_ccb->con_state == GAP_CCB_STATE_LISTENING) && (p_ccb->psm == psm) &&
684 ((p_ccb->rem_addr_specified == false) ||
685 (!memcmp(bd_addr, p_ccb->rem_dev_address, BD_ADDR_LEN))))
686 break;
687 }
688
689 if (xx == GAP_MAX_CONNECTIONS) {
690 GAP_TRACE_WARNING("*******");
691 GAP_TRACE_WARNING(
692 "WARNING: GAP Conn Indication for Unexpected Bd Addr...Disconnecting");
693 GAP_TRACE_WARNING("*******");
694
695 /* Disconnect because it is an unexpected connection */
696 L2CA_DISCONNECT_REQ(l2cap_cid);
697 return;
698 }
699
700 /* Transition to the next appropriate state, waiting for config setup. */
701 if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
702 p_ccb->con_state = GAP_CCB_STATE_CFG_SETUP;
703
704 /* Save the BD Address and Channel ID. */
705 memcpy(&p_ccb->rem_dev_address[0], bd_addr, BD_ADDR_LEN);
706 p_ccb->connection_id = l2cap_cid;
707
708 /* Send response to the L2CAP layer. */
709 if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
710 L2CA_CONNECT_RSP(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK,
711 &p_ccb->ertm_info);
712
713 if (p_ccb->transport == BT_TRANSPORT_LE) {
714 L2CA_CONNECT_COC_RSP(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK,
715 L2CAP_CONN_OK, &p_ccb->local_coc_cfg);
716
717 /* get the remote coc configuration */
718 L2CA_GET_PEER_COC_CONFIG(l2cap_cid, &p_ccb->peer_coc_cfg);
719 p_ccb->rem_mtu_size = p_ccb->peer_coc_cfg.mtu;
720
721 /* configuration is not required for LE COC */
722 p_ccb->con_flags |= GAP_CCB_FLAGS_HIS_CFG_DONE;
723 p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE;
724 gap_checks_con_flags(p_ccb);
725 }
726
727 GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP conn ind, CID: 0x%x",
728 p_ccb->connection_id);
729
730 /* Send a Configuration Request. */
731 if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
732 L2CA_CONFIG_REQ(l2cap_cid, &p_ccb->cfg);
733 }
734
735 /*******************************************************************************
736 *
737 * Function gap_checks_con_flags
738 *
739 * Description This function processes the L2CAP configuration indication
740 * event.
741 *
742 * Returns void
743 *
744 ******************************************************************************/
gap_checks_con_flags(tGAP_CCB * p_ccb)745 static void gap_checks_con_flags(tGAP_CCB* p_ccb) {
746 GAP_TRACE_EVENT("gap_checks_con_flags conn_flags:0x%x, ", p_ccb->con_flags);
747 /* if all the required con_flags are set, report the OPEN event now */
748 if ((p_ccb->con_flags & GAP_CCB_FLAGS_CONN_DONE) == GAP_CCB_FLAGS_CONN_DONE) {
749 p_ccb->con_state = GAP_CCB_STATE_CONNECTED;
750
751 p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_OPENED);
752 }
753 }
754
755 /*******************************************************************************
756 *
757 * Function gap_sec_check_complete
758 *
759 * Description The function called when Security Manager finishes
760 * verification of the service side connection
761 *
762 * Returns void
763 *
764 ******************************************************************************/
gap_sec_check_complete(UNUSED_ATTR BD_ADDR bd_addr,UNUSED_ATTR tBT_TRANSPORT transport,void * p_ref_data,uint8_t res)765 static void gap_sec_check_complete(UNUSED_ATTR BD_ADDR bd_addr,
766 UNUSED_ATTR tBT_TRANSPORT transport,
767 void* p_ref_data, uint8_t res) {
768 tGAP_CCB* p_ccb = (tGAP_CCB*)p_ref_data;
769
770 GAP_TRACE_EVENT(
771 "gap_sec_check_complete conn_state:%d, conn_flags:0x%x, status:%d",
772 p_ccb->con_state, p_ccb->con_flags, res);
773 if (p_ccb->con_state == GAP_CCB_STATE_IDLE) return;
774
775 if (res == BTM_SUCCESS) {
776 p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
777 gap_checks_con_flags(p_ccb);
778 } else {
779 /* security failed - disconnect the channel */
780 L2CA_DISCONNECT_REQ(p_ccb->connection_id);
781 }
782 }
783
784 /*******************************************************************************
785 *
786 * Function gap_connect_cfm
787 *
788 * Description This function handles the connect confirm events
789 * from L2CAP. This is the case when we are acting as a
790 * client and have sent a connect request.
791 *
792 * Returns void
793 *
794 ******************************************************************************/
gap_connect_cfm(uint16_t l2cap_cid,uint16_t result)795 static void gap_connect_cfm(uint16_t l2cap_cid, uint16_t result) {
796 tGAP_CCB* p_ccb;
797
798 /* Find CCB based on CID */
799 p_ccb = gap_find_ccb_by_cid(l2cap_cid);
800 if (p_ccb == NULL) return;
801
802 /* initiate security process, if needed */
803 if ((p_ccb->con_flags & GAP_CCB_FLAGS_SEC_DONE) == 0 &&
804 p_ccb->transport != BT_TRANSPORT_LE) {
805 btm_sec_mx_access_request(p_ccb->rem_dev_address, p_ccb->psm, true, 0, 0,
806 &gap_sec_check_complete, p_ccb);
807 }
808
809 /* If the connection response contains success status, then */
810 /* Transition to the next state and startup the timer. */
811 if ((result == L2CAP_CONN_OK) &&
812 (p_ccb->con_state == GAP_CCB_STATE_CONN_SETUP)) {
813 if (p_ccb->transport == BT_TRANSPORT_BR_EDR) {
814 p_ccb->con_state = GAP_CCB_STATE_CFG_SETUP;
815
816 /* Send a Configuration Request. */
817 L2CA_CONFIG_REQ(l2cap_cid, &p_ccb->cfg);
818 }
819
820 if (p_ccb->transport == BT_TRANSPORT_LE) {
821 /* get the remote coc configuration */
822 L2CA_GET_PEER_COC_CONFIG(l2cap_cid, &p_ccb->peer_coc_cfg);
823 p_ccb->rem_mtu_size = p_ccb->peer_coc_cfg.mtu;
824
825 /* configuration is not required for LE COC */
826 p_ccb->con_flags |= GAP_CCB_FLAGS_HIS_CFG_DONE;
827 p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE;
828 p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
829 gap_checks_con_flags(p_ccb);
830 }
831 } else {
832 /* Tell the user if he has a callback */
833 if (p_ccb->p_callback)
834 (*p_ccb->p_callback)(p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
835
836 gap_release_ccb(p_ccb);
837 }
838 }
839
840 /*******************************************************************************
841 *
842 * Function gap_config_ind
843 *
844 * Description This function processes the L2CAP configuration indication
845 * event.
846 *
847 * Returns void
848 *
849 ******************************************************************************/
gap_config_ind(uint16_t l2cap_cid,tL2CAP_CFG_INFO * p_cfg)850 static void gap_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
851 tGAP_CCB* p_ccb;
852 uint16_t local_mtu_size;
853
854 /* Find CCB based on CID */
855 p_ccb = gap_find_ccb_by_cid(l2cap_cid);
856 if (p_ccb == NULL) return;
857
858 /* Remember the remote MTU size */
859
860 if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
861 local_mtu_size =
862 p_ccb->ertm_info.user_tx_buf_size - sizeof(BT_HDR) - L2CAP_MIN_OFFSET;
863 } else
864 local_mtu_size = L2CAP_MTU_SIZE;
865
866 if ((!p_cfg->mtu_present) || (p_cfg->mtu > local_mtu_size)) {
867 p_ccb->rem_mtu_size = local_mtu_size;
868 } else
869 p_ccb->rem_mtu_size = p_cfg->mtu;
870
871 /* For now, always accept configuration from the other side */
872 p_cfg->flush_to_present = false;
873 p_cfg->mtu_present = false;
874 p_cfg->result = L2CAP_CFG_OK;
875 p_cfg->fcs_present = false;
876
877 L2CA_CONFIG_RSP(l2cap_cid, p_cfg);
878
879 p_ccb->con_flags |= GAP_CCB_FLAGS_HIS_CFG_DONE;
880
881 gap_checks_con_flags(p_ccb);
882 }
883
884 /*******************************************************************************
885 *
886 * Function gap_config_cfm
887 *
888 * Description This function processes the L2CAP configuration confirmation
889 * event.
890 *
891 * Returns void
892 *
893 ******************************************************************************/
gap_config_cfm(uint16_t l2cap_cid,tL2CAP_CFG_INFO * p_cfg)894 static void gap_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
895 tGAP_CCB* p_ccb;
896
897 /* Find CCB based on CID */
898 p_ccb = gap_find_ccb_by_cid(l2cap_cid);
899 if (p_ccb == NULL) return;
900
901 if (p_cfg->result == L2CAP_CFG_OK) {
902 p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE;
903
904 if (p_ccb->cfg.fcr_present)
905 p_ccb->cfg.fcr.mode = p_cfg->fcr.mode;
906 else
907 p_ccb->cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
908
909 gap_checks_con_flags(p_ccb);
910 } else {
911 p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
912 gap_release_ccb(p_ccb);
913 }
914 }
915
916 /*******************************************************************************
917 *
918 * Function gap_disconnect_ind
919 *
920 * Description This function handles a disconnect event from L2CAP. If
921 * requested to, we ack the disconnect before dropping the CCB
922 *
923 * Returns void
924 *
925 ******************************************************************************/
gap_disconnect_ind(uint16_t l2cap_cid,bool ack_needed)926 static void gap_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) {
927 tGAP_CCB* p_ccb;
928
929 GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
930
931 /* Find CCB based on CID */
932 p_ccb = gap_find_ccb_by_cid(l2cap_cid);
933 if (p_ccb == NULL) return;
934
935 if (ack_needed) L2CA_DISCONNECT_RSP(l2cap_cid);
936
937 p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
938 gap_release_ccb(p_ccb);
939 }
940
941 /*******************************************************************************
942 *
943 * Function gap_data_ind
944 *
945 * Description This function is called when data is received from L2CAP.
946 *
947 * Returns void
948 *
949 ******************************************************************************/
gap_data_ind(uint16_t l2cap_cid,BT_HDR * p_msg)950 static void gap_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg) {
951 tGAP_CCB* p_ccb;
952
953 /* Find CCB based on CID */
954 p_ccb = gap_find_ccb_by_cid(l2cap_cid);
955 if (p_ccb == NULL) {
956 osi_free(p_msg);
957 return;
958 }
959
960 if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) {
961 fixed_queue_enqueue(p_ccb->rx_queue, p_msg);
962
963 p_ccb->rx_queue_size += p_msg->len;
964 /*
965 GAP_TRACE_EVENT ("gap_data_ind - rx_queue_size=%d, msg len=%d",
966 p_ccb->rx_queue_size, p_msg->len);
967 */
968
969 p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_DATA_AVAIL);
970 } else {
971 osi_free(p_msg);
972 }
973 }
974
975 /*******************************************************************************
976 *
977 * Function gap_congestion_ind
978 *
979 * Description This is a callback function called by L2CAP when
980 * data L2CAP congestion status changes
981 *
982 ******************************************************************************/
gap_congestion_ind(uint16_t lcid,bool is_congested)983 static void gap_congestion_ind(uint16_t lcid, bool is_congested) {
984 tGAP_CCB* p_ccb;
985 uint16_t event;
986 BT_HDR* p_buf;
987 uint8_t status;
988
989 GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP Is Congested (%d), CID: 0x%x",
990 is_congested, lcid);
991
992 /* Find CCB based on CID */
993 p_ccb = gap_find_ccb_by_cid(lcid);
994 if (p_ccb == NULL) return;
995
996 p_ccb->is_congested = is_congested;
997
998 event = (is_congested) ? GAP_EVT_CONN_CONGESTED : GAP_EVT_CONN_UNCONGESTED;
999 p_ccb->p_callback(p_ccb->gap_handle, event);
1000
1001 if (!is_congested) {
1002 while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->tx_queue)) !=
1003 NULL) {
1004 status = L2CA_DATA_WRITE(p_ccb->connection_id, p_buf);
1005
1006 if (status == L2CAP_DW_CONGESTED) {
1007 p_ccb->is_congested = true;
1008 break;
1009 } else if (status != L2CAP_DW_SUCCESS)
1010 break;
1011 }
1012 }
1013 }
1014
1015 /*******************************************************************************
1016 *
1017 * Function gap_find_ccb_by_cid
1018 *
1019 * Description This function searches the CCB table for an entry with the
1020 * passed CID.
1021 *
1022 * Returns the CCB address, or NULL if not found.
1023 *
1024 ******************************************************************************/
gap_find_ccb_by_cid(uint16_t cid)1025 static tGAP_CCB* gap_find_ccb_by_cid(uint16_t cid) {
1026 uint16_t xx;
1027 tGAP_CCB* p_ccb;
1028
1029 /* Look through each connection control block */
1030 for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS;
1031 xx++, p_ccb++) {
1032 if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) &&
1033 (p_ccb->connection_id == cid))
1034 return (p_ccb);
1035 }
1036
1037 /* If here, not found */
1038 return (NULL);
1039 }
1040
1041 /*******************************************************************************
1042 *
1043 * Function gap_find_ccb_by_handle
1044 *
1045 * Description This function searches the CCB table for an entry with the
1046 * passed handle.
1047 *
1048 * Returns the CCB address, or NULL if not found.
1049 *
1050 ******************************************************************************/
gap_find_ccb_by_handle(uint16_t handle)1051 static tGAP_CCB* gap_find_ccb_by_handle(uint16_t handle) {
1052 tGAP_CCB* p_ccb;
1053
1054 /* Check that handle is valid */
1055 if (handle < GAP_MAX_CONNECTIONS) {
1056 p_ccb = &gap_cb.conn.ccb_pool[handle];
1057
1058 if (p_ccb->con_state != GAP_CCB_STATE_IDLE) return (p_ccb);
1059 }
1060
1061 /* If here, handle points to invalid connection */
1062 return (NULL);
1063 }
1064
1065 /*******************************************************************************
1066 *
1067 * Function gap_allocate_ccb
1068 *
1069 * Description This function allocates a new CCB.
1070 *
1071 * Returns CCB address, or NULL if none available.
1072 *
1073 ******************************************************************************/
gap_allocate_ccb(void)1074 static tGAP_CCB* gap_allocate_ccb(void) {
1075 uint16_t xx;
1076 tGAP_CCB* p_ccb;
1077
1078 /* Look through each connection control block for a free one */
1079 for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS;
1080 xx++, p_ccb++) {
1081 if (p_ccb->con_state == GAP_CCB_STATE_IDLE) {
1082 memset(p_ccb, 0, sizeof(tGAP_CCB));
1083 p_ccb->tx_queue = fixed_queue_new(SIZE_MAX);
1084 p_ccb->rx_queue = fixed_queue_new(SIZE_MAX);
1085
1086 p_ccb->gap_handle = xx;
1087 p_ccb->rem_mtu_size = L2CAP_MTU_SIZE;
1088
1089 return (p_ccb);
1090 }
1091 }
1092
1093 /* If here, no free CCB found */
1094 return (NULL);
1095 }
1096
1097 /*******************************************************************************
1098 *
1099 * Function gap_release_ccb
1100 *
1101 * Description This function releases a CCB.
1102 *
1103 * Returns void
1104 *
1105 ******************************************************************************/
gap_release_ccb(tGAP_CCB * p_ccb)1106 static void gap_release_ccb(tGAP_CCB* p_ccb) {
1107 /* Drop any buffers we may be holding */
1108 p_ccb->rx_queue_size = 0;
1109
1110 while (!fixed_queue_is_empty(p_ccb->rx_queue))
1111 osi_free(fixed_queue_try_dequeue(p_ccb->rx_queue));
1112 fixed_queue_free(p_ccb->rx_queue, NULL);
1113 p_ccb->rx_queue = NULL;
1114
1115 while (!fixed_queue_is_empty(p_ccb->tx_queue))
1116 osi_free(fixed_queue_try_dequeue(p_ccb->tx_queue));
1117 fixed_queue_free(p_ccb->tx_queue, NULL);
1118 p_ccb->tx_queue = NULL;
1119
1120 p_ccb->con_state = GAP_CCB_STATE_IDLE;
1121
1122 /* If no-one else is using the PSM, deregister from L2CAP */
1123 tGAP_CCB* p_ccb_local = gap_cb.conn.ccb_pool;
1124 for (uint16_t i = 0; i < GAP_MAX_CONNECTIONS; i++, p_ccb_local++) {
1125 if ((p_ccb_local->con_state != GAP_CCB_STATE_IDLE) &&
1126 (p_ccb_local->psm == p_ccb->psm)) {
1127 GAP_TRACE_EVENT("%s :%d PSM is still in use, do not deregister",
1128 __func__, p_ccb_local->psm);
1129 return;
1130 }
1131 }
1132
1133 /* Free the security record for this PSM */
1134 BTM_SecClrService(p_ccb->service_id);
1135 if (p_ccb->transport == BT_TRANSPORT_BR_EDR) L2CA_DEREGISTER(p_ccb->psm);
1136 if (p_ccb->transport == BT_TRANSPORT_LE) L2CA_DEREGISTER_COC(p_ccb->psm);
1137 }
1138
1139 #endif /* GAP_CONN_INCLUDED */
1140