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
36using android::base::StringPrintf;
37
38extern 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*******************************************************************************/
50void 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*******************************************************************************/
68void 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 = NULL;
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*******************************************************************************/
103static 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*******************************************************************************/
128tLLCP_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*******************************************************************************/
200static 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*******************************************************************************/
224static 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*******************************************************************************/
293uint8_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*******************************************************************************/
325static 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 = NULL;
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*******************************************************************************/
352void 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 = NULL;
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 = NULL;
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*******************************************************************************/
385tLLCP_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