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 <base/logging.h>
26 #include <string.h> // memset
27
28 #include "gd/common/init_flags.h"
29 #include "osi/include/allocator.h"
30 #include "osi/include/osi.h" // UNUSED_ATTR
31 #include "stack/include/bt_hdr.h"
32 #include "stack/include/bt_types.h"
33 #include "stack/include/btm_api_types.h"
34 #include "stack/include/l2c_api.h"
35 #include "stack/include/sdp_api.h"
36 #include "stack/sdp/sdpint.h"
37 #include "types/raw_address.h"
38
39 /******************************************************************************/
40 /* G L O B A L S D P D A T A */
41 /******************************************************************************/
42 tSDP_CB sdp_cb;
43
44 /******************************************************************************/
45 /* L O C A L F U N C T I O N P R O T O T Y P E S */
46 /******************************************************************************/
47 static void sdp_connect_ind(const RawAddress& bd_addr, uint16_t l2cap_cid,
48 UNUSED_ATTR uint16_t psm, uint8_t l2cap_id);
49 static void sdp_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
50 static void sdp_config_cfm(uint16_t l2cap_cid, uint16_t result,
51 tL2CAP_CFG_INFO* p_cfg);
52 static void sdp_disconnect_ind(uint16_t l2cap_cid, bool ack_needed);
53 static void sdp_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg);
54
55 static void sdp_connect_cfm(uint16_t l2cap_cid, uint16_t result);
56 static void sdp_disconnect_cfm(uint16_t l2cap_cid, uint16_t result);
57 static void sdp_on_l2cap_error(uint16_t l2cap_cid, uint16_t result);
58
59 /*******************************************************************************
60 *
61 * Function sdp_init
62 *
63 * Description This function initializes the SDP unit.
64 *
65 * Returns void
66 *
67 ******************************************************************************/
sdp_init(void)68 void sdp_init(void) {
69 /* Clears all structures and local SDP database (if Server is enabled) */
70 memset(&sdp_cb, 0, sizeof(tSDP_CB));
71
72 for (int i = 0; i < SDP_MAX_CONNECTIONS; i++) {
73 sdp_cb.ccb[i].sdp_conn_timer = alarm_new("sdp.sdp_conn_timer");
74 }
75
76 /* Initialize the L2CAP configuration. We only care about MTU */
77 sdp_cb.l2cap_my_cfg.mtu_present = true;
78 sdp_cb.l2cap_my_cfg.mtu = SDP_MTU_SIZE;
79
80 sdp_cb.max_attr_list_size = SDP_MTU_SIZE - 16;
81 sdp_cb.max_recs_per_search = SDP_MAX_DISC_SERVER_RECS;
82
83 sdp_cb.trace_level = BT_TRACE_LEVEL_WARNING;
84
85 sdp_cb.reg_info.pL2CA_ConnectInd_Cb = sdp_connect_ind;
86 sdp_cb.reg_info.pL2CA_ConnectCfm_Cb = sdp_connect_cfm;
87 sdp_cb.reg_info.pL2CA_ConfigInd_Cb = sdp_config_ind;
88 sdp_cb.reg_info.pL2CA_ConfigCfm_Cb = sdp_config_cfm;
89 sdp_cb.reg_info.pL2CA_DisconnectInd_Cb = sdp_disconnect_ind;
90 sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb = sdp_disconnect_cfm;
91 sdp_cb.reg_info.pL2CA_DataInd_Cb = sdp_data_ind;
92 sdp_cb.reg_info.pL2CA_Error_Cb = sdp_on_l2cap_error;
93
94 /* Now, register with L2CAP */
95 if (!L2CA_Register2(BT_PSM_SDP, sdp_cb.reg_info, true /* enable_snoop */,
96 nullptr, SDP_MTU_SIZE, 0, BTM_SEC_NONE)) {
97 SDP_TRACE_ERROR("SDP Registration failed");
98 }
99 }
100
sdp_free(void)101 void sdp_free(void) {
102 for (int i = 0; i < SDP_MAX_CONNECTIONS; i++) {
103 alarm_free(sdp_cb.ccb[i].sdp_conn_timer);
104 sdp_cb.ccb[i].sdp_conn_timer = NULL;
105 }
106 }
107
108 /*******************************************************************************
109 *
110 * Function sdp_connect_ind
111 *
112 * Description This function handles an inbound connection indication
113 * from L2CAP. This is the case where we are acting as a
114 * server.
115 *
116 * Returns void
117 *
118 ******************************************************************************/
sdp_connect_ind(const RawAddress & bd_addr,uint16_t l2cap_cid,UNUSED_ATTR uint16_t psm,uint8_t l2cap_id)119 static void sdp_connect_ind(const RawAddress& bd_addr, uint16_t l2cap_cid,
120 UNUSED_ATTR uint16_t psm, uint8_t l2cap_id) {
121 tCONN_CB* p_ccb = sdpu_allocate_ccb();
122 if (p_ccb == NULL) return;
123
124 /* Transition to the next appropriate state, waiting for config setup. */
125 p_ccb->con_state = SDP_STATE_CFG_SETUP;
126
127 /* Save the BD Address and Channel ID. */
128 p_ccb->device_address = bd_addr;
129 p_ccb->connection_id = l2cap_cid;
130 }
131
sdp_on_l2cap_error(uint16_t l2cap_cid,uint16_t result)132 static void sdp_on_l2cap_error(uint16_t l2cap_cid, uint16_t result) {
133 tCONN_CB* p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
134 if (p_ccb == nullptr) return;
135 sdp_disconnect(p_ccb, SDP_CFG_FAILED);
136 }
137
138 /*******************************************************************************
139 *
140 * Function sdp_connect_cfm
141 *
142 * Description This function handles the connect confirm events
143 * from L2CAP. This is the case when we are acting as a
144 * client and have sent a connect request.
145 *
146 * Returns void
147 *
148 ******************************************************************************/
sdp_connect_cfm(uint16_t l2cap_cid,uint16_t result)149 static void sdp_connect_cfm(uint16_t l2cap_cid, uint16_t result) {
150 tCONN_CB* p_ccb;
151
152 /* Find CCB based on CID */
153 p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
154 if (p_ccb == NULL) {
155 SDP_TRACE_WARNING("SDP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid);
156 return;
157 }
158
159 /* If the connection response contains success status, then */
160 /* Transition to the next state and startup the timer. */
161 if ((result == L2CAP_CONN_OK) && (p_ccb->con_state == SDP_STATE_CONN_SETUP)) {
162 p_ccb->con_state = SDP_STATE_CFG_SETUP;
163 } else {
164 LOG(ERROR) << __func__ << ": invoked with non OK status";
165 }
166 }
167
168 /*******************************************************************************
169 *
170 * Function sdp_config_ind
171 *
172 * Description This function processes the L2CAP configuration indication
173 * event.
174 *
175 * Returns void
176 *
177 ******************************************************************************/
sdp_config_ind(uint16_t l2cap_cid,tL2CAP_CFG_INFO * p_cfg)178 static void sdp_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
179 tCONN_CB* p_ccb;
180
181 /* Find CCB based on CID */
182 p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
183 if (p_ccb == NULL) {
184 SDP_TRACE_WARNING("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
185 return;
186 }
187
188 /* Remember the remote MTU size */
189 if (!p_cfg->mtu_present) {
190 /* use min(L2CAP_DEFAULT_MTU,SDP_MTU_SIZE) for GKI buffer size reasons */
191 p_ccb->rem_mtu_size =
192 (L2CAP_DEFAULT_MTU > SDP_MTU_SIZE) ? SDP_MTU_SIZE : L2CAP_DEFAULT_MTU;
193 } else {
194 if (p_cfg->mtu > SDP_MTU_SIZE)
195 p_ccb->rem_mtu_size = SDP_MTU_SIZE;
196 else
197 p_ccb->rem_mtu_size = p_cfg->mtu;
198 }
199
200 SDP_TRACE_EVENT("SDP - Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
201 }
202
203 /*******************************************************************************
204 *
205 * Function sdp_config_cfm
206 *
207 * Description This function processes the L2CAP configuration confirmation
208 * event.
209 *
210 * Returns void
211 *
212 ******************************************************************************/
sdp_config_cfm(uint16_t l2cap_cid,uint16_t initiator,tL2CAP_CFG_INFO * p_cfg)213 static void sdp_config_cfm(uint16_t l2cap_cid, uint16_t initiator,
214 tL2CAP_CFG_INFO* p_cfg) {
215 sdp_config_ind(l2cap_cid, p_cfg);
216
217 tCONN_CB* p_ccb;
218
219 SDP_TRACE_EVENT("SDP - Rcvd cfg cfm, CID: 0x%x", l2cap_cid);
220
221 /* Find CCB based on CID */
222 p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
223 if (p_ccb == NULL) {
224 SDP_TRACE_WARNING("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
225 return;
226 }
227
228 /* For now, always accept configuration from the other side */
229 p_ccb->con_state = SDP_STATE_CONNECTED;
230
231 if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) {
232 sdp_disc_connected(p_ccb);
233 } else {
234 /* Start inactivity timer */
235 alarm_set_on_mloop(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
236 sdp_conn_timer_timeout, p_ccb);
237 }
238 }
239
240 /*******************************************************************************
241 *
242 * Function sdp_disconnect_ind
243 *
244 * Description This function handles a disconnect event from L2CAP. If
245 * requested to, we ack the disconnect before dropping the CCB
246 *
247 * Returns void
248 *
249 ******************************************************************************/
sdp_disconnect_ind(uint16_t l2cap_cid,bool ack_needed)250 static void sdp_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) {
251 tCONN_CB* p_ccb;
252
253 /* Find CCB based on CID */
254 p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
255 if (p_ccb == NULL) {
256 SDP_TRACE_WARNING("SDP - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
257 return;
258 }
259 tCONN_CB& ccb = *p_ccb;
260
261 const tSDP_REASON reason =
262 (ccb.con_state == SDP_STATE_CONNECTED) ? SDP_SUCCESS : SDP_CONN_FAILED;
263 sdpu_callback(ccb, reason);
264
265 if (ack_needed) {
266 SDP_TRACE_WARNING("SDP - Rcvd L2CAP disc, process pend sdp ccb: 0x%x",
267 l2cap_cid);
268 sdpu_process_pend_ccb_new_cid(ccb);
269 } else {
270 SDP_TRACE_WARNING("SDP - Rcvd L2CAP disc, clear pend sdp ccb: 0x%x",
271 l2cap_cid);
272 sdpu_clear_pend_ccb(ccb);
273 }
274
275 sdpu_release_ccb(ccb);
276 }
277
278 /*******************************************************************************
279 *
280 * Function sdp_data_ind
281 *
282 * Description This function is called when data is received from L2CAP.
283 * if we are the originator of the connection, we are the SDP
284 * client, and the received message is queued for the client.
285 *
286 * If we are the destination of the connection, we are the SDP
287 * server, so the message is passed to the server processing
288 * function.
289 *
290 * Returns void
291 *
292 ******************************************************************************/
sdp_data_ind(uint16_t l2cap_cid,BT_HDR * p_msg)293 static void sdp_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg) {
294 tCONN_CB* p_ccb;
295
296 /* Find CCB based on CID */
297 p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
298 if (p_ccb != NULL) {
299 if (p_ccb->con_state == SDP_STATE_CONNECTED) {
300 if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
301 sdp_disc_server_rsp(p_ccb, p_msg);
302 else
303 sdp_server_handle_client_req(p_ccb, p_msg);
304 } else {
305 SDP_TRACE_WARNING(
306 "SDP - Ignored L2CAP data while in state: %d, CID: 0x%x",
307 p_ccb->con_state, l2cap_cid);
308 }
309 } else {
310 SDP_TRACE_WARNING("SDP - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
311 }
312
313 osi_free(p_msg);
314 }
315
316 /*******************************************************************************
317 *
318 * Function sdp_conn_originate
319 *
320 * Description This function is called from the API to originate a
321 * connection.
322 *
323 * Returns void
324 *
325 ******************************************************************************/
sdp_conn_originate(const RawAddress & p_bd_addr)326 tCONN_CB* sdp_conn_originate(const RawAddress& p_bd_addr) {
327 tCONN_CB* p_ccb;
328 uint16_t cid;
329
330 /* Allocate a new CCB. Return if none available. */
331 p_ccb = sdpu_allocate_ccb();
332 if (p_ccb == NULL) {
333 SDP_TRACE_WARNING("%s: no spare CCB for peer %s", __func__,
334 p_bd_addr.ToString().c_str());
335 return (NULL);
336 }
337
338 SDP_TRACE_EVENT("%s: SDP - Originate started for peer %s", __func__,
339 p_bd_addr.ToString().c_str());
340
341 /* We are the originator of this connection */
342 p_ccb->con_flags |= SDP_FLAGS_IS_ORIG;
343
344 /* Save the BD Address and Channel ID. */
345 p_ccb->device_address = p_bd_addr;
346
347 /* Transition to the next appropriate state, waiting for connection confirm.
348 */
349 p_ccb->con_state = SDP_STATE_CONN_SETUP;
350
351 // Look for any active sdp connection on the remote device
352 cid = sdpu_get_active_ccb_cid(p_bd_addr);
353
354 if (!bluetooth::common::init_flags::sdp_serialization_is_enabled() ||
355 cid == 0) {
356 p_ccb->con_state = SDP_STATE_CONN_SETUP;
357 cid = L2CA_ConnectReq2(BT_PSM_SDP, p_bd_addr, BTM_SEC_NONE);
358 } else {
359 p_ccb->con_state = SDP_STATE_CONN_PEND;
360 SDP_TRACE_WARNING("SDP already active for peer %s. cid=%#0x",
361 p_bd_addr.ToString().c_str(), cid);
362 }
363
364 /* Check if L2CAP started the connection process */
365 if (cid == 0) {
366 SDP_TRACE_WARNING("%s: SDP - Originate failed for peer %s", __func__,
367 p_bd_addr.ToString().c_str());
368 sdpu_release_ccb(*p_ccb);
369 return (NULL);
370 }
371 p_ccb->connection_id = cid;
372 return (p_ccb);
373 }
374
375 /*******************************************************************************
376 *
377 * Function sdp_disconnect
378 *
379 * Description This function disconnects a connection.
380 *
381 * Returns void
382 *
383 ******************************************************************************/
sdp_disconnect(tCONN_CB * p_ccb,tSDP_REASON reason)384 void sdp_disconnect(tCONN_CB* p_ccb, tSDP_REASON reason) {
385 tCONN_CB& ccb = *p_ccb;
386 SDP_TRACE_EVENT("SDP - disconnect CID: 0x%x", ccb.connection_id);
387
388 /* Check if we have a connection ID */
389 if (ccb.connection_id != 0) {
390 ccb.disconnect_reason = reason;
391 if (SDP_SUCCESS == reason && sdpu_process_pend_ccb_same_cid(*p_ccb)) {
392 sdpu_callback(ccb, reason);
393 sdpu_release_ccb(ccb);
394 return;
395 } else {
396 L2CA_DisconnectReq(ccb.connection_id);
397 }
398 }
399
400 /* If at setup state, we may not get callback ind from L2CAP */
401 /* Call user callback immediately */
402 if (ccb.con_state == SDP_STATE_CONN_SETUP) {
403 sdpu_callback(ccb, reason);
404 sdpu_release_ccb(ccb);
405 }
406 }
407
408 /*******************************************************************************
409 *
410 * Function sdp_disconnect_cfm
411 *
412 * Description This function handles a disconnect confirm event from L2CAP.
413 *
414 * Returns void
415 *
416 ******************************************************************************/
sdp_disconnect_cfm(uint16_t l2cap_cid,UNUSED_ATTR uint16_t result)417 static void sdp_disconnect_cfm(uint16_t l2cap_cid,
418 UNUSED_ATTR uint16_t result) {
419 tCONN_CB* p_ccb;
420
421 /* Find CCB based on CID */
422 p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
423 if (p_ccb == NULL) {
424 SDP_TRACE_WARNING("SDP - Rcvd L2CAP disc cfm, unknown CID: 0x%x",
425 l2cap_cid);
426 return;
427 }
428 tCONN_CB& ccb = *p_ccb;
429
430 SDP_TRACE_EVENT("SDP - Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
431
432 sdpu_callback(ccb, static_cast<tSDP_STATUS>(ccb.disconnect_reason));
433 sdpu_process_pend_ccb_new_cid(ccb);
434 sdpu_release_ccb(ccb);
435 }
436
437 /*******************************************************************************
438 *
439 * Function sdp_conn_timer_timeout
440 *
441 * Description This function processes a timeout. Currently, we simply send
442 * a disconnect request to L2CAP.
443 *
444 * Returns void
445 *
446 ******************************************************************************/
sdp_conn_timer_timeout(void * data)447 void sdp_conn_timer_timeout(void* data) {
448 tCONN_CB& ccb = *(tCONN_CB*)data;
449
450 SDP_TRACE_EVENT("SDP - CCB timeout in state: %d CID: 0x%x", ccb.con_state,
451 ccb.connection_id);
452
453 L2CA_DisconnectReq(ccb.connection_id);
454
455 sdpu_callback(ccb, SDP_CONN_FAILED);
456 sdpu_clear_pend_ccb(ccb);
457 sdpu_release_ccb(ccb);
458 }
459