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