1/******************************************************************************
2 *
3 *  Copyright (C) 2008-2014 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 ATT protocol functions
22 *
23 ******************************************************************************/
24
25#include "bt_target.h"
26
27#if BLE_INCLUDED == TRUE
28
29#include "gatt_int.h"
30#include "l2c_api.h"
31
32#define GATT_HDR_FIND_TYPE_VALUE_LEN    21
33#define GATT_OP_CODE_SIZE   1
34#define GATT_START_END_HANDLE_SIZE    4
35
36/**********************************************************************
37**   ATT protocl message building utility                              *
38***********************************************************************/
39/*******************************************************************************
40**
41** Function         attp_build_mtu_exec_cmd
42**
43** Description      Build a exchange MTU request
44**
45** Returns          None.
46**
47*******************************************************************************/
48BT_HDR *attp_build_mtu_cmd(UINT8 op_code, UINT16 rx_mtu)
49{
50    UINT8 *p;
51    BT_HDR *p_buf =
52        (BT_HDR *)osi_malloc(sizeof(BT_HDR) + GATT_HDR_SIZE + L2CAP_MIN_OFFSET);
53
54    p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
55    UINT8_TO_STREAM(p, op_code);
56    UINT16_TO_STREAM(p, rx_mtu);
57
58    p_buf->offset = L2CAP_MIN_OFFSET;
59    p_buf->len = GATT_HDR_SIZE; /* opcode + 2 bytes mtu */
60
61    return p_buf;
62}
63/*******************************************************************************
64**
65** Function         attp_build_exec_write_cmd
66**
67** Description      Build a execute write request or response.
68**
69** Returns          None.
70**
71*******************************************************************************/
72BT_HDR *attp_build_exec_write_cmd (UINT8 op_code, UINT8 flag)
73{
74    BT_HDR      *p_buf = (BT_HDR *)osi_malloc(GATT_DATA_BUF_SIZE);
75    UINT8       *p;
76
77    p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
78
79    p_buf->offset = L2CAP_MIN_OFFSET;
80    p_buf->len = GATT_OP_CODE_SIZE;
81
82    UINT8_TO_STREAM(p, op_code);
83
84    if (op_code == GATT_REQ_EXEC_WRITE) {
85        flag &= GATT_PREP_WRITE_EXEC;
86        UINT8_TO_STREAM (p, flag);
87        p_buf->len += 1;
88    }
89
90    return p_buf;
91}
92
93/*******************************************************************************
94**
95** Function         attp_build_err_cmd
96**
97** Description      Build a exchange MTU request
98**
99** Returns          None.
100**
101*******************************************************************************/
102BT_HDR *attp_build_err_cmd(UINT8 cmd_code, UINT16 err_handle, UINT8 reason)
103{
104    UINT8 *p;
105    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + 5);
106
107    p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
108    UINT8_TO_STREAM(p, GATT_RSP_ERROR);
109    UINT8_TO_STREAM(p, cmd_code);
110    UINT16_TO_STREAM(p, err_handle);
111    UINT8_TO_STREAM(p, reason);
112
113    p_buf->offset = L2CAP_MIN_OFFSET;
114    /* GATT_HDR_SIZE (1B ERR_RSP op code+ 2B handle) + 1B cmd_op_code  + 1B status */
115    p_buf->len = GATT_HDR_SIZE + 1 + 1;
116
117    return p_buf;
118}
119/*******************************************************************************
120**
121** Function         attp_build_browse_cmd
122**
123** Description      Build a read information request or read by type request
124**
125** Returns          None.
126**
127*******************************************************************************/
128BT_HDR *attp_build_browse_cmd(UINT8 op_code, UINT16 s_hdl, UINT16 e_hdl, tBT_UUID uuid)
129{
130    const size_t payload_size = (GATT_OP_CODE_SIZE) + (GATT_START_END_HANDLE_SIZE) + (LEN_UUID_128);
131    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
132
133    UINT8 *p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
134    /* Describe the built message location and size */
135    p_buf->offset = L2CAP_MIN_OFFSET;
136    p_buf->len = GATT_OP_CODE_SIZE + 4;
137
138    UINT8_TO_STREAM(p, op_code);
139    UINT16_TO_STREAM(p, s_hdl);
140    UINT16_TO_STREAM(p, e_hdl);
141    p_buf->len += gatt_build_uuid_to_stream(&p, uuid);
142
143    return p_buf;
144}
145
146/*******************************************************************************
147**
148** Function         attp_build_read_handles_cmd
149**
150** Description      Build a read by type and value request.
151**
152** Returns          pointer to the command buffer.
153**
154*******************************************************************************/
155BT_HDR *attp_build_read_by_type_value_cmd (UINT16 payload_size, tGATT_FIND_TYPE_VALUE *p_value_type)
156{
157    UINT8 *p;
158    UINT16 len = p_value_type->value_len;
159    BT_HDR *p_buf =
160        (BT_HDR *)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
161
162    p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
163    p_buf->offset = L2CAP_MIN_OFFSET;
164    p_buf->len = 5; /* opcode + s_handle + e_handle */
165
166    UINT8_TO_STREAM(p, GATT_REQ_FIND_TYPE_VALUE);
167    UINT16_TO_STREAM(p, p_value_type->s_handle);
168    UINT16_TO_STREAM(p, p_value_type->e_handle);
169
170    p_buf->len += gatt_build_uuid_to_stream(&p, p_value_type->uuid);
171
172    if (p_value_type->value_len +  p_buf->len > payload_size)
173        len = payload_size - p_buf->len;
174
175    memcpy(p, p_value_type->value, len);
176    p_buf->len += len;
177
178    return p_buf;
179}
180
181/*******************************************************************************
182**
183** Function         attp_build_read_multi_cmd
184**
185** Description      Build a read multiple request
186**
187** Returns          None.
188**
189*******************************************************************************/
190BT_HDR *attp_build_read_multi_cmd(UINT16 payload_size, UINT16 num_handle, UINT16 *p_handle)
191{
192    UINT8 *p, i = 0;
193    BT_HDR *p_buf =
194        (BT_HDR *)osi_malloc(sizeof(BT_HDR) + num_handle * 2 + 1 + L2CAP_MIN_OFFSET);
195
196    p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
197    p_buf->offset = L2CAP_MIN_OFFSET;
198    p_buf->len = 1;
199
200    UINT8_TO_STREAM(p, GATT_REQ_READ_MULTI);
201
202    for (i = 0; i < num_handle && p_buf->len + 2 <= payload_size; i ++) {
203      UINT16_TO_STREAM (p, *(p_handle + i));
204      p_buf->len += 2;
205    }
206
207    return p_buf;
208}
209/*******************************************************************************
210**
211** Function         attp_build_handle_cmd
212**
213** Description      Build a read /read blob request
214**
215** Returns          None.
216**
217*******************************************************************************/
218BT_HDR *attp_build_handle_cmd(UINT8 op_code, UINT16 handle, UINT16 offset)
219{
220    UINT8 *p;
221    BT_HDR *p_buf =
222        (BT_HDR *)osi_malloc(sizeof(BT_HDR) + 5 + L2CAP_MIN_OFFSET);
223
224    p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
225    p_buf->offset = L2CAP_MIN_OFFSET;
226
227    UINT8_TO_STREAM(p, op_code);
228    p_buf->len  = 1;
229
230    UINT16_TO_STREAM(p, handle);
231    p_buf->len += 2;
232
233    if (op_code == GATT_REQ_READ_BLOB) {
234        UINT16_TO_STREAM (p, offset);
235        p_buf->len += 2;
236    }
237
238    return p_buf;
239}
240
241/*******************************************************************************
242**
243** Function         attp_build_opcode_cmd
244**
245** Description      Build a  request/response with opcode only.
246**
247** Returns          None.
248**
249*******************************************************************************/
250BT_HDR *attp_build_opcode_cmd(UINT8 op_code)
251{
252    UINT8 *p;
253    BT_HDR *p_buf =
254        (BT_HDR *)osi_malloc(sizeof(BT_HDR) + 1 + L2CAP_MIN_OFFSET);
255
256    p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
257    p_buf->offset = L2CAP_MIN_OFFSET;
258
259    UINT8_TO_STREAM(p, op_code);
260    p_buf->len  = 1;
261
262    return p_buf;
263}
264
265/*******************************************************************************
266**
267** Function         attp_build_value_cmd
268**
269** Description      Build a attribute value request
270**
271** Returns          None.
272**
273*******************************************************************************/
274BT_HDR *attp_build_value_cmd (UINT16 payload_size, UINT8 op_code, UINT16 handle,
275                              UINT16 offset, UINT16 len, UINT8 *p_data)
276{
277    UINT8 *p, *pp, pair_len, *p_pair_len;
278    BT_HDR *p_buf =
279        (BT_HDR *)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
280
281    p = pp = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
282    UINT8_TO_STREAM(p, op_code);
283    p_buf->offset = L2CAP_MIN_OFFSET;
284    p_buf->len = 1;
285
286    if (op_code == GATT_RSP_READ_BY_TYPE) {
287        p_pair_len = p;
288        pair_len = len + 2;
289        UINT8_TO_STREAM (p, pair_len);
290        p_buf->len += 1;
291    }
292    if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ) {
293        UINT16_TO_STREAM (p, handle);
294        p_buf->len += 2;
295    }
296
297    if (op_code == GATT_REQ_PREPARE_WRITE ||op_code == GATT_RSP_PREPARE_WRITE) {
298        UINT16_TO_STREAM (p, offset);
299        p_buf->len += 2;
300    }
301
302    if (len > 0 && p_data != NULL) {
303        /* ensure data not exceed MTU size */
304        if (payload_size - p_buf->len < len) {
305            len = payload_size - p_buf->len;
306            /* update handle value pair length */
307            if (op_code == GATT_RSP_READ_BY_TYPE)
308                *p_pair_len = (len + 2);
309
310            GATT_TRACE_WARNING("attribute value too long, to be truncated to %d", len);
311        }
312
313        ARRAY_TO_STREAM(p, p_data, len);
314        p_buf->len += len;
315    }
316
317    return p_buf;
318}
319
320/*******************************************************************************
321**
322** Function         attp_send_msg_to_l2cap
323**
324** Description      Send message to L2CAP.
325**
326*******************************************************************************/
327tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP)
328{
329    UINT16      l2cap_ret;
330
331
332    if (p_tcb->att_lcid == L2CAP_ATT_CID)
333        l2cap_ret = L2CA_SendFixedChnlData (L2CAP_ATT_CID, p_tcb->peer_bda, p_toL2CAP);
334    else
335        l2cap_ret = (UINT16) L2CA_DataWrite (p_tcb->att_lcid, p_toL2CAP);
336
337    if (l2cap_ret == L2CAP_DW_FAILED)
338    {
339        GATT_TRACE_ERROR("ATT   failed to pass msg:0x%0x to L2CAP",
340            *((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset));
341        return GATT_INTERNAL_ERROR;
342    }
343    else if (l2cap_ret == L2CAP_DW_CONGESTED)
344    {
345        GATT_TRACE_DEBUG("ATT congested, message accepted");
346        return GATT_CONGESTED;
347    }
348    return GATT_SUCCESS;
349}
350
351/*******************************************************************************
352**
353** Function         attp_build_sr_msg
354**
355** Description      Build ATT Server PDUs.
356**
357*******************************************************************************/
358BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, UINT8 op_code, tGATT_SR_MSG *p_msg)
359{
360    BT_HDR          *p_cmd = NULL;
361    UINT16          offset = 0;
362
363    switch (op_code)
364    {
365    case GATT_RSP_READ_BLOB:
366    case GATT_RSP_PREPARE_WRITE:
367        GATT_TRACE_EVENT ("ATT_RSP_READ_BLOB/GATT_RSP_PREPARE_WRITE: len = %d offset = %d",
368                    p_msg->attr_value.len, p_msg->attr_value.offset);
369        offset = p_msg->attr_value.offset;
370/* Coverity: [FALSE-POSITIVE error] intended fall through */
371/* Missing break statement between cases in switch statement */
372        /* fall through */
373    case GATT_RSP_READ_BY_TYPE:
374    case GATT_RSP_READ:
375    case GATT_HANDLE_VALUE_NOTIF:
376    case GATT_HANDLE_VALUE_IND:
377        p_cmd = attp_build_value_cmd(p_tcb->payload_size,
378                                     op_code,
379                                     p_msg->attr_value.handle,
380                                     offset,
381                                     p_msg->attr_value.len,
382                                     p_msg->attr_value.value);
383        break;
384
385    case GATT_RSP_WRITE:
386        p_cmd = attp_build_opcode_cmd(op_code);
387        break;
388
389    case GATT_RSP_ERROR:
390        p_cmd = attp_build_err_cmd(p_msg->error.cmd_code, p_msg->error.handle, p_msg->error.reason);
391        break;
392
393    case GATT_RSP_EXEC_WRITE:
394        p_cmd = attp_build_exec_write_cmd(op_code, 0);
395        break;
396
397    case GATT_RSP_MTU:
398        p_cmd = attp_build_mtu_cmd(op_code, p_msg->mtu);
399        break;
400
401    default:
402        GATT_TRACE_DEBUG("attp_build_sr_msg: unknown op code = %d", op_code);
403        break;
404    }
405
406    if (!p_cmd)
407        GATT_TRACE_ERROR("No resources");
408
409    return p_cmd;
410}
411
412/*******************************************************************************
413**
414** Function         attp_send_sr_msg
415**
416** Description      This function sends the server response or indication message
417**                  to client.
418**
419** Parameter        p_tcb: pointer to the connecton control block.
420**                  p_msg: pointer to message parameters structure.
421**
422** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
423**
424**
425*******************************************************************************/
426tGATT_STATUS attp_send_sr_msg (tGATT_TCB *p_tcb, BT_HDR *p_msg)
427{
428    tGATT_STATUS     cmd_sent = GATT_NO_RESOURCES;
429
430    if (p_tcb != NULL)
431    {
432        if (p_msg != NULL)
433        {
434            p_msg->offset = L2CAP_MIN_OFFSET;
435            cmd_sent = attp_send_msg_to_l2cap (p_tcb, p_msg);
436        }
437    }
438    return cmd_sent;
439}
440
441/*******************************************************************************
442**
443** Function         attp_cl_send_cmd
444**
445** Description      Send a ATT command or enqueue it.
446**
447** Returns          GATT_SUCCESS if command sent
448**                  GATT_CONGESTED if command sent but channel congested
449**                  GATT_CMD_STARTED if command queue up in GATT
450**                  GATT_ERROR if command sending failure
451**
452*******************************************************************************/
453tGATT_STATUS attp_cl_send_cmd(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 cmd_code, BT_HDR *p_cmd)
454{
455    tGATT_STATUS att_ret = GATT_SUCCESS;
456
457    if (p_tcb != NULL)
458    {
459        cmd_code &= ~GATT_AUTH_SIGN_MASK;
460
461        /* no pending request or value confirmation */
462        if (p_tcb->pending_cl_req == p_tcb->next_slot_inq ||
463            cmd_code == GATT_HANDLE_VALUE_CONF)
464        {
465            att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd);
466            if (att_ret == GATT_CONGESTED || att_ret == GATT_SUCCESS)
467            {
468                /* do not enq cmd if handle value confirmation or set request */
469                if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE)
470                {
471                    gatt_start_rsp_timer (clcb_idx);
472                    gatt_cmd_enq(p_tcb, clcb_idx, FALSE, cmd_code, NULL);
473                }
474            }
475            else
476                att_ret = GATT_INTERNAL_ERROR;
477        }
478        else
479        {
480            att_ret = GATT_CMD_STARTED;
481            gatt_cmd_enq(p_tcb, clcb_idx, TRUE, cmd_code, p_cmd);
482        }
483    }
484    else
485        att_ret = GATT_ERROR;
486
487    return att_ret;
488}
489/*******************************************************************************
490**
491** Function         attp_send_cl_msg
492**
493** Description      This function sends the client request or confirmation message
494**                  to server.
495**
496** Parameter        p_tcb: pointer to the connectino control block.
497**                  clcb_idx: clcb index
498**                  op_code: message op code.
499**                  p_msg: pointer to message parameters structure.
500**
501** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
502**
503**
504*******************************************************************************/
505tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, tGATT_CL_MSG *p_msg)
506{
507    tGATT_STATUS     status = GATT_NO_RESOURCES;
508    BT_HDR          *p_cmd = NULL;
509    UINT16          offset = 0, handle;
510
511    if (p_tcb != NULL)
512    {
513        switch (op_code)
514        {
515        case GATT_REQ_MTU:
516            if (p_msg->mtu <= GATT_MAX_MTU_SIZE)
517            {
518                p_tcb->payload_size = p_msg->mtu;
519                p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu);
520            }
521            else
522                status = GATT_ILLEGAL_PARAMETER;
523            break;
524
525        case GATT_REQ_FIND_INFO:
526        case GATT_REQ_READ_BY_TYPE:
527        case GATT_REQ_READ_BY_GRP_TYPE:
528            if (GATT_HANDLE_IS_VALID (p_msg->browse.s_handle) &&
529                GATT_HANDLE_IS_VALID (p_msg->browse.e_handle)  &&
530                p_msg->browse.s_handle <= p_msg->browse.e_handle)
531            {
532                p_cmd = attp_build_browse_cmd(op_code,
533                                            p_msg->browse.s_handle,
534                                            p_msg->browse.e_handle,
535                                            p_msg->browse.uuid);
536            }
537            else
538                status = GATT_ILLEGAL_PARAMETER;
539            break;
540
541        case GATT_REQ_READ_BLOB:
542            offset = p_msg->read_blob.offset;
543            /* fall through */
544        case GATT_REQ_READ:
545            handle = (op_code == GATT_REQ_READ) ? p_msg->handle: p_msg->read_blob.handle;
546            /*  handle checking */
547            if (GATT_HANDLE_IS_VALID (handle))
548            {
549                p_cmd = attp_build_handle_cmd(op_code, handle, offset);
550            }
551            else
552                status = GATT_ILLEGAL_PARAMETER;
553            break;
554
555        case GATT_HANDLE_VALUE_CONF:
556            p_cmd = attp_build_opcode_cmd(op_code);
557            break;
558
559        case GATT_REQ_PREPARE_WRITE:
560            offset = p_msg->attr_value.offset;
561            /* fall through */
562        case GATT_REQ_WRITE:
563        case GATT_CMD_WRITE:
564        case GATT_SIGN_CMD_WRITE:
565            if (GATT_HANDLE_IS_VALID (p_msg->attr_value.handle))
566            {
567                p_cmd = attp_build_value_cmd (p_tcb->payload_size,
568                                              op_code, p_msg->attr_value.handle,
569                                              offset,
570                                              p_msg->attr_value.len,
571                                              p_msg->attr_value.value);
572            }
573            else
574                status = GATT_ILLEGAL_PARAMETER;
575            break;
576
577        case GATT_REQ_EXEC_WRITE:
578            p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write);
579            break;
580
581        case GATT_REQ_FIND_TYPE_VALUE:
582            p_cmd = attp_build_read_by_type_value_cmd(p_tcb->payload_size, &p_msg->find_type_value);
583            break;
584
585        case GATT_REQ_READ_MULTI:
586            p_cmd = attp_build_read_multi_cmd(p_tcb->payload_size,
587                                              p_msg->read_multi.num_handles,
588                                              p_msg->read_multi.handles);
589            break;
590
591        default:
592            break;
593        }
594
595        if (p_cmd != NULL)
596            status = attp_cl_send_cmd(p_tcb, clcb_idx, op_code, p_cmd);
597
598    }
599    else
600    {
601        GATT_TRACE_ERROR("Peer device not connected");
602    }
603
604    return status;
605}
606#endif
607