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