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