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