• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  Copyright 1999-2013 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 #include "bt_target.h"
20 #include "bt_utils.h"
21 #include "gatt_api.h"
22 #include "gatt_int.h"
23 #include "osi/include/osi.h"
24 #include "srvc_eng_int.h"
25 
26 #include "srvc_battery_int.h"
27 #include "srvc_dis_int.h"
28 
29 using base::StringPrintf;
30 static void srvc_eng_s_request_cback(uint16_t conn_id, uint32_t trans_id,
31                                      uint8_t op_code, tGATTS_DATA* p_data);
32 static void srvc_eng_connect_cback(UNUSED_ATTR tGATT_IF gatt_if,
33                                    const RawAddress& bda, uint16_t conn_id,
34                                    bool connected, tGATT_DISCONN_REASON reason,
35                                    tBT_TRANSPORT transport);
36 static void srvc_eng_c_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
37                                   tGATT_STATUS status,
38                                   tGATT_CL_COMPLETE* p_data);
39 
40 static tGATT_CBACK srvc_gatt_cback = {srvc_eng_connect_cback,
41                                       srvc_eng_c_cmpl_cback,
42                                       NULL,
43                                       NULL,
44                                       srvc_eng_s_request_cback,
45                                       NULL,
46                                       NULL,
47                                       NULL,
48                                       NULL};
49 /* type for action functions */
50 typedef void (*tSRVC_ENG_C_CMPL_ACTION)(tSRVC_CLCB* p_clcb, tGATTC_OPTYPE op,
51                                         tGATT_STATUS status,
52                                         tGATT_CL_COMPLETE* p_data);
53 
54 const tSRVC_ENG_C_CMPL_ACTION srvc_eng_c_cmpl_act[SRVC_ID_MAX] = {
55     dis_c_cmpl_cback,
56 };
57 
58 tSRVC_ENG_CB srvc_eng_cb;
59 
60 /*******************************************************************************
61  *
62  * Function         srvc_eng_find_conn_id_by_bd_addr
63  *
64  * Description      The function searches all LCB with macthing bd address
65  *
66  * Returns          total number of clcb found.
67  *
68  ******************************************************************************/
srvc_eng_find_conn_id_by_bd_addr(const RawAddress & bda)69 uint16_t srvc_eng_find_conn_id_by_bd_addr(const RawAddress& bda) {
70   uint8_t i_clcb;
71   tSRVC_CLCB* p_clcb = NULL;
72 
73   for (i_clcb = 0, p_clcb = srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS;
74        i_clcb++, p_clcb++) {
75     if (p_clcb->in_use && p_clcb->connected && p_clcb->bda == bda) {
76       return p_clcb->conn_id;
77     }
78   }
79 
80   return GATT_INVALID_CONN_ID;
81 }
82 
83 /*******************************************************************************
84  *
85  * Function         srvc_eng_find_clcb_by_bd_addr
86  *
87  * Description      The function searches all LCBs with macthing bd address.
88  *
89  * Returns          Pointer to the found link conenction control block.
90  *
91  ******************************************************************************/
srvc_eng_find_clcb_by_bd_addr(const RawAddress & bda)92 tSRVC_CLCB* srvc_eng_find_clcb_by_bd_addr(const RawAddress& bda) {
93   uint8_t i_clcb;
94   tSRVC_CLCB* p_clcb = NULL;
95 
96   for (i_clcb = 0, p_clcb = srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS;
97        i_clcb++, p_clcb++) {
98     if (p_clcb->in_use && p_clcb->connected && p_clcb->bda == bda) {
99       return p_clcb;
100     }
101   }
102 
103   return NULL;
104 }
105 /*******************************************************************************
106  *
107  * Function         srvc_eng_find_clcb_by_conn_id
108  *
109  * Description      The function searches all LCBs with macthing connection ID.
110  *
111  * Returns          Pointer to the found link conenction control block.
112  *
113  ******************************************************************************/
srvc_eng_find_clcb_by_conn_id(uint16_t conn_id)114 tSRVC_CLCB* srvc_eng_find_clcb_by_conn_id(uint16_t conn_id) {
115   uint8_t i_clcb;
116   tSRVC_CLCB* p_clcb = NULL;
117 
118   for (i_clcb = 0, p_clcb = srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS;
119        i_clcb++, p_clcb++) {
120     if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id) {
121       return p_clcb;
122     }
123   }
124 
125   return NULL;
126 }
127 /*******************************************************************************
128  *
129  * Function         srvc_eng_find_clcb_by_conn_id
130  *
131  * Description      The function searches all LCBs with macthing connection ID.
132  *
133  * Returns          Pointer to the found link conenction control block.
134  *
135  ******************************************************************************/
srvc_eng_find_clcb_idx_by_conn_id(uint16_t conn_id)136 uint8_t srvc_eng_find_clcb_idx_by_conn_id(uint16_t conn_id) {
137   uint8_t i_clcb;
138   tSRVC_CLCB* p_clcb = NULL;
139 
140   for (i_clcb = 0, p_clcb = srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS;
141        i_clcb++, p_clcb++) {
142     if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id) {
143       return i_clcb;
144     }
145   }
146 
147   return SRVC_MAX_APPS;
148 }
149 /*******************************************************************************
150  *
151  * Function         srvc_eng_clcb_alloc
152  *
153  * Description      Allocate a GATT profile connection link control block
154  *
155  * Returns          NULL if not found. Otherwise pointer to the connection link
156  *                  block.
157  *
158  ******************************************************************************/
srvc_eng_clcb_alloc(uint16_t conn_id,const RawAddress & bda)159 tSRVC_CLCB* srvc_eng_clcb_alloc(uint16_t conn_id, const RawAddress& bda) {
160   uint8_t i_clcb = 0;
161   tSRVC_CLCB* p_clcb = NULL;
162 
163   for (i_clcb = 0, p_clcb = srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS;
164        i_clcb++, p_clcb++) {
165     if (!p_clcb->in_use) {
166       p_clcb->in_use = true;
167       p_clcb->conn_id = conn_id;
168       p_clcb->connected = true;
169       p_clcb->bda = bda;
170       break;
171     }
172   }
173   return p_clcb;
174 }
175 /*******************************************************************************
176  *
177  * Function         srvc_eng_clcb_dealloc
178  *
179  * Description      De-allocate a GATT profile connection link control block
180  *
181  * Returns          True the deallocation is successful
182  *
183  ******************************************************************************/
srvc_eng_clcb_dealloc(uint16_t conn_id)184 bool srvc_eng_clcb_dealloc(uint16_t conn_id) {
185   uint8_t i_clcb = 0;
186   tSRVC_CLCB* p_clcb = NULL;
187 
188   for (i_clcb = 0, p_clcb = srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS;
189        i_clcb++, p_clcb++) {
190     if (p_clcb->in_use && p_clcb->connected && (p_clcb->conn_id == conn_id)) {
191       unsigned j;
192       for (j = 0; j < ARRAY_SIZE(p_clcb->dis_value.data_string); j++)
193         osi_free(p_clcb->dis_value.data_string[j]);
194 
195       memset(p_clcb, 0, sizeof(tSRVC_CLCB));
196       return true;
197     }
198   }
199   return false;
200 }
201 /*******************************************************************************
202  *   Service Engine Server Attributes Database Read/Read Blob Request process
203  ******************************************************************************/
srvc_eng_process_read_req(uint8_t clcb_idx,tGATT_READ_REQ * p_data,tGATTS_RSP * p_rsp,tGATT_STATUS * p_status)204 uint8_t srvc_eng_process_read_req(uint8_t clcb_idx, tGATT_READ_REQ* p_data,
205                                   tGATTS_RSP* p_rsp, tGATT_STATUS* p_status) {
206   tGATT_STATUS status = GATT_NOT_FOUND;
207   uint8_t act = SRVC_ACT_RSP;
208 
209   if (p_data->is_long) p_rsp->attr_value.offset = p_data->offset;
210 
211   p_rsp->attr_value.handle = p_data->handle;
212 
213   if (dis_valid_handle_range(p_data->handle))
214     act = dis_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value,
215                               p_data->is_long, p_status);
216 
217   else if (battery_valid_handle_range(p_data->handle))
218     act =
219         battery_s_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value,
220                                   p_data->is_long, p_status);
221 
222   else
223     *p_status = status;
224   return act;
225 }
226 /*******************************************************************************
227  *   Service Engine Server Attributes Database write Request process
228  ******************************************************************************/
srvc_eng_process_write_req(uint8_t clcb_idx,tGATT_WRITE_REQ * p_data,UNUSED_ATTR tGATTS_RSP * p_rsp,tGATT_STATUS * p_status)229 uint8_t srvc_eng_process_write_req(uint8_t clcb_idx, tGATT_WRITE_REQ* p_data,
230                                    UNUSED_ATTR tGATTS_RSP* p_rsp,
231                                    tGATT_STATUS* p_status) {
232   uint8_t act = SRVC_ACT_RSP;
233 
234   if (dis_valid_handle_range(p_data->handle)) {
235     act = dis_write_attr_value(p_data, p_status);
236   } else if (battery_valid_handle_range(p_data->handle)) {
237     act = battery_s_write_attr_value(clcb_idx, p_data, p_status);
238   } else
239     *p_status = GATT_NOT_FOUND;
240 
241   return act;
242 }
243 
244 /*******************************************************************************
245  *
246  * Function         srvc_eng_s_request_cback
247  *
248  * Description      GATT DIS attribute access request callback.
249  *
250  * Returns          void.
251  *
252  ******************************************************************************/
srvc_eng_s_request_cback(uint16_t conn_id,uint32_t trans_id,tGATTS_REQ_TYPE type,tGATTS_DATA * p_data)253 static void srvc_eng_s_request_cback(uint16_t conn_id, uint32_t trans_id,
254                                      tGATTS_REQ_TYPE type,
255                                      tGATTS_DATA* p_data) {
256   uint8_t status = GATT_INVALID_PDU;
257   tGATTS_RSP rsp_msg;
258   uint8_t act = SRVC_ACT_IGNORE;
259   uint8_t clcb_idx = srvc_eng_find_clcb_idx_by_conn_id(conn_id);
260 
261   VLOG(1) << StringPrintf("srvc_eng_s_request_cback : recv type (0x%02x)",
262                           type);
263 
264   memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
265 
266   srvc_eng_cb.clcb[clcb_idx].trans_id = trans_id;
267 
268   switch (type) {
269     case GATTS_REQ_TYPE_READ_CHARACTERISTIC:
270     case GATTS_REQ_TYPE_READ_DESCRIPTOR:
271       act = srvc_eng_process_read_req(clcb_idx, &p_data->read_req, &rsp_msg,
272                                       &status);
273       break;
274 
275     case GATTS_REQ_TYPE_WRITE_CHARACTERISTIC:
276     case GATTS_REQ_TYPE_WRITE_DESCRIPTOR:
277       act = srvc_eng_process_write_req(clcb_idx, &p_data->write_req, &rsp_msg,
278                                        &status);
279       if (!p_data->write_req.need_rsp) act = SRVC_ACT_IGNORE;
280       break;
281 
282     case GATTS_REQ_TYPE_WRITE_EXEC:
283       VLOG(1) << "Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD";
284       break;
285 
286     case GATTS_REQ_TYPE_MTU:
287       VLOG(1) << "Get MTU exchange new mtu size: " << p_data->mtu;
288       break;
289 
290     default:
291       VLOG(1) << StringPrintf("Unknown/unexpected LE GAP ATT request: 0x%02x",
292                               type);
293       break;
294   }
295 
296   srvc_eng_cb.clcb[clcb_idx].trans_id = 0;
297 
298   if (act == SRVC_ACT_RSP) GATTS_SendRsp(conn_id, trans_id, status, &rsp_msg);
299 }
300 
301 /*******************************************************************************
302  *
303  * Function         srvc_eng_c_cmpl_cback
304  *
305  * Description      Client operation complete callback.
306  *
307  * Returns          void
308  *
309  ******************************************************************************/
srvc_eng_c_cmpl_cback(uint16_t conn_id,tGATTC_OPTYPE op,tGATT_STATUS status,tGATT_CL_COMPLETE * p_data)310 static void srvc_eng_c_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
311                                   tGATT_STATUS status,
312                                   tGATT_CL_COMPLETE* p_data) {
313   tSRVC_CLCB* p_clcb = srvc_eng_find_clcb_by_conn_id(conn_id);
314 
315   VLOG(1) << StringPrintf(
316       "srvc_eng_c_cmpl_cback() - op_code: 0x%02x  status: 0x%02x ", op, status);
317 
318   if (p_clcb == NULL) {
319     LOG(ERROR) << __func__ << " received for unknown connection";
320     return;
321   }
322 
323   if (p_clcb->cur_srvc_id != SRVC_ID_NONE && p_clcb->cur_srvc_id <= SRVC_ID_MAX)
324     srvc_eng_c_cmpl_act[p_clcb->cur_srvc_id - 1](p_clcb, op, status, p_data);
325 }
326 
327 /*******************************************************************************
328  *
329  * Function         srvc_eng_connect_cback
330  *
331  * Description      Gatt profile connection callback.
332  *
333  * Returns          void
334  *
335  ******************************************************************************/
srvc_eng_connect_cback(UNUSED_ATTR tGATT_IF gatt_if,const RawAddress & bda,uint16_t conn_id,bool connected,tGATT_DISCONN_REASON reason,UNUSED_ATTR tBT_TRANSPORT transport)336 static void srvc_eng_connect_cback(UNUSED_ATTR tGATT_IF gatt_if,
337                                    const RawAddress& bda, uint16_t conn_id,
338                                    bool connected, tGATT_DISCONN_REASON reason,
339                                    UNUSED_ATTR tBT_TRANSPORT transport) {
340   VLOG(1) << __func__ << ": from " << bda
341           << StringPrintf(" connected:%d conn_id=%d reason = 0x%04x", connected,
342                           conn_id, reason);
343 
344   if (connected) {
345     if (srvc_eng_clcb_alloc(conn_id, bda) == NULL) {
346       LOG(ERROR) << __func__ << "srvc_eng_connect_cback: no_resource";
347       return;
348     }
349   } else {
350     srvc_eng_clcb_dealloc(conn_id);
351   }
352 }
353 /*******************************************************************************
354  *
355  * Function         srvc_eng_c_cmpl_cback
356  *
357  * Description      Client operation complete callback.
358  *
359  * Returns          void
360  *
361  ******************************************************************************/
srvc_eng_request_channel(const RawAddress & remote_bda,uint8_t srvc_id)362 bool srvc_eng_request_channel(const RawAddress& remote_bda, uint8_t srvc_id) {
363   bool set = true;
364   tSRVC_CLCB* p_clcb = srvc_eng_find_clcb_by_bd_addr(remote_bda);
365 
366   if (p_clcb == NULL) p_clcb = srvc_eng_clcb_alloc(0, remote_bda);
367 
368   if (p_clcb && p_clcb->cur_srvc_id == SRVC_ID_NONE)
369     p_clcb->cur_srvc_id = srvc_id;
370   else
371     set = false;
372 
373   return set;
374 }
375 /*******************************************************************************
376  *
377  * Function         srvc_eng_release_channel
378  *
379  * Description      Client operation complete callback.
380  *
381  * Returns          void
382  *
383  ******************************************************************************/
srvc_eng_release_channel(uint16_t conn_id)384 void srvc_eng_release_channel(uint16_t conn_id) {
385   tSRVC_CLCB* p_clcb = srvc_eng_find_clcb_by_conn_id(conn_id);
386 
387   if (p_clcb == NULL) {
388     LOG(ERROR) << __func__ << ": invalid connection id " << conn_id;
389     return;
390   }
391 
392   p_clcb->cur_srvc_id = SRVC_ID_NONE;
393 
394   /* check pending request */
395   GATT_Disconnect(p_clcb->conn_id);
396 }
397 /*******************************************************************************
398  *
399  * Function         srvc_eng_init
400  *
401  * Description      Initializa the GATT Service engine.
402  *
403  ******************************************************************************/
srvc_eng_init(void)404 tGATT_STATUS srvc_eng_init(void) {
405 
406   if (srvc_eng_cb.enabled) {
407     LOG(ERROR) << "DIS already initalized";
408   } else {
409     memset(&srvc_eng_cb, 0, sizeof(tSRVC_ENG_CB));
410 
411     /* Create a GATT profile service */
412     bluetooth::Uuid app_uuid =
413         bluetooth::Uuid::From16Bit(UUID_SERVCLASS_DEVICE_INFO);
414     srvc_eng_cb.gatt_if = GATT_Register(app_uuid, &srvc_gatt_cback);
415     GATT_StartIf(srvc_eng_cb.gatt_if);
416 
417     VLOG(1) << "Srvc_Init:  gatt_if=" << +srvc_eng_cb.gatt_if;
418 
419     srvc_eng_cb.enabled = true;
420     dis_cb.dis_read_uuid_idx = 0xff;
421   }
422   return GATT_SUCCESS;
423 }
424 
srvc_sr_rsp(uint8_t clcb_idx,tGATT_STATUS st,tGATTS_RSP * p_rsp)425 void srvc_sr_rsp(uint8_t clcb_idx, tGATT_STATUS st, tGATTS_RSP* p_rsp) {
426   if (srvc_eng_cb.clcb[clcb_idx].trans_id != 0) {
427     GATTS_SendRsp(srvc_eng_cb.clcb[clcb_idx].conn_id,
428                   srvc_eng_cb.clcb[clcb_idx].trans_id, st, p_rsp);
429 
430     srvc_eng_cb.clcb[clcb_idx].trans_id = 0;
431   }
432 }
srvc_sr_notify(const RawAddress & remote_bda,uint16_t handle,uint16_t len,uint8_t * p_value)433 void srvc_sr_notify(const RawAddress& remote_bda, uint16_t handle, uint16_t len,
434                     uint8_t* p_value) {
435   uint16_t conn_id = srvc_eng_find_conn_id_by_bd_addr(remote_bda);
436 
437   if (conn_id != GATT_INVALID_CONN_ID) {
438     GATTS_HandleValueNotification(conn_id, handle, len, p_value);
439   }
440 }
441