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