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