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