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