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