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