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