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 Service Discovery
22 *
23 ******************************************************************************/
24
25 #include <string.h>
26
27 #include <android-base/stringprintf.h>
28 #include <base/logging.h>
29
30 #include "bt_types.h"
31 #include "gki.h"
32 #include "llcp_api.h"
33 #include "llcp_int.h"
34 #include "nfa_dm_int.h"
35
36 using android::base::StringPrintf;
37
38 extern bool nfc_debug_enabled;
39
40 /*******************************************************************************
41 **
42 ** Function llcp_sdp_proc_data
43 **
44 ** Description Do nothing
45 **
46 **
47 ** Returns void
48 **
49 *******************************************************************************/
llcp_sdp_proc_data(tLLCP_SAP_CBACK_DATA * p_data)50 void llcp_sdp_proc_data(__attribute__((unused)) tLLCP_SAP_CBACK_DATA* p_data) {
51 /*
52 ** Do nothing
53 ** llcp_sdp_proc_SNL () is called by link layer
54 */
55 }
56
57 /*******************************************************************************
58 **
59 ** Function llcp_sdp_check_send_snl
60 **
61 ** Description Enqueue Service Name Lookup PDU into sig_xmit_q for
62 ** transmitting
63 **
64 **
65 ** Returns void
66 **
67 *******************************************************************************/
llcp_sdp_check_send_snl(void)68 void llcp_sdp_check_send_snl(void) {
69 uint8_t* p;
70
71 if (llcp_cb.sdp_cb.p_snl) {
72 DLOG_IF(INFO, nfc_debug_enabled) << __func__;
73
74 llcp_cb.sdp_cb.p_snl->len += LLCP_PDU_HEADER_SIZE;
75 llcp_cb.sdp_cb.p_snl->offset -= LLCP_PDU_HEADER_SIZE;
76
77 p = (uint8_t*)(llcp_cb.sdp_cb.p_snl + 1) + llcp_cb.sdp_cb.p_snl->offset;
78 UINT16_TO_BE_STREAM(
79 p, LLCP_GET_PDU_HEADER(LLCP_SAP_SDP, LLCP_PDU_SNL_TYPE, LLCP_SAP_SDP));
80
81 GKI_enqueue(&llcp_cb.lcb.sig_xmit_q, llcp_cb.sdp_cb.p_snl);
82 llcp_cb.sdp_cb.p_snl = nullptr;
83 } else {
84 /* Notify DTA after sending out SNL with SDRES not to send SNLs in AGF PDU
85 */
86 if (llcp_cb.p_dta_cback && llcp_cb.dta_snl_resp) {
87 llcp_cb.dta_snl_resp = false;
88 (*llcp_cb.p_dta_cback)();
89 }
90 }
91 }
92
93 /*******************************************************************************
94 **
95 ** Function llcp_sdp_add_sdreq
96 **
97 ** Description Add Service Discovery Request into SNL PDU
98 **
99 **
100 ** Returns void
101 **
102 *******************************************************************************/
llcp_sdp_add_sdreq(uint8_t tid,char * p_name)103 static void llcp_sdp_add_sdreq(uint8_t tid, char* p_name) {
104 uint8_t* p;
105 uint16_t name_len = (uint16_t)strlen(p_name);
106
107 p = (uint8_t*)(llcp_cb.sdp_cb.p_snl + 1) + llcp_cb.sdp_cb.p_snl->offset +
108 llcp_cb.sdp_cb.p_snl->len;
109
110 UINT8_TO_BE_STREAM(p, LLCP_SDREQ_TYPE);
111 UINT8_TO_BE_STREAM(p, (1 + name_len));
112 UINT8_TO_BE_STREAM(p, tid);
113 ARRAY_TO_BE_STREAM(p, p_name, name_len);
114
115 llcp_cb.sdp_cb.p_snl->len += LLCP_SDREQ_MIN_LEN + name_len;
116 }
117
118 /*******************************************************************************
119 **
120 ** Function llcp_sdp_send_sdreq
121 **
122 ** Description Send Service Discovery Request
123 **
124 **
125 ** Returns LLCP_STATUS
126 **
127 *******************************************************************************/
llcp_sdp_send_sdreq(uint8_t tid,char * p_name)128 tLLCP_STATUS llcp_sdp_send_sdreq(uint8_t tid, char* p_name) {
129 tLLCP_STATUS status;
130 uint16_t name_len;
131 uint16_t available_bytes;
132
133 DLOG_IF(INFO, nfc_debug_enabled)
134 << StringPrintf("tid=0x%x, ServiceName=%s", tid, p_name);
135
136 /* if there is no pending SNL */
137 if (!llcp_cb.sdp_cb.p_snl) {
138 llcp_cb.sdp_cb.p_snl = (NFC_HDR*)GKI_getpoolbuf(LLCP_POOL_ID);
139
140 if (llcp_cb.sdp_cb.p_snl) {
141 llcp_cb.sdp_cb.p_snl->offset =
142 NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE + LLCP_PDU_HEADER_SIZE;
143 llcp_cb.sdp_cb.p_snl->len = 0;
144 }
145 }
146
147 if (llcp_cb.sdp_cb.p_snl) {
148 available_bytes = GKI_get_buf_size(llcp_cb.sdp_cb.p_snl) - NFC_HDR_SIZE -
149 llcp_cb.sdp_cb.p_snl->offset - llcp_cb.sdp_cb.p_snl->len;
150
151 name_len = (uint16_t)strlen(p_name);
152
153 /* if SDREQ parameter can be added in SNL */
154 if ((available_bytes >= LLCP_SDREQ_MIN_LEN + name_len) &&
155 (llcp_cb.sdp_cb.p_snl->len + LLCP_SDREQ_MIN_LEN + name_len <=
156 llcp_cb.lcb.effective_miu)) {
157 llcp_sdp_add_sdreq(tid, p_name);
158 status = LLCP_STATUS_SUCCESS;
159 } else {
160 /* send pending SNL PDU to LM */
161 llcp_sdp_check_send_snl();
162
163 llcp_cb.sdp_cb.p_snl = (NFC_HDR*)GKI_getpoolbuf(LLCP_POOL_ID);
164
165 if (llcp_cb.sdp_cb.p_snl) {
166 llcp_cb.sdp_cb.p_snl->offset =
167 NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE + LLCP_PDU_HEADER_SIZE;
168 llcp_cb.sdp_cb.p_snl->len = 0;
169
170 llcp_sdp_add_sdreq(tid, p_name);
171
172 status = LLCP_STATUS_SUCCESS;
173 } else {
174 status = LLCP_STATUS_FAIL;
175 }
176 }
177 } else {
178 status = LLCP_STATUS_FAIL;
179 }
180
181 /* if LM is waiting for PDUs from upper layer */
182 if ((status == LLCP_STATUS_SUCCESS) &&
183 (llcp_cb.lcb.symm_state == LLCP_LINK_SYMM_LOCAL_XMIT_NEXT)) {
184 llcp_link_check_send_data();
185 }
186
187 return status;
188 }
189
190 /*******************************************************************************
191 **
192 ** Function llcp_sdp_add_sdres
193 **
194 ** Description Add Service Discovery Response into SNL PDU
195 **
196 **
197 ** Returns void
198 **
199 *******************************************************************************/
llcp_sdp_add_sdres(uint8_t tid,uint8_t sap)200 static void llcp_sdp_add_sdres(uint8_t tid, uint8_t sap) {
201 uint8_t* p;
202
203 p = (uint8_t*)(llcp_cb.sdp_cb.p_snl + 1) + llcp_cb.sdp_cb.p_snl->offset +
204 llcp_cb.sdp_cb.p_snl->len;
205
206 UINT8_TO_BE_STREAM(p, LLCP_SDRES_TYPE);
207 UINT8_TO_BE_STREAM(p, LLCP_SDRES_LEN);
208 UINT8_TO_BE_STREAM(p, tid);
209 UINT8_TO_BE_STREAM(p, sap);
210
211 llcp_cb.sdp_cb.p_snl->len += 2 + LLCP_SDRES_LEN; /* type and length */
212 }
213
214 /*******************************************************************************
215 **
216 ** Function llcp_sdp_send_sdres
217 **
218 ** Description Send Service Discovery Response
219 **
220 **
221 ** Returns LLCP_STATUS
222 **
223 *******************************************************************************/
llcp_sdp_send_sdres(uint8_t tid,uint8_t sap)224 static tLLCP_STATUS llcp_sdp_send_sdres(uint8_t tid, uint8_t sap) {
225 tLLCP_STATUS status;
226 uint16_t available_bytes;
227
228 DLOG_IF(INFO, nfc_debug_enabled)
229 << StringPrintf("tid=0x%x, SAP=0x%x", tid, sap);
230
231 /* if there is no pending SNL */
232 if (!llcp_cb.sdp_cb.p_snl) {
233 llcp_cb.sdp_cb.p_snl = (NFC_HDR*)GKI_getpoolbuf(LLCP_POOL_ID);
234
235 if (llcp_cb.sdp_cb.p_snl) {
236 llcp_cb.sdp_cb.p_snl->offset =
237 NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE + LLCP_PDU_HEADER_SIZE;
238 llcp_cb.sdp_cb.p_snl->len = 0;
239 }
240 }
241
242 if (llcp_cb.sdp_cb.p_snl) {
243 available_bytes = GKI_get_buf_size(llcp_cb.sdp_cb.p_snl) - NFC_HDR_SIZE -
244 llcp_cb.sdp_cb.p_snl->offset - llcp_cb.sdp_cb.p_snl->len;
245
246 /* if SDRES parameter can be added in SNL */
247 if ((available_bytes >= 2 + LLCP_SDRES_LEN) &&
248 (llcp_cb.sdp_cb.p_snl->len + 2 + LLCP_SDRES_LEN <=
249 llcp_cb.lcb.effective_miu)) {
250 llcp_sdp_add_sdres(tid, sap);
251 status = LLCP_STATUS_SUCCESS;
252 } else {
253 /* send pending SNL PDU to LM */
254 llcp_sdp_check_send_snl();
255
256 llcp_cb.sdp_cb.p_snl = (NFC_HDR*)GKI_getpoolbuf(LLCP_POOL_ID);
257
258 if (llcp_cb.sdp_cb.p_snl) {
259 llcp_cb.sdp_cb.p_snl->offset =
260 NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE + LLCP_PDU_HEADER_SIZE;
261 llcp_cb.sdp_cb.p_snl->len = 0;
262
263 llcp_sdp_add_sdres(tid, sap);
264
265 status = LLCP_STATUS_SUCCESS;
266 } else {
267 status = LLCP_STATUS_FAIL;
268 }
269 }
270 } else {
271 status = LLCP_STATUS_FAIL;
272 }
273
274 /* if LM is waiting for PDUs from upper layer */
275 if ((status == LLCP_STATUS_SUCCESS) &&
276 (llcp_cb.lcb.symm_state == LLCP_LINK_SYMM_LOCAL_XMIT_NEXT)) {
277 llcp_link_check_send_data();
278 }
279
280 return status;
281 }
282
283 /*******************************************************************************
284 **
285 ** Function llcp_sdp_get_sap_by_name
286 **
287 ** Description Search SAP by service name
288 **
289 **
290 ** Returns SAP if success
291 **
292 *******************************************************************************/
llcp_sdp_get_sap_by_name(char * p_name,uint8_t length)293 uint8_t llcp_sdp_get_sap_by_name(char* p_name, uint8_t length) {
294 uint8_t sap;
295 tLLCP_APP_CB* p_app_cb;
296
297 for (sap = LLCP_SAP_SDP; sap <= LLCP_UPPER_BOUND_SDP_SAP; sap++) {
298 p_app_cb = llcp_util_get_app_cb(sap);
299
300 if ((p_app_cb) && (p_app_cb->p_app_cback) &&
301 (strlen((char*)p_app_cb->p_service_name) == length) &&
302 (!strncmp((char*)p_app_cb->p_service_name, p_name, length))) {
303 /* if device is under LLCP DTA testing */
304 if (llcp_cb.p_dta_cback && (!strncmp((char*)p_app_cb->p_service_name,
305 "urn:nfc:sn:cl-echo-in", length))) {
306 llcp_cb.dta_snl_resp = true;
307 }
308
309 return (sap);
310 }
311 }
312 return 0;
313 }
314
315 /*******************************************************************************
316 **
317 ** Function llcp_sdp_return_sap
318 **
319 ** Description Report TID and SAP to requester
320 **
321 **
322 ** Returns void
323 **
324 *******************************************************************************/
llcp_sdp_return_sap(uint8_t tid,uint8_t sap)325 static void llcp_sdp_return_sap(uint8_t tid, uint8_t sap) {
326 uint8_t i;
327
328 DLOG_IF(INFO, nfc_debug_enabled)
329 << StringPrintf("tid=0x%x, SAP=0x%x", tid, sap);
330
331 for (i = 0; i < LLCP_MAX_SDP_TRANSAC; i++) {
332 if ((llcp_cb.sdp_cb.transac[i].p_cback) &&
333 (llcp_cb.sdp_cb.transac[i].tid == tid)) {
334 (*llcp_cb.sdp_cb.transac[i].p_cback)(tid, sap);
335
336 llcp_cb.sdp_cb.transac[i].p_cback = nullptr;
337 }
338 }
339 }
340
341 /*******************************************************************************
342 **
343 ** Function llcp_sdp_proc_deactivation
344 **
345 ** Description Report SDP failure for any pending request because of
346 ** deactivation
347 **
348 **
349 ** Returns void
350 **
351 *******************************************************************************/
llcp_sdp_proc_deactivation(void)352 void llcp_sdp_proc_deactivation(void) {
353 uint8_t i;
354
355 DLOG_IF(INFO, nfc_debug_enabled) << __func__;
356
357 for (i = 0; i < LLCP_MAX_SDP_TRANSAC; i++) {
358 if (llcp_cb.sdp_cb.transac[i].p_cback) {
359 (*llcp_cb.sdp_cb.transac[i].p_cback)(llcp_cb.sdp_cb.transac[i].tid, 0x00);
360
361 llcp_cb.sdp_cb.transac[i].p_cback = nullptr;
362 }
363 }
364
365 /* free any pending SNL PDU */
366 if (llcp_cb.sdp_cb.p_snl) {
367 GKI_freebuf(llcp_cb.sdp_cb.p_snl);
368 llcp_cb.sdp_cb.p_snl = nullptr;
369 }
370
371 llcp_cb.sdp_cb.next_tid = 0;
372 llcp_cb.dta_snl_resp = false;
373 }
374
375 /*******************************************************************************
376 **
377 ** Function llcp_sdp_proc_snl
378 **
379 ** Description Process SDREQ and SDRES in SNL
380 **
381 **
382 ** Returns LLCP_STATUS
383 **
384 *******************************************************************************/
llcp_sdp_proc_snl(uint16_t sdu_length,uint8_t * p)385 tLLCP_STATUS llcp_sdp_proc_snl(uint16_t sdu_length, uint8_t* p) {
386 uint8_t type, length, tid, sap, *p_value;
387
388 DLOG_IF(INFO, nfc_debug_enabled) << __func__;
389
390 if ((llcp_cb.lcb.agreed_major_version < LLCP_MIN_SNL_MAJOR_VERSION) ||
391 ((llcp_cb.lcb.agreed_major_version == LLCP_MIN_SNL_MAJOR_VERSION) &&
392 (llcp_cb.lcb.agreed_minor_version < LLCP_MIN_SNL_MINOR_VERSION))) {
393 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
394 "version number less than 1.1, SNL not "
395 "supported.");
396 return LLCP_STATUS_FAIL;
397 }
398 while (sdu_length >= 2) /* at least type and length */
399 {
400 BE_STREAM_TO_UINT8(type, p);
401 BE_STREAM_TO_UINT8(length, p);
402
403 switch (type) {
404 case LLCP_SDREQ_TYPE:
405 if ((length > 1) /* TID and sevice name */
406 &&
407 (sdu_length >= 2 + length)) /* type, length, TID and service name */
408 {
409 p_value = p;
410 BE_STREAM_TO_UINT8(tid, p_value);
411 sap = llcp_sdp_get_sap_by_name((char*)p_value, (uint8_t)(length - 1));
412 /* fix to pass TC_CTO_TAR_BI_03_x (x=5) test case
413 * As per the LLCP test specification v1.2.00 by receiving erroneous
414 * SNL PDU i'e with improper service name "urn:nfc:sn:dta-co-echo-in",
415 * the IUT should not send any PDU except SYMM PDU */
416 if (appl_dta_mode_flag == 1 && sap == 0x00) {
417 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
418 "%s: In dta mode sap == 0x00 p_value = %s", __func__, p_value);
419 if ((length - 1) == strlen((const char*)p_value)) {
420 DLOG_IF(INFO, nfc_debug_enabled)
421 << StringPrintf("%s: Strings are not equal", __func__);
422 llcp_sdp_send_sdres(tid, sap);
423 }
424 } else {
425 llcp_sdp_send_sdres(tid, sap);
426 }
427 } else {
428 /*For P2P in LLCP mode TC_CTO_TAR_BI_03_x(x=3) fix*/
429 if (appl_dta_mode_flag == 1 &&
430 ((nfa_dm_cb.eDtaMode & 0x0F) == NFA_DTA_LLCP_MODE)) {
431 LOG(ERROR) << StringPrintf("%s: Calling llcp_sdp_send_sdres",
432 __func__);
433 tid = 0x01;
434 sap = 0x00;
435 llcp_sdp_send_sdres(tid, sap);
436 }
437 LOG(ERROR) << StringPrintf("bad length (%d) in LLCP_SDREQ_TYPE",
438 length);
439 }
440 break;
441
442 case LLCP_SDRES_TYPE:
443 if ((length == LLCP_SDRES_LEN) /* TID and SAP */
444 && (sdu_length >= 2 + length)) /* type, length, TID and SAP */
445 {
446 p_value = p;
447 BE_STREAM_TO_UINT8(tid, p_value);
448 BE_STREAM_TO_UINT8(sap, p_value);
449 llcp_sdp_return_sap(tid, sap);
450 } else {
451 LOG(ERROR) << StringPrintf("bad length (%d) in LLCP_SDRES_TYPE",
452 length);
453 }
454 break;
455
456 default:
457 LOG(WARNING) << StringPrintf("Unknown type (0x%x) is ignored", type);
458 break;
459 }
460
461 if (sdu_length >= 2 + length) /* type, length, value */
462 {
463 sdu_length -= 2 + length;
464 p += length;
465 } else {
466 break;
467 }
468 }
469
470 if (sdu_length) {
471 LOG(ERROR) << StringPrintf("Bad format of SNL");
472 return LLCP_STATUS_FAIL;
473 } else {
474 return LLCP_STATUS_SUCCESS;
475 }
476 }
477