OSDN Git Service

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