• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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