gatt_db.c revision 5702d5c6197404823f5e594764e2c67cf2416da1
1/******************************************************************************
2 *
3 *  Copyright (C) 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 "bt_target.h"
26
27#if BLE_INCLUDED == TRUE
28
29#include "bt_trace.h"
30
31#include <stdio.h>
32#include <string.h>
33#include "gatt_int.h"
34#include "l2c_api.h"
35#include "btm_int.h"
36
37/********************************************************************************
38**              L O C A L    F U N C T I O N     P R O T O T Y P E S            *
39*********************************************************************************/
40static BOOLEAN allocate_svc_db_buf(tGATT_SVC_DB *p_db);
41static void *allocate_attr_in_db(tGATT_SVC_DB *p_db, UINT16 uuid16, UINT8 *p_uuid128, tGATT_PERM perm);
42static BOOLEAN deallocate_attr_in_db(tGATT_SVC_DB *p_db, void *p_attr);
43static BOOLEAN copy_extra_byte_in_db(tGATT_SVC_DB *p_db, void **p_dst, UINT16 len);
44
45static void gatts_db_add_service_declaration(tGATT_SVC_DB *p_db, tBT_UUID service, BOOLEAN is_pri);
46static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, UINT8 op_code,
47                                                UINT16 handle, UINT16 offset, UINT32 trans_id);
48
49/*******************************************************************************
50**
51** Function         gatts_init_service_db
52**
53** Description      This function initialize a memory space to be a service database.
54**
55** Parameter        p_db: database pointer.
56**                  len: size of the memory space.
57**
58** Returns          Status of te operation.
59**
60*******************************************************************************/
61BOOLEAN gatts_init_service_db (tGATT_SVC_DB *p_db, tBT_UUID service,  BOOLEAN is_pri,
62                               UINT16 s_hdl, UINT16 num_handle)
63{
64    if (!allocate_svc_db_buf(p_db))
65    {
66        GATT_TRACE_ERROR0("gatts_init_service_db failed, no resources");
67        return FALSE;
68    }
69
70    GATT_TRACE_DEBUG0("gatts_init_service_db");
71    GATT_TRACE_DEBUG2("s_hdl = %d num_handle = %d", s_hdl, num_handle );
72
73    /* update service database information */
74    p_db->next_handle   = s_hdl;
75    p_db->end_handle    = s_hdl + num_handle;
76
77    gatts_db_add_service_declaration(p_db, service, is_pri);
78
79    return TRUE;
80}
81
82/*******************************************************************************
83**
84** Function         gatts_init_service_db
85**
86** Description      This function initialize a memory space to be a service database.
87**
88** Parameter        p_db: database pointer.
89**                  len: size of the memory space.
90**
91** Returns          Status of te operation.
92**
93*******************************************************************************/
94tBT_UUID * gatts_get_service_uuid (tGATT_SVC_DB *p_db)
95{
96    if (!p_db || !p_db->p_attr_list)
97    {
98        GATT_TRACE_ERROR0("service DB empty");
99
100        return NULL;
101    }
102    else
103    {
104        return &((tGATT_ATTR16 *)p_db->p_attr_list)->p_value->uuid;
105    }
106}
107
108/*******************************************************************************
109**
110** Function         gatts_check_attr_readability
111**
112** Description      check attribute readability
113**
114** Returns          status of operation.
115**
116*******************************************************************************/
117static tGATT_STATUS gatts_check_attr_readability(tGATT_ATTR16 *p_attr,
118                                                 BOOLEAN read_long,
119                                                 tGATT_SEC_FLAG sec_flag,
120                                                 UINT8 key_size)
121{
122    UINT16          min_key_size;
123    tGATT_PERM      perm = p_attr->permission;
124
125    min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12));
126    if (min_key_size != 0 )
127    {
128        min_key_size +=6;
129    }
130
131    if (!(perm & GATT_READ_ALLOWED))
132    {
133        GATT_TRACE_ERROR0( "GATT_READ_NOT_PERMIT");
134        return GATT_READ_NOT_PERMIT;
135    }
136
137    if ((perm & GATT_READ_AUTH_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED) &&
138        !(sec_flag & BTM_SEC_FLAG_ENCRYPTED))
139    {
140        GATT_TRACE_ERROR0( "GATT_INSUF_AUTHENTICATION");
141        return GATT_INSUF_AUTHENTICATION;
142    }
143
144    if ((perm & GATT_READ_MITM_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED))
145    {
146        GATT_TRACE_ERROR0( "GATT_INSUF_AUTHENTICATION: MITM Required");
147        return GATT_INSUF_AUTHENTICATION;
148    }
149
150    if ((perm & GATT_READ_ENCRYPTED_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED))
151    {
152        GATT_TRACE_ERROR0( "GATT_INSUF_ENCRYPTION");
153        return GATT_INSUF_ENCRYPTION;
154    }
155
156    if ( (perm & GATT_READ_ENCRYPTED_REQUIRED) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && (key_size < min_key_size))
157    {
158        GATT_TRACE_ERROR0( "GATT_INSUF_KEY_SIZE");
159        return GATT_INSUF_KEY_SIZE;
160    }
161
162
163    if (read_long)
164    {
165        switch (p_attr->uuid)
166        {
167            case GATT_UUID_PRI_SERVICE:
168            case GATT_UUID_SEC_SERVICE:
169            case GATT_UUID_CHAR_DECLARE:
170            case GATT_UUID_INCLUDE_SERVICE:
171            case GATT_UUID_CHAR_EXT_PROP:
172            case GATT_UUID_CHAR_CLIENT_CONFIG:
173            case GATT_UUID_CHAR_SRVR_CONFIG:
174            case GATT_UUID_CHAR_PRESENT_FORMAT:
175                GATT_TRACE_ERROR0("GATT_NOT_LONG");
176                return GATT_NOT_LONG;
177
178            default:
179                break;
180        }
181    }
182
183    return GATT_SUCCESS;
184}
185
186/*******************************************************************************
187**
188** Function         read_attr_value
189**
190** Description      Utility function to read an attribute value.
191**
192** Parameter        p_attr: pointer to the attribute to read.
193**                  offset: read offset.
194**                  p_value: output parameter to carry out the attribute value.
195**                  p_len: output parameter to carry out the attribute length.
196**                  read_long: this is a read blob request.
197**                  mtu: MTU
198**                  sec_flag: current link security status.
199**                  key_size: encryption key size.
200**
201** Returns          status of operation.
202**
203*******************************************************************************/
204static tGATT_STATUS read_attr_value (void *p_attr,
205                                     UINT16 offset,
206                                     UINT8 **p_data,
207                                     BOOLEAN read_long,
208                                     UINT16 mtu,
209                                     UINT16 *p_len,
210                                     tGATT_SEC_FLAG sec_flag,
211                                     UINT8 key_size)
212{
213    UINT16          len = 0, uuid16 = 0;
214    UINT8           *p = *p_data;
215    tGATT_STATUS    status;
216    UINT16          read_long_uuid=0;
217    tGATT_ATTR16    *p_attr16  = (tGATT_ATTR16  *)p_attr;
218
219    GATT_TRACE_DEBUG5("read_attr_value uuid=0x%04x perm=0x%0x sec_flag=0x%x offset=%d read_long=%d",
220                      p_attr16->uuid,
221                      p_attr16->permission,
222                      sec_flag,
223                      offset,
224                      read_long);
225
226    status = gatts_check_attr_readability((tGATT_ATTR16 *)p_attr, read_long, sec_flag, key_size);
227
228    if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_16)
229        uuid16 = p_attr16->uuid;
230
231    if (status != GATT_SUCCESS)
232        return status;
233
234    status = GATT_NO_RESOURCES;
235
236    if (read_long &&
237        (uuid16 == GATT_UUID_CHAR_DESCRIPTION || uuid16 == GATT_UUID_CHAR_AGG_FORMAT))
238    {
239        read_long_uuid = p_attr16->uuid;
240    }
241
242    if (uuid16 == GATT_UUID_PRI_SERVICE || uuid16 == GATT_UUID_SEC_SERVICE)
243    {
244        len = p_attr16->p_value->uuid.len;
245        if (mtu >= p_attr16->p_value->uuid.len)
246        {
247            gatt_build_uuid_to_stream(&p, p_attr16->p_value->uuid);
248            status = GATT_SUCCESS;
249        }
250    }
251    else if (uuid16 == GATT_UUID_CHAR_DECLARE)
252    {
253        len = (((tGATT_ATTR16 *)(p_attr16->p_next))->uuid_type == GATT_ATTR_UUID_TYPE_16) ? 5 :19;
254
255        if (mtu >= len)
256        {
257            UINT8_TO_STREAM(p, p_attr16->p_value->char_decl.property);
258            UINT16_TO_STREAM(p, p_attr16->p_value->char_decl.char_val_handle);
259
260            if (((tGATT_ATTR16 *)(p_attr16->p_next))->uuid_type == GATT_ATTR_UUID_TYPE_16)
261            {
262                UINT16_TO_STREAM(p, ((tGATT_ATTR16 *)(p_attr16->p_next))->uuid);
263            }
264            else
265            {
266                ARRAY_TO_STREAM (p, ((tGATT_ATTR128 *)(p_attr16->p_next))->uuid, LEN_UUID_128);
267            }
268            status = GATT_SUCCESS;
269        }
270
271    }
272    else if (uuid16 == GATT_UUID_INCLUDE_SERVICE)
273    {
274        len = (p_attr16->p_value->incl_handle.service_type.len == 2) ? 6 : 4;
275        if (mtu >= len)
276        {
277            UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.s_handle);
278            UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.e_handle);
279
280            if (p_attr16->p_value->incl_handle.service_type.len == 2)
281            {
282                UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.service_type.uu.uuid16);
283            }
284            status = GATT_SUCCESS;
285        }
286    }
287    else /* characteristic description or characteristic value */
288    {
289        status = GATT_PENDING;
290    }
291
292    *p_len = len;
293    *p_data = p;
294    return status;
295}
296
297/*******************************************************************************
298**
299** Function         gatts_db_read_attr_value_by_type
300**
301** Description      Query attribute value by attribute type.
302**
303** Parameter        p_db: pointer to the attribute database.
304**                  p_rsp: Read By type response data.
305**                  s_handle: starting handle of the range we are looking for.
306**                  e_handle: ending handle of the range we are looking for.
307**                  type: Attribute type.
308**                  mtu: MTU.
309**                  sec_flag: current link security status.
310**                  key_size: encryption key size.
311**
312** Returns          Status of the operation.
313**
314*******************************************************************************/
315tGATT_STATUS gatts_db_read_attr_value_by_type (tGATT_TCB   *p_tcb,
316                                               tGATT_SVC_DB    *p_db,
317                                               UINT8        op_code,
318                                               BT_HDR      *p_rsp,
319                                               UINT16       s_handle,
320                                               UINT16       e_handle,
321                                               tBT_UUID     type,
322                                               UINT16      *p_len,
323                                               tGATT_SEC_FLAG sec_flag,
324                                               UINT8        key_size,
325                                               UINT32       trans_id,
326                                               UINT16       *p_cur_handle)
327{
328    tGATT_STATUS status = GATT_NOT_FOUND;
329    tGATT_ATTR16  *p_attr;
330    UINT16      len = 0;
331    UINT8       *p = (UINT8 *)(p_rsp + 1) + p_rsp->len + L2CAP_MIN_OFFSET;
332    tBT_UUID    attr_uuid;
333#if (defined(BLE_DELAY_REQUEST_ENC) && (BLE_DELAY_REQUEST_ENC == TRUE))
334    UINT8       flag;
335#endif
336
337    if (p_db && p_db->p_attr_list)
338    {
339        p_attr = (tGATT_ATTR16 *)p_db->p_attr_list;
340
341        while (p_attr && p_attr->handle <= e_handle)
342        {
343            if (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16)
344            {
345                attr_uuid.len = LEN_UUID_16;
346                attr_uuid.uu.uuid16 = p_attr->uuid;
347            }
348            else
349            {
350                attr_uuid.len = LEN_UUID_128;
351                memcpy(attr_uuid.uu.uuid128, ((tGATT_ATTR128 *)p_attr)->uuid, LEN_UUID_128);
352            }
353
354            if (p_attr->handle >= s_handle && gatt_uuid_compare(type, attr_uuid))
355            {
356                if (*p_len <= 2)
357                {
358                    status = GATT_NO_RESOURCES;
359                    break;
360                }
361
362                UINT16_TO_STREAM (p, p_attr->handle);
363
364                status = read_attr_value ((void *)p_attr, 0, &p, FALSE, (UINT16)(*p_len -2), &len, sec_flag, key_size);
365
366                if (status == GATT_PENDING)
367                {
368                    status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, 0, trans_id);
369
370                    /* one callback at a time */
371                    break;
372                }
373                else if (status == GATT_SUCCESS)
374                {
375                    if (p_rsp->offset == 0)
376                        p_rsp->offset = len + 2;
377
378                    if (p_rsp->offset == len + 2)
379                    {
380                        p_rsp->len += (len  + 2);
381                        *p_len -= (len + 2);
382                    }
383                    else
384                    {
385                        GATT_TRACE_ERROR0("format mismatch");
386                        status = GATT_NO_RESOURCES;
387                        break;
388                    }
389                }
390                else
391                {
392                    *p_cur_handle = p_attr->handle;
393                    break;
394                }
395            }
396            p_attr = (tGATT_ATTR16 *)p_attr->p_next;
397        }
398    }
399
400#if (defined(BLE_DELAY_REQUEST_ENC) && (BLE_DELAY_REQUEST_ENC == TRUE))
401    if (BTM_GetSecurityFlags(p_tcb->peer_bda, &flag))
402    {
403        if ((p_tcb->att_lcid == L2CAP_ATT_CID) && (status == GATT_PENDING) &&
404            (type.uu.uuid16 == GATT_UUID_GAP_DEVICE_NAME))
405        {
406            if ((flag & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_FLAG_ENCRYPTED)) ==
407                 BTM_SEC_LINK_KEY_KNOWN)
408            {
409                tACL_CONN         *p;
410                p = btm_bda_to_acl(p_tcb->peer_bda);
411                if ((p != NULL) && (p->link_role == BTM_ROLE_MASTER))
412                {
413                    tBTM_BLE_SEC_ACT sec_act = BTM_BLE_SEC_ENCRYPT;
414                    btm_ble_set_encryption(p_tcb->peer_bda, &sec_act, p->link_role);
415                }
416            }
417        }
418    }
419#endif
420    return status;
421}
422
423/*******************************************************************************
424**
425** Function         gatts_add_included_service
426**
427** Description      This function adds an included service into a database.
428**
429** Parameter        p_db: database pointer.
430**                  inc_srvc_type: included service type.
431**
432** Returns          Status of the operation.
433**
434*******************************************************************************/
435UINT16 gatts_add_included_service (tGATT_SVC_DB *p_db, UINT16 s_handle, UINT16 e_handle,
436                                   tBT_UUID service)
437{
438    tGATT_ATTR16      *p_attr;
439
440    GATT_TRACE_DEBUG3("gatts_add_included_service: s_hdl = 0x%04x e_hdl = 0x%04x uuid = 0x%04x",
441                      s_handle, e_handle, service.uu.uuid16);
442
443    if (service.len == 0 || s_handle == 0 || e_handle == 0)
444    {
445        GATT_TRACE_ERROR0("gatts_add_included_service Illegal Params.");
446        return 0;
447    }
448
449    if ((p_attr = (tGATT_ATTR16 *) allocate_attr_in_db(p_db, GATT_UUID_INCLUDE_SERVICE, NULL, GATT_PERM_READ)) != NULL)
450    {
451        if (copy_extra_byte_in_db(p_db, (void **)&p_attr->p_value, sizeof(tGATT_INCL_SRVC)))
452        {
453            p_attr->p_value->incl_handle.s_handle = s_handle;
454            p_attr->p_value->incl_handle.e_handle = e_handle;
455            memcpy(&p_attr->p_value->incl_handle.service_type, &service, sizeof(tBT_UUID));
456
457            return p_attr->handle;
458        }
459        else
460        {
461            deallocate_attr_in_db(p_db, p_attr);
462        }
463    }
464
465    return 0;
466}
467
468/*******************************************************************************
469**
470** Function         gatts_add_characteristic
471**
472** Description      This function add a characteristics and its descriptor into
473**                  a servce identified by the service database pointer.
474**
475** Parameter        p_db: database pointer.
476**                  perm: permission (authentication and key size requirements)
477**                  property: property of the characteristic.
478**                  p_char: characteristic value information.
479**
480** Returns          Status of te operation.
481**
482*******************************************************************************/
483UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm,
484                                 tGATT_CHAR_PROP property,
485                                 tBT_UUID * p_char_uuid)
486{
487    tGATT_ATTR16     *p_char_decl, *p_char_val;
488    UINT16          uuid16 = (p_char_uuid->len == LEN_UUID_16) ? p_char_uuid->uu.uuid16 : 0;
489
490    GATT_TRACE_DEBUG2("gatts_add_characteristic perm=0x%0x property=0x%0x", perm, property);
491
492    if ((p_char_decl = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, GATT_UUID_CHAR_DECLARE, NULL, GATT_PERM_READ)) != NULL)
493    {
494        if (!copy_extra_byte_in_db(p_db, (void **)&p_char_decl->p_value, sizeof(tGATT_CHAR_DECL)))
495        {
496            deallocate_attr_in_db(p_db, p_char_decl);
497            return 0;
498        }
499
500        p_char_val = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, uuid16, p_char_uuid->uu.uuid128, perm);
501
502        if (p_char_val == NULL)
503        {
504            deallocate_attr_in_db(p_db, p_char_decl);
505            return 0;
506        }
507
508        p_char_decl->p_value->char_decl.property = property;
509        p_char_decl->p_value->char_decl.char_val_handle  = p_char_val->handle;
510
511        p_char_val->p_value = NULL;
512
513        return p_char_val->handle;
514    }
515
516    return 0;
517}
518
519/*******************************************************************************
520**
521** Function         gatt_convertchar_descr_type
522**
523** Description      This function convert a char descript UUID into descriptor type.
524**
525** Returns          descriptor type.
526**
527*******************************************************************************/
528UINT8 gatt_convertchar_descr_type(tBT_UUID *p_descr_uuid)
529{
530    tBT_UUID std_descr = {LEN_UUID_16, {GATT_UUID_CHAR_EXT_PROP}};
531
532    if (gatt_uuid_compare(std_descr, * p_descr_uuid))
533        return GATT_DESCR_EXT_DSCPTOR;
534
535    std_descr.uu.uuid16 ++;
536    if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
537        return GATT_DESCR_USER_DSCPTOR;
538
539    std_descr.uu.uuid16 ++;
540    if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
541        return GATT_DESCR_CLT_CONFIG;
542
543    std_descr.uu.uuid16 ++;
544    if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
545        return GATT_DESCR_SVR_CONFIG;
546
547    std_descr.uu.uuid16 ++;
548    if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
549        return GATT_DESCR_PRES_FORMAT;
550
551    std_descr.uu.uuid16 ++;
552    if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
553        return GATT_DESCR_AGGR_FORMAT;
554
555    std_descr.uu.uuid16 ++;
556    if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
557        return GATT_DESCR_VALID_RANGE;
558
559
560    return GATT_DESCR_UNKNOWN;
561}
562
563/*******************************************************************************
564**
565** Function         gatts_add_char_descr
566**
567** Description      This function add a characteristics descriptor.
568**
569** Parameter        p_db: database pointer.
570**                  perm: characteristic descriptor permission type.
571**                  char_dscp_tpye: the characteristic descriptor masks.
572**                  p_dscp_params: characteristic descriptors values.
573**
574** Returns          Status of the operation.
575**
576*******************************************************************************/
577UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm,
578                             tBT_UUID *     p_descr_uuid)
579{
580    tGATT_ATTR16    *p_char_dscptr;
581    UINT16    uuid16  = (p_descr_uuid->len == LEN_UUID_16)? p_descr_uuid->uu.uuid16 : 0;
582
583    GATT_TRACE_DEBUG1("gatts_add_char_descr uuid=0x%04x", p_descr_uuid->uu.uuid16);
584
585    /* Add characteristic descriptors */
586    if ((p_char_dscptr = (tGATT_ATTR16 *)allocate_attr_in_db(p_db,
587                                                             uuid16,
588                                                             p_descr_uuid->uu.uuid128,
589                                                             perm))
590        == NULL)
591    {
592        GATT_TRACE_DEBUG0("gatts_add_char_descr Fail for adding char descriptors.");
593        return 0;
594    }
595    else
596    {
597        return p_char_dscptr->handle;
598    }
599}
600
601/*******************************************************************************/
602/* Service Attribute Database Query Utility Functions */
603/*******************************************************************************/
604/*******************************************************************************
605**
606** Function         gatts_read_attr_value_by_handle
607**
608** Description      Query attribute value by attribute handle.
609**
610** Parameter        p_db: pointer to the attribute database.
611**                  handle: Attribute handle to read.
612**                  offset: Read offset.
613**                  p_value: output parameter to carry out the attribute value.
614**                  p_len: output parameter as attribute length read.
615**                  read_long: this is a read blob request.
616**                  mtu: MTU.
617**                  sec_flag: current link security status.
618**                  key_size: encryption key size
619**
620** Returns          Status of operation.
621**
622*******************************************************************************/
623tGATT_STATUS gatts_read_attr_value_by_handle(tGATT_TCB *p_tcb,
624                                             tGATT_SVC_DB *p_db,
625                                             UINT8 op_code,
626                                             UINT16 handle, UINT16 offset,
627                                             UINT8 *p_value, UINT16 *p_len,
628                                             UINT16 mtu,
629                                             tGATT_SEC_FLAG sec_flag,
630                                             UINT8 key_size,
631                                             UINT32 trans_id)
632{
633    tGATT_STATUS status = GATT_NOT_FOUND;
634    tGATT_ATTR16  *p_attr;
635    UINT8       *pp = p_value;
636
637    if (p_db && p_db->p_attr_list)
638    {
639        p_attr = (tGATT_ATTR16 *)p_db->p_attr_list;
640
641        while (p_attr && handle >= p_attr->handle)
642        {
643            if (p_attr->handle == handle)
644            {
645                status = read_attr_value (p_attr, offset, &pp,
646                                          (BOOLEAN)(op_code == GATT_REQ_READ_BLOB),
647                                          mtu, p_len, sec_flag, key_size);
648
649                if (status == GATT_PENDING)
650                {
651                    status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, offset, trans_id);
652                }
653                break;
654            }
655            p_attr = (tGATT_ATTR16 *)p_attr->p_next;
656        }
657    }
658
659    return status;
660}
661
662/*******************************************************************************
663**
664** Function         gatts_read_attr_perm_check
665**
666** Description      Check attribute readability.
667**
668** Parameter        p_db: pointer to the attribute database.
669**                  handle: Attribute handle to read.
670**                  offset: Read offset.
671**                  p_value: output parameter to carry out the attribute value.
672**                  p_len: output parameter as attribute length read.
673**                  read_long: this is a read blob request.
674**                  mtu: MTU.
675**                  sec_flag: current link security status.
676**                  key_size: encryption key size
677**
678** Returns          Status of operation.
679**
680*******************************************************************************/
681tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB *p_db,
682                                        BOOLEAN is_long,
683                                        UINT16 handle,
684                                        tGATT_SEC_FLAG sec_flag,
685                                        UINT8 key_size)
686{
687    tGATT_STATUS status = GATT_NOT_FOUND;
688    tGATT_ATTR16  *p_attr;
689
690    if (p_db && p_db->p_attr_list)
691    {
692        p_attr = (tGATT_ATTR16 *)p_db->p_attr_list;
693
694        while (p_attr && handle >= p_attr->handle)
695        {
696            if (p_attr->handle == handle)
697            {
698                status = gatts_check_attr_readability (p_attr,
699                                                       is_long,
700                                                       sec_flag, key_size);
701                break;
702            }
703            p_attr = (tGATT_ATTR16 *) p_attr->p_next;
704        }
705    }
706
707    return status;
708}
709/*******************************************************************************
710**
711** Function         gatts_write_attr_perm_check
712**
713** Description      Write attribute value into database.
714**
715** Parameter        p_db: pointer to the attribute database.
716**                  op_code:op code of this write.
717**                  handle: handle of the attribute to write.
718**                  offset: Write offset if write op code is write blob.
719**                  p_data: Attribute value to write.
720**                  len: attribute data length.
721**                  sec_flag: current link security status.
722**                  key_size: encryption key size
723**
724** Returns          Status of the operation.
725**
726*******************************************************************************/
727tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, UINT8 op_code,
728                                          UINT16 handle, UINT16 offset, UINT8 *p_data,
729                                          UINT16 len, tGATT_SEC_FLAG sec_flag, UINT8 key_size)
730{
731    tGATT_STATUS    status = GATT_NOT_FOUND;
732    tGATT_ATTR16    *p_attr;
733    UINT16          max_size = 0;
734    tGATT_PERM      perm;
735    UINT16          min_key_size;
736
737    GATT_TRACE_DEBUG6( "gatts_write_attr_perm_check op_code=0x%0x handle=0x%04x offset=%d len=%d sec_flag=0x%0x key_size=%d",
738                       op_code, handle, offset, len, sec_flag, key_size);
739
740    if (p_db != NULL)
741    {
742        p_attr = (tGATT_ATTR16 *) p_db->p_attr_list;
743
744        while (p_attr != NULL)
745        {
746            if (p_attr->handle == handle)
747            {
748                perm = p_attr->permission;
749                min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12));
750                if (min_key_size != 0 )
751                {
752                    min_key_size +=6;
753                }
754                GATT_TRACE_DEBUG2( "gatts_write_attr_perm_check p_attr->permission =0x%04x min_key_size==0x%04x",
755                                   p_attr->permission,
756                                   min_key_size);
757
758                if ((op_code == GATT_CMD_WRITE || op_code == GATT_REQ_WRITE)
759                    && (perm & GATT_WRITE_SIGNED_PERM))
760                {
761                    /* use the rules for the mixed security see section 10.2.3*/
762                    /* use security mode 1 level 2 when the following condition follows */
763                    /* LE security mode 2 level 1 and LE security mode 1 level 2 */
764                    if ((perm & GATT_PERM_WRITE_SIGNED) && (perm & GATT_PERM_WRITE_ENCRYPTED))
765                    {
766                        perm = GATT_PERM_WRITE_ENCRYPTED;
767                    }
768                    /* use security mode 1 level 3 when the following condition follows */
769                    /* LE security mode 2 level 2 and security mode 1 and LE */
770                    else if (((perm & GATT_PERM_WRITE_SIGNED_MITM) && (perm & GATT_PERM_WRITE_ENCRYPTED)) ||
771                              /* LE security mode 2 and security mode 1 level 3 */
772                             ((perm & GATT_WRITE_SIGNED_PERM) && (perm & GATT_PERM_WRITE_ENC_MITM)))
773                    {
774                        perm = GATT_PERM_WRITE_ENC_MITM;
775                    }
776                }
777
778                if ((op_code == GATT_SIGN_CMD_WRITE) && !(perm & GATT_WRITE_SIGNED_PERM))
779                {
780                    status = GATT_WRITE_NOT_PERMIT;
781                    GATT_TRACE_DEBUG0( "gatts_write_attr_perm_check - sign cmd write not allowed");
782                }
783                 if ((op_code == GATT_SIGN_CMD_WRITE) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED))
784                {
785                    status = GATT_INVALID_PDU;
786                    GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - Error!! sign cmd write sent on a encypted link");
787                }
788                else if (!(perm & GATT_WRITE_ALLOWED))
789                {
790                    status = GATT_WRITE_NOT_PERMIT;
791                    GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_WRITE_NOT_PERMIT");
792                }
793                /* require authentication, but not been authenticated */
794                else if ((perm & GATT_WRITE_AUTH_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED))
795                {
796                    status = GATT_INSUF_AUTHENTICATION;
797                    GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION");
798                }
799                else if ((perm & GATT_WRITE_MITM_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED))
800                {
801                    status = GATT_INSUF_AUTHENTICATION;
802                    GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION: MITM required");
803                }
804                else if ((perm & GATT_WRITE_ENCRYPTED_PERM ) && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED))
805                {
806                    status = GATT_INSUF_ENCRYPTION;
807                    GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_INSUF_ENCRYPTION");
808                }
809                else if ((perm & GATT_WRITE_ENCRYPTED_PERM ) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && (key_size < min_key_size))
810                {
811                    status = GATT_INSUF_KEY_SIZE;
812                    GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_INSUF_KEY_SIZE");
813                }
814                /* LE security mode 2 attribute  */
815                else if (perm & GATT_WRITE_SIGNED_PERM && op_code != GATT_SIGN_CMD_WRITE && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED))
816                {
817                    status = GATT_INSUF_AUTHENTICATION;
818                    GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION: LE security mode 2 required");
819                }
820                else /* writable: must be char value declaration or char descritpors */
821                {
822                    if(p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16)
823                    {
824                    switch (p_attr->uuid)
825                    {
826                        case GATT_UUID_CHAR_PRESENT_FORMAT:/* should be readable only */
827                        case GATT_UUID_CHAR_EXT_PROP:/* should be readable only */
828                        case GATT_UUID_CHAR_AGG_FORMAT: /* should be readable only */
829                            case GATT_UUID_CHAR_VALID_RANGE:
830                            status = GATT_WRITE_NOT_PERMIT;
831                            break;
832
833                        case GATT_UUID_CHAR_CLIENT_CONFIG:
834/* coverity[MISSING_BREAK] */
835/* intnended fall through, ignored */
836                            /* fall through */
837                        case GATT_UUID_CHAR_SRVR_CONFIG:
838                            max_size = 2;
839                        case GATT_UUID_CHAR_DESCRIPTION:
840                        default: /* any other must be character value declaration */
841                            status = GATT_SUCCESS;
842                            break;
843                        }
844                    }
845                    else if (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_128)
846                    {
847                         status = GATT_SUCCESS;
848                    }
849                    else
850                    {
851                        status = GATT_INVALID_PDU;
852                    }
853
854                    if (p_data == NULL && len  > 0)
855                    {
856                        status = GATT_INVALID_PDU;
857                    }
858                    /* these attribute does not allow write blob */
859// btla-specific ++
860                    else if ( (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16) &&
861                              (p_attr->uuid == GATT_UUID_CHAR_CLIENT_CONFIG ||
862                               p_attr->uuid == GATT_UUID_CHAR_SRVR_CONFIG) )
863// btla-specific --
864                    {
865                        if (op_code == GATT_REQ_PREPARE_WRITE && offset != 0) /* does not allow write blob */
866                        {
867                            status = GATT_NOT_LONG;
868                            GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_NOT_LONG");
869                        }
870                        else if (len != max_size)    /* data does not match the required format */
871                        {
872                            status = GATT_INVALID_ATTR_LEN;
873                            GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_INVALID_PDU");
874                        }
875                        else
876                        {
877                            status = GATT_SUCCESS;
878                        }
879                    }
880                }
881                break;
882            }
883            else
884                p_attr = (tGATT_ATTR16 *)p_attr->p_next;
885        }
886    }
887
888    return status;
889}
890
891/*******************************************************************************
892**
893** Function         allocate_attr_in_db
894**
895** Description      Allocate a memory space for a new attribute, and link this
896**                  attribute into the database attribute list.
897**
898**
899** Parameter        p_db    : database pointer.
900**                  service : type of attribute to be added.
901**
902** Returns          pointer to the newly allocated attribute.
903**
904*******************************************************************************/
905static void *allocate_attr_in_db(tGATT_SVC_DB *p_db, UINT16 uuid16, UINT8 *uuid128, tGATT_PERM perm)
906{
907    tGATT_ATTR16    *p_attr16 = NULL, *p_last;
908    tGATT_ATTR128   *p_attr128 = NULL;
909    UINT16      len = (uuid16 == 0) ? sizeof(tGATT_ATTR128): sizeof(tGATT_ATTR16);
910
911    GATT_TRACE_DEBUG1("allocate attr %d bytes ",len);
912
913    if (uuid16 == GATT_ILLEGAL_UUID && uuid128 == NULL)
914    {
915        GATT_TRACE_ERROR0("illegal UUID");
916        return NULL;
917    }
918
919    if (p_db->end_handle <= p_db->next_handle)
920    {
921        GATT_TRACE_DEBUG2("handle space full. handle_max = %d next_handle = %d",
922                          p_db->end_handle, p_db->next_handle);
923        return NULL;
924    }
925
926    if (p_db->mem_free < len)
927    {
928        if (!allocate_svc_db_buf(p_db))
929        {
930            GATT_TRACE_ERROR0("allocate_attr_in_db failed, no resources");
931            return NULL;
932        }
933    }
934
935    p_attr16 = (tGATT_ATTR16 *) p_db->p_free_mem;
936    p_attr128 = (tGATT_ATTR128 *) p_db->p_free_mem;
937
938    memset(p_attr16, 0, len);
939
940    if (uuid16 != GATT_ILLEGAL_UUID)
941    {
942        p_attr16->uuid_type = GATT_ATTR_UUID_TYPE_16;
943        p_attr16->uuid = uuid16;
944    }
945    else
946    {
947        p_attr128->uuid_type = GATT_ATTR_UUID_TYPE_128;
948        memcpy(p_attr128->uuid, uuid128, LEN_UUID_128);
949    }
950
951    p_db->p_free_mem += len;
952    p_db->mem_free -= len;
953
954    p_attr16->handle = p_db->next_handle++;
955    p_attr16->permission = perm;
956    p_attr16->p_next = NULL;
957
958    /* link the attribute record into the end of DB */
959    if (p_db->p_attr_list == NULL)
960        p_db->p_attr_list = p_attr16;
961    else
962    {
963        p_last = (tGATT_ATTR16 *)p_db->p_attr_list;
964
965        while (p_last != NULL && p_last->p_next != NULL)
966            p_last = (tGATT_ATTR16 *)p_last->p_next;
967
968        p_last->p_next = p_attr16;
969    }
970
971    if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_16)
972    {
973        GATT_TRACE_DEBUG3("=====> handle = [0x%04x] uuid = [0x%04x] perm=0x%02x ",
974                          p_attr16->handle, p_attr16->uuid, p_attr16->permission);
975    }
976    else
977    {
978        GATT_TRACE_DEBUG4("=====> handle = [0x%04x] uuid128 = [0x%02x:0x%02x] perm=0x%02x ",
979                          p_attr128->handle, p_attr128->uuid[0],p_attr128->uuid[1],
980                          p_attr128->permission);
981    }
982    return(void *)p_attr16;
983}
984
985/*******************************************************************************
986**
987** Function         deallocate_attr_in_db
988**
989** Description      Free an attribute within the database.
990**
991** Parameter        p_db: database pointer.
992**                  p_attr: pointer to the attribute record to be freed.
993**
994** Returns          BOOLEAN: success
995**
996*******************************************************************************/
997static BOOLEAN deallocate_attr_in_db(tGATT_SVC_DB *p_db, void *p_attr)
998{
999    tGATT_ATTR16  *p_cur, *p_next;
1000    BOOLEAN     found = FALSE;
1001
1002    if (p_db->p_attr_list == NULL)
1003        return found;
1004
1005    p_cur   = (tGATT_ATTR16 *) p_db->p_attr_list;
1006    p_next  = (tGATT_ATTR16 *) p_cur->p_next;
1007
1008    for (; p_cur != NULL && p_next != NULL;
1009        p_cur = p_next, p_next = (tGATT_ATTR16 *)p_next->p_next)
1010    {
1011        if (p_next == p_attr)
1012        {
1013            p_cur->p_next = p_next->p_next;
1014            found = TRUE;
1015        }
1016    }
1017    if (p_cur == p_attr && p_cur == p_db->p_attr_list)
1018    {
1019        p_db->p_attr_list = p_cur->p_next;
1020        found = TRUE;
1021    }
1022    /* else attr not found */
1023    if ( found)
1024        p_db->next_handle --;
1025
1026    return found;
1027}
1028
1029/*******************************************************************************
1030**
1031** Function         copy_extra_byte_in_db
1032**
1033** Description      Utility function to allocate extra bytes memory in DB and copy
1034**                  the value from a source place.
1035**
1036**
1037** Parameter        p_db: database pointer.
1038**                  p_dst: destination data pointer.
1039**                  p_src: source data pointer.
1040**                  len: data length to be copied.
1041**
1042** Returns          None.
1043**
1044*******************************************************************************/
1045static BOOLEAN copy_extra_byte_in_db(tGATT_SVC_DB *p_db, void **p_dst, UINT16 len)
1046{
1047    UINT8 *p = (UINT8 *)*p_dst;
1048
1049    if (p_db->mem_free < len)
1050    {
1051        if (!allocate_svc_db_buf(p_db))
1052        {
1053            GATT_TRACE_ERROR0("copy_extra_byte_in_db failed, no resources");
1054            return FALSE;
1055        }
1056    }
1057
1058    p = p_db->p_free_mem;
1059    p_db->p_free_mem += len;
1060    p_db->mem_free -= len;
1061    memset((void *)p, 0, len);
1062    *p_dst = (void *)p;
1063
1064    return TRUE;
1065}
1066
1067/*******************************************************************************
1068**
1069** Function         allocate_svc_db_buf
1070**
1071** Description      Utility function to allocate extra buffer for service database.
1072**
1073** Returns          TRUE if allocation succeed, otherwise FALSE.
1074**
1075*******************************************************************************/
1076static BOOLEAN allocate_svc_db_buf(tGATT_SVC_DB *p_db)
1077{
1078    BT_HDR  *p_buf;
1079
1080    GATT_TRACE_DEBUG0("allocate_svc_db_buf allocating extra buffer");
1081
1082    if ((p_buf = (BT_HDR *)GKI_getpoolbuf(GATT_DB_POOL_ID)) == NULL)
1083    {
1084        GATT_TRACE_ERROR0("allocate_svc_db_buf failed, no resources");
1085        return FALSE;
1086    }
1087
1088    memset(p_buf, 0, GKI_get_buf_size(p_buf));
1089    p_db->p_free_mem    = (UINT8 *) p_buf;
1090    p_db->mem_free      = GKI_get_buf_size(p_buf);
1091
1092    GKI_enqueue(&p_db->svc_buffer, p_buf);
1093
1094    return TRUE;
1095
1096}
1097
1098/*******************************************************************************
1099**
1100** Function         gatts_send_app_read_request
1101**
1102** Description      Send application read request callback
1103**
1104** Returns          status of operation.
1105**
1106*******************************************************************************/
1107static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, UINT8 op_code,
1108                                                UINT16 handle, UINT16 offset, UINT32 trans_id)
1109{
1110    tGATTS_DATA   sr_data;
1111    UINT8       i_rcb;
1112    tGATT_SR_REG *p_sreg;
1113    UINT16   conn_id;
1114
1115    i_rcb = gatt_sr_find_i_rcb_by_handle(handle);
1116    p_sreg = &gatt_cb.sr_reg[i_rcb];
1117    conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_sreg->gatt_if);
1118
1119    if (trans_id == 0)
1120    {
1121        trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
1122        gatt_sr_update_cback_cnt(p_tcb, p_sreg->gatt_if, TRUE, TRUE);
1123    }
1124
1125    if (trans_id != 0 )
1126    {
1127        memset(&sr_data, 0, sizeof(tGATTS_DATA));
1128
1129        sr_data.read_req.handle = handle;
1130        sr_data.read_req.is_long = (BOOLEAN)(op_code == GATT_REQ_READ_BLOB);
1131        sr_data.read_req.offset = offset;
1132
1133        gatt_sr_send_req_callback(conn_id,
1134                                  trans_id, GATTS_REQ_TYPE_READ, &sr_data);
1135        return(tGATT_STATUS) GATT_PENDING;
1136    }
1137    else
1138        return(tGATT_STATUS) GATT_BUSY; /* max pending command, application error */
1139
1140}
1141
1142/*******************************************************************************
1143**
1144** Function         gatts_db_add_service_declaration
1145**
1146** Description      Update a service database service declaration record.
1147**
1148** Parameter        p_db: database pointer.
1149**                  service: UUID of the service.
1150**
1151** Returns          void
1152**
1153*******************************************************************************/
1154static void gatts_db_add_service_declaration(tGATT_SVC_DB *p_db, tBT_UUID service, BOOLEAN is_pri)
1155{
1156    tGATT_ATTR16  *p_attr;
1157    UINT16      service_type = is_pri ? GATT_UUID_PRI_SERVICE: GATT_UUID_SEC_SERVICE;
1158
1159    GATT_TRACE_DEBUG0( "add_service_declaration");
1160
1161    /* add service declration record */
1162    if ((p_attr = (tGATT_ATTR16 *)(allocate_attr_in_db(p_db, service_type, NULL, GATT_PERM_READ))) != NULL)
1163    {
1164        if (copy_extra_byte_in_db (p_db, (void **)&p_attr->p_value, sizeof(tBT_UUID)))
1165        {
1166            memcpy (&p_attr->p_value->uuid, &service, sizeof(tBT_UUID));
1167        }
1168    }
1169}
1170
1171#endif /* BLE_INCLUDED */
1172