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