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