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