1 /******************************************************************************
2  *
3  *  Copyright (C) 1999-2012 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 /******************************************************************************
20  *
21  *  This file contains the main SDP functions
22  *
23  ******************************************************************************/
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "bt_common.h"
30 #include "bt_target.h"
31 #include "bt_utils.h"
32 #include "hcidefs.h"
33 #include "hcimsgs.h"
34 
35 #include "l2c_api.h"
36 #include "l2cdefs.h"
37 #include "osi/include/osi.h"
38 
39 #include "btm_api.h"
40 #include "btu.h"
41 
42 #include "sdp_api.h"
43 #include "sdpint.h"
44 
45 extern fixed_queue_t* btu_general_alarm_queue;
46 
47 /******************************************************************************/
48 /*                     G L O B A L      S D P       D A T A                   */
49 /******************************************************************************/
50 tSDP_CB sdp_cb;
51 
52 /******************************************************************************/
53 /*            L O C A L    F U N C T I O N     P R O T O T Y P E S            */
54 /******************************************************************************/
55 static void sdp_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid,
56                             UNUSED_ATTR uint16_t psm, uint8_t l2cap_id);
57 static void sdp_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
58 static void sdp_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
59 static void sdp_disconnect_ind(uint16_t l2cap_cid, bool ack_needed);
60 static void sdp_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg);
61 
62 static void sdp_connect_cfm(uint16_t l2cap_cid, uint16_t result);
63 static void sdp_disconnect_cfm(uint16_t l2cap_cid, uint16_t result);
64 
65 /*******************************************************************************
66  *
67  * Function         sdp_init
68  *
69  * Description      This function initializes the SDP unit.
70  *
71  * Returns          void
72  *
73  ******************************************************************************/
sdp_init(void)74 void sdp_init(void) {
75   /* Clears all structures and local SDP database (if Server is enabled) */
76   memset(&sdp_cb, 0, sizeof(tSDP_CB));
77 
78   /* Initialize the L2CAP configuration. We only care about MTU and flush */
79   sdp_cb.l2cap_my_cfg.mtu_present = true;
80   sdp_cb.l2cap_my_cfg.mtu = SDP_MTU_SIZE;
81   sdp_cb.l2cap_my_cfg.flush_to_present = true;
82   sdp_cb.l2cap_my_cfg.flush_to = SDP_FLUSH_TO;
83 
84   sdp_cb.max_attr_list_size = SDP_MTU_SIZE - 16;
85   sdp_cb.max_recs_per_search = SDP_MAX_DISC_SERVER_RECS;
86 
87 #if (SDP_SERVER_ENABLED == TRUE)
88   /* Register with Security Manager for the specific security level */
89   if (!BTM_SetSecurityLevel(false, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER,
90                             SDP_SECURITY_LEVEL, SDP_PSM, 0, 0)) {
91     SDP_TRACE_ERROR("Security Registration Server failed");
92     return;
93   }
94 #endif
95 
96   /* Register with Security Manager for the specific security level */
97   if (!BTM_SetSecurityLevel(true, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER,
98                             SDP_SECURITY_LEVEL, SDP_PSM, 0, 0)) {
99     SDP_TRACE_ERROR("Security Registration for Client failed");
100     return;
101   }
102 
103 #if defined(SDP_INITIAL_TRACE_LEVEL)
104   sdp_cb.trace_level = SDP_INITIAL_TRACE_LEVEL;
105 #else
106   sdp_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
107 #endif
108 
109   sdp_cb.reg_info.pL2CA_ConnectInd_Cb = sdp_connect_ind;
110   sdp_cb.reg_info.pL2CA_ConnectCfm_Cb = sdp_connect_cfm;
111   sdp_cb.reg_info.pL2CA_ConnectPnd_Cb = NULL;
112   sdp_cb.reg_info.pL2CA_ConfigInd_Cb = sdp_config_ind;
113   sdp_cb.reg_info.pL2CA_ConfigCfm_Cb = sdp_config_cfm;
114   sdp_cb.reg_info.pL2CA_DisconnectInd_Cb = sdp_disconnect_ind;
115   sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb = sdp_disconnect_cfm;
116   sdp_cb.reg_info.pL2CA_QoSViolationInd_Cb = NULL;
117   sdp_cb.reg_info.pL2CA_DataInd_Cb = sdp_data_ind;
118   sdp_cb.reg_info.pL2CA_CongestionStatus_Cb = NULL;
119   sdp_cb.reg_info.pL2CA_TxComplete_Cb = NULL;
120 
121   /* Now, register with L2CAP */
122   if (!L2CA_Register(SDP_PSM, &sdp_cb.reg_info)) {
123     SDP_TRACE_ERROR("SDP Registration failed");
124   }
125 }
126 
127 #if (SDP_DEBUG == TRUE)
128 /*******************************************************************************
129  *
130  * Function         sdp_set_max_attr_list_size
131  *
132  * Description      This function sets the max attribute list size to use
133  *
134  * Returns          void
135  *
136  ******************************************************************************/
sdp_set_max_attr_list_size(uint16_t max_size)137 uint16_t sdp_set_max_attr_list_size(uint16_t max_size) {
138   if (max_size > (sdp_cb.l2cap_my_cfg.mtu - 16))
139     max_size = sdp_cb.l2cap_my_cfg.mtu - 16;
140 
141   sdp_cb.max_attr_list_size = max_size;
142 
143   return sdp_cb.max_attr_list_size;
144 }
145 #endif
146 
147 /*******************************************************************************
148  *
149  * Function         sdp_connect_ind
150  *
151  * Description      This function handles an inbound connection indication
152  *                  from L2CAP. This is the case where we are acting as a
153  *                  server.
154  *
155  * Returns          void
156  *
157  ******************************************************************************/
sdp_connect_ind(BD_ADDR bd_addr,uint16_t l2cap_cid,UNUSED_ATTR uint16_t psm,uint8_t l2cap_id)158 static void sdp_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid,
159                             UNUSED_ATTR uint16_t psm, uint8_t l2cap_id) {
160 #if (SDP_SERVER_ENABLED == TRUE)
161   tCONN_CB* p_ccb;
162 
163   /* Allocate a new CCB. Return if none available. */
164   p_ccb = sdpu_allocate_ccb();
165   if (p_ccb == NULL) return;
166 
167   /* Transition to the next appropriate state, waiting for config setup. */
168   p_ccb->con_state = SDP_STATE_CFG_SETUP;
169 
170   /* Save the BD Address and Channel ID. */
171   memcpy(&p_ccb->device_address[0], bd_addr, sizeof(BD_ADDR));
172   p_ccb->connection_id = l2cap_cid;
173 
174   /* Send response to the L2CAP layer. */
175   L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
176   {
177     tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg;
178 
179     if (cfg.fcr_present) {
180       SDP_TRACE_DEBUG(
181           "sdp_connect_ind:  mode %u, txwinsz %u, max_trans %u, rtrans_tout "
182           "%u, mon_tout %u, mps %u",
183           cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit,
184           cfg.fcr.rtrans_tout, cfg.fcr.mon_tout, cfg.fcr.mps);
185     }
186 
187     if ((!L2CA_ConfigReq(l2cap_cid, &cfg)) && cfg.fcr_present &&
188         cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) {
189       /* FCR not desired; try again in basic mode */
190       cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
191       cfg.fcr_present = false;
192       L2CA_ConfigReq(l2cap_cid, &cfg);
193     }
194   }
195 
196   SDP_TRACE_EVENT("SDP - Rcvd L2CAP conn ind, sent config req, CID 0x%x",
197                   p_ccb->connection_id);
198 #else /* No server */
199   /* Reject the connection */
200   L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_PSM, 0);
201 #endif
202 }
203 
204 /*******************************************************************************
205  *
206  * Function         sdp_connect_cfm
207  *
208  * Description      This function handles the connect confirm events
209  *                  from L2CAP. This is the case when we are acting as a
210  *                  client and have sent a connect request.
211  *
212  * Returns          void
213  *
214  ******************************************************************************/
sdp_connect_cfm(uint16_t l2cap_cid,uint16_t result)215 static void sdp_connect_cfm(uint16_t l2cap_cid, uint16_t result) {
216   tCONN_CB* p_ccb;
217   tL2CAP_CFG_INFO cfg;
218 
219   /* Find CCB based on CID */
220   p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
221   if (p_ccb == NULL) {
222     SDP_TRACE_WARNING("SDP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid);
223     return;
224   }
225 
226   /* If the connection response contains success status, then */
227   /* Transition to the next state and startup the timer.      */
228   if ((result == L2CAP_CONN_OK) && (p_ccb->con_state == SDP_STATE_CONN_SETUP)) {
229     p_ccb->con_state = SDP_STATE_CFG_SETUP;
230 
231     cfg = sdp_cb.l2cap_my_cfg;
232 
233     if (cfg.fcr_present) {
234       SDP_TRACE_DEBUG(
235           "sdp_connect_cfm:  mode %u, txwinsz %u, max_trans %u, rtrans_tout "
236           "%u, mon_tout %u, mps %u",
237           cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit,
238           cfg.fcr.rtrans_tout, cfg.fcr.mon_tout, cfg.fcr.mps);
239     }
240 
241     if ((!L2CA_ConfigReq(l2cap_cid, &cfg)) && cfg.fcr_present &&
242         cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) {
243       /* FCR not desired; try again in basic mode */
244       cfg.fcr_present = false;
245       cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
246       L2CA_ConfigReq(l2cap_cid, &cfg);
247     }
248 
249     SDP_TRACE_EVENT("SDP - got conn cnf, sent cfg req, CID: 0x%x",
250                     p_ccb->connection_id);
251   } else {
252     SDP_TRACE_WARNING("SDP - Rcvd conn cnf with error: 0x%x  CID 0x%x", result,
253                       p_ccb->connection_id);
254 
255     /* Tell the user if he has a callback */
256     if (p_ccb->p_cb || p_ccb->p_cb2) {
257       uint16_t err = -1;
258       if ((result == HCI_ERR_HOST_REJECT_SECURITY) ||
259           (result == HCI_ERR_AUTH_FAILURE) ||
260           (result == HCI_ERR_PAIRING_NOT_ALLOWED) ||
261           (result == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
262           (result == HCI_ERR_KEY_MISSING))
263         err = SDP_SECURITY_ERR;
264       else if (result == HCI_ERR_HOST_REJECT_DEVICE)
265         err = SDP_CONN_REJECTED;
266       else
267         err = SDP_CONN_FAILED;
268       if (p_ccb->p_cb)
269         (*p_ccb->p_cb)(err);
270       else if (p_ccb->p_cb2)
271         (*p_ccb->p_cb2)(err, p_ccb->user_data);
272     }
273     sdpu_release_ccb(p_ccb);
274   }
275 }
276 
277 /*******************************************************************************
278  *
279  * Function         sdp_config_ind
280  *
281  * Description      This function processes the L2CAP configuration indication
282  *                  event.
283  *
284  * Returns          void
285  *
286  ******************************************************************************/
sdp_config_ind(uint16_t l2cap_cid,tL2CAP_CFG_INFO * p_cfg)287 static void sdp_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
288   tCONN_CB* p_ccb;
289 
290   /* Find CCB based on CID */
291   p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
292   if (p_ccb == NULL) {
293     SDP_TRACE_WARNING("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
294     return;
295   }
296 
297   /* Remember the remote MTU size */
298   if (!p_cfg->mtu_present) {
299     /* use min(L2CAP_DEFAULT_MTU,SDP_MTU_SIZE) for GKI buffer size reasons */
300     p_ccb->rem_mtu_size =
301         (L2CAP_DEFAULT_MTU > SDP_MTU_SIZE) ? SDP_MTU_SIZE : L2CAP_DEFAULT_MTU;
302   } else {
303     if (p_cfg->mtu > SDP_MTU_SIZE)
304       p_ccb->rem_mtu_size = SDP_MTU_SIZE;
305     else
306       p_ccb->rem_mtu_size = p_cfg->mtu;
307   }
308 
309   /* For now, always accept configuration from the other side */
310   p_cfg->flush_to_present = false;
311   p_cfg->mtu_present = false;
312   p_cfg->result = L2CAP_CFG_OK;
313 
314   /* Check peer config request against our rfcomm configuration */
315   if (p_cfg->fcr_present) {
316     /* Reject the window size if it is bigger than we want it to be */
317     if (p_cfg->fcr.mode != L2CAP_FCR_BASIC_MODE) {
318       if (sdp_cb.l2cap_my_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE &&
319           p_cfg->fcr.tx_win_sz > sdp_cb.l2cap_my_cfg.fcr.tx_win_sz) {
320         p_cfg->fcr.tx_win_sz = sdp_cb.l2cap_my_cfg.fcr.tx_win_sz;
321         p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
322         SDP_TRACE_DEBUG(
323             "sdp_config_ind(CONFIG) -> Please try again with SMALLER TX "
324             "WINDOW");
325       }
326 
327       /* Reject if locally we want basic and they don't */
328       if (sdp_cb.l2cap_my_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE) {
329         /* Ask for a new setup */
330         p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
331         p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
332         SDP_TRACE_DEBUG(
333             "sdp_config_ind(CONFIG) -> Please try again with BASIC mode");
334       }
335       /* Remain in configure state and give the peer our desired configuration
336        */
337       if (p_cfg->result != L2CAP_CFG_OK) {
338         SDP_TRACE_WARNING(
339             "SDP - Rcvd cfg ind, Unacceptable Parameters sent cfg cfm, CID: "
340             "0x%x",
341             l2cap_cid);
342         L2CA_ConfigRsp(l2cap_cid, p_cfg);
343         return;
344       }
345     } else /* We agree with peer's request */
346       p_cfg->fcr_present = false;
347   }
348 
349   L2CA_ConfigRsp(l2cap_cid, p_cfg);
350 
351   SDP_TRACE_EVENT("SDP - Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
352 
353   p_ccb->con_flags |= SDP_FLAGS_HIS_CFG_DONE;
354 
355   if (p_ccb->con_flags & SDP_FLAGS_MY_CFG_DONE) {
356     p_ccb->con_state = SDP_STATE_CONNECTED;
357 
358     if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) {
359       sdp_disc_connected(p_ccb);
360     } else {
361       /* Start inactivity timer */
362       alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
363                          sdp_conn_timer_timeout, p_ccb,
364                          btu_general_alarm_queue);
365     }
366   }
367 }
368 
369 /*******************************************************************************
370  *
371  * Function         sdp_config_cfm
372  *
373  * Description      This function processes the L2CAP configuration confirmation
374  *                  event.
375  *
376  * Returns          void
377  *
378  ******************************************************************************/
sdp_config_cfm(uint16_t l2cap_cid,tL2CAP_CFG_INFO * p_cfg)379 static void sdp_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
380   tCONN_CB* p_ccb;
381 
382   SDP_TRACE_EVENT("SDP - Rcvd cfg cfm, CID: 0x%x  Result: %d", l2cap_cid,
383                   p_cfg->result);
384 
385   /* Find CCB based on CID */
386   p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
387   if (p_ccb == NULL) {
388     SDP_TRACE_WARNING("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
389     return;
390   }
391 
392   /* For now, always accept configuration from the other side */
393   if (p_cfg->result == L2CAP_CFG_OK) {
394     p_ccb->con_flags |= SDP_FLAGS_MY_CFG_DONE;
395 
396     if (p_ccb->con_flags & SDP_FLAGS_HIS_CFG_DONE) {
397       p_ccb->con_state = SDP_STATE_CONNECTED;
398 
399       if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) {
400         sdp_disc_connected(p_ccb);
401       } else {
402         /* Start inactivity timer */
403         alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
404                            sdp_conn_timer_timeout, p_ccb,
405                            btu_general_alarm_queue);
406       }
407     }
408   } else {
409     /* If peer has rejected FCR and suggested basic then try basic */
410     if (p_cfg->fcr_present) {
411       tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg;
412       cfg.fcr_present = false;
413       L2CA_ConfigReq(l2cap_cid, &cfg);
414 
415       /* Remain in configure state */
416       return;
417     }
418 
419     sdp_disconnect(p_ccb, SDP_CFG_FAILED);
420   }
421 }
422 
423 /*******************************************************************************
424  *
425  * Function         sdp_disconnect_ind
426  *
427  * Description      This function handles a disconnect event from L2CAP. If
428  *                  requested to, we ack the disconnect before dropping the CCB
429  *
430  * Returns          void
431  *
432  ******************************************************************************/
sdp_disconnect_ind(uint16_t l2cap_cid,bool ack_needed)433 static void sdp_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) {
434   tCONN_CB* p_ccb;
435 
436   /* Find CCB based on CID */
437   p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
438   if (p_ccb == NULL) {
439     SDP_TRACE_WARNING("SDP - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
440     return;
441   }
442 
443   if (ack_needed) L2CA_DisconnectRsp(l2cap_cid);
444 
445   SDP_TRACE_EVENT("SDP - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
446   /* Tell the user if he has a callback */
447   if (p_ccb->p_cb)
448     (*p_ccb->p_cb)((uint16_t)((p_ccb->con_state == SDP_STATE_CONNECTED)
449                                   ? SDP_SUCCESS
450                                   : SDP_CONN_FAILED));
451   else if (p_ccb->p_cb2)
452     (*p_ccb->p_cb2)(
453         (uint16_t)((p_ccb->con_state == SDP_STATE_CONNECTED) ? SDP_SUCCESS
454                                                              : SDP_CONN_FAILED),
455         p_ccb->user_data);
456 
457   sdpu_release_ccb(p_ccb);
458 }
459 
460 /*******************************************************************************
461  *
462  * Function         sdp_data_ind
463  *
464  * Description      This function is called when data is received from L2CAP.
465  *                  if we are the originator of the connection, we are the SDP
466  *                  client, and the received message is queued for the client.
467  *
468  *                  If we are the destination of the connection, we are the SDP
469  *                  server, so the message is passed to the server processing
470  *                  function.
471  *
472  * Returns          void
473  *
474  ******************************************************************************/
sdp_data_ind(uint16_t l2cap_cid,BT_HDR * p_msg)475 static void sdp_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg) {
476   tCONN_CB* p_ccb;
477 
478   /* Find CCB based on CID */
479   p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
480   if (p_ccb != NULL) {
481     if (p_ccb->con_state == SDP_STATE_CONNECTED) {
482       if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
483         sdp_disc_server_rsp(p_ccb, p_msg);
484       else
485         sdp_server_handle_client_req(p_ccb, p_msg);
486     } else {
487       SDP_TRACE_WARNING(
488           "SDP - Ignored L2CAP data while in state: %d, CID: 0x%x",
489           p_ccb->con_state, l2cap_cid);
490     }
491   } else {
492     SDP_TRACE_WARNING("SDP - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
493   }
494 
495   osi_free(p_msg);
496 }
497 
498 /*******************************************************************************
499  *
500  * Function         sdp_conn_originate
501  *
502  * Description      This function is called from the API to originate a
503  *                  connection.
504  *
505  * Returns          void
506  *
507  ******************************************************************************/
sdp_conn_originate(uint8_t * p_bd_addr)508 tCONN_CB* sdp_conn_originate(uint8_t* p_bd_addr) {
509   tCONN_CB* p_ccb;
510   uint16_t cid;
511 
512   /* Allocate a new CCB. Return if none available. */
513   p_ccb = sdpu_allocate_ccb();
514   if (p_ccb == NULL) {
515     SDP_TRACE_WARNING("SDP - no spare CCB for orig");
516     return (NULL);
517   }
518 
519   SDP_TRACE_EVENT("SDP - Originate started");
520 
521   /* We are the originator of this connection */
522   p_ccb->con_flags |= SDP_FLAGS_IS_ORIG;
523 
524   /* Save the BD Address and Channel ID. */
525   memcpy(&p_ccb->device_address[0], p_bd_addr, sizeof(BD_ADDR));
526 
527   /* Transition to the next appropriate state, waiting for connection confirm.
528    */
529   p_ccb->con_state = SDP_STATE_CONN_SETUP;
530 
531   cid = L2CA_ConnectReq(SDP_PSM, p_bd_addr);
532 
533   /* Check if L2CAP started the connection process */
534   if (cid != 0) {
535     p_ccb->connection_id = cid;
536 
537     return (p_ccb);
538   } else {
539     SDP_TRACE_WARNING("SDP - Originate failed");
540     sdpu_release_ccb(p_ccb);
541     return (NULL);
542   }
543 }
544 
545 /*******************************************************************************
546  *
547  * Function         sdp_disconnect
548  *
549  * Description      This function disconnects a connection.
550  *
551  * Returns          void
552  *
553  ******************************************************************************/
sdp_disconnect(tCONN_CB * p_ccb,uint16_t reason)554 void sdp_disconnect(tCONN_CB* p_ccb, uint16_t reason) {
555 #if (SDP_BROWSE_PLUS == TRUE)
556 
557   /* If we are browsing for multiple UUIDs ... */
558   if ((p_ccb->con_state == SDP_STATE_CONNECTED) &&
559       (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) &&
560       ((reason == SDP_SUCCESS) || (reason == SDP_NO_RECS_MATCH))) {
561     /* If the browse found something, do no more searching */
562     if ((p_ccb->cur_uuid_idx == 0) && (p_ccb->p_db->p_first_rec))
563       p_ccb->cur_uuid_idx = p_ccb->p_db->num_uuid_filters;
564 
565     while (++p_ccb->cur_uuid_idx < p_ccb->p_db->num_uuid_filters) {
566       /* Check we have not already found the UUID (maybe through browse) */
567       if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len == 2) &&
568           (SDP_FindServiceInDb(
569               p_ccb->p_db,
570               p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].uu.uuid16, NULL)))
571         continue;
572 
573       if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len > 2) &&
574           (SDP_FindServiceUUIDInDb(
575               p_ccb->p_db, &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx],
576               NULL)))
577         continue;
578 
579       p_ccb->cur_handle = 0;
580 
581       SDP_TRACE_EVENT("SDP - looking for for more,  CID: 0x%x",
582                       p_ccb->connection_id);
583 
584       sdp_disc_connected(p_ccb);
585       return;
586     }
587   }
588 
589   if ((reason == SDP_NO_RECS_MATCH) && (p_ccb->p_db->p_first_rec))
590     reason = SDP_SUCCESS;
591 
592 #endif
593 
594   SDP_TRACE_EVENT("SDP - disconnect  CID: 0x%x", p_ccb->connection_id);
595 
596   /* Check if we have a connection ID */
597   if (p_ccb->connection_id != 0) {
598     L2CA_DisconnectReq(p_ccb->connection_id);
599     p_ccb->disconnect_reason = reason;
600   }
601 
602   /* If at setup state, we may not get callback ind from L2CAP */
603   /* Call user callback immediately */
604   if (p_ccb->con_state == SDP_STATE_CONN_SETUP) {
605     /* Tell the user if he has a callback */
606     if (p_ccb->p_cb)
607       (*p_ccb->p_cb)(reason);
608     else if (p_ccb->p_cb2)
609       (*p_ccb->p_cb2)(reason, p_ccb->user_data);
610 
611     sdpu_release_ccb(p_ccb);
612   }
613 }
614 
615 /*******************************************************************************
616  *
617  * Function         sdp_disconnect_cfm
618  *
619  * Description      This function handles a disconnect confirm event from L2CAP.
620  *
621  * Returns          void
622  *
623  ******************************************************************************/
sdp_disconnect_cfm(uint16_t l2cap_cid,UNUSED_ATTR uint16_t result)624 static void sdp_disconnect_cfm(uint16_t l2cap_cid,
625                                UNUSED_ATTR uint16_t result) {
626   tCONN_CB* p_ccb;
627 
628   /* Find CCB based on CID */
629   p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
630   if (p_ccb == NULL) {
631     SDP_TRACE_WARNING("SDP - Rcvd L2CAP disc cfm, unknown CID: 0x%x",
632                       l2cap_cid);
633     return;
634   }
635 
636   SDP_TRACE_EVENT("SDP - Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
637 
638   /* Tell the user if he has a callback */
639   if (p_ccb->p_cb)
640     (*p_ccb->p_cb)(p_ccb->disconnect_reason);
641   else if (p_ccb->p_cb2)
642     (*p_ccb->p_cb2)(p_ccb->disconnect_reason, p_ccb->user_data);
643 
644   sdpu_release_ccb(p_ccb);
645 }
646 
647 
648 /*******************************************************************************
649  *
650  * Function         sdp_conn_timer_timeout
651  *
652  * Description      This function processes a timeout. Currently, we simply send
653  *                  a disconnect request to L2CAP.
654  *
655  * Returns          void
656  *
657  ******************************************************************************/
sdp_conn_timer_timeout(void * data)658 void sdp_conn_timer_timeout(void* data) {
659   tCONN_CB* p_ccb = (tCONN_CB*)data;
660 
661   SDP_TRACE_EVENT("SDP - CCB timeout in state: %d  CID: 0x%x", p_ccb->con_state,
662                   p_ccb->connection_id);
663 
664   L2CA_DisconnectReq(p_ccb->connection_id);
665   /* Tell the user if he has a callback */
666   if (p_ccb->p_cb)
667     (*p_ccb->p_cb)(SDP_CONN_FAILED);
668   else if (p_ccb->p_cb2)
669     (*p_ccb->p_cb2)(SDP_CONN_FAILED, p_ccb->user_data);
670   sdpu_release_ccb(p_ccb);
671 }
672