1 /******************************************************************************
2 *
3 * Copyright (C) 1999-2012 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 SDP interface functions
22 *
23 ******************************************************************************/
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28
29 #include "bt_target.h"
30 #include "bt_utils.h"
31 #include "gki.h"
32 #include "l2cdefs.h"
33 #include "hcidefs.h"
34 #include "hcimsgs.h"
35
36 #include "sdp_api.h"
37 #include "sdpint.h"
38 #include "btu.h"
39
40 /**********************************************************************
41 ** C L I E N T F U N C T I O N P R O T O T Y P E S *
42 ***********************************************************************/
43
44 /*******************************************************************************
45 **
46 ** Function SDP_InitDiscoveryDb
47 **
48 ** Description This function is called to initialize a discovery database.
49 **
50 ** Parameters: p_db - (input) address of an area of memory where the
51 ** discovery database is managed.
52 ** len - (input) size (in bytes) of the memory
53 ** NOTE: This must be larger than sizeof(tSDP_DISCOVERY_DB)
54 ** num_uuid - (input) number of UUID filters applied
55 ** p_uuid_list - (input) list of UUID filters
56 ** num_attr - (input) number of attribute filters applied
57 ** p_attr_list - (input) list of attribute filters
58 **
59 **
60 ** Returns BOOLEAN
61 ** TRUE if successful
62 ** FALSE if one or more parameters are bad
63 **
64 *******************************************************************************/
SDP_InitDiscoveryDb(tSDP_DISCOVERY_DB * p_db,UINT32 len,UINT16 num_uuid,tSDP_UUID * p_uuid_list,UINT16 num_attr,UINT16 * p_attr_list)65 BOOLEAN SDP_InitDiscoveryDb (tSDP_DISCOVERY_DB *p_db, UINT32 len, UINT16 num_uuid,
66 tSDP_UUID *p_uuid_list, UINT16 num_attr, UINT16 *p_attr_list)
67 {
68 #if SDP_CLIENT_ENABLED == TRUE
69 UINT16 xx;
70
71 /* verify the parameters */
72 if (p_db == NULL || (sizeof (tSDP_DISCOVERY_DB) > len) ||
73 num_attr > SDP_MAX_ATTR_FILTERS || num_uuid > SDP_MAX_UUID_FILTERS)
74 {
75 SDP_TRACE_ERROR("SDP_InitDiscoveryDb Illegal param: p_db 0x%x, len %d, num_uuid %d, num_attr %d",
76 (UINT32)p_db, len, num_uuid, num_attr);
77
78 return(FALSE);
79 }
80
81 memset (p_db, 0, (size_t)len);
82
83 p_db->mem_size = len - sizeof (tSDP_DISCOVERY_DB);
84 p_db->mem_free = p_db->mem_size;
85 p_db->p_first_rec = NULL;
86 p_db->p_free_mem = (UINT8 *)(p_db + 1);
87
88 for (xx = 0; xx < num_uuid; xx++)
89 p_db->uuid_filters[xx] = *p_uuid_list++;
90
91 p_db->num_uuid_filters = num_uuid;
92
93 for (xx = 0; xx < num_attr; xx++)
94 p_db->attr_filters[xx] = *p_attr_list++;
95
96 /* sort attributes */
97 sdpu_sort_attr_list( num_attr, p_db );
98
99 p_db->num_attr_filters = num_attr;
100 #endif
101 return(TRUE);
102 }
103
104
105
106 /*******************************************************************************
107 **
108 ** Function SDP_CancelServiceSearch
109 **
110 ** Description This function cancels an active query to an SDP server.
111 **
112 ** Returns TRUE if discovery cancelled, FALSE if a matching activity is not found.
113 **
114 *******************************************************************************/
SDP_CancelServiceSearch(tSDP_DISCOVERY_DB * p_db)115 BOOLEAN SDP_CancelServiceSearch (tSDP_DISCOVERY_DB *p_db)
116 {
117 #if SDP_CLIENT_ENABLED == TRUE
118 tCONN_CB *p_ccb = sdpu_find_ccb_by_db (p_db);
119 if (!p_ccb)
120 return(FALSE);
121
122 sdp_disconnect (p_ccb, SDP_CANCEL);
123 p_ccb->disc_state = SDP_DISC_WAIT_CANCEL;
124 #endif
125 return(TRUE);
126 }
127
128
129
130 /*******************************************************************************
131 **
132 ** Function SDP_ServiceSearchRequest
133 **
134 ** Description This function queries an SDP server for information.
135 **
136 ** Returns TRUE if discovery started, FALSE if failed.
137 **
138 *******************************************************************************/
SDP_ServiceSearchRequest(UINT8 * p_bd_addr,tSDP_DISCOVERY_DB * p_db,tSDP_DISC_CMPL_CB * p_cb)139 BOOLEAN SDP_ServiceSearchRequest (UINT8 *p_bd_addr, tSDP_DISCOVERY_DB *p_db,
140 tSDP_DISC_CMPL_CB *p_cb)
141 {
142 #if SDP_CLIENT_ENABLED == TRUE
143 tCONN_CB *p_ccb;
144
145 /* Specific BD address */
146 p_ccb = sdp_conn_originate (p_bd_addr);
147
148 if (!p_ccb)
149 return(FALSE);
150
151 p_ccb->disc_state = SDP_DISC_WAIT_CONN;
152 p_ccb->p_db = p_db;
153 p_ccb->p_cb = p_cb;
154
155 return(TRUE);
156 #else
157 return(FALSE);
158 #endif
159 }
160
161
162 /*******************************************************************************
163 **
164 ** Function SDP_ServiceSearchAttributeRequest
165 **
166 ** Description This function queries an SDP server for information.
167 **
168 ** The difference between this API function and the function
169 ** SDP_ServiceSearchRequest is that this one does a
170 ** combined ServiceSearchAttributeRequest SDP function.
171 ** (This is for Unplug Testing)
172 **
173 ** Returns TRUE if discovery started, FALSE if failed.
174 **
175 *******************************************************************************/
SDP_ServiceSearchAttributeRequest(UINT8 * p_bd_addr,tSDP_DISCOVERY_DB * p_db,tSDP_DISC_CMPL_CB * p_cb)176 BOOLEAN SDP_ServiceSearchAttributeRequest (UINT8 *p_bd_addr, tSDP_DISCOVERY_DB *p_db,
177 tSDP_DISC_CMPL_CB *p_cb)
178 {
179 #if SDP_CLIENT_ENABLED == TRUE
180 tCONN_CB *p_ccb;
181
182 /* Specific BD address */
183 p_ccb = sdp_conn_originate (p_bd_addr);
184
185 if (!p_ccb)
186 return(FALSE);
187
188 p_ccb->disc_state = SDP_DISC_WAIT_CONN;
189 p_ccb->p_db = p_db;
190 p_ccb->p_cb = p_cb;
191
192 p_ccb->is_attr_search = TRUE;
193
194 return(TRUE);
195 #else
196 return(FALSE);
197 #endif
198 }
199 /*******************************************************************************
200 **
201 ** Function SDP_ServiceSearchAttributeRequest2
202 **
203 ** Description This function queries an SDP server for information.
204 **
205 ** The difference between this API function and the function
206 ** SDP_ServiceSearchRequest is that this one does a
207 ** combined ServiceSearchAttributeRequest SDP function.
208 ** (This is for Unplug Testing)
209 **
210 ** Returns TRUE if discovery started, FALSE if failed.
211 **
212 *******************************************************************************/
SDP_ServiceSearchAttributeRequest2(UINT8 * p_bd_addr,tSDP_DISCOVERY_DB * p_db,tSDP_DISC_CMPL_CB2 * p_cb2,void * user_data)213 BOOLEAN SDP_ServiceSearchAttributeRequest2 (UINT8 *p_bd_addr, tSDP_DISCOVERY_DB *p_db,
214 tSDP_DISC_CMPL_CB2 *p_cb2, void * user_data)
215 {
216 #if SDP_CLIENT_ENABLED == TRUE
217 tCONN_CB *p_ccb;
218
219 /* Specific BD address */
220 p_ccb = sdp_conn_originate (p_bd_addr);
221
222 if (!p_ccb)
223 return(FALSE);
224
225 p_ccb->disc_state = SDP_DISC_WAIT_CONN;
226 p_ccb->p_db = p_db;
227 p_ccb->p_cb2 = p_cb2;
228
229 p_ccb->is_attr_search = TRUE;
230 p_ccb->user_data = user_data;
231
232 return(TRUE);
233 #else
234 return(FALSE);
235 #endif
236 }
237
238 #if SDP_CLIENT_ENABLED == TRUE
SDP_SetIdleTimeout(BD_ADDR addr,UINT16 timeout)239 void SDP_SetIdleTimeout (BD_ADDR addr, UINT16 timeout)
240 {
241 UNUSED(addr);
242 UNUSED(timeout);
243 }
244 #endif
245
246 /*******************************************************************************
247 **
248 ** Function SDP_FindAttributeInDb
249 **
250 ** Description This function queries an SDP database for a specific attribute.
251 ** If the p_start_rec pointer is NULL, it looks from the beginning
252 ** of the database, else it continues from the next record after
253 ** p_start_rec.
254 **
255 ** Returns Pointer to matching record, or NULL
256 **
257 *******************************************************************************/
SDP_FindAttributeInDb(tSDP_DISCOVERY_DB * p_db,UINT16 attr_id,tSDP_DISC_REC * p_start_rec)258 tSDP_DISC_REC *SDP_FindAttributeInDb (tSDP_DISCOVERY_DB *p_db, UINT16 attr_id,
259 tSDP_DISC_REC *p_start_rec)
260 {
261 #if SDP_CLIENT_ENABLED == TRUE
262 tSDP_DISC_REC *p_rec;
263 tSDP_DISC_ATTR *p_attr;
264
265 /* Must have a valid database */
266 if (p_db == NULL)
267 return(NULL);
268
269 if (!p_start_rec)
270 p_rec = p_db->p_first_rec;
271 else
272 p_rec = p_start_rec->p_next_rec;
273
274 while (p_rec)
275 {
276 p_attr = p_rec->p_first_attr;
277 while (p_attr)
278 {
279 if (p_attr->attr_id == attr_id)
280 return(p_rec);
281
282 p_attr = p_attr->p_next_attr;
283 }
284
285 p_rec = p_rec->p_next_rec;
286 }
287 #endif
288 /* If here, no matching attribute found */
289 return(NULL);
290 }
291
292
293 /*******************************************************************************
294 **
295 ** Function SDP_FindAttributeInRec
296 **
297 ** Description This function searches an SDP discovery record for a specific
298 ** attribute.
299 **
300 ** Returns Pointer to matching attribute entry, or NULL
301 **
302 *******************************************************************************/
SDP_FindAttributeInRec(tSDP_DISC_REC * p_rec,UINT16 attr_id)303 tSDP_DISC_ATTR *SDP_FindAttributeInRec (tSDP_DISC_REC *p_rec, UINT16 attr_id)
304 {
305 #if SDP_CLIENT_ENABLED == TRUE
306 tSDP_DISC_ATTR *p_attr;
307
308 p_attr = p_rec->p_first_attr;
309 while (p_attr)
310 {
311 if (p_attr->attr_id == attr_id)
312 return(p_attr);
313
314 p_attr = p_attr->p_next_attr;
315 }
316 #endif
317 /* If here, no matching attribute found */
318 return(NULL);
319 }
320
321 /*******************************************************************************
322 **
323 ** Function SDP_FindServiceUUIDInRec
324 **
325 ** Description This function is called to read the service UUID within a record
326 ** if there is any.
327 **
328 ** Parameters: p_rec - pointer to a SDP record.
329 ** p_uuid - output parameter to save the UUID found.
330 **
331 ** Returns TRUE if found, otherwise FALSE.
332 **
333 *******************************************************************************/
SDP_FindServiceUUIDInRec(tSDP_DISC_REC * p_rec,tBT_UUID * p_uuid)334 BOOLEAN SDP_FindServiceUUIDInRec(tSDP_DISC_REC *p_rec, tBT_UUID * p_uuid)
335 {
336 #if SDP_CLIENT_ENABLED == TRUE
337 tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr;
338
339 p_attr = p_rec->p_first_attr;
340
341 while (p_attr)
342 {
343 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
344 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
345 {
346 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
347 {
348 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
349 {
350 if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_16)
351 {
352 p_uuid->len = LEN_UUID_16;
353 p_uuid->uu.uuid16 = p_sattr->attr_value.v.u16;
354 }
355 else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_128)
356 {
357 p_uuid->len = LEN_UUID_128;
358 for (uint8_t i = 0; i != LEN_UUID_128; ++i)
359 p_uuid->uu.uuid128[i] = p_sattr->attr_value.v.array[LEN_UUID_128-i-1];
360 }
361 else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_32)
362 {
363 p_uuid->len = LEN_UUID_32;
364 p_uuid->uu.uuid32 = p_sattr->attr_value.v.u32;
365 }
366
367 return(TRUE);
368 }
369
370 /* Checking for Toyota G Block Car Kit:
371 ** This car kit puts an extra data element sequence
372 ** where the UUID is suppose to be!!!
373 */
374 else
375 {
376 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)
377 {
378 /* Look through data element sequence until no more UUIDs */
379 for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr)
380 {
381 /* Increment past this to see if the next attribut is UUID */
382 if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE)
383 /* only support 16 bits UUID for now */
384 && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2))
385 {
386 p_uuid->len = 2;
387 p_uuid->uu.uuid16 = p_extra_sattr->attr_value.v.u16;
388 return(TRUE);
389 }
390 }
391 }
392 }
393 }
394 break;
395 }
396 else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
397 {
398 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
399 /* only support 16 bits UUID for now */
400 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2))
401 {
402 p_uuid->len = 2;
403 p_uuid->uu.uuid16 = p_attr->attr_value.v.u16;
404 return(TRUE);
405 }
406 }
407 p_attr = p_attr->p_next_attr;
408 }
409 return FALSE;
410 #endif
411 }
412
413 /*******************************************************************************
414 **
415 ** Function SDP_FindServiceUUIDInRec_128bit
416 **
417 ** Description This function is called to read the 128-bit service UUID within a record
418 ** if there is any.
419 **
420 ** Parameters: p_rec - pointer to a SDP record.
421 ** p_uuid - output parameter to save the UUID found.
422 **
423 ** Returns TRUE if found, otherwise FALSE.
424 **
425 *******************************************************************************/
SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC * p_rec,tBT_UUID * p_uuid)426 BOOLEAN SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC *p_rec, tBT_UUID * p_uuid)
427 {
428 #if SDP_CLIENT_ENABLED == TRUE
429 tSDP_DISC_ATTR *p_attr, *p_sattr;
430
431 p_attr = p_rec->p_first_attr;
432
433 while (p_attr)
434 {
435 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
436 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
437 {
438 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
439 {
440 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
441 {
442 /* only support 128 bits UUID for now */
443 if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16)
444 {
445 p_uuid->len = LEN_UUID_128;
446 for (uint8_t i = 0; i != LEN_UUID_128; ++i)
447 p_uuid->uu.uuid128[i] = p_sattr->attr_value.v.array[LEN_UUID_128-i-1];
448 }
449 return(TRUE);
450 }
451 }
452 break;
453 }
454 else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
455 {
456 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
457 /* only support 128 bits UUID for now */
458 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16))
459 {
460 p_uuid->len = LEN_UUID_128;
461 for (uint8_t i = 0; i != LEN_UUID_128; ++i)
462 p_uuid->uu.uuid128[i] = p_attr->attr_value.v.array[LEN_UUID_128-i-1];
463 return(TRUE);
464 }
465 }
466 p_attr = p_attr->p_next_attr;
467 }
468 return FALSE;
469 #endif
470 }
471
472 /*******************************************************************************
473 **
474 ** Function SDP_FindServiceInDb
475 **
476 ** Description This function queries an SDP database for a specific service.
477 ** If the p_start_rec pointer is NULL, it looks from the beginning
478 ** of the database, else it continues from the next record after
479 ** p_start_rec.
480 **
481 ** Returns Pointer to record containing service class, or NULL
482 **
483 *******************************************************************************/
SDP_FindServiceInDb(tSDP_DISCOVERY_DB * p_db,UINT16 service_uuid,tSDP_DISC_REC * p_start_rec)484 tSDP_DISC_REC *SDP_FindServiceInDb (tSDP_DISCOVERY_DB *p_db, UINT16 service_uuid, tSDP_DISC_REC *p_start_rec)
485 {
486 #if SDP_CLIENT_ENABLED == TRUE
487 tSDP_DISC_REC *p_rec;
488 tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr;
489
490 /* Must have a valid database */
491 if (p_db == NULL)
492 return(NULL);
493
494 if (!p_start_rec)
495 p_rec = p_db->p_first_rec;
496 else
497 p_rec = p_start_rec->p_next_rec;
498
499 while (p_rec)
500 {
501 p_attr = p_rec->p_first_attr;
502 while (p_attr)
503 {
504 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
505 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
506 {
507 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
508 {
509
510 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
511 && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) ) {
512 SDP_TRACE_DEBUG("SDP_FindServiceInDb - p_sattr value = 0x%x serviceuuid = 0x%x\r\n",
513 p_sattr->attr_value.v.u16, service_uuid);
514 if(service_uuid == UUID_SERVCLASS_HDP_PROFILE)
515 {
516 if( (p_sattr->attr_value.v.u16==UUID_SERVCLASS_HDP_SOURCE) || ( p_sattr->attr_value.v.u16==UUID_SERVCLASS_HDP_SINK))
517 {
518 SDP_TRACE_DEBUG("SDP_FindServiceInDb found HDP source or sink\n" );
519 return (p_rec);
520 }
521 }
522
523 }
524
525 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE && (service_uuid == 0
526 || (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2
527 && p_sattr->attr_value.v.u16 == service_uuid)))
528 /* for a specific uuid, or any one */
529 {
530 return(p_rec);
531 }
532
533 /* Checking for Toyota G Block Car Kit:
534 ** This car kit puts an extra data element sequence
535 ** where the UUID is suppose to be!!!
536 */
537 else
538 {
539 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)
540 {
541 /* Look through data element sequence until no more UUIDs */
542 for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr)
543 {
544 /* Increment past this to see if the next attribut is UUID */
545 if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE)
546 && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2)
547 /* for a specific uuid, or any one */
548 && ((p_extra_sattr->attr_value.v.u16 == service_uuid) || (service_uuid == 0)))
549 {
550 return(p_rec);
551 }
552 }
553 }
554 }
555 }
556 break;
557 }
558 else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
559 {
560 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
561 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)
562 /* find a specific UUID or anyone */
563 && ((p_attr->attr_value.v.u16 == service_uuid) || service_uuid == 0))
564 return(p_rec);
565 }
566
567 p_attr = p_attr->p_next_attr;
568 }
569
570 p_rec = p_rec->p_next_rec;
571 }
572 #endif
573 /* If here, no matching UUID found */
574 return(NULL);
575 }
576
577 /*******************************************************************************
578 **
579 ** Function SDP_FindServiceInDb_128bit
580 **
581 ** Description This function queries an SDP database for a specific service.
582 ** If the p_start_rec pointer is NULL, it looks from the beginning
583 ** of the database, else it continues from the next record after
584 ** p_start_rec.
585 **
586 ** This function is kept separate from SDP_FindServiceInDb since
587 ** that API is expected to return only 16-bit UUIDs
588 **
589 ** Returns Pointer to record containing service class, or NULL
590 **
591 *******************************************************************************/
SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB * p_db,tSDP_DISC_REC * p_start_rec)592 tSDP_DISC_REC *SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_start_rec)
593 {
594 #if SDP_CLIENT_ENABLED == TRUE
595 tSDP_DISC_REC *p_rec;
596 tSDP_DISC_ATTR *p_attr, *p_sattr;
597
598 /* Must have a valid database */
599 if (p_db == NULL)
600 return(NULL);
601
602 if (!p_start_rec)
603 p_rec = p_db->p_first_rec;
604 else
605 p_rec = p_start_rec->p_next_rec;
606
607 while (p_rec)
608 {
609 p_attr = p_rec->p_first_attr;
610 while (p_attr)
611 {
612 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
613 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
614 {
615 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
616 {
617 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
618 && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16))
619 {
620 return(p_rec);
621 }
622 }
623 break;
624 }
625 else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
626 {
627 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
628 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16))
629 return(p_rec);
630 }
631
632 p_attr = p_attr->p_next_attr;
633 }
634
635 p_rec = p_rec->p_next_rec;
636 }
637 #endif
638 /* If here, no matching UUID found */
639 return(NULL);
640 }
641
642
643 /*******************************************************************************
644 **
645 ** Function SDP_FindServiceUUIDInDb
646 **
647 ** Description This function queries an SDP database for a specific service.
648 ** If the p_start_rec pointer is NULL, it looks from the beginning
649 ** of the database, else it continues from the next record after
650 ** p_start_rec.
651 **
652 ** NOTE the only difference between this function and the previous function
653 ** "SDP_FindServiceInDb()" is that this function takes a tBT_UUID input
654 **
655 ** Returns Pointer to record containing service class, or NULL
656 **
657 *******************************************************************************/
SDP_FindServiceUUIDInDb(tSDP_DISCOVERY_DB * p_db,tBT_UUID * p_uuid,tSDP_DISC_REC * p_start_rec)658 tSDP_DISC_REC *SDP_FindServiceUUIDInDb (tSDP_DISCOVERY_DB *p_db, tBT_UUID *p_uuid, tSDP_DISC_REC *p_start_rec)
659 {
660 #if SDP_CLIENT_ENABLED == TRUE
661 tSDP_DISC_REC *p_rec;
662 tSDP_DISC_ATTR *p_attr, *p_sattr;
663
664 /* Must have a valid database */
665 if (p_db == NULL)
666 return(NULL);
667
668 if (!p_start_rec)
669 p_rec = p_db->p_first_rec;
670 else
671 p_rec = p_start_rec->p_next_rec;
672
673 while (p_rec)
674 {
675 p_attr = p_rec->p_first_attr;
676 while (p_attr)
677 {
678 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
679 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
680 {
681 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
682 {
683 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
684 {
685 if (sdpu_compare_uuid_with_attr (p_uuid, p_sattr))
686 return(p_rec);
687 }
688 }
689 break;
690 }
691 else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
692 {
693 if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE )
694 {
695 if (sdpu_compare_uuid_with_attr (p_uuid, p_attr))
696 return(p_rec);
697 }
698 }
699
700 p_attr = p_attr->p_next_attr;
701 }
702
703 p_rec = p_rec->p_next_rec;
704 }
705 #endif /* CLIENT_ENABLED == TRUE */
706 /* If here, no matching UUID found */
707 return(NULL);
708 }
709
710 #if SDP_CLIENT_ENABLED == TRUE
711 /*******************************************************************************
712 **
713 ** Function sdp_fill_proto_elem
714 **
715 ** Description This function retrieves the protocol element.
716 **
717 ** Returns TRUE if found, FALSE if not
718 ** If found, the passed protocol list element is filled in.
719 **
720 *******************************************************************************/
sdp_fill_proto_elem(tSDP_DISC_ATTR * p_attr,UINT16 layer_uuid,tSDP_PROTOCOL_ELEM * p_elem)721 static BOOLEAN sdp_fill_proto_elem( tSDP_DISC_ATTR *p_attr, UINT16 layer_uuid,
722 tSDP_PROTOCOL_ELEM *p_elem)
723 {
724 tSDP_DISC_ATTR *p_sattr;
725
726 /* Walk through the protocol descriptor list */
727 for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr)
728 {
729 /* Safety check - each entry should itself be a sequence */
730 if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
731 return(FALSE);
732
733 /* Now, see if the entry contains the layer we are interested in */
734 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
735 {
736 /* SDP_TRACE_DEBUG ("SDP - p_sattr 0x%x, layer_uuid:0x%x, u16:0x%x####",
737 p_sattr, layer_uuid, p_sattr->attr_value.v.u16); */
738
739 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
740 && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)
741 && (p_sattr->attr_value.v.u16 == layer_uuid))
742 {
743 /* Bingo. Now fill in the passed element */
744 p_elem->protocol_uuid = layer_uuid;
745 p_elem->num_params = 0;
746
747 /* Store the parameters, if any */
748 for (p_sattr = p_sattr->p_next_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
749 {
750 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) != UINT_DESC_TYPE)
751 break;
752
753 if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)
754 p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u16;
755 else
756 p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u8;
757
758 if (p_elem->num_params >= SDP_MAX_PROTOCOL_PARAMS)
759 break;
760 }
761 return(TRUE);
762 }
763 }
764 }
765
766 return(FALSE);
767 }
768 #endif /* CLIENT_ENABLED == TRUE */
769
770 /*******************************************************************************
771 **
772 ** Function SDP_FindProtocolListElemInRec
773 **
774 ** Description This function looks at a specific discovery record for a protocol
775 ** list element.
776 **
777 ** Returns TRUE if found, FALSE if not
778 ** If found, the passed protocol list element is filled in.
779 **
780 *******************************************************************************/
SDP_FindProtocolListElemInRec(tSDP_DISC_REC * p_rec,UINT16 layer_uuid,tSDP_PROTOCOL_ELEM * p_elem)781 BOOLEAN SDP_FindProtocolListElemInRec (tSDP_DISC_REC *p_rec, UINT16 layer_uuid, tSDP_PROTOCOL_ELEM *p_elem)
782 {
783 #if SDP_CLIENT_ENABLED == TRUE
784 tSDP_DISC_ATTR *p_attr;
785
786 p_attr = p_rec->p_first_attr;
787 while (p_attr)
788 {
789 /* Find the protocol descriptor list */
790 if ((p_attr->attr_id == ATTR_ID_PROTOCOL_DESC_LIST)
791 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
792 {
793 return sdp_fill_proto_elem(p_attr, layer_uuid, p_elem);
794 }
795 p_attr = p_attr->p_next_attr;
796 }
797 #endif
798 /* If here, no match found */
799 return(FALSE);
800 }
801
802
803 /*******************************************************************************
804 **
805 ** Function SDP_FindAddProtoListsElemInRec
806 **
807 ** Description This function looks at a specific discovery record for a protocol
808 ** list element.
809 **
810 ** Returns TRUE if found, FALSE if not
811 ** If found, the passed protocol list element is filled in.
812 **
813 *******************************************************************************/
SDP_FindAddProtoListsElemInRec(tSDP_DISC_REC * p_rec,UINT16 layer_uuid,tSDP_PROTOCOL_ELEM * p_elem)814 BOOLEAN SDP_FindAddProtoListsElemInRec (tSDP_DISC_REC *p_rec, UINT16 layer_uuid, tSDP_PROTOCOL_ELEM *p_elem)
815 {
816 #if SDP_CLIENT_ENABLED == TRUE
817 tSDP_DISC_ATTR *p_attr, *p_sattr;
818 BOOLEAN ret = FALSE;
819
820 p_attr = p_rec->p_first_attr;
821 while (p_attr)
822 {
823 /* Find the additional protocol descriptor list attribute */
824 if ((p_attr->attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS)
825 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
826 {
827 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
828 {
829 /* Safety check - each entry should itself be a sequence */
830 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)
831 {
832 if ( (ret = sdp_fill_proto_elem(p_sattr, layer_uuid, p_elem)) == TRUE)
833 break;
834 }
835 }
836 return ret;
837 }
838 p_attr = p_attr->p_next_attr;
839 }
840 #endif
841 /* If here, no match found */
842 return(FALSE);
843 }
844
845
846 /*******************************************************************************
847 **
848 ** Function SDP_FindProfileVersionInRec
849 **
850 ** Description This function looks at a specific discovery record for the
851 ** Profile list descriptor, and pulls out the version number.
852 ** The version number consists of an 8-bit major version and
853 ** an 8-bit minor version.
854 **
855 ** Returns TRUE if found, FALSE if not
856 ** If found, the major and minor version numbers that were passed
857 ** in are filled in.
858 **
859 *******************************************************************************/
SDP_FindProfileVersionInRec(tSDP_DISC_REC * p_rec,UINT16 profile_uuid,UINT16 * p_version)860 BOOLEAN SDP_FindProfileVersionInRec (tSDP_DISC_REC *p_rec, UINT16 profile_uuid, UINT16 *p_version)
861 {
862 #if SDP_CLIENT_ENABLED == TRUE
863 tSDP_DISC_ATTR *p_attr, *p_sattr;
864
865 p_attr = p_rec->p_first_attr;
866 while (p_attr)
867 {
868 /* Find the profile descriptor list */
869 if ((p_attr->attr_id == ATTR_ID_BT_PROFILE_DESC_LIST)
870 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
871 {
872 /* Walk through the protocol descriptor list */
873 for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr)
874 {
875 /* Safety check - each entry should itself be a sequence */
876 if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
877 return(FALSE);
878
879 /* Now, see if the entry contains the profile UUID we are interested in */
880 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
881 {
882 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
883 && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) /* <- This is bytes, not size code! */
884 && (p_sattr->attr_value.v.u16 == profile_uuid))
885 {
886 /* Now fill in the major and minor numbers */
887 /* if the attribute matches the description for version (type UINT, size 2 bytes) */
888 p_sattr = p_sattr->p_next_attr;
889
890 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UINT_DESC_TYPE) &&
891 (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2))
892 {
893 /* The high order 8 bits is the major number, low order is the minor number (big endian) */
894 *p_version = p_sattr->attr_value.v.u16;
895
896 return(TRUE);
897 }
898 else
899 return(FALSE); /* The type and/or size was not valid for the profile list version */
900 }
901 }
902 }
903
904 return(FALSE);
905 }
906 p_attr = p_attr->p_next_attr;
907 }
908 #endif /* CLIENT_ENABLED == TRUE */
909
910 /* If here, no match found */
911 return(FALSE);
912 }
913
914 /*******************************************************************************
915 ** Device Identification (DI) Client Functions
916 *******************************************************************************/
917
918 /*******************************************************************************
919 **
920 ** Function SDP_DiDiscover
921 **
922 ** Description This function queries a remote device for DI information.
923 **
924 ** Returns SDP_SUCCESS if query started successfully, else error
925 **
926 *******************************************************************************/
SDP_DiDiscover(BD_ADDR remote_device,tSDP_DISCOVERY_DB * p_db,UINT32 len,tSDP_DISC_CMPL_CB * p_cb)927 UINT16 SDP_DiDiscover( BD_ADDR remote_device, tSDP_DISCOVERY_DB *p_db,
928 UINT32 len, tSDP_DISC_CMPL_CB *p_cb )
929 {
930 #if SDP_CLIENT_ENABLED == TRUE
931 UINT16 result = SDP_DI_DISC_FAILED;
932 UINT16 num_uuids = 1;
933 UINT16 di_uuid = UUID_SERVCLASS_PNP_INFORMATION;
934
935 /* build uuid for db init */
936 tSDP_UUID init_uuid;
937 init_uuid.len = 2;
938 init_uuid.uu.uuid16 = di_uuid;
939
940 if ( SDP_InitDiscoveryDb(p_db, len, num_uuids, &init_uuid, 0, NULL) )
941 if ( SDP_ServiceSearchRequest(remote_device, p_db, p_cb) )
942 result = SDP_SUCCESS;
943
944 return result;
945 #else
946 return SDP_DI_DISC_FAILED;
947 #endif
948 }
949
950 /*******************************************************************************
951 **
952 ** Function SDP_GetNumDiRecords
953 **
954 ** Description Searches specified database for DI records
955 **
956 ** Returns number of DI records found
957 **
958 *******************************************************************************/
SDP_GetNumDiRecords(tSDP_DISCOVERY_DB * p_db)959 UINT8 SDP_GetNumDiRecords( tSDP_DISCOVERY_DB *p_db )
960 {
961 #if SDP_CLIENT_ENABLED == TRUE
962 UINT8 num_records = 0;
963 tSDP_DISC_REC *p_curr_record = NULL;
964
965 do
966 {
967 p_curr_record = SDP_FindServiceInDb( p_db, UUID_SERVCLASS_PNP_INFORMATION,
968 p_curr_record );
969 if ( p_curr_record )
970 num_records++;
971 }while ( p_curr_record );
972
973 return num_records;
974 #else
975 return 0;
976 #endif
977 }
978
979 /*******************************************************************************
980 **
981 ** Function SDP_AttrStringCopy
982 **
983 ** Description This function copy given attribute to specified buffer as a string
984 **
985 ** Returns none
986 **
987 *******************************************************************************/
SDP_AttrStringCopy(char * dst,tSDP_DISC_ATTR * p_attr,UINT16 dst_size)988 static void SDP_AttrStringCopy(char *dst, tSDP_DISC_ATTR *p_attr, UINT16 dst_size)
989 {
990 if ( dst == NULL ) return;
991 if ( p_attr )
992 {
993 UINT16 len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
994 if ( len > dst_size - 1 )
995 {
996 len = dst_size - 1;
997 }
998 memcpy(dst, (char *)p_attr->attr_value.v.array, len);
999 dst[len] = '\0';
1000 }
1001 else
1002 {
1003 dst[0] = '\0';
1004 }
1005 }
1006
1007 /*******************************************************************************
1008 **
1009 ** Function SDP_GetDiRecord
1010 **
1011 ** Description This function retrieves a remote device's DI record from
1012 ** the specified database.
1013 **
1014 ** Returns SDP_SUCCESS if record retrieved, else error
1015 **
1016 *******************************************************************************/
SDP_GetDiRecord(UINT8 get_record_index,tSDP_DI_GET_RECORD * p_device_info,tSDP_DISCOVERY_DB * p_db)1017 UINT16 SDP_GetDiRecord( UINT8 get_record_index, tSDP_DI_GET_RECORD *p_device_info,
1018 tSDP_DISCOVERY_DB *p_db )
1019 {
1020 #if SDP_CLIENT_ENABLED == TRUE
1021 UINT16 result = SDP_NO_DI_RECORD_FOUND;
1022 UINT8 curr_record_index = 1;
1023
1024 tSDP_DISC_REC *p_curr_record = NULL;
1025
1026 /* find the requested SDP record in the discovery database */
1027 do
1028 {
1029 p_curr_record = SDP_FindServiceInDb( p_db, UUID_SERVCLASS_PNP_INFORMATION,
1030 p_curr_record );
1031 if ( p_curr_record )
1032 {
1033 if ( curr_record_index++ == get_record_index )
1034 {
1035 result = SDP_SUCCESS;
1036 break;
1037 }
1038 }
1039 }while ( p_curr_record );
1040
1041 if ( result == SDP_SUCCESS )
1042 {
1043 /* copy the information from the SDP record to the DI record */
1044 tSDP_DISC_ATTR *p_curr_attr = NULL;
1045
1046 /* ClientExecutableURL is optional */
1047 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_CLIENT_EXE_URL );
1048 SDP_AttrStringCopy( p_device_info->rec.client_executable_url, p_curr_attr,
1049 SDP_MAX_ATTR_LEN );
1050
1051 /* Service Description is optional */
1052 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_SERVICE_DESCRIPTION );
1053 SDP_AttrStringCopy( p_device_info->rec.service_description, p_curr_attr, SDP_MAX_ATTR_LEN );
1054
1055 /* DocumentationURL is optional */
1056 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_DOCUMENTATION_URL );
1057 SDP_AttrStringCopy( p_device_info->rec.documentation_url, p_curr_attr, SDP_MAX_ATTR_LEN );
1058
1059 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_SPECIFICATION_ID );
1060 if ( p_curr_attr )
1061 p_device_info->spec_id = p_curr_attr->attr_value.v.u16;
1062 else
1063 result = SDP_ERR_ATTR_NOT_PRESENT;
1064
1065 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_VENDOR_ID );
1066 if ( p_curr_attr )
1067 p_device_info->rec.vendor = p_curr_attr->attr_value.v.u16;
1068 else
1069 result = SDP_ERR_ATTR_NOT_PRESENT;
1070
1071 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_VENDOR_ID_SOURCE );
1072 if ( p_curr_attr )
1073 p_device_info->rec.vendor_id_source = p_curr_attr->attr_value.v.u16;
1074 else
1075 result = SDP_ERR_ATTR_NOT_PRESENT;
1076
1077 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRODUCT_ID );
1078 if ( p_curr_attr )
1079 p_device_info->rec.product = p_curr_attr->attr_value.v.u16;
1080 else
1081 result = SDP_ERR_ATTR_NOT_PRESENT;
1082
1083 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRODUCT_VERSION );
1084 if ( p_curr_attr )
1085 p_device_info->rec.version = p_curr_attr->attr_value.v.u16;
1086 else
1087 result = SDP_ERR_ATTR_NOT_PRESENT;
1088
1089 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRIMARY_RECORD );
1090 if ( p_curr_attr )
1091 p_device_info->rec.primary_record = (BOOLEAN)p_curr_attr->attr_value.v.u8;
1092 else
1093 result = SDP_ERR_ATTR_NOT_PRESENT;
1094 }
1095
1096 return result;
1097 #else /* SDP_CLIENT_ENABLED is FALSE */
1098 return SDP_NO_DI_RECORD_FOUND;
1099 #endif
1100 }
1101
1102 /*******************************************************************************
1103 ** Device Identification (DI) Server Functions
1104 *******************************************************************************/
1105
1106 /*******************************************************************************
1107 **
1108 ** Function SDP_SetLocalDiRecord
1109 **
1110 ** Description This function adds a DI record to the local SDP database.
1111 **
1112 **
1113 **
1114 ** Returns Returns SDP_SUCCESS if record added successfully, else error
1115 **
1116 *******************************************************************************/
SDP_SetLocalDiRecord(tSDP_DI_RECORD * p_device_info,UINT32 * p_handle)1117 UINT16 SDP_SetLocalDiRecord( tSDP_DI_RECORD *p_device_info, UINT32 *p_handle )
1118 {
1119 #if SDP_SERVER_ENABLED == TRUE
1120 UINT16 result = SDP_SUCCESS;
1121 UINT32 handle;
1122 UINT16 di_uuid = UUID_SERVCLASS_PNP_INFORMATION;
1123 UINT16 di_specid = BLUETOOTH_DI_SPECIFICATION;
1124 UINT8 temp_u16[2];
1125 UINT8 *p_temp;
1126 UINT8 u8;
1127
1128 *p_handle = 0;
1129 if ( p_device_info == NULL )
1130 return SDP_ILLEGAL_PARAMETER;
1131
1132 /* if record is to be primary record, get handle to replace old primary */
1133 if ( p_device_info->primary_record == TRUE && sdp_cb.server_db.di_primary_handle )
1134 handle = sdp_cb.server_db.di_primary_handle;
1135 else
1136 {
1137 if ( (handle = SDP_CreateRecord()) == 0 )
1138 return SDP_NO_RESOURCES;
1139 }
1140
1141 *p_handle = handle;
1142
1143 /* build the SDP entry */
1144 /* Add the UUID to the Service Class ID List */
1145 if ((SDP_AddServiceClassIdList(handle, 1, &di_uuid)) == FALSE)
1146 result = SDP_DI_REG_FAILED;
1147
1148 /* mandatory */
1149 if ( result == SDP_SUCCESS)
1150 {
1151 p_temp = temp_u16;
1152 UINT16_TO_BE_STREAM(p_temp, di_specid);
1153 if ( !(SDP_AddAttribute(handle, ATTR_ID_SPECIFICATION_ID,
1154 UINT_DESC_TYPE, sizeof(di_specid),
1155 temp_u16)) )
1156 result = SDP_DI_REG_FAILED;
1157 }
1158
1159 /* optional - if string is null, do not add attribute */
1160 if ( result == SDP_SUCCESS )
1161 {
1162 if ( p_device_info->client_executable_url[0] != '\0' )
1163 {
1164 if ( !((strlen(p_device_info->client_executable_url)+1 <= SDP_MAX_ATTR_LEN) &&
1165 SDP_AddAttribute(handle, ATTR_ID_CLIENT_EXE_URL, URL_DESC_TYPE,
1166 (UINT32)(strlen(p_device_info->client_executable_url)+1),
1167 (UINT8 *)p_device_info->client_executable_url)) )
1168 result = SDP_DI_REG_FAILED;
1169 }
1170 }
1171
1172 /* optional - if string is null, do not add attribute */
1173 if ( result == SDP_SUCCESS )
1174 {
1175 if ( p_device_info->service_description[0] != '\0' )
1176 {
1177 if ( !((strlen(p_device_info->service_description)+1 <= SDP_MAX_ATTR_LEN) &&
1178 SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION,
1179 TEXT_STR_DESC_TYPE,
1180 (UINT32)(strlen(p_device_info->service_description)+1),
1181 (UINT8 *)p_device_info->service_description)) )
1182 result = SDP_DI_REG_FAILED;
1183 }
1184 }
1185
1186 /* optional - if string is null, do not add attribute */
1187 if ( result == SDP_SUCCESS )
1188 {
1189 if ( p_device_info->documentation_url[0] != '\0' )
1190 {
1191 if ( !((strlen(p_device_info->documentation_url)+1 <= SDP_MAX_ATTR_LEN) &&
1192 SDP_AddAttribute(handle, ATTR_ID_DOCUMENTATION_URL, URL_DESC_TYPE,
1193 (UINT32)(strlen(p_device_info->documentation_url)+1),
1194 (UINT8 *)p_device_info->documentation_url)) )
1195 result = SDP_DI_REG_FAILED;
1196 }
1197 }
1198
1199 /* mandatory */
1200 if ( result == SDP_SUCCESS)
1201 {
1202 p_temp = temp_u16;
1203 UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor);
1204 if ( !(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID, UINT_DESC_TYPE,
1205 sizeof(p_device_info->vendor), temp_u16)) )
1206 result = SDP_DI_REG_FAILED;
1207 }
1208
1209 /* mandatory */
1210 if ( result == SDP_SUCCESS)
1211 {
1212 p_temp = temp_u16;
1213 UINT16_TO_BE_STREAM (p_temp, p_device_info->product);
1214 if ( !(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_ID,
1215 UINT_DESC_TYPE, sizeof(p_device_info->product), temp_u16)) )
1216 result = SDP_DI_REG_FAILED;
1217 }
1218
1219 /* mandatory */
1220 if ( result == SDP_SUCCESS)
1221 {
1222 p_temp = temp_u16;
1223 UINT16_TO_BE_STREAM (p_temp, p_device_info->version);
1224 if ( !(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_VERSION, UINT_DESC_TYPE,
1225 sizeof(p_device_info->version), temp_u16)) )
1226 result = SDP_DI_REG_FAILED;
1227 }
1228
1229 /* mandatory */
1230 if ( result == SDP_SUCCESS)
1231 {
1232 u8 = (UINT8)p_device_info->primary_record;
1233 if ( !(SDP_AddAttribute(handle, ATTR_ID_PRIMARY_RECORD,
1234 BOOLEAN_DESC_TYPE, 1, &u8)) )
1235 result = SDP_DI_REG_FAILED;
1236 }
1237
1238 /* mandatory */
1239 if ( result == SDP_SUCCESS)
1240 {
1241 p_temp = temp_u16;
1242 UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor_id_source);
1243 if ( !(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID_SOURCE, UINT_DESC_TYPE,
1244 sizeof(p_device_info->vendor_id_source), temp_u16)) )
1245 result = SDP_DI_REG_FAILED;
1246 }
1247
1248 if ( result != SDP_SUCCESS )
1249 SDP_DeleteRecord( handle );
1250 else if (p_device_info->primary_record == TRUE)
1251 sdp_cb.server_db.di_primary_handle = handle;
1252
1253 return result;
1254 #else /* SDP_SERVER_ENABLED is FALSE */
1255 return SDP_DI_REG_FAILED;
1256 #endif /* if SDP_SERVER_ENABLED */
1257 }
1258
1259 /*******************************************************************************
1260 **
1261 ** Function SDP_SetTraceLevel
1262 **
1263 ** Description This function sets the trace level for SDP. If called with
1264 ** a value of 0xFF, it simply reads the current trace level.
1265 **
1266 ** Returns the new (current) trace level
1267 **
1268 *******************************************************************************/
SDP_SetTraceLevel(UINT8 new_level)1269 UINT8 SDP_SetTraceLevel (UINT8 new_level)
1270 {
1271 if (new_level != 0xFF)
1272 sdp_cb.trace_level = new_level;
1273
1274 return(sdp_cb.trace_level);
1275 }
1276