1 /******************************************************************************
2 *
3 * Copyright 2009-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 GATT database building and query functions
22 *
23 ******************************************************************************/
24
25 #include <base/logging.h>
26 #include <log/log.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include "bt_target.h"
31 #include "bt_trace.h"
32 #include "gatt_int.h"
33 #include "l2c_api.h"
34 #include "osi/include/osi.h"
35 #include "stack/btm/btm_ble_int.h"
36 #include "stack/btm/btm_sec.h"
37 #include "stack/include/acl_api.h"
38 #include "stack/include/bt_hdr.h"
39 #include "types/bluetooth/uuid.h"
40
41 using base::StringPrintf;
42 using bluetooth::Uuid;
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 tGATT_ATTR& allocate_attr_in_db(tGATT_SVC_DB& db, const Uuid& uuid,
48 tGATT_PERM perm);
49 static tGATT_STATUS gatts_send_app_read_request(
50 tGATT_TCB& tcb, uint16_t cid, uint8_t op_code, uint16_t handle,
51 uint16_t offset, uint32_t trans_id, bt_gatt_db_attribute_type_t gatt_type);
52
53 /**
54 * Initialize a memory space to be a service database.
55 */
gatts_init_service_db(tGATT_SVC_DB & db,const Uuid & service_uuid,bool is_pri,uint16_t s_hdl,uint16_t num_handle)56 void gatts_init_service_db(tGATT_SVC_DB& db, const Uuid& service_uuid,
57 bool is_pri, uint16_t s_hdl, uint16_t num_handle) {
58 db.attr_list.reserve(num_handle);
59
60 VLOG(1) << StringPrintf("%s: s_hdl= %d num_handle= %d", __func__, s_hdl,
61 num_handle);
62
63 /* update service database information */
64 db.next_handle = s_hdl;
65 db.end_handle = s_hdl + num_handle;
66
67 /* add service declration record */
68 Uuid uuid =
69 Uuid::From16Bit(is_pri ? GATT_UUID_PRI_SERVICE : GATT_UUID_SEC_SERVICE);
70 tGATT_ATTR& attr = allocate_attr_in_db(db, uuid, GATT_PERM_READ);
71 attr.p_value.reset(new tGATT_ATTR_VALUE);
72 attr.p_value->uuid = service_uuid;
73 }
74
gatts_get_service_uuid(tGATT_SVC_DB * p_db)75 Uuid* gatts_get_service_uuid(tGATT_SVC_DB* p_db) {
76 if (!p_db || p_db->attr_list.empty()) {
77 LOG(ERROR) << "service DB empty";
78 return NULL;
79 } else {
80 return &p_db->attr_list[0].p_value->uuid;
81 }
82 }
83
84 /** Check attribute readability. Returns status of operation. */
gatts_check_attr_readability(const tGATT_ATTR & attr,UNUSED_ATTR uint16_t offset,bool read_long,tGATT_SEC_FLAG sec_flag,uint8_t key_size)85 static tGATT_STATUS gatts_check_attr_readability(const tGATT_ATTR& attr,
86 UNUSED_ATTR uint16_t offset,
87 bool read_long,
88 tGATT_SEC_FLAG sec_flag,
89 uint8_t key_size) {
90 uint16_t min_key_size;
91 tGATT_PERM perm = attr.permission;
92
93 min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12));
94 if (min_key_size != 0) {
95 min_key_size += 6;
96 }
97
98 if (!(perm & GATT_READ_ALLOWED)) {
99 LOG(ERROR) << __func__ << ": GATT_READ_NOT_PERMIT";
100 return GATT_READ_NOT_PERMIT;
101 }
102
103 if ((perm & GATT_READ_AUTH_REQUIRED) && !sec_flag.is_link_key_known &&
104 !sec_flag.is_encrypted) {
105 LOG(ERROR) << __func__ << ": GATT_INSUF_AUTHENTICATION";
106 return GATT_INSUF_AUTHENTICATION;
107 }
108
109 if ((perm & GATT_READ_MITM_REQUIRED) && !sec_flag.is_link_key_authed) {
110 LOG(ERROR) << __func__ << ": GATT_INSUF_AUTHENTICATION: MITM Required";
111 return GATT_INSUF_AUTHENTICATION;
112 }
113
114 if ((perm & GATT_READ_ENCRYPTED_REQUIRED) && !sec_flag.is_encrypted) {
115 LOG(ERROR) << __func__ << ": GATT_INSUF_ENCRYPTION";
116 return GATT_INSUF_ENCRYPTION;
117 }
118
119 if ((perm & GATT_READ_ENCRYPTED_REQUIRED) && sec_flag.is_encrypted &&
120 (key_size < min_key_size)) {
121 LOG(ERROR) << __func__ << ": GATT_INSUF_KEY_SIZE";
122 return GATT_INSUF_KEY_SIZE;
123 }
124
125 if (perm & GATT_PERM_READ_IF_ENCRYPTED_OR_DISCOVERABLE) {
126 if (sec_flag.can_read_discoverable_characteristics) {
127 // no checks here
128 } else {
129 if (!sec_flag.is_link_key_known || !sec_flag.is_encrypted) {
130 return GATT_INSUF_AUTHENTICATION;
131 }
132 if (key_size < min_key_size) {
133 return GATT_INSUF_KEY_SIZE;
134 }
135 }
136 }
137
138 if (read_long && attr.uuid.Is16Bit()) {
139 switch (attr.uuid.As16Bit()) {
140 case GATT_UUID_PRI_SERVICE:
141 case GATT_UUID_SEC_SERVICE:
142 case GATT_UUID_CHAR_DECLARE:
143 case GATT_UUID_INCLUDE_SERVICE:
144 case GATT_UUID_CHAR_EXT_PROP:
145 case GATT_UUID_CHAR_CLIENT_CONFIG:
146 case GATT_UUID_CHAR_SRVR_CONFIG:
147 case GATT_UUID_CHAR_PRESENT_FORMAT:
148 LOG(ERROR) << __func__ << ": GATT_NOT_LONG";
149 return GATT_NOT_LONG;
150
151 default:
152 break;
153 }
154 }
155
156 return GATT_SUCCESS;
157 }
158
159 /*******************************************************************************
160 *
161 * Function read_attr_value
162 *
163 * Description Utility function to read an attribute value.
164 *
165 * Parameter attr16: pointer to the attribute to read.
166 * offset: read offset.
167 * p_data: output parameter to carry out the attribute value.
168 * read_long: this is a read blob request.
169 * mtu: MTU
170 * p_len: output parameter to carry out the attribute length.
171 * sec_flag: current link security status.
172 * key_size: encryption key size.
173 *
174 * Returns status of operation.
175 *
176 ******************************************************************************/
read_attr_value(tGATT_ATTR & attr16,uint16_t offset,uint8_t ** p_data,bool read_long,uint16_t mtu,uint16_t * p_len,tGATT_SEC_FLAG sec_flag,uint8_t key_size)177 static tGATT_STATUS read_attr_value(tGATT_ATTR& attr16, uint16_t offset,
178 uint8_t** p_data, bool read_long,
179 uint16_t mtu, uint16_t* p_len,
180 tGATT_SEC_FLAG sec_flag, uint8_t key_size) {
181 uint8_t* p = *p_data;
182
183 VLOG(1) << __func__ << " uuid=" << attr16.uuid
184 << StringPrintf(" perm=0x%02x offset=%d read_long=%d",
185 attr16.permission, offset, read_long);
186
187 tGATT_STATUS status = gatts_check_attr_readability(attr16, offset, read_long,
188 sec_flag, key_size);
189 if (status != GATT_SUCCESS) return status;
190
191 if (!attr16.uuid.Is16Bit()) {
192 /* characteristic description or characteristic value */
193 return GATT_PENDING;
194 }
195
196 uint16_t uuid16 = attr16.uuid.As16Bit();
197
198 if (uuid16 == GATT_UUID_PRI_SERVICE || uuid16 == GATT_UUID_SEC_SERVICE) {
199 *p_len = gatt_build_uuid_to_stream_len(attr16.p_value->uuid);
200 if (mtu < *p_len) return GATT_NO_RESOURCES;
201
202 gatt_build_uuid_to_stream(&p, attr16.p_value->uuid);
203 *p_data = p;
204 return GATT_SUCCESS;
205 }
206
207 if (uuid16 == GATT_UUID_CHAR_DECLARE) {
208 tGATT_ATTR* val_attr = &attr16 + 1;
209 uint8_t val_len = val_attr->uuid.GetShortestRepresentationSize();
210 *p_len = (val_len == Uuid::kNumBytes16) ? 5 : 19;
211
212 if (mtu < *p_len) return GATT_NO_RESOURCES;
213
214 UINT8_TO_STREAM(p, attr16.p_value->char_decl.property);
215 UINT16_TO_STREAM(p, attr16.p_value->char_decl.char_val_handle);
216
217 if (val_len == Uuid::kNumBytes16) {
218 UINT16_TO_STREAM(p, val_attr->uuid.As16Bit());
219 } else {
220 /* if 32 bit UUID, convert to 128 bit */
221 ARRAY_TO_STREAM(p, val_attr->uuid.To128BitLE(), (int)Uuid::kNumBytes128);
222 }
223 *p_data = p;
224 return GATT_SUCCESS;
225 }
226
227 if (uuid16 == GATT_UUID_INCLUDE_SERVICE) {
228 tGATT_INCL_SRVC& incl_handle = attr16.p_value->incl_handle;
229 if (incl_handle.service_type.Is16Bit())
230 *p_len = 6;
231 else
232 *p_len = 4;
233
234 if (mtu < *p_len) return GATT_NO_RESOURCES;
235
236 UINT16_TO_STREAM(p, incl_handle.s_handle);
237 UINT16_TO_STREAM(p, incl_handle.e_handle);
238
239 if (incl_handle.service_type.Is16Bit()) {
240 UINT16_TO_STREAM(p, incl_handle.service_type.As16Bit());
241 }
242 *p_data = p;
243 return GATT_SUCCESS;
244 }
245
246 if (uuid16 == GATT_UUID_CHAR_EXT_PROP) {
247 // sometimes this descriptor is added by users manually, we need to check if
248 // the p_value is nullptr.
249 uint16_t char_ext_prop =
250 attr16.p_value ? attr16.p_value->char_ext_prop : 0x0000;
251 *p_len = 2;
252
253 if (mtu < *p_len) {
254 return GATT_NO_RESOURCES;
255 }
256
257 UINT16_TO_STREAM(p, char_ext_prop);
258 *p_data = p;
259 return GATT_SUCCESS;
260 }
261
262 /* characteristic descriptor or characteristic value (again) */
263 return GATT_PENDING;
264 }
265
266 /*******************************************************************************
267 *
268 * Function gatts_db_read_attr_value_by_type
269 *
270 * Description Query attribute value by attribute type.
271 *
272 * Parameter p_db: pointer to the attribute database.
273 * p_rsp: Read By type response data.
274 * s_handle: starting handle of the range we are looking for.
275 * e_handle: ending handle of the range we are looking for.
276 * type: Attribute type.
277 * mtu: MTU.
278 * sec_flag: current link security status.
279 * key_size: encryption key size.
280 *
281 * Returns Status of the operation.
282 *
283 ******************************************************************************/
gatts_db_read_attr_value_by_type(tGATT_TCB & tcb,uint16_t cid,tGATT_SVC_DB * p_db,uint8_t op_code,BT_HDR * p_rsp,uint16_t s_handle,uint16_t e_handle,const Uuid & type,uint16_t * p_len,tGATT_SEC_FLAG sec_flag,uint8_t key_size,uint32_t trans_id,uint16_t * p_cur_handle)284 tGATT_STATUS gatts_db_read_attr_value_by_type(
285 tGATT_TCB& tcb, uint16_t cid, tGATT_SVC_DB* p_db, uint8_t op_code,
286 BT_HDR* p_rsp, uint16_t s_handle, uint16_t e_handle, const Uuid& type,
287 uint16_t* p_len, tGATT_SEC_FLAG sec_flag, uint8_t key_size,
288 uint32_t trans_id, uint16_t* p_cur_handle) {
289 tGATT_STATUS status = GATT_NOT_FOUND;
290 uint16_t len = 0;
291 uint8_t* p = (uint8_t*)(p_rsp + 1) + p_rsp->len + L2CAP_MIN_OFFSET;
292
293 if (p_db) {
294 for (tGATT_ATTR& attr : p_db->attr_list) {
295 if (attr.handle >= s_handle && type == attr.uuid) {
296 if (*p_len <= 2) {
297 status = GATT_NO_RESOURCES;
298 break;
299 }
300
301 UINT16_TO_STREAM(p, attr.handle);
302
303 status = read_attr_value(attr, 0, &p, false, (uint16_t)(*p_len - 2),
304 &len, sec_flag, key_size);
305
306 if (status == GATT_PENDING) {
307 status = gatts_send_app_read_request(tcb, cid, op_code, attr.handle,
308 0, trans_id, attr.gatt_type);
309
310 /* one callback at a time */
311 break;
312 } else if (status == GATT_SUCCESS) {
313 if (p_rsp->offset == 0) p_rsp->offset = len + 2;
314
315 if (p_rsp->offset == len + 2) {
316 p_rsp->len += (len + 2);
317 *p_len -= (len + 2);
318 } else {
319 LOG(ERROR) << "format mismatch";
320 status = GATT_NO_RESOURCES;
321 break;
322 }
323 } else {
324 *p_cur_handle = attr.handle;
325 break;
326 }
327 }
328 }
329 }
330
331 return status;
332 }
333
334 /**
335 * This function adds an included service into a database.
336 *
337 * Parameter db: database pointer.
338 * inc_srvc_type: included service type.
339 *
340 * Returns Status of the operation.
341 *
342 */
gatts_add_included_service(tGATT_SVC_DB & db,uint16_t s_handle,uint16_t e_handle,const Uuid & service)343 uint16_t gatts_add_included_service(tGATT_SVC_DB& db, uint16_t s_handle,
344 uint16_t e_handle, const Uuid& service) {
345 Uuid uuid = Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE);
346
347 VLOG(1) << __func__
348 << StringPrintf(": s_hdl=0x%04x e_hdl=0x%04x ", s_handle, e_handle)
349 << "service uuid = " << service;
350
351 if (service.IsEmpty() || s_handle == 0 || e_handle == 0) {
352 LOG(ERROR) << __func__ << ": Illegal Params.";
353 return 0;
354 }
355
356 tGATT_ATTR& attr = allocate_attr_in_db(db, uuid, GATT_PERM_READ);
357
358 attr.p_value.reset(new tGATT_ATTR_VALUE);
359 attr.p_value->incl_handle.s_handle = s_handle;
360 attr.p_value->incl_handle.e_handle = e_handle;
361 attr.p_value->incl_handle.service_type = service;
362
363 return attr.handle;
364 }
365
366 /*******************************************************************************
367 *
368 * Function gatts_add_characteristic
369 *
370 * Description This function add a characteristics and its descriptor into
371 * a servce identified by the service database pointer.
372 *
373 * Parameter db: database.
374 * perm: permission (authentication and key size requirements)
375 * property: property of the characteristic.
376 * extended_properties: characteristic extended properties.
377 * p_char: characteristic value information.
378 *
379 * Returns Status of te operation.
380 *
381 ******************************************************************************/
gatts_add_characteristic(tGATT_SVC_DB & db,tGATT_PERM perm,tGATT_CHAR_PROP property,const Uuid & char_uuid)382 uint16_t gatts_add_characteristic(tGATT_SVC_DB& db, tGATT_PERM perm,
383 tGATT_CHAR_PROP property,
384 const Uuid& char_uuid) {
385 Uuid uuid = Uuid::From16Bit(GATT_UUID_CHAR_DECLARE);
386
387 VLOG(1) << StringPrintf("%s: perm=0x%0x property=0x%0x", __func__, perm,
388 property);
389
390 tGATT_ATTR& char_decl = allocate_attr_in_db(db, uuid, GATT_PERM_READ);
391 tGATT_ATTR& char_val = allocate_attr_in_db(db, char_uuid, perm);
392
393 char_decl.p_value.reset(new tGATT_ATTR_VALUE);
394 char_decl.p_value->char_decl.property = property;
395 char_decl.p_value->char_decl.char_val_handle = char_val.handle;
396 char_val.gatt_type = BTGATT_DB_CHARACTERISTIC;
397
398 return char_val.handle;
399 }
400
401 /*******************************************************************************
402 *
403 * Function gatts_add_char_ext_prop_descr
404 *
405 * Description add a characteristics extended properties descriptor.
406 *
407 * Parameter db: database pointer.
408 * extended_properties: characteristic descriptors values.
409 *
410 * Returns Status of the operation.
411 *
412 ******************************************************************************/
gatts_add_char_ext_prop_descr(tGATT_SVC_DB & db,uint16_t extended_properties)413 uint16_t gatts_add_char_ext_prop_descr(
414 tGATT_SVC_DB& db, uint16_t extended_properties) {
415 Uuid descr_uuid = Uuid::From16Bit(GATT_UUID_CHAR_EXT_PROP);
416
417 VLOG(1) << StringPrintf("gatts_add_char_ext_prop_descr uuid=%s",
418 descr_uuid.ToString().c_str());
419
420 tGATT_ATTR& char_dscptr = allocate_attr_in_db(db, descr_uuid, GATT_PERM_READ);
421 char_dscptr.gatt_type = BTGATT_DB_DESCRIPTOR;
422 char_dscptr.p_value.reset(new tGATT_ATTR_VALUE);
423 char_dscptr.p_value->char_ext_prop = extended_properties;
424
425 return char_dscptr.handle;
426 }
427
428 /*******************************************************************************
429 *
430 * Function gatts_add_char_descr
431 *
432 * Description This function add a characteristics descriptor.
433 *
434 * Parameter p_db: database pointer.
435 * perm: characteristic descriptor permission type.
436 * char_dscp_tpye: the characteristic descriptor masks.
437 * p_dscp_params: characteristic descriptors values.
438 *
439 * Returns Status of the operation.
440 *
441 ******************************************************************************/
gatts_add_char_descr(tGATT_SVC_DB & db,tGATT_PERM perm,const Uuid & descr_uuid)442 uint16_t gatts_add_char_descr(tGATT_SVC_DB& db, tGATT_PERM perm,
443 const Uuid& descr_uuid) {
444 VLOG(1) << StringPrintf("gatts_add_char_descr uuid=%s",
445 descr_uuid.ToString().c_str());
446
447 /* Add characteristic descriptors */
448 tGATT_ATTR& char_dscptr = allocate_attr_in_db(db, descr_uuid, perm);
449 char_dscptr.gatt_type = BTGATT_DB_DESCRIPTOR;
450 return char_dscptr.handle;
451 }
452
453 /******************************************************************************/
454 /* Service Attribute Database Query Utility Functions */
455 /******************************************************************************/
find_attr_by_handle(tGATT_SVC_DB * p_db,uint16_t handle)456 tGATT_ATTR* find_attr_by_handle(tGATT_SVC_DB* p_db, uint16_t handle) {
457 if (!p_db) return nullptr;
458
459 for (auto& attr : p_db->attr_list) {
460 if (attr.handle == handle) return &attr;
461 if (attr.handle > handle) return nullptr;
462 }
463
464 return nullptr;
465 }
466
467 /*******************************************************************************
468 *
469 * Function gatts_read_attr_value_by_handle
470 *
471 * Description Query attribute value by attribute handle.
472 *
473 * Parameter p_db: pointer to the attribute database.
474 * handle: Attribute handle to read.
475 * offset: Read offset.
476 * p_value: output parameter to carry out the attribute value.
477 * p_len: output parameter as attribute length read.
478 * read_long: this is a read blob request.
479 * mtu: MTU.
480 * sec_flag: current link security status.
481 * key_size: encryption key size
482 *
483 * Returns Status of operation.
484 *
485 ******************************************************************************/
gatts_read_attr_value_by_handle(tGATT_TCB & tcb,uint16_t cid,tGATT_SVC_DB * p_db,uint8_t op_code,uint16_t handle,uint16_t offset,uint8_t * p_value,uint16_t * p_len,uint16_t mtu,tGATT_SEC_FLAG sec_flag,uint8_t key_size,uint32_t trans_id)486 tGATT_STATUS gatts_read_attr_value_by_handle(
487 tGATT_TCB& tcb, uint16_t cid, tGATT_SVC_DB* p_db, uint8_t op_code,
488 uint16_t handle, uint16_t offset, uint8_t* p_value, uint16_t* p_len,
489 uint16_t mtu, tGATT_SEC_FLAG sec_flag, uint8_t key_size,
490 uint32_t trans_id) {
491 tGATT_ATTR* p_attr = find_attr_by_handle(p_db, handle);
492 if (!p_attr) return GATT_NOT_FOUND;
493
494 uint8_t* pp = p_value;
495 tGATT_STATUS status = read_attr_value(*p_attr, offset, &pp,
496 (bool)(op_code == GATT_REQ_READ_BLOB),
497 mtu, p_len, sec_flag, key_size);
498
499 if (status == GATT_PENDING) {
500 status = gatts_send_app_read_request(tcb, cid, op_code, p_attr->handle,
501 offset, trans_id, p_attr->gatt_type);
502 }
503 return status;
504 }
505
506 /*******************************************************************************
507 *
508 * Function gatts_read_attr_perm_check
509 *
510 * Description Check attribute readability.
511 *
512 * Parameter p_db: pointer to the attribute database.
513 * handle: Attribute handle to read.
514 * offset: Read offset.
515 * p_value: output parameter to carry out the attribute value.
516 * p_len: output parameter as attribute length read.
517 * read_long: this is a read blob request.
518 * mtu: MTU.
519 * sec_flag: current link security status.
520 * key_size: encryption key size
521 *
522 * Returns Status of operation.
523 *
524 ******************************************************************************/
gatts_read_attr_perm_check(tGATT_SVC_DB * p_db,bool is_long,uint16_t handle,tGATT_SEC_FLAG sec_flag,uint8_t key_size)525 tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB* p_db, bool is_long,
526 uint16_t handle,
527 tGATT_SEC_FLAG sec_flag,
528 uint8_t key_size) {
529 tGATT_ATTR* p_attr = find_attr_by_handle(p_db, handle);
530 if (!p_attr) return GATT_NOT_FOUND;
531
532 return gatts_check_attr_readability(*p_attr, 0, is_long, sec_flag, key_size);
533 }
534
535 /*******************************************************************************
536 *
537 * Function gatts_write_attr_perm_check
538 *
539 * Description Write attribute value into database.
540 *
541 * Parameter p_db: pointer to the attribute database.
542 * op_code:op code of this write.
543 * handle: handle of the attribute to write.
544 * offset: Write offset if write op code is write blob.
545 * p_data: Attribute value to write.
546 * len: attribute data length.
547 * sec_flag: current link security status.
548 * key_size: encryption key size
549 *
550 * Returns Status of the operation.
551 *
552 ******************************************************************************/
gatts_write_attr_perm_check(tGATT_SVC_DB * p_db,uint8_t op_code,uint16_t handle,uint16_t offset,uint8_t * p_data,uint16_t len,tGATT_SEC_FLAG sec_flag,uint8_t key_size)553 tGATT_STATUS gatts_write_attr_perm_check(tGATT_SVC_DB* p_db, uint8_t op_code,
554 uint16_t handle, uint16_t offset,
555 uint8_t* p_data, uint16_t len,
556 tGATT_SEC_FLAG sec_flag,
557 uint8_t key_size) {
558 VLOG(1) << StringPrintf(
559 "%s: op_code=0x%0x handle=0x%04x offset=%d len=%d "
560 "key_size=%d",
561 __func__, op_code, handle, offset, len, key_size);
562
563 tGATT_ATTR* p_attr = find_attr_by_handle(p_db, handle);
564 if (!p_attr) return GATT_NOT_FOUND;
565
566 tGATT_PERM perm = p_attr->permission;
567 uint16_t min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12));
568 if (min_key_size != 0) {
569 min_key_size += 6;
570 }
571 VLOG(1) << StringPrintf("%s: p_attr->permission =0x%04x min_key_size==0x%04x",
572 __func__, p_attr->permission, min_key_size);
573
574 if ((op_code == GATT_CMD_WRITE || op_code == GATT_REQ_WRITE) &&
575 (perm & GATT_WRITE_SIGNED_PERM)) {
576 /* use the rules for the mixed security see section 10.2.3*/
577 /* use security mode 1 level 2 when the following condition follows */
578 /* LE security mode 2 level 1 and LE security mode 1 level 2 */
579 if ((perm & GATT_PERM_WRITE_SIGNED) && (perm & GATT_PERM_WRITE_ENCRYPTED)) {
580 perm = GATT_PERM_WRITE_ENCRYPTED;
581 }
582 /* use security mode 1 level 3 when the following condition follows */
583 /* LE security mode 2 level 2 and security mode 1 and LE */
584 else if (((perm & GATT_PERM_WRITE_SIGNED_MITM) &&
585 (perm & GATT_PERM_WRITE_ENCRYPTED)) ||
586 /* LE security mode 2 and security mode 1 level 3 */
587 ((perm & GATT_WRITE_SIGNED_PERM) &&
588 (perm & GATT_PERM_WRITE_ENC_MITM))) {
589 perm = GATT_PERM_WRITE_ENC_MITM;
590 }
591 }
592
593 tGATT_STATUS status = GATT_NOT_FOUND;
594 if ((op_code == GATT_SIGN_CMD_WRITE) && !(perm & GATT_WRITE_SIGNED_PERM)) {
595 status = GATT_WRITE_NOT_PERMIT;
596 VLOG(1) << __func__ << ": sign cmd write not allowed";
597 }
598 if ((op_code == GATT_SIGN_CMD_WRITE) && sec_flag.is_encrypted) {
599 status = GATT_INVALID_PDU;
600 LOG(ERROR) << __func__
601 << ": Error!! sign cmd write sent on a encypted link";
602 } else if (!(perm & GATT_WRITE_ALLOWED)) {
603 status = GATT_WRITE_NOT_PERMIT;
604 LOG(ERROR) << __func__ << ": GATT_WRITE_NOT_PERMIT";
605 }
606 /* require authentication, but not been authenticated */
607 else if ((perm & GATT_WRITE_AUTH_REQUIRED) && !sec_flag.is_link_key_known) {
608 status = GATT_INSUF_AUTHENTICATION;
609 LOG(ERROR) << __func__ << ": GATT_INSUF_AUTHENTICATION";
610 } else if ((perm & GATT_WRITE_MITM_REQUIRED) &&
611 !sec_flag.is_link_key_authed) {
612 status = GATT_INSUF_AUTHENTICATION;
613 LOG(ERROR) << __func__ << ": GATT_INSUF_AUTHENTICATION: MITM required";
614 } else if ((perm & GATT_WRITE_ENCRYPTED_PERM) && !sec_flag.is_encrypted) {
615 status = GATT_INSUF_ENCRYPTION;
616 LOG(ERROR) << __func__ << ": GATT_INSUF_ENCRYPTION";
617 } else if ((perm & GATT_WRITE_ENCRYPTED_PERM) && sec_flag.is_encrypted &&
618 (key_size < min_key_size)) {
619 status = GATT_INSUF_KEY_SIZE;
620 LOG(ERROR) << __func__ << ": GATT_INSUF_KEY_SIZE";
621 }
622 /* LE security mode 2 attribute */
623 else if (perm & GATT_WRITE_SIGNED_PERM && op_code != GATT_SIGN_CMD_WRITE &&
624 !sec_flag.is_encrypted && (perm & GATT_WRITE_ALLOWED) == 0) {
625 status = GATT_INSUF_AUTHENTICATION;
626 LOG(ERROR) << __func__
627 << ": GATT_INSUF_AUTHENTICATION: LE security mode 2 required";
628 } else /* writable: must be char value declaration or char descritpors */
629 {
630 uint16_t max_size = 0;
631
632 if (p_attr->uuid.IsEmpty()) {
633 status = GATT_INVALID_PDU;
634 } else if (p_attr->uuid.Is16Bit()) {
635 switch (p_attr->uuid.As16Bit()) {
636 case GATT_UUID_CHAR_PRESENT_FORMAT: /* should be readable only */
637 case GATT_UUID_CHAR_EXT_PROP: /* should be readable only */
638 case GATT_UUID_CHAR_AGG_FORMAT: /* should be readable only */
639 case GATT_UUID_CHAR_VALID_RANGE:
640 status = GATT_WRITE_NOT_PERMIT;
641 break;
642
643 case GATT_UUID_CHAR_CLIENT_CONFIG:
644 FALLTHROUGH_INTENDED; /* FALLTHROUGH */
645 case GATT_UUID_CHAR_SRVR_CONFIG:
646 max_size = 2;
647 FALLTHROUGH_INTENDED; /* FALLTHROUGH */
648 case GATT_UUID_CHAR_DESCRIPTION:
649 default: /* any other must be character value declaration */
650 status = GATT_SUCCESS;
651 break;
652 }
653 } else { // 32 or 128 bit UUID
654 status = GATT_SUCCESS;
655 }
656
657 if (p_data == NULL && len > 0) {
658 return GATT_INVALID_PDU;
659 }
660
661 /* these attribute does not allow write blob */
662 if (p_attr->uuid.Is16Bit() &&
663 (p_attr->uuid.As16Bit() == GATT_UUID_CHAR_CLIENT_CONFIG ||
664 p_attr->uuid.As16Bit() == GATT_UUID_CHAR_SRVR_CONFIG)) {
665 if (op_code == GATT_REQ_PREPARE_WRITE && offset != 0) {
666 /* does not allow write blob */
667 status = GATT_NOT_LONG;
668 LOG(ERROR) << __func__ << ": GATT_NOT_LONG";
669 } else if (len != max_size) {
670 /* data does not match the required format */
671 status = GATT_INVALID_ATTR_LEN;
672 LOG(ERROR) << __func__ << ": GATT_INVALID_PDU";
673 } else {
674 return GATT_SUCCESS;
675 }
676 }
677 }
678
679 return status;
680 }
681
682 /**
683 * Description Allocate a memory space for a new attribute, and link this
684 * attribute into the database attribute list.
685 *
686 *
687 * Parameter p_db : database pointer.
688 * uuid: attribute UUID
689 *
690 * Returns pointer to the newly allocated attribute.
691 *
692 */
allocate_attr_in_db(tGATT_SVC_DB & db,const Uuid & uuid,tGATT_PERM perm)693 static tGATT_ATTR& allocate_attr_in_db(tGATT_SVC_DB& db, const Uuid& uuid,
694 tGATT_PERM perm) {
695 if (db.next_handle >= db.end_handle) {
696 LOG(FATAL) << __func__
697 << " wrong number of handles! handle_max = " << +db.end_handle
698 << ", next_handle = " << +db.next_handle;
699 }
700
701 db.attr_list.emplace_back();
702 tGATT_ATTR& attr = db.attr_list.back();
703 attr.handle = db.next_handle++;
704 attr.uuid = uuid;
705 attr.permission = perm;
706 return attr;
707 }
708
709 /*******************************************************************************
710 *
711 * Function gatts_send_app_read_request
712 *
713 * Description Send application read request callback
714 *
715 * Returns status of operation.
716 *
717 ******************************************************************************/
gatts_send_app_read_request(tGATT_TCB & tcb,uint16_t cid,uint8_t op_code,uint16_t handle,uint16_t offset,uint32_t trans_id,bt_gatt_db_attribute_type_t gatt_type)718 static tGATT_STATUS gatts_send_app_read_request(
719 tGATT_TCB& tcb, uint16_t cid, uint8_t op_code, uint16_t handle,
720 uint16_t offset, uint32_t trans_id, bt_gatt_db_attribute_type_t gatt_type) {
721 tGATT_SRV_LIST_ELEM& el = *gatt_sr_find_i_rcb_by_handle(handle);
722 uint16_t conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, el.gatt_if);
723
724 if (trans_id == 0) {
725 trans_id = gatt_sr_enqueue_cmd(tcb, cid, op_code, handle);
726 gatt_sr_update_cback_cnt(tcb, cid, el.gatt_if, true, true);
727 }
728
729 if (trans_id != 0) {
730 tGATTS_DATA sr_data;
731 memset(&sr_data, 0, sizeof(tGATTS_DATA));
732
733 sr_data.read_req.handle = handle;
734 sr_data.read_req.is_long = (bool)(op_code == GATT_REQ_READ_BLOB);
735 sr_data.read_req.offset = offset;
736
737 uint8_t opcode;
738 if (gatt_type == BTGATT_DB_DESCRIPTOR) {
739 opcode = GATTS_REQ_TYPE_READ_DESCRIPTOR;
740 } else if (gatt_type == BTGATT_DB_CHARACTERISTIC) {
741 opcode = GATTS_REQ_TYPE_READ_CHARACTERISTIC;
742 } else {
743 LOG(ERROR) << __func__
744 << ": Attempt to read attribute that's not tied with "
745 "characteristic or descriptor value.";
746 return GATT_ERROR;
747 }
748
749 gatt_sr_send_req_callback(conn_id, trans_id, opcode, &sr_data);
750 return (tGATT_STATUS)GATT_PENDING;
751 } else
752 return (tGATT_STATUS)GATT_BUSY; /* max pending command, application error */
753 }
754