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