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