1/******************************************************************************
2 *
3 *  Copyright (C) 2010-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 *
22 *  This file contains the LLCP utilities
23 *
24 ******************************************************************************/
25
26#include <string.h>
27#include "gki.h"
28#include "nfc_target.h"
29#include "bt_types.h"
30#include "trace_api.h"
31#include "llcp_int.h"
32#include "llcp_defs.h"
33#include "nfc_int.h"
34
35/*******************************************************************************
36**
37** Function         llcp_util_parse_link_params
38**
39** Description      Parse LLCP Link parameters
40**
41** Returns          TRUE if success
42**
43*******************************************************************************/
44BOOLEAN llcp_util_parse_link_params (UINT16 length, UINT8 *p_bytes)
45{
46    UINT8 param_type, param_len, *p = p_bytes;
47
48    while (length)
49    {
50        BE_STREAM_TO_UINT8 (param_type, p);
51        length--;
52
53        switch (param_type)
54        {
55        case LLCP_VERSION_TYPE:
56            BE_STREAM_TO_UINT8 (param_len, p);
57            BE_STREAM_TO_UINT8 (llcp_cb.lcb.peer_version, p);
58            LLCP_TRACE_DEBUG1 ("Peer Version - 0x%02X", llcp_cb.lcb.peer_version);
59            break;
60
61        case LLCP_MIUX_TYPE:
62            BE_STREAM_TO_UINT8 (param_len, p);
63            BE_STREAM_TO_UINT16 (llcp_cb.lcb.peer_miu, p);
64            llcp_cb.lcb.peer_miu &= LLCP_MIUX_MASK;
65            llcp_cb.lcb.peer_miu += LLCP_DEFAULT_MIU;
66            LLCP_TRACE_DEBUG1 ("Peer MIU - %d bytes", llcp_cb.lcb.peer_miu);
67            break;
68
69        case LLCP_WKS_TYPE:
70            BE_STREAM_TO_UINT8 (param_len, p);
71            BE_STREAM_TO_UINT16 (llcp_cb.lcb.peer_wks, p);
72            LLCP_TRACE_DEBUG1 ("Peer WKS - 0x%04X", llcp_cb.lcb.peer_wks);
73            break;
74
75        case LLCP_LTO_TYPE:
76            BE_STREAM_TO_UINT8 (param_len, p);
77            BE_STREAM_TO_UINT8 (llcp_cb.lcb.peer_lto, p);
78            llcp_cb.lcb.peer_lto *= LLCP_LTO_UNIT;  /* 10ms unit */
79            LLCP_TRACE_DEBUG1 ("Peer LTO - %d ms", llcp_cb.lcb.peer_lto);
80            break;
81
82        case LLCP_OPT_TYPE:
83            BE_STREAM_TO_UINT8 (param_len, p);
84            BE_STREAM_TO_UINT8 (llcp_cb.lcb.peer_opt, p);
85            LLCP_TRACE_DEBUG1 ("Peer OPT - 0x%02X", llcp_cb.lcb.peer_opt);
86            break;
87
88        default:
89            LLCP_TRACE_ERROR1 ("llcp_util_parse_link_params (): Unexpected type 0x%x", param_type);
90            BE_STREAM_TO_UINT8 (param_len, p);
91            p += param_len;
92            break;
93        }
94
95        if (length >= param_len + 1)
96            length -= param_len + 1;
97        else
98        {
99            LLCP_TRACE_ERROR0 ("llcp_util_parse_link_params (): Bad LTV's");
100            return (FALSE);
101        }
102    }
103    return (TRUE);
104}
105
106/*******************************************************************************
107**
108** Function         llcp_util_adjust_ll_congestion
109**
110** Description      adjust tx/rx congestion thresholds on logical link
111**
112** Returns          void
113**
114*******************************************************************************/
115void llcp_util_adjust_ll_congestion (void)
116{
117    /* buffer quota is allocated equally for each logical data link */
118    if (llcp_cb.num_logical_data_link)
119    {
120        llcp_cb.ll_tx_congest_start = llcp_cb.max_num_ll_tx_buff / llcp_cb.num_logical_data_link;
121        llcp_cb.ll_rx_congest_start = llcp_cb.max_num_ll_rx_buff / llcp_cb.num_logical_data_link;
122    }
123    else
124    {
125        llcp_cb.ll_tx_congest_start = llcp_cb.max_num_ll_tx_buff;
126        llcp_cb.ll_rx_congest_start = llcp_cb.max_num_ll_rx_buff;
127    }
128
129    /* at least one for each logical data link */
130    if (llcp_cb.ll_tx_congest_start == 0)
131    {
132        llcp_cb.ll_tx_congest_start = 1;
133    }
134    if (llcp_cb.ll_rx_congest_start == 0)
135    {
136        llcp_cb.ll_rx_congest_start = 1;
137    }
138
139    if (llcp_cb.ll_tx_congest_start > 1)
140    {
141        llcp_cb.ll_tx_congest_end = 1;
142    }
143    else
144    {
145        llcp_cb.ll_tx_congest_end = 0;
146    }
147
148    LLCP_TRACE_DEBUG4 ("num_logical_data_link=%d, ll_tx_congest_start=%d, ll_tx_congest_end=%d, ll_rx_congest_start=%d",
149                       llcp_cb.num_logical_data_link,
150                       llcp_cb.ll_tx_congest_start,
151                       llcp_cb.ll_tx_congest_end,
152                       llcp_cb.ll_rx_congest_start);
153}
154
155/*******************************************************************************
156**
157** Function         llcp_util_adjust_dl_rx_congestion
158**
159** Description      adjust rx congestion thresholds on data link
160**
161** Returns          void
162**
163*******************************************************************************/
164void llcp_util_adjust_dl_rx_congestion (void)
165{
166    UINT8 idx, rx_congest_start;
167
168    if (llcp_cb.num_data_link_connection)
169    {
170        rx_congest_start = llcp_cb.num_rx_buff / llcp_cb.num_data_link_connection;
171
172        for (idx = 0; idx < LLCP_MAX_DATA_LINK; idx++)
173        {
174            if (llcp_cb.dlcb[idx].state == LLCP_DLC_STATE_CONNECTED)
175            {
176                if (rx_congest_start > llcp_cb.dlcb[idx].local_rw)
177                {
178                    /*
179                    ** set rx congestion threshold LLCP_DL_MIN_RX_CONGEST at least
180                    ** so, we don't need to flow off too often.
181                    */
182                    if (llcp_cb.dlcb[idx].local_rw + 1 > LLCP_DL_MIN_RX_CONGEST)
183                        llcp_cb.dlcb[idx].rx_congest_threshold = llcp_cb.dlcb[idx].local_rw + 1;
184                    else
185                        llcp_cb.dlcb[idx].rx_congest_threshold = LLCP_DL_MIN_RX_CONGEST;
186                }
187                else
188                {
189                    llcp_cb.dlcb[idx].rx_congest_threshold = LLCP_DL_MIN_RX_CONGEST;
190                }
191
192                LLCP_TRACE_DEBUG3 ("DLC[%d], local_rw=%d, rx_congest_threshold=%d",
193                                   idx,
194                                   llcp_cb.dlcb[idx].local_rw,
195                                   llcp_cb.dlcb[idx].rx_congest_threshold);
196            }
197        }
198    }
199
200}
201
202/*******************************************************************************
203**
204** Function         llcp_util_check_rx_congested_status
205**
206** Description      Update rx congested status
207**
208** Returns          void
209**
210*******************************************************************************/
211void llcp_util_check_rx_congested_status (void)
212{
213    UINT8 idx;
214
215    if (llcp_cb.overall_rx_congested)
216    {
217        /* check if rx congestion clear */
218        if (llcp_cb.total_rx_ui_pdu + llcp_cb.total_rx_i_pdu <= llcp_cb.overall_rx_congest_end)
219        {
220            LLCP_TRACE_DEBUG3 ("llcp_util_check_rx_congested_status (): rx link is uncongested, %d+%d <= %d",
221                                llcp_cb.total_rx_ui_pdu, llcp_cb.total_rx_i_pdu,
222                                llcp_cb.overall_rx_congest_end);
223
224            llcp_cb.overall_rx_congested = FALSE;
225
226            for (idx = 0; idx < LLCP_MAX_DATA_LINK; idx++)
227            {
228                /* set flag to clear local busy status on data link connections */
229                if (  (llcp_cb.dlcb[idx].state == LLCP_DLC_STATE_CONNECTED)
230                    &&(llcp_cb.dlcb[idx].is_rx_congested == FALSE)  )
231                {
232                    llcp_cb.dlcb[idx].flags |= LLCP_DATA_LINK_FLAG_PENDING_RR_RNR;
233                }
234            }
235        }
236    }
237    else
238    {
239        /* check if rx link is congested */
240        if (llcp_cb.total_rx_ui_pdu + llcp_cb.total_rx_i_pdu >= llcp_cb.overall_rx_congest_start)
241        {
242            LLCP_TRACE_WARNING3 ("llcp_util_check_rx_congested_status (): rx link is congested, %d+%d >= %d",
243                                  llcp_cb.total_rx_ui_pdu, llcp_cb.total_rx_i_pdu,
244                                  llcp_cb.overall_rx_congest_start);
245
246            llcp_cb.overall_rx_congested = TRUE;
247
248            /* rx link congestion is started, send RNR to remote end point */
249            for (idx = 0; idx < LLCP_MAX_DATA_LINK; idx++)
250            {
251                if (  (llcp_cb.dlcb[idx].state == LLCP_DLC_STATE_CONNECTED)
252                    &&(llcp_cb.dlcb[idx].is_rx_congested == FALSE)  )
253                {
254                    llcp_cb.dlcb[idx].flags |= LLCP_DATA_LINK_FLAG_PENDING_RR_RNR;
255                }
256            }
257        }
258    }
259}
260
261/*******************************************************************************
262**
263** Function         llcp_util_send_ui
264**
265** Description      Send UI PDU
266**
267** Returns          tLLCP_STATUS
268**
269*******************************************************************************/
270tLLCP_STATUS llcp_util_send_ui (UINT8 ssap, UINT8 dsap, tLLCP_APP_CB *p_app_cb, BT_HDR *p_msg)
271{
272    UINT8        *p;
273    tLLCP_STATUS status = LLCP_STATUS_SUCCESS;
274
275    p_msg->offset -= LLCP_PDU_HEADER_SIZE;
276    p_msg->len    += LLCP_PDU_HEADER_SIZE;
277
278    p = (UINT8 *) (p_msg + 1) + p_msg->offset;
279    UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (dsap, LLCP_PDU_UI_TYPE, ssap));
280
281    GKI_enqueue (&p_app_cb->ui_xmit_q, p_msg);
282    llcp_cb.total_tx_ui_pdu++;
283
284    llcp_link_check_send_data ();
285
286    if (  (p_app_cb->is_ui_tx_congested)
287        ||(p_app_cb->ui_xmit_q.count >= llcp_cb.ll_tx_congest_start)
288        ||(llcp_cb.overall_tx_congested)
289        ||(llcp_cb.total_tx_ui_pdu >= llcp_cb.max_num_ll_tx_buff)  )
290    {
291        /* set congested here so overall congestion check routine will not report event again, */
292        /* or notify uncongestion later                                                        */
293        p_app_cb->is_ui_tx_congested = TRUE;
294
295        LLCP_TRACE_WARNING2 ("Logical link (SAP=0x%X) congested: ui_xmit_q.count=%d",
296                              ssap, p_app_cb->ui_xmit_q.count);
297
298        status = LLCP_STATUS_CONGESTED;
299    }
300
301    return status;
302}
303
304/*******************************************************************************
305**
306** Function         llcp_util_send_disc
307**
308** Description      Send DISC PDU
309**
310** Returns          void
311**
312*******************************************************************************/
313void llcp_util_send_disc (UINT8 dsap, UINT8 ssap)
314{
315    BT_HDR *p_msg;
316    UINT8  *p;
317
318    p_msg = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID);
319
320    if (p_msg)
321    {
322        p_msg->len      = LLCP_PDU_DISC_SIZE;
323        p_msg->offset   = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
324
325        p = (UINT8 *) (p_msg + 1) + p_msg->offset;
326        UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (dsap, LLCP_PDU_DISC_TYPE, ssap));
327
328        GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, p_msg);
329        llcp_link_check_send_data ();
330    }
331}
332
333/*******************************************************************************
334**
335** Function         llcp_util_allocate_data_link
336**
337** Description      Allocate tLLCP_DLCB for data link connection
338**
339** Returns          tLLCP_DLCB *
340**
341******************************************************************************/
342tLLCP_DLCB *llcp_util_allocate_data_link (UINT8 reg_sap, UINT8 remote_sap)
343{
344    tLLCP_DLCB *p_dlcb = NULL;
345    int         idx;
346
347    LLCP_TRACE_DEBUG2 ("llcp_util_allocate_data_link (): reg_sap = 0x%x, remote_sap = 0x%x",
348                        reg_sap, remote_sap);
349
350    for (idx = 0; idx < LLCP_MAX_DATA_LINK; idx++)
351    {
352        if (llcp_cb.dlcb[idx].state == LLCP_DLC_STATE_IDLE)
353        {
354            p_dlcb = &(llcp_cb.dlcb[idx]);
355
356            memset (p_dlcb, 0, sizeof (tLLCP_DLCB));
357            break;
358        }
359    }
360
361    if (!p_dlcb)
362    {
363        LLCP_TRACE_ERROR0 ("llcp_util_allocate_data_link (): Out of DLCB");
364    }
365    else
366    {
367        p_dlcb->p_app_cb    = llcp_util_get_app_cb (reg_sap);
368        p_dlcb->local_sap   = reg_sap;
369        p_dlcb->remote_sap  = remote_sap;
370        p_dlcb->timer.param = (TIMER_PARAM_TYPE) p_dlcb;
371
372        /* this is for inactivity timer and congestion control. */
373        llcp_cb.num_data_link_connection++;
374
375        LLCP_TRACE_DEBUG3 ("llcp_util_allocate_data_link (): local_sap = 0x%x, remote_sap = 0x%x, num_data_link_connection = %d",
376                            p_dlcb->local_sap, p_dlcb->remote_sap, llcp_cb.num_data_link_connection);
377    }
378    return p_dlcb;
379}
380
381/*******************************************************************************
382**
383** Function         llcp_util_deallocate_data_link
384**
385** Description      Deallocate tLLCP_DLCB
386**
387** Returns          void
388**
389******************************************************************************/
390void llcp_util_deallocate_data_link (tLLCP_DLCB *p_dlcb)
391{
392    if (p_dlcb)
393    {
394        LLCP_TRACE_DEBUG1 ("llcp_util_deallocate_data_link (): local_sap = 0x%x", p_dlcb->local_sap);
395
396        if (p_dlcb->state != LLCP_DLC_STATE_IDLE)
397        {
398            nfc_stop_quick_timer (&p_dlcb->timer);
399            llcp_dlc_flush_q (p_dlcb);
400
401            p_dlcb->state = LLCP_DLC_STATE_IDLE;
402
403            if (llcp_cb.num_data_link_connection > 0)
404            {
405                llcp_cb.num_data_link_connection--;
406            }
407
408            LLCP_TRACE_DEBUG1 ("llcp_util_deallocate_data_link (): num_data_link_connection = %d", llcp_cb.num_data_link_connection);
409        }
410    }
411}
412
413/*******************************************************************************
414**
415** Function         llcp_util_send_connect
416**
417** Description      Send CONNECT PDU
418**
419** Returns          tLLCP_STATUS
420**
421******************************************************************************/
422tLLCP_STATUS llcp_util_send_connect (tLLCP_DLCB *p_dlcb, tLLCP_CONNECTION_PARAMS *p_params)
423{
424    BT_HDR *p_msg;
425    UINT8  *p;
426    UINT16  miu_len = 0, rw_len = 0, sn_len = 0;
427
428    if (p_params->miu != LLCP_DEFAULT_MIU)
429    {
430        miu_len = 4;    /* TYPE, LEN, 2 bytes MIU */
431    }
432    if (p_params->rw != LLCP_DEFAULT_RW)
433    {
434        rw_len = 3;     /* TYPE, LEN, 1 byte RW */
435        p_params->rw &= 0x0F;   /* only 4 bits  */
436    }
437    if ((strlen (p_params->sn)) && (p_dlcb->remote_sap == LLCP_SAP_SDP))
438    {
439        sn_len = (UINT16) (2 + strlen (p_params->sn));    /* TYPE, LEN, SN */
440    }
441
442    p_msg = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID);
443
444    if (p_msg)
445    {
446        p_msg->len    = LLCP_PDU_HEADER_SIZE + miu_len + rw_len + sn_len;
447        p_msg->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
448
449        p = (UINT8 *) (p_msg + 1) + p_msg->offset;
450
451        UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (p_dlcb->remote_sap, LLCP_PDU_CONNECT_TYPE, p_dlcb->local_sap));
452
453        if (miu_len)
454        {
455            UINT8_TO_BE_STREAM (p, LLCP_MIUX_TYPE);
456            UINT8_TO_BE_STREAM (p, LLCP_MIUX_LEN);
457            UINT16_TO_BE_STREAM (p, p_params->miu - LLCP_DEFAULT_MIU);
458        }
459
460        if (rw_len)
461        {
462            UINT8_TO_BE_STREAM (p, LLCP_RW_TYPE);
463            UINT8_TO_BE_STREAM (p, LLCP_RW_LEN);
464            UINT8_TO_BE_STREAM (p, p_params->rw);
465        }
466
467        if (sn_len)
468        {
469            UINT8_TO_BE_STREAM (p, LLCP_SN_TYPE);
470            UINT8_TO_BE_STREAM (p, sn_len - 2);
471            memcpy (p, p_params->sn, sn_len - 2);
472        }
473
474        GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, p_msg);
475        llcp_link_check_send_data ();
476
477        return LLCP_STATUS_SUCCESS;
478    }
479
480    return LLCP_STATUS_FAIL;
481}
482
483/*******************************************************************************
484**
485** Function         llcp_util_parse_connect
486**
487** Description      Parse CONNECT PDU
488**
489** Returns          tLLCP_STATUS
490**
491*******************************************************************************/
492tLLCP_STATUS llcp_util_parse_connect (UINT8  *p_bytes, UINT16 length, tLLCP_CONNECTION_PARAMS *p_params)
493{
494    UINT8 param_type, param_len, *p = p_bytes;
495
496    p_params->miu = LLCP_DEFAULT_MIU;
497    p_params->rw  = LLCP_DEFAULT_RW;
498    p_params->sn[0] = 0;
499    p_params->sn[1] = 0;
500
501    while (length)
502    {
503        BE_STREAM_TO_UINT8 (param_type, p);
504        length--;
505
506        switch (param_type)
507        {
508        case LLCP_MIUX_TYPE:
509            BE_STREAM_TO_UINT8 (param_len, p);
510            BE_STREAM_TO_UINT16 (p_params->miu, p);
511            p_params->miu &= LLCP_MIUX_MASK;
512            p_params->miu += LLCP_DEFAULT_MIU;
513
514            LLCP_TRACE_DEBUG1 ("llcp_util_parse_connect (): LLCP_MIUX_TYPE:%d", p_params->miu);
515            break;
516
517        case LLCP_RW_TYPE:
518            BE_STREAM_TO_UINT8 (param_len, p);
519            BE_STREAM_TO_UINT8 (p_params->rw, p);
520            p_params->rw &= 0x0F;
521
522            LLCP_TRACE_DEBUG1 ("llcp_util_parse_connect (): LLCP_RW_TYPE:%d", p_params->rw);
523            break;
524
525        case LLCP_SN_TYPE:
526            BE_STREAM_TO_UINT8 (param_len, p);
527
528            if (param_len == 0)
529            {
530                /* indicate that SN type is included without SN */
531                p_params->sn[1] = LLCP_SN_TYPE;
532            }
533            else if (param_len <= LLCP_MAX_SN_LEN)
534            {
535                memcpy (p_params->sn, p, param_len);
536                p_params->sn[param_len] = 0;
537            }
538            else
539            {
540                memcpy (p_params->sn, p, LLCP_MAX_SN_LEN);
541                p_params->sn[LLCP_MAX_SN_LEN] = 0;
542            }
543            p += param_len;
544
545            LLCP_TRACE_DEBUG1 ("llcp_util_parse_connect (): LLCP_SN_TYPE:<%s>", p_params->sn);
546            break;
547
548        default:
549            LLCP_TRACE_ERROR1 ("llcp_util_parse_connect (): Unexpected type 0x%x", param_type);
550            BE_STREAM_TO_UINT8 (param_len, p);
551            p += param_len;
552            break;
553        }
554
555        /* check remaining lengh */
556        if (length >= param_len + 1)
557        {
558            length -= param_len + 1;
559        }
560        else
561        {
562            LLCP_TRACE_ERROR0 ("llcp_util_parse_connect (): Bad LTV's");
563            return LLCP_STATUS_FAIL;
564        }
565    }
566    return LLCP_STATUS_SUCCESS;
567}
568
569/*******************************************************************************
570**
571** Function         llcp_util_send_cc
572**
573** Description      Send CC PDU
574**
575** Returns          tLLCP_STATUS
576**
577******************************************************************************/
578tLLCP_STATUS llcp_util_send_cc (tLLCP_DLCB *p_dlcb, tLLCP_CONNECTION_PARAMS *p_params)
579{
580    BT_HDR *p_msg;
581    UINT8  *p;
582    UINT16  miu_len = 0, rw_len = 0;
583
584    if (p_params->miu != LLCP_DEFAULT_MIU)
585    {
586        miu_len = 4;
587    }
588    if (p_params->rw != LLCP_DEFAULT_RW)
589    {
590        rw_len = 3;
591        p_params->rw &= 0x0F;
592    }
593
594    p_msg = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID);
595
596    if (p_msg)
597    {
598        p_msg->len      = LLCP_PDU_HEADER_SIZE + miu_len + rw_len;
599        p_msg->offset   = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
600
601        p = (UINT8 *) (p_msg + 1) + p_msg->offset;
602
603        UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (p_dlcb->remote_sap, LLCP_PDU_CC_TYPE, p_dlcb->local_sap));
604
605        if (miu_len)
606        {
607            UINT8_TO_BE_STREAM (p, LLCP_MIUX_TYPE);
608            UINT8_TO_BE_STREAM (p, LLCP_MIUX_LEN);
609            UINT16_TO_BE_STREAM (p, p_params->miu - LLCP_DEFAULT_MIU);
610        }
611
612        if (rw_len)
613        {
614            UINT8_TO_BE_STREAM (p, LLCP_RW_TYPE);
615            UINT8_TO_BE_STREAM (p, LLCP_RW_LEN);
616            UINT8_TO_BE_STREAM (p, p_params->rw);
617        }
618
619        GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, p_msg);
620        llcp_link_check_send_data ();
621
622        return LLCP_STATUS_SUCCESS;
623    }
624
625    return LLCP_STATUS_FAIL;
626}
627
628/*******************************************************************************
629**
630** Function         llcp_util_parse_cc
631**
632** Description      Parse CC PDU
633**
634** Returns          tLLCP_STATUS
635**
636*******************************************************************************/
637tLLCP_STATUS llcp_util_parse_cc (UINT8 *p_bytes, UINT16 length, UINT16 *p_miu, UINT8 *p_rw)
638{
639    UINT8 param_type, param_len, *p = p_bytes;
640
641    *p_miu = LLCP_DEFAULT_MIU;
642    *p_rw  = LLCP_DEFAULT_RW;
643
644    while (length)
645    {
646        BE_STREAM_TO_UINT8 (param_type, p);
647        length--;
648
649        switch (param_type)
650        {
651        case LLCP_MIUX_TYPE:
652            BE_STREAM_TO_UINT8 (param_len, p);
653            BE_STREAM_TO_UINT16 ((*p_miu), p);
654            (*p_miu) &= LLCP_MIUX_MASK;
655            (*p_miu) += LLCP_DEFAULT_MIU;
656
657            LLCP_TRACE_DEBUG1 ("llcp_util_parse_cc (): LLCP_MIUX_TYPE:%d", *p_miu);
658            break;
659
660        case LLCP_RW_TYPE:
661            BE_STREAM_TO_UINT8 (param_len, p);
662            BE_STREAM_TO_UINT8 ((*p_rw), p);
663            (*p_rw) &= 0x0F;
664
665            LLCP_TRACE_DEBUG1 ("llcp_util_parse_cc (): LLCP_RW_TYPE:%d", *p_rw);
666            break;
667
668        default:
669            LLCP_TRACE_ERROR1 ("llcp_util_parse_cc (): Unexpected type 0x%x", param_type);
670            BE_STREAM_TO_UINT8 (param_len, p);
671            p += param_len;
672            break;
673        }
674
675        if (length >= param_len + 1)
676            length -= param_len + 1;
677        else
678        {
679            LLCP_TRACE_ERROR0 ("llcp_util_parse_cc (): Bad LTV's");
680            return LLCP_STATUS_FAIL;
681        }
682    }
683    return LLCP_STATUS_SUCCESS;
684}
685
686/*******************************************************************************
687**
688** Function         llcp_util_send_dm
689**
690** Description      Send DM PDU
691**
692** Returns          void
693**
694*******************************************************************************/
695void llcp_util_send_dm (UINT8 dsap, UINT8 ssap, UINT8 reason)
696{
697    BT_HDR *p_msg;
698    UINT8  *p;
699
700    p_msg = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID);
701
702    if (p_msg)
703    {
704        p_msg->len    = LLCP_PDU_DM_SIZE;
705        p_msg->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
706
707        p = (UINT8 *) (p_msg + 1) + p_msg->offset;
708        UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (dsap, LLCP_PDU_DM_TYPE, ssap));
709        UINT8_TO_BE_STREAM  (p, reason);
710
711        GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, p_msg);
712        llcp_link_check_send_data ();
713    }
714}
715
716/*******************************************************************************
717**
718** Function         llcp_util_build_info_pdu
719**
720** Description      Add DSAP, PTYPE, SSAP and sequence numbers and update local ack
721**                  sequence
722**
723** Returns          void
724**
725*******************************************************************************/
726void llcp_util_build_info_pdu (tLLCP_DLCB *p_dlcb, BT_HDR *p_msg)
727{
728    UINT8  *p;
729    UINT8  rcv_seq;
730
731    p_msg->offset -= LLCP_PDU_HEADER_SIZE + LLCP_SEQUENCE_SIZE;
732    p_msg->len    += LLCP_PDU_HEADER_SIZE + LLCP_SEQUENCE_SIZE;
733    p = (UINT8 *) (p_msg + 1) + p_msg->offset;
734
735    UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (p_dlcb->remote_sap, LLCP_PDU_I_TYPE, p_dlcb->local_sap));
736
737    /* if local_busy or rx congested then do not update receive sequence number to flow off */
738    if (  (p_dlcb->local_busy)
739        ||(p_dlcb->is_rx_congested)
740        ||(llcp_cb.overall_rx_congested)  )
741    {
742        rcv_seq = p_dlcb->sent_ack_seq;
743    }
744    else
745    {
746        p_dlcb->sent_ack_seq = p_dlcb->next_rx_seq;
747        rcv_seq = p_dlcb->sent_ack_seq;
748    }
749    UINT8_TO_BE_STREAM  (p, LLCP_GET_SEQUENCE (p_dlcb->next_tx_seq, rcv_seq));
750}
751
752/*******************************************************************************
753**
754** Function         llcp_util_send_frmr
755**
756** Description      Send FRMR PDU
757**
758** Returns          tLLCP_STATUS
759**
760*******************************************************************************/
761tLLCP_STATUS llcp_util_send_frmr (tLLCP_DLCB *p_dlcb, UINT8 flags, UINT8 ptype, UINT8 sequence)
762{
763    BT_HDR *p_msg;
764    UINT8  *p;
765
766    p_msg = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID);
767
768    if (p_msg)
769    {
770        p_msg->len      = LLCP_PDU_FRMR_SIZE;
771        p_msg->offset   = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
772
773        p = (UINT8 *) (p_msg + 1) + p_msg->offset;
774
775        UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (p_dlcb->remote_sap, LLCP_PDU_FRMR_TYPE, p_dlcb->local_sap));
776        UINT8_TO_BE_STREAM (p, (flags << 4) | ptype);
777        UINT8_TO_BE_STREAM (p, sequence);
778        UINT8_TO_BE_STREAM (p, (p_dlcb->next_tx_seq << 4) | p_dlcb->next_rx_seq);
779        UINT8_TO_BE_STREAM (p, (p_dlcb->rcvd_ack_seq << 4) | p_dlcb->sent_ack_seq);
780
781        GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, p_msg);
782        llcp_link_check_send_data ();
783
784        return LLCP_STATUS_SUCCESS;
785    }
786    else
787    {
788        LLCP_TRACE_ERROR0 ("llcp_util_send_frmr (): Out of resource");
789        return LLCP_STATUS_FAIL;
790    }
791}
792
793/*******************************************************************************
794**
795** Function         llcp_util_send_rr_rnr
796**
797** Description      Send RR or RNR PDU
798**
799** Returns          void
800**
801*******************************************************************************/
802void llcp_util_send_rr_rnr (tLLCP_DLCB *p_dlcb)
803{
804    BT_HDR *p_msg;
805    UINT8  *p;
806    UINT8   pdu_type;
807    UINT8   pdu_size;
808    UINT8   rcv_seq;
809
810    /* if no indication of change in local busy or rx congestion */
811    if ((p_dlcb->flags & LLCP_DATA_LINK_FLAG_PENDING_RR_RNR) == 0)
812    {
813        /* if all ack is sent */
814        if (p_dlcb->sent_ack_seq == p_dlcb->next_rx_seq)
815        {
816            /* we don't need to send RR/RNR */
817            return;
818        }
819        else
820        {
821            /* if rx flow off because of local busy or congestion */
822            if (  (p_dlcb->local_busy)
823                ||(p_dlcb->is_rx_congested)
824                ||(llcp_cb.overall_rx_congested)  )
825            {
826                /* don't send RR/RNR */
827                return;
828            }
829        }
830    }
831
832    if (  (p_dlcb->local_busy)
833        ||(p_dlcb->is_rx_congested)
834        ||(llcp_cb.overall_rx_congested)  )
835    {
836        LLCP_TRACE_DEBUG3 ("llcp_util_send_rr_rnr (): local_busy=%d,is_rx_congested=%d,overall_rx_congested=%d",
837                            p_dlcb->local_busy, p_dlcb->is_rx_congested, llcp_cb.overall_rx_congested);
838
839        /* if local_busy or rx congested then do not update receive sequence number to flow off */
840        pdu_type = LLCP_PDU_RNR_TYPE;
841        pdu_size = LLCP_PDU_RNR_SIZE;
842        rcv_seq = p_dlcb->sent_ack_seq;
843    }
844    else
845    {
846        pdu_type = LLCP_PDU_RR_TYPE;
847        pdu_size = LLCP_PDU_RR_SIZE;
848
849        p_dlcb->sent_ack_seq = p_dlcb->next_rx_seq;
850        rcv_seq = p_dlcb->sent_ack_seq;
851    }
852
853    p_msg = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID);
854
855    if (p_msg)
856    {
857        p_dlcb->flags &= ~LLCP_DATA_LINK_FLAG_PENDING_RR_RNR;
858
859        p_msg->len    = pdu_size;
860        p_msg->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
861
862        p = (UINT8 *) (p_msg + 1) + p_msg->offset;
863
864        UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (p_dlcb->remote_sap, pdu_type, p_dlcb->local_sap));
865
866        UINT8_TO_BE_STREAM (p, rcv_seq);
867
868#if (BT_TRACE_VERBOSE == TRUE)
869        LLCP_TRACE_DEBUG5 ("LLCP TX - N(S,R):(NA,%d) V(S,SA,R,RA):(%d,%d,%d,%d)",
870                            p_dlcb->next_rx_seq,
871                            p_dlcb->next_tx_seq, p_dlcb->rcvd_ack_seq,
872                            p_dlcb->next_rx_seq, p_dlcb->sent_ack_seq);
873#endif
874        GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, p_msg);
875        llcp_link_check_send_data ();
876    }
877    else
878    {
879        LLCP_TRACE_ERROR0 ("llcp_util_send_rr_rnr (): Out of resource");
880    }
881}
882
883/*******************************************************************************
884**
885** Function         llcp_util_get_app_cb
886**
887** Description      get pointer of application registered control block by SAP
888**
889** Returns          tLLCP_APP_CB *
890**
891*******************************************************************************/
892tLLCP_APP_CB *llcp_util_get_app_cb (UINT8 local_sap)
893{
894    tLLCP_APP_CB *p_app_cb = NULL;
895
896    if (local_sap <= LLCP_UPPER_BOUND_WK_SAP)
897    {
898        if ((local_sap != LLCP_SAP_LM) && (local_sap < LLCP_MAX_WKS))
899        {
900            p_app_cb = &llcp_cb.wks_cb[local_sap];
901        }
902    }
903    else if (local_sap <= LLCP_UPPER_BOUND_SDP_SAP)
904    {
905        if (local_sap - LLCP_LOWER_BOUND_SDP_SAP < LLCP_MAX_SERVER)
906        {
907            p_app_cb = &llcp_cb.server_cb[local_sap - LLCP_LOWER_BOUND_SDP_SAP];
908        }
909    }
910    else if (local_sap <= LLCP_UPPER_BOUND_LOCAL_SAP)
911    {
912        if (local_sap - LLCP_LOWER_BOUND_LOCAL_SAP < LLCP_MAX_CLIENT)
913        {
914            p_app_cb = &llcp_cb.client_cb[local_sap - LLCP_LOWER_BOUND_LOCAL_SAP];
915        }
916    }
917
918    return (p_app_cb);
919}
920