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