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