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