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