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