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