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