gatt_cl.c revision 5fe6f0cf6b223e3ed6be4912d55b3ed5b41ce0cd
1/******************************************************************************
2 *
3 *  Copyright (C) 1999-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 the main GATT client functions
22 *
23 ******************************************************************************/
24
25#include "bt_target.h"
26
27#if BLE_INCLUDED == TRUE
28
29#include <string.h>
30#include "bt_utils.h"
31#include "bt_common.h"
32#include "gatt_int.h"
33#include "l2c_int.h"
34
35#define GATT_WRITE_LONG_HDR_SIZE    5 /* 1 opcode + 2 handle + 2 offset */
36#define GATT_READ_CHAR_VALUE_HDL    (GATT_READ_CHAR_VALUE | 0x80)
37#define GATT_READ_INC_SRV_UUID128   (GATT_DISC_INC_SRVC   | 0x90)
38
39#define GATT_PREP_WRITE_RSP_MIN_LEN 4
40#define GATT_NOTIFICATION_MIN_LEN 2
41#define GATT_WRITE_RSP_MIN_LEN  2
42#define GATT_INFO_RSP_MIN_LEN   1
43#define GATT_MTU_RSP_MIN_LEN    2
44#define GATT_READ_BY_TYPE_RSP_MIN_LEN    1
45
46/********************************************************************************
47**                       G L O B A L      G A T T       D A T A                 *
48*********************************************************************************/
49void gatt_send_prepare_write(tGATT_TCB  *p_tcb, tGATT_CLCB *p_clcb);
50
51UINT8   disc_type_to_att_opcode[GATT_DISC_MAX] =
52{
53    0,
54    GATT_REQ_READ_BY_GRP_TYPE,     /*  GATT_DISC_SRVC_ALL = 1, */
55    GATT_REQ_FIND_TYPE_VALUE,      /*  GATT_DISC_SRVC_BY_UUID,  */
56    GATT_REQ_READ_BY_TYPE,         /*  GATT_DISC_INC_SRVC,      */
57    GATT_REQ_READ_BY_TYPE,         /*  GATT_DISC_CHAR,          */
58    GATT_REQ_FIND_INFO             /*  GATT_DISC_CHAR_DSCPT,    */
59};
60
61UINT16 disc_type_to_uuid[GATT_DISC_MAX] =
62{
63    0,                  /* reserved */
64    GATT_UUID_PRI_SERVICE, /* <service> DISC_SRVC_ALL */
65    GATT_UUID_PRI_SERVICE, /* <service> for DISC_SERVC_BY_UUID */
66    GATT_UUID_INCLUDE_SERVICE, /* <include_service> for DISC_INC_SRVC */
67    GATT_UUID_CHAR_DECLARE,   /* <characteristic> for DISC_CHAR */
68    0                   /* no type filtering for DISC_CHAR_DSCPT */
69};
70
71
72/*******************************************************************************
73**
74** Function         gatt_act_discovery
75**
76** Description      GATT discovery operation.
77**
78** Returns          void.
79**
80*******************************************************************************/
81void gatt_act_discovery(tGATT_CLCB *p_clcb)
82{
83    UINT8       op_code = disc_type_to_att_opcode[p_clcb->op_subtype];
84    tGATT_CL_MSG   cl_req;
85    tGATT_STATUS    st;
86
87    if (p_clcb->s_handle <= p_clcb->e_handle && p_clcb->s_handle != 0)
88    {
89        memset(&cl_req, 0, sizeof(tGATT_CL_MSG));
90
91        cl_req.browse.s_handle = p_clcb->s_handle;
92        cl_req.browse.e_handle = p_clcb->e_handle;
93
94        if (disc_type_to_uuid[p_clcb->op_subtype] != 0)
95        {
96            cl_req.browse.uuid.len = 2;
97            cl_req.browse.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
98        }
99
100        if (p_clcb->op_subtype == GATT_DISC_SRVC_BY_UUID) /* fill in the FindByTypeValue request info*/
101        {
102            cl_req.find_type_value.uuid.len = 2;
103            cl_req.find_type_value.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
104            cl_req.find_type_value.s_handle = p_clcb->s_handle;
105            cl_req.find_type_value.e_handle = p_clcb->e_handle;
106            cl_req.find_type_value.value_len = p_clcb->uuid.len;
107            /* if service type is 32 bits UUID, convert it now */
108            if (p_clcb->uuid.len == LEN_UUID_32)
109            {
110                cl_req.find_type_value.value_len = LEN_UUID_128;
111                gatt_convert_uuid32_to_uuid128(cl_req.find_type_value.value, p_clcb->uuid.uu.uuid32);
112            }
113            else
114            memcpy (cl_req.find_type_value.value,  &p_clcb->uuid.uu, p_clcb->uuid.len);
115        }
116
117        st = attp_send_cl_msg(p_clcb->p_tcb, p_clcb->clcb_idx, op_code, &cl_req);
118
119        if (st !=  GATT_SUCCESS && st != GATT_CMD_STARTED)
120        {
121            gatt_end_operation(p_clcb, GATT_ERROR, NULL);
122        }
123    }
124    else /* end of handle range */
125        gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
126}
127
128/*******************************************************************************
129**
130** Function         gatt_act_read
131**
132** Description      GATT read operation.
133**
134** Returns          void.
135**
136*******************************************************************************/
137void gatt_act_read (tGATT_CLCB *p_clcb, UINT16 offset)
138{
139    tGATT_TCB  *p_tcb = p_clcb->p_tcb;
140    UINT8   rt = GATT_INTERNAL_ERROR;
141    tGATT_CL_MSG  msg;
142    UINT8        op_code = 0;
143
144    memset (&msg, 0, sizeof(tGATT_CL_MSG));
145
146    switch (p_clcb->op_subtype)
147    {
148        case GATT_READ_CHAR_VALUE:
149        case GATT_READ_BY_TYPE:
150            op_code = GATT_REQ_READ_BY_TYPE;
151            msg.browse.s_handle = p_clcb->s_handle;
152            msg.browse.e_handle = p_clcb->e_handle;
153            if (p_clcb->op_subtype == GATT_READ_BY_TYPE)
154                memcpy(&msg.browse.uuid, &p_clcb->uuid, sizeof(tBT_UUID));
155            else
156            {
157                msg.browse.uuid.len = LEN_UUID_16;
158                msg.browse.uuid.uu.uuid16 = GATT_UUID_CHAR_DECLARE;
159            }
160            break;
161
162        case GATT_READ_CHAR_VALUE_HDL:
163        case GATT_READ_BY_HANDLE:
164            if (!p_clcb->counter)
165            {
166                op_code = GATT_REQ_READ;
167                msg.handle = p_clcb->s_handle;
168            }
169            else
170            {
171                if (!p_clcb->first_read_blob_after_read)
172                    p_clcb->first_read_blob_after_read = TRUE;
173                else
174                    p_clcb->first_read_blob_after_read = FALSE;
175
176                GATT_TRACE_DEBUG("gatt_act_read first_read_blob_after_read=%d",
177                                  p_clcb->first_read_blob_after_read);
178                op_code = GATT_REQ_READ_BLOB;
179                msg.read_blob.offset = offset;
180                msg.read_blob.handle = p_clcb->s_handle;
181            }
182            p_clcb->op_subtype &= ~ 0x80;
183            break;
184
185        case GATT_READ_PARTIAL:
186            op_code = GATT_REQ_READ_BLOB;
187            msg.read_blob.handle = p_clcb->s_handle;
188            msg.read_blob.offset = offset;
189            break;
190
191        case GATT_READ_MULTIPLE:
192            op_code = GATT_REQ_READ_MULTI;
193            memcpy (&msg.read_multi, p_clcb->p_attr_buf, sizeof(tGATT_READ_MULTI));
194            break;
195
196        case GATT_READ_INC_SRV_UUID128:
197            op_code = GATT_REQ_READ;
198            msg.handle = p_clcb->s_handle;
199            p_clcb->op_subtype &= ~ 0x90;
200            break;
201
202        default:
203            GATT_TRACE_ERROR("Unknown read type: %d", p_clcb->op_subtype);
204            break;
205    }
206
207    if (op_code != 0)
208        rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, op_code, &msg);
209
210    if ( op_code == 0 || (rt != GATT_SUCCESS && rt != GATT_CMD_STARTED))
211    {
212        gatt_end_operation(p_clcb, rt, NULL);
213    }
214}
215
216/*******************************************************************************
217**
218** Function         gatt_act_write
219**
220** Description      GATT write operation.
221**
222** Returns          void.
223**
224*******************************************************************************/
225void gatt_act_write (tGATT_CLCB *p_clcb, UINT8 sec_act)
226{
227    tGATT_TCB           *p_tcb = p_clcb->p_tcb;
228    UINT8               rt = GATT_SUCCESS, op_code = 0;
229    tGATT_VALUE         *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
230
231    if (p_attr)
232    {
233        switch (p_clcb->op_subtype)
234        {
235            case GATT_WRITE_NO_RSP:
236                p_clcb->s_handle = p_attr->handle;
237                op_code = (sec_act == GATT_SEC_SIGN_DATA) ? GATT_SIGN_CMD_WRITE : GATT_CMD_WRITE;
238                rt = gatt_send_write_msg(p_tcb,
239                                         p_clcb->clcb_idx,
240                                         op_code,
241                                         p_attr->handle,
242                                         p_attr->len,
243                                         0,
244                                         p_attr->value);
245                break;
246
247            case GATT_WRITE:
248                if (p_attr->len <= (p_tcb->payload_size - GATT_HDR_SIZE))
249                {
250                    p_clcb->s_handle = p_attr->handle;
251
252                    rt = gatt_send_write_msg(p_tcb,
253                                             p_clcb->clcb_idx,
254                                             GATT_REQ_WRITE,
255                                             p_attr->handle,
256                                             p_attr->len,
257                                             0,
258                                             p_attr->value);
259                }
260                else /* prepare write for long attribute */
261                {
262                    gatt_send_prepare_write(p_tcb, p_clcb);
263                }
264                break;
265
266            case GATT_WRITE_PREPARE:
267                gatt_send_prepare_write(p_tcb, p_clcb);
268                break;
269
270            default:
271                rt = GATT_INTERNAL_ERROR;
272                GATT_TRACE_ERROR("Unknown write type: %d", p_clcb->op_subtype);
273                break;
274        }
275    }
276    else
277        rt = GATT_INTERNAL_ERROR;
278
279    if ((rt != GATT_SUCCESS  && rt != GATT_CMD_STARTED && rt != GATT_CONGESTED)
280        || (rt != GATT_CMD_STARTED && p_clcb->op_subtype == GATT_WRITE_NO_RSP))
281    {
282        if (rt != GATT_SUCCESS)
283        {
284            GATT_TRACE_ERROR("gatt_act_write() failed op_code=0x%x rt=%d", op_code, rt);
285        }
286        gatt_end_operation(p_clcb, rt, NULL);
287    }
288}
289/*******************************************************************************
290**
291** Function         gatt_send_queue_write_cancel
292**
293** Description      send queue write cancel
294**
295** Returns          void.
296**
297*******************************************************************************/
298void gatt_send_queue_write_cancel (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_EXEC_FLAG flag)
299{
300    UINT8       rt ;
301
302    GATT_TRACE_DEBUG("gatt_send_queue_write_cancel ");
303
304    rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_EXEC_WRITE, (tGATT_CL_MSG *)&flag);
305
306    if (rt != GATT_SUCCESS)
307    {
308        gatt_end_operation(p_clcb, rt, NULL);
309    }
310}
311/*******************************************************************************
312**
313** Function         gatt_check_write_long_terminate
314**
315** Description      To terminate write long or not.
316**
317** Returns          TRUE: write long is terminated; FALSE keep sending.
318**
319*******************************************************************************/
320BOOLEAN gatt_check_write_long_terminate(tGATT_TCB  *p_tcb, tGATT_CLCB *p_clcb, tGATT_VALUE *p_rsp_value)
321{
322    tGATT_VALUE         *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
323    BOOLEAN             exec = FALSE;
324    tGATT_EXEC_FLAG     flag = GATT_PREP_WRITE_EXEC;
325
326    GATT_TRACE_DEBUG("gatt_check_write_long_terminate ");
327    /* check the first write response status */
328    if (p_rsp_value != NULL)
329    {
330        if (p_rsp_value->handle != p_attr->handle ||
331            p_rsp_value->len != p_clcb->counter ||
332            memcmp(p_rsp_value->value, p_attr->value + p_attr->offset, p_rsp_value->len))
333        {
334            /* data does not match    */
335            p_clcb->status = GATT_ERROR;
336            flag = GATT_PREP_WRITE_CANCEL;
337            exec = TRUE;
338        }
339        else /* response checking is good */
340        {
341            p_clcb->status = GATT_SUCCESS;
342            /* update write offset and check if end of attribute value */
343            if ((p_attr->offset += p_rsp_value->len) >= p_attr->len)
344                exec = TRUE;
345        }
346    }
347    if (exec)
348    {
349        gatt_send_queue_write_cancel (p_tcb, p_clcb, flag);
350        return TRUE;
351    }
352    return FALSE;
353}
354/*******************************************************************************
355**
356** Function         gatt_send_prepare_write
357**
358** Description      Send prepare write.
359**
360** Returns          void.
361**
362*******************************************************************************/
363void gatt_send_prepare_write(tGATT_TCB  *p_tcb, tGATT_CLCB *p_clcb)
364{
365    tGATT_VALUE  *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
366    UINT16  to_send, offset;
367    UINT8   rt = GATT_SUCCESS;
368    UINT8   type = p_clcb->op_subtype;
369
370    GATT_TRACE_DEBUG("gatt_send_prepare_write type=0x%x", type );
371    to_send = p_attr->len - p_attr->offset;
372
373    if (to_send > (p_tcb->payload_size - GATT_WRITE_LONG_HDR_SIZE)) /* 2 = UINT16 offset bytes  */
374        to_send = p_tcb->payload_size - GATT_WRITE_LONG_HDR_SIZE;
375
376    p_clcb->s_handle = p_attr->handle;
377
378    offset = p_attr->offset;
379    if (type == GATT_WRITE_PREPARE)
380    {
381        offset += p_clcb->start_offset;
382    }
383
384    GATT_TRACE_DEBUG("offset =0x%x len=%d", offset, to_send );
385
386    rt = gatt_send_write_msg(p_tcb,
387                             p_clcb->clcb_idx,
388                             GATT_REQ_PREPARE_WRITE,
389                             p_attr->handle,
390                             to_send,                           /* length */
391                             offset,                            /* used as offset */
392                             p_attr->value + p_attr->offset);   /* data */
393
394    /* remember the write long attribute length */
395    p_clcb->counter = to_send;
396
397    if (rt != GATT_SUCCESS && rt != GATT_CMD_STARTED)
398    {
399        gatt_end_operation(p_clcb, rt, NULL);
400    }
401}
402
403
404/*******************************************************************************
405**
406** Function         gatt_process_find_type_value_rsp
407**
408** Description      This function is called to handle find by type value response.
409**
410**
411** Returns          void
412**
413*******************************************************************************/
414void gatt_process_find_type_value_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data)
415{
416    tGATT_DISC_RES      result;
417    UINT8               *p = p_data;
418
419    UNUSED(p_tcb);
420
421    GATT_TRACE_DEBUG("gatt_process_find_type_value_rsp ");
422    /* unexpected response */
423    if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_SRVC_BY_UUID)
424        return;
425
426    memset (&result, 0, sizeof(tGATT_DISC_RES));
427    result.type.len = 2;
428    result.type.uu.uuid16 = GATT_UUID_PRI_SERVICE;
429
430    /* returns a series of handle ranges */
431    while (len >= 4)
432    {
433        STREAM_TO_UINT16 (result.handle, p);
434        STREAM_TO_UINT16 (result.value.group_value.e_handle, p);
435        memcpy (&result.value.group_value.service_type,  &p_clcb->uuid, sizeof(tBT_UUID));
436
437        len -= 4;
438
439        if (p_clcb->p_reg->app_cb.p_disc_res_cb)
440            (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
441    }
442
443    /* last handle  + 1 */
444    p_clcb->s_handle = (result.value.group_value.e_handle == 0) ? 0 : (result.value.group_value.e_handle + 1);
445    /* initiate another request */
446    gatt_act_discovery(p_clcb) ;
447}
448/*******************************************************************************
449**
450** Function         gatt_process_read_info_rsp
451**
452** Description      This function is called to handle the read information
453**                  response.
454**
455**
456** Returns          void
457**
458*******************************************************************************/
459void gatt_process_read_info_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
460                                UINT16 len, UINT8 *p_data)
461{
462    tGATT_DISC_RES  result;
463    UINT8   *p = p_data, uuid_len = 0, type;
464
465    UNUSED(p_tcb);
466    UNUSED(op_code);
467
468    if (len < GATT_INFO_RSP_MIN_LEN)
469    {
470        GATT_TRACE_ERROR("invalid Info Response PDU received, discard.");
471        gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL);
472        return;
473    }
474    /* unexpected response */
475    if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_CHAR_DSCPT)
476        return;
477
478    STREAM_TO_UINT8(type, p);
479    len -= 1;
480
481    if (type == GATT_INFO_TYPE_PAIR_16)
482        uuid_len = LEN_UUID_16;
483    else if (type == GATT_INFO_TYPE_PAIR_128)
484        uuid_len = LEN_UUID_128;
485
486    while (len >= uuid_len + 2)
487    {
488        STREAM_TO_UINT16 (result.handle, p);
489
490        if (uuid_len > 0)
491        {
492            if (!gatt_parse_uuid_from_cmd(&result.type, uuid_len, &p))
493                break;
494        }
495        else
496            memcpy (&result.type, &p_clcb->uuid, sizeof(tBT_UUID));
497
498        len -= (uuid_len + 2);
499
500        if (p_clcb->p_reg->app_cb.p_disc_res_cb)
501            (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
502    }
503
504    p_clcb->s_handle = (result.handle == 0) ? 0 :(result.handle + 1);
505    /* initiate another request */
506    gatt_act_discovery(p_clcb) ;
507}
508/*******************************************************************************
509**
510** Function         gatt_proc_disc_error_rsp
511**
512** Description      This function process the read by type response and send another
513**                  request if needed.
514**
515** Returns          void.
516**
517*******************************************************************************/
518void gatt_proc_disc_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 opcode,
519                              UINT16 handle, UINT8 reason)
520{
521    tGATT_STATUS    status = (tGATT_STATUS) reason;
522
523    UNUSED(p_tcb);
524    UNUSED(handle);
525
526    GATT_TRACE_DEBUG("gatt_proc_disc_error_rsp reason: %02x cmd_code %04x", reason, opcode);
527
528    switch (opcode)
529    {
530        case GATT_REQ_READ_BY_GRP_TYPE:
531        case GATT_REQ_FIND_TYPE_VALUE:
532        case GATT_REQ_READ_BY_TYPE:
533        case GATT_REQ_FIND_INFO:
534            if (reason == GATT_NOT_FOUND)
535            {
536                status = GATT_SUCCESS;
537                GATT_TRACE_DEBUG("Discovery completed");
538            }
539            break;
540        default:
541            GATT_TRACE_ERROR("Incorrect discovery opcode %04x",   opcode);
542            break;
543    }
544
545    gatt_end_operation(p_clcb, status, NULL);
546}
547
548/*******************************************************************************
549**
550** Function         gatt_process_error_rsp
551**
552** Description      This function is called to handle the error response
553**
554**
555** Returns          void
556**
557*******************************************************************************/
558void gatt_process_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
559                            UINT16 len, UINT8 *p_data)
560{
561    UINT8   opcode, reason, * p= p_data;
562    UINT16  handle;
563    tGATT_VALUE  *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
564
565    UNUSED(op_code);
566    UNUSED(len);
567
568    GATT_TRACE_DEBUG("gatt_process_error_rsp ");
569    STREAM_TO_UINT8(opcode, p);
570    STREAM_TO_UINT16(handle, p);
571    STREAM_TO_UINT8(reason, p);
572
573    if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)
574    {
575        gatt_proc_disc_error_rsp(p_tcb, p_clcb, opcode, handle, reason);
576    }
577    else
578    {
579        if ( (p_clcb->operation == GATTC_OPTYPE_WRITE) &&
580             (p_clcb->op_subtype == GATT_WRITE) &&
581             (opcode == GATT_REQ_PREPARE_WRITE) &&
582             (p_attr) &&
583             (handle == p_attr->handle)  )
584        {
585            p_clcb->status = reason;
586            gatt_send_queue_write_cancel(p_tcb, p_clcb, GATT_PREP_WRITE_CANCEL);
587        }
588        else if ((p_clcb->operation == GATTC_OPTYPE_READ) &&
589                 ((p_clcb->op_subtype == GATT_READ_CHAR_VALUE_HDL) ||
590                  (p_clcb->op_subtype == GATT_READ_BY_HANDLE)) &&
591                 (opcode == GATT_REQ_READ_BLOB) &&
592                 p_clcb->first_read_blob_after_read &&
593                 (reason == GATT_NOT_LONG))
594        {
595            gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p_clcb->p_attr_buf);
596        }
597        else
598            gatt_end_operation(p_clcb, reason, NULL);
599    }
600}
601/*******************************************************************************
602**
603** Function         gatt_process_prep_write_rsp
604**
605** Description      This function is called to handle the read response
606**
607**
608** Returns          void
609**
610*******************************************************************************/
611void gatt_process_prep_write_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
612                                  UINT16 len, UINT8 *p_data)
613{
614    tGATT_VALUE  value = {0};
615    UINT8        *p= p_data;
616
617    GATT_TRACE_ERROR("value resp op_code = %s len = %d", gatt_dbg_op_name(op_code), len);
618
619    if (len < GATT_PREP_WRITE_RSP_MIN_LEN)
620    {
621        GATT_TRACE_ERROR("illegal prepare write response length, discard");
622        gatt_end_operation(p_clcb, GATT_INVALID_PDU, &value);
623        return;
624    }
625
626    STREAM_TO_UINT16 (value.handle, p);
627    STREAM_TO_UINT16 (value.offset, p);
628
629    value.len = len - 4;
630
631    memcpy (value.value, p, value.len);
632
633    if (p_clcb->op_subtype == GATT_WRITE_PREPARE)
634    {
635        p_clcb->status = GATT_SUCCESS;
636        /* application should verify handle offset
637           and value are matched or not */
638
639        gatt_end_operation(p_clcb, p_clcb->status, &value);
640    }
641    else if (p_clcb->op_subtype == GATT_WRITE )
642    {
643        if (!gatt_check_write_long_terminate(p_tcb, p_clcb, &value))
644            gatt_send_prepare_write(p_tcb, p_clcb);
645    }
646
647}
648/*******************************************************************************
649**
650** Function         gatt_process_notification
651**
652** Description      This function is called to handle the handle value indication
653**                  or handle value notification.
654**
655**
656** Returns          void
657**
658*******************************************************************************/
659void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code,
660                               UINT16 len, UINT8 *p_data)
661{
662    tGATT_VALUE     value = {0};
663    tGATT_REG       *p_reg;
664    UINT16          conn_id;
665    tGATT_STATUS    encrypt_status;
666    UINT8           *p= p_data, i,
667    event = (op_code == GATT_HANDLE_VALUE_NOTIF) ? GATTC_OPTYPE_NOTIFICATION : GATTC_OPTYPE_INDICATION;
668
669    GATT_TRACE_DEBUG("gatt_process_notification ");
670
671    if (len < GATT_NOTIFICATION_MIN_LEN)
672    {
673        GATT_TRACE_ERROR("illegal notification PDU length, discard");
674        return;
675    }
676
677    STREAM_TO_UINT16 (value.handle, p);
678    value.len = len - 2;
679    memcpy (value.value, p, value.len);
680
681    if (!GATT_HANDLE_IS_VALID(value.handle))
682    {
683        /* illegal handle, send ack now */
684        if (op_code == GATT_HANDLE_VALUE_IND)
685            attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
686        return;
687    }
688
689    if (event == GATTC_OPTYPE_INDICATION)
690    {
691        if (p_tcb->ind_count)
692        {
693            /* this is an error case that receiving an indication but we
694               still has an indication not being acked yet.
695               For now, just log the error reset the counter.
696               Later we need to disconnect the link unconditionally.
697            */
698            GATT_TRACE_ERROR("gatt_process_notification rcv Ind. but ind_count=%d (will reset ind_count)",  p_tcb->ind_count);
699        }
700        p_tcb->ind_count = 0;
701    }
702
703    /* should notify all registered client with the handle value notificaion/indication
704       Note: need to do the indication count and start timer first then do callback
705     */
706
707    for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++)
708    {
709        if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb && (event == GATTC_OPTYPE_INDICATION))
710            p_tcb->ind_count++;
711    }
712
713    if (event == GATTC_OPTYPE_INDICATION)
714    {
715        /* start a timer for app confirmation */
716        if (p_tcb->ind_count > 0)
717            gatt_start_ind_ack_timer(p_tcb);
718        else /* no app to indicate, or invalid handle */
719            attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
720    }
721
722    encrypt_status = gatt_get_link_encrypt_status(p_tcb);
723    for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++)
724    {
725        if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb)
726        {
727            conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
728            (*p_reg->app_cb.p_cmpl_cb) (conn_id, event, encrypt_status, (tGATT_CL_COMPLETE *)&value);
729        }
730    }
731
732}
733
734/*******************************************************************************
735**
736** Function         gatt_process_read_by_type_rsp
737**
738** Description      This function is called to handle the read by type response.
739**                  read by type can be used for discovery, or read by type or
740**                  read characteristic value.
741**
742** Returns          void
743**
744*******************************************************************************/
745void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
746                                    UINT16 len, UINT8 *p_data)
747{
748    tGATT_DISC_RES      result;
749    tGATT_DISC_VALUE    record_value;
750    UINT8               *p = p_data, value_len, handle_len = 2;
751    UINT16              handle = 0;
752
753    /* discovery procedure and no callback function registered */
754    if (((!p_clcb->p_reg) || (!p_clcb->p_reg->app_cb.p_disc_res_cb)) && (p_clcb->operation == GATTC_OPTYPE_DISCOVERY))
755        return;
756
757    if (len < GATT_READ_BY_TYPE_RSP_MIN_LEN)
758    {
759        GATT_TRACE_ERROR("Illegal ReadByType/ReadByGroupType Response length, discard");
760        gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL);
761        return;
762    }
763
764    STREAM_TO_UINT8(value_len, p);
765
766    if ((value_len > (p_tcb->payload_size - 2)) || (value_len > (len-1))  )
767    {
768        /* this is an error case that server's response containing a value length which is larger than MTU-2
769           or value_len > message total length -1 */
770        GATT_TRACE_ERROR("gatt_process_read_by_type_rsp: Discard response op_code=%d vale_len=%d > (MTU-2=%d or msg_len-1=%d)",
771                          op_code, value_len, (p_tcb->payload_size - 2), (len-1));
772        gatt_end_operation(p_clcb, GATT_ERROR, NULL);
773        return;
774    }
775
776    if (op_code == GATT_RSP_READ_BY_GRP_TYPE)
777        handle_len = 4;
778
779    value_len -= handle_len; /* substract the handle pairs bytes */
780    len -= 1;
781
782    while (len >= (handle_len + value_len))
783    {
784        STREAM_TO_UINT16(handle, p);
785
786        if (!GATT_HANDLE_IS_VALID(handle))
787        {
788            gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
789            return;
790        }
791
792        memset(&result, 0, sizeof(tGATT_DISC_RES));
793        memset(&record_value, 0, sizeof(tGATT_DISC_VALUE));
794
795        result.handle = handle;
796        result.type.len = 2;
797        result.type.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
798
799        /* discover all services */
800        if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
801            p_clcb->op_subtype == GATT_DISC_SRVC_ALL &&
802            op_code == GATT_RSP_READ_BY_GRP_TYPE)
803        {
804            STREAM_TO_UINT16(handle, p);
805
806            if (!GATT_HANDLE_IS_VALID(handle))
807            {
808                gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
809                return;
810            }
811            else
812            {
813                record_value.group_value.e_handle = handle;
814                if (!gatt_parse_uuid_from_cmd(&record_value.group_value.service_type, value_len, &p))
815                {
816                    GATT_TRACE_ERROR("discover all service response parsing failure");
817                    break;
818                }
819            }
820        }
821        /* discover included service */
822        else if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->op_subtype == GATT_DISC_INC_SRVC)
823        {
824            STREAM_TO_UINT16(record_value.incl_service.s_handle, p);
825            STREAM_TO_UINT16(record_value.incl_service.e_handle, p);
826
827            if (!GATT_HANDLE_IS_VALID(record_value.incl_service.s_handle) ||
828                !GATT_HANDLE_IS_VALID(record_value.incl_service.e_handle))
829            {
830                gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
831                return;
832            }
833
834            if(value_len == 6)
835            {
836                STREAM_TO_UINT16(record_value.incl_service.service_type.uu.uuid16, p);
837                record_value.incl_service.service_type.len = LEN_UUID_16;
838            }
839            else if (value_len == 4)
840            {
841                p_clcb->s_handle = record_value.incl_service.s_handle;
842                p_clcb->read_uuid128.wait_for_read_rsp = TRUE;
843                p_clcb->read_uuid128.next_disc_start_hdl = handle + 1;
844                memcpy(&p_clcb->read_uuid128.result, &result, sizeof(result));
845                memcpy(&p_clcb->read_uuid128.result.value, &record_value, sizeof (result.value));
846                p_clcb->op_subtype |= 0x90;
847                gatt_act_read(p_clcb, 0);
848                return;
849            }
850            else
851            {
852               GATT_TRACE_ERROR("gatt_process_read_by_type_rsp INCL_SRVC failed with invalid data value_len=%d", value_len);
853               gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void *)p);
854               return;
855            }
856        }
857        /* read by type */
858        else if (p_clcb->operation == GATTC_OPTYPE_READ && p_clcb->op_subtype == GATT_READ_BY_TYPE)
859        {
860            p_clcb->counter = len - 2;
861            p_clcb->s_handle = handle;
862            if ( p_clcb->counter == (p_clcb->p_tcb->payload_size -4))
863            {
864                p_clcb->op_subtype = GATT_READ_BY_HANDLE;
865                if (!p_clcb->p_attr_buf)
866                    p_clcb->p_attr_buf = (UINT8 *)osi_malloc(GATT_MAX_ATTR_LEN);
867                if (p_clcb->counter <= GATT_MAX_ATTR_LEN) {
868                    memcpy(p_clcb->p_attr_buf, p, p_clcb->counter);
869                    gatt_act_read(p_clcb, p_clcb->counter);
870                } else {
871                    gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, (void *)p);
872                }
873            }
874            else
875            {
876                 gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p);
877            }
878            return;
879        }
880        else /* discover characterisitic */
881        {
882            STREAM_TO_UINT8 (record_value.dclr_value.char_prop, p);
883            STREAM_TO_UINT16(record_value.dclr_value.val_handle, p);
884            if (!GATT_HANDLE_IS_VALID(record_value.dclr_value.val_handle))
885            {
886                gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
887                return;
888            }
889            if (!gatt_parse_uuid_from_cmd(&record_value.dclr_value.char_uuid, (UINT16)(value_len - 3), &p))
890            {
891                gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
892                /* invalid format, and skip the result */
893                return;
894            }
895
896            /* UUID not matching */
897            if (!gatt_uuid_compare(record_value.dclr_value.char_uuid, p_clcb->uuid))
898            {
899                len -= (value_len + 2);
900                continue; /* skip the result, and look for next one */
901            }
902            else if (p_clcb->operation == GATTC_OPTYPE_READ)
903            /* UUID match for read characteristic value */
904            {
905                /* only read the first matching UUID characteristic value, and
906                  discard the rest results */
907                p_clcb->s_handle = record_value.dclr_value.val_handle;
908                p_clcb->op_subtype |= 0x80;
909                gatt_act_read(p_clcb, 0);
910                return;
911            }
912        }
913        len -= (value_len + handle_len);
914
915        /* result is (handle, 16bits UUID) pairs */
916        memcpy (&result.value, &record_value, sizeof (result.value));
917
918        /* send callback if is discover procedure */
919        if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->p_reg->app_cb.p_disc_res_cb)
920            (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
921    }
922
923    p_clcb->s_handle = (handle == 0) ? 0 : (handle + 1);
924
925    if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)
926    {
927        /* initiate another request */
928        gatt_act_discovery(p_clcb) ;
929    }
930    else /* read characteristic value */
931    {
932        gatt_act_read(p_clcb, 0);
933    }
934}
935
936/*******************************************************************************
937**
938** Function         gatt_process_read_rsp
939**
940** Description      This function is called to handle the read BLOB response
941**
942**
943** Returns          void
944**
945*******************************************************************************/
946void gatt_process_read_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb,  UINT8 op_code,
947                           UINT16 len, UINT8 *p_data)
948{
949    UINT16      offset = p_clcb->counter;
950    UINT8       * p= p_data;
951
952    UNUSED(op_code);
953
954    if (p_clcb->operation == GATTC_OPTYPE_READ)
955    {
956        if (p_clcb->op_subtype != GATT_READ_BY_HANDLE)
957        {
958            p_clcb->counter = len;
959            gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p);
960        }
961        else
962        {
963
964            /* allocate GKI buffer holding up long attribute value  */
965            if (!p_clcb->p_attr_buf)
966                p_clcb->p_attr_buf = (UINT8 *)osi_malloc(GATT_MAX_ATTR_LEN);
967
968            /* copy attrobute value into cb buffer  */
969            if (offset < GATT_MAX_ATTR_LEN) {
970                if ((len + offset) > GATT_MAX_ATTR_LEN)
971                    len = GATT_MAX_ATTR_LEN - offset;
972
973                p_clcb->counter += len;
974
975                memcpy(p_clcb->p_attr_buf + offset, p, len);
976
977                /* send next request if needed  */
978
979                if (len == (p_tcb->payload_size - 1) && /* full packet for read or read blob rsp */
980                    len + offset < GATT_MAX_ATTR_LEN)
981                {
982                    GATT_TRACE_DEBUG("full pkt issue read blob for remianing bytes old offset=%d len=%d new offset=%d",
983                                      offset, len, p_clcb->counter);
984                    gatt_act_read(p_clcb, p_clcb->counter);
985                }
986                else /* end of request, send callback */
987                {
988                    gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p_clcb->p_attr_buf);
989                }
990            }
991            else /* exception, should not happen */
992            {
993                GATT_TRACE_ERROR("attr offset = %d p_attr_buf = %d ", offset, p_clcb->p_attr_buf);
994                gatt_end_operation(p_clcb, GATT_NO_RESOURCES, (void *)p_clcb->p_attr_buf);
995            }
996        }
997    }
998    else
999    {
1000        if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
1001            p_clcb->op_subtype == GATT_DISC_INC_SRVC &&
1002            p_clcb->read_uuid128.wait_for_read_rsp )
1003        {
1004            p_clcb->s_handle = p_clcb->read_uuid128.next_disc_start_hdl;
1005            p_clcb->read_uuid128.wait_for_read_rsp = FALSE;
1006            if (len == LEN_UUID_128)
1007            {
1008
1009                memcpy(p_clcb->read_uuid128.result.value.incl_service.service_type.uu.uuid128, p, len);
1010                p_clcb->read_uuid128.result.value.incl_service.service_type.len = LEN_UUID_128;
1011                if ( p_clcb->p_reg->app_cb.p_disc_res_cb)
1012                    (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &p_clcb->read_uuid128.result);
1013                gatt_act_discovery(p_clcb) ;
1014            }
1015            else
1016            {
1017                gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void *)p);
1018            }
1019        }
1020    }
1021
1022}
1023
1024
1025/*******************************************************************************
1026**
1027** Function         gatt_process_handle_rsp
1028**
1029** Description      This function is called to handle the write response
1030**
1031**
1032** Returns          void
1033**
1034*******************************************************************************/
1035void gatt_process_handle_rsp(tGATT_CLCB *p_clcb)
1036{
1037    gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
1038}
1039/*******************************************************************************
1040**
1041** Function         gatt_process_mtu_rsp
1042**
1043** Description      This function is called to process the configure MTU response.
1044**
1045**
1046** Returns          void
1047**
1048*******************************************************************************/
1049void gatt_process_mtu_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data)
1050{
1051    UINT16 mtu;
1052    tGATT_STATUS    status = GATT_SUCCESS;
1053
1054    if (len < GATT_MTU_RSP_MIN_LEN)
1055    {
1056        GATT_TRACE_ERROR("invalid MTU response PDU received, discard.");
1057        status = GATT_INVALID_PDU;
1058    }
1059    else
1060    {
1061    STREAM_TO_UINT16(mtu, p_data);
1062
1063    if (mtu < p_tcb->payload_size && mtu >= GATT_DEF_BLE_MTU_SIZE)
1064        p_tcb->payload_size = mtu;
1065    }
1066
1067    l2cble_set_fixed_channel_tx_data_length(p_tcb->peer_bda, L2CAP_ATT_CID, p_tcb->payload_size);
1068    gatt_end_operation(p_clcb, status, NULL);
1069}
1070/*******************************************************************************
1071**
1072** Function         gatt_cmd_to_rsp_code
1073**
1074** Description      The function convert a ATT command op code into the corresponding
1075**                  response code assume no error occurs.
1076**
1077** Returns          response code.
1078**
1079*******************************************************************************/
1080UINT8 gatt_cmd_to_rsp_code (UINT8 cmd_code)
1081{
1082    UINT8   rsp_code  = 0;
1083
1084    if (cmd_code > 1 && cmd_code != GATT_CMD_WRITE)
1085    {
1086        rsp_code = cmd_code + 1;
1087    }
1088    return rsp_code;
1089}
1090/*******************************************************************************
1091**
1092** Function         gatt_cl_send_next_cmd_inq
1093**
1094** Description      Find next command in queue and sent to server
1095**
1096** Returns          TRUE if command sent, otherwise FALSE.
1097**
1098*******************************************************************************/
1099BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb)
1100{
1101    tGATT_CMD_Q  *p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
1102    BOOLEAN     sent = FALSE;
1103    UINT8       rsp_code;
1104    tGATT_CLCB   *p_clcb = NULL;
1105    tGATT_STATUS att_ret = GATT_SUCCESS;
1106
1107    while (!sent &&
1108           p_tcb->pending_cl_req != p_tcb->next_slot_inq &&
1109           p_cmd->to_send && p_cmd->p_cmd != NULL)
1110    {
1111        att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd->p_cmd);
1112
1113        if (att_ret == GATT_SUCCESS || att_ret == GATT_CONGESTED)
1114        {
1115            sent = TRUE;
1116            p_cmd->to_send = FALSE;
1117            p_cmd->p_cmd = NULL;
1118
1119            /* dequeue the request if is write command or sign write */
1120            if (p_cmd->op_code != GATT_CMD_WRITE && p_cmd->op_code != GATT_SIGN_CMD_WRITE)
1121            {
1122                gatt_start_rsp_timer (p_cmd->clcb_idx);
1123            }
1124            else
1125            {
1126                p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
1127
1128                /* if no ack needed, keep sending */
1129                if (att_ret == GATT_SUCCESS)
1130                    sent = FALSE;
1131
1132                p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
1133                /* send command complete callback here */
1134                gatt_end_operation(p_clcb, att_ret, NULL);
1135            }
1136        }
1137        else
1138        {
1139            GATT_TRACE_ERROR("gatt_cl_send_next_cmd_inq: L2CAP sent error");
1140
1141            memset(p_cmd, 0, sizeof(tGATT_CMD_Q));
1142            p_tcb->pending_cl_req ++;
1143            p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
1144        }
1145
1146    }
1147    return sent;
1148}
1149
1150/*******************************************************************************
1151**
1152** Function         gatt_client_handle_server_rsp
1153**
1154** Description      This function is called to handle the server response to
1155**                  client.
1156**
1157**
1158** Returns          void
1159**
1160*******************************************************************************/
1161void gatt_client_handle_server_rsp (tGATT_TCB *p_tcb, UINT8 op_code,
1162                                    UINT16 len, UINT8 *p_data)
1163{
1164    tGATT_CLCB   *p_clcb = NULL;
1165    UINT8        rsp_code;
1166
1167    if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF)
1168    {
1169        p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
1170
1171        rsp_code = gatt_cmd_to_rsp_code(rsp_code);
1172
1173        if (p_clcb == NULL || (rsp_code != op_code && op_code != GATT_RSP_ERROR))
1174        {
1175            GATT_TRACE_WARNING ("ATT - Ignore wrong response. Receives (%02x) \
1176                                Request(%02x) Ignored", op_code, rsp_code);
1177
1178            return;
1179        }
1180        else
1181        {
1182            alarm_cancel(p_clcb->gatt_rsp_timer_ent);
1183            p_clcb->retry_count = 0;
1184        }
1185    }
1186    /* the size of the message may not be bigger than the local max PDU size*/
1187    /* The message has to be smaller than the agreed MTU, len does not count op_code */
1188    if (len >= p_tcb->payload_size)
1189    {
1190        GATT_TRACE_ERROR("invalid response/indicate pkt size: %d, PDU size: %d", len + 1, p_tcb->payload_size);
1191        if (op_code != GATT_HANDLE_VALUE_NOTIF &&
1192            op_code != GATT_HANDLE_VALUE_IND)
1193            gatt_end_operation(p_clcb, GATT_ERROR, NULL);
1194    }
1195    else
1196    {
1197        switch (op_code)
1198        {
1199            case GATT_RSP_ERROR:
1200                gatt_process_error_rsp(p_tcb, p_clcb, op_code, len, p_data);
1201                break;
1202
1203            case GATT_RSP_MTU:       /* 2 bytes mtu */
1204                gatt_process_mtu_rsp(p_tcb, p_clcb, len ,p_data);
1205                break;
1206
1207            case GATT_RSP_FIND_INFO:
1208                gatt_process_read_info_rsp(p_tcb, p_clcb, op_code, len, p_data);
1209                break;
1210
1211            case GATT_RSP_READ_BY_TYPE:
1212            case GATT_RSP_READ_BY_GRP_TYPE:
1213                gatt_process_read_by_type_rsp(p_tcb, p_clcb, op_code, len, p_data);
1214                break;
1215
1216            case GATT_RSP_READ:
1217            case GATT_RSP_READ_BLOB:
1218            case GATT_RSP_READ_MULTI:
1219                gatt_process_read_rsp(p_tcb, p_clcb, op_code, len, p_data);
1220                break;
1221
1222            case GATT_RSP_FIND_TYPE_VALUE: /* disc service with UUID */
1223                gatt_process_find_type_value_rsp(p_tcb, p_clcb, len, p_data);
1224                break;
1225
1226            case GATT_RSP_WRITE:
1227                gatt_process_handle_rsp(p_clcb);
1228                break;
1229
1230            case GATT_RSP_PREPARE_WRITE:
1231                gatt_process_prep_write_rsp(p_tcb, p_clcb, op_code, len, p_data);
1232                break;
1233
1234            case GATT_RSP_EXEC_WRITE:
1235                gatt_end_operation(p_clcb, p_clcb->status, NULL);
1236                break;
1237
1238            case GATT_HANDLE_VALUE_NOTIF:
1239            case GATT_HANDLE_VALUE_IND:
1240                gatt_process_notification(p_tcb, op_code, len, p_data);
1241                break;
1242
1243            default:
1244                GATT_TRACE_ERROR("Unknown opcode = %d", op_code);
1245                break;
1246        }
1247    }
1248
1249    if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF)
1250    {
1251        gatt_cl_send_next_cmd_inq(p_tcb);
1252    }
1253
1254    return;
1255}
1256
1257#endif  /* BLE_INCLUDED */
1258