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                         memcpy(p_uuid->uu.uuid128, p_sattr->attr_value.v.array, LEN_UUID_128);
359                     }
360                     else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_32)
361                     {
362                         p_uuid->len = LEN_UUID_32;
363                         p_uuid->uu.uuid32 = p_sattr->attr_value.v.u32;
364                     }
365 
366                     return(TRUE);
367                 }
368 
369                 /* Checking for Toyota G Block Car Kit:
370                 **  This car kit puts an extra data element sequence
371                 **  where the UUID is suppose to be!!!
372                 */
373                 else
374                 {
375                     if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)
376                     {
377                         /* Look through data element sequence until no more UUIDs */
378                         for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr)
379                         {
380                             /* Increment past this to see if the next attribut is UUID */
381                             if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE)
382                                 /* only support 16 bits UUID for now */
383                                 && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2))
384                             {
385                                 p_uuid->len = 2;
386                                 p_uuid->uu.uuid16 = p_extra_sattr->attr_value.v.u16;
387                                 return(TRUE);
388                             }
389                         }
390                     }
391                 }
392             }
393             break;
394         }
395         else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
396         {
397             if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
398                 /* only support 16 bits UUID for now */
399                 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2))
400             {
401                 p_uuid->len = 2;
402                 p_uuid->uu.uuid16 = p_attr->attr_value.v.u16;
403                 return(TRUE);
404             }
405         }
406         p_attr = p_attr->p_next_attr;
407     }
408     return FALSE;
409 #endif
410 }
411 
412 /*******************************************************************************
413 **
414 ** Function         SDP_FindServiceUUIDInRec_128bit
415 **
416 ** Description      This function is called to read the 128-bit service UUID within a record
417 **                  if there is any.
418 **
419 ** Parameters:      p_rec      - pointer to a SDP record.
420 **                  p_uuid     - output parameter to save the UUID found.
421 **
422 ** Returns          TRUE if found, otherwise FALSE.
423 **
424 *******************************************************************************/
SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC * p_rec,tBT_UUID * p_uuid)425 BOOLEAN SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC *p_rec, tBT_UUID * p_uuid)
426 {
427 #if SDP_CLIENT_ENABLED == TRUE
428     tSDP_DISC_ATTR  *p_attr, *p_sattr;
429 
430     p_attr = p_rec->p_first_attr;
431 
432     while (p_attr)
433     {
434         if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
435             && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
436         {
437             for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
438             {
439                 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
440                 {
441                     /* only support 128 bits UUID for now */
442                     if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16)
443                     {
444                         p_uuid->len = 16;
445                         memcpy(p_uuid->uu.uuid128, p_sattr->attr_value.v.array, MAX_UUID_SIZE);
446                     }
447                     return(TRUE);
448                 }
449             }
450             break;
451         }
452         else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
453         {
454             if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
455                 /* only support 128 bits UUID for now */
456                 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16))
457             {
458                 p_uuid->len = 16;
459                 memcpy(p_uuid->uu.uuid128, p_attr->attr_value.v.array, MAX_UUID_SIZE);
460                 return(TRUE);
461             }
462         }
463         p_attr = p_attr->p_next_attr;
464     }
465     return FALSE;
466 #endif
467 }
468 
469 /*******************************************************************************
470 **
471 ** Function         SDP_FindServiceInDb
472 **
473 ** Description      This function queries an SDP database for a specific service.
474 **                  If the p_start_rec pointer is NULL, it looks from the beginning
475 **                  of the database, else it continues from the next record after
476 **                  p_start_rec.
477 **
478 ** Returns          Pointer to record containing service class, or NULL
479 **
480 *******************************************************************************/
SDP_FindServiceInDb(tSDP_DISCOVERY_DB * p_db,UINT16 service_uuid,tSDP_DISC_REC * p_start_rec)481 tSDP_DISC_REC *SDP_FindServiceInDb (tSDP_DISCOVERY_DB *p_db, UINT16 service_uuid, tSDP_DISC_REC *p_start_rec)
482 {
483 #if SDP_CLIENT_ENABLED == TRUE
484     tSDP_DISC_REC   *p_rec;
485     tSDP_DISC_ATTR  *p_attr, *p_sattr, *p_extra_sattr;
486 
487     /* Must have a valid database */
488     if (p_db == NULL)
489         return(NULL);
490 
491     if (!p_start_rec)
492         p_rec = p_db->p_first_rec;
493     else
494         p_rec = p_start_rec->p_next_rec;
495 
496     while (p_rec)
497     {
498         p_attr = p_rec->p_first_attr;
499         while (p_attr)
500         {
501             if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
502                 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
503             {
504                 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
505                 {
506 
507                     if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
508                      && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) ) {
509                         SDP_TRACE_DEBUG("SDP_FindServiceInDb - p_sattr value = 0x%x serviceuuid = 0x%x\r\n",
510                                         p_sattr->attr_value.v.u16, service_uuid);
511                         if(service_uuid == UUID_SERVCLASS_HDP_PROFILE)
512                         {
513                             if( (p_sattr->attr_value.v.u16==UUID_SERVCLASS_HDP_SOURCE) || ( p_sattr->attr_value.v.u16==UUID_SERVCLASS_HDP_SINK))
514                             {
515                                 SDP_TRACE_DEBUG("SDP_FindServiceInDb found HDP source or sink\n" );
516                                 return (p_rec);
517                             }
518                         }
519 
520                     }
521 
522                     if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE && (service_uuid == 0
523                         || (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2
524                             && p_sattr->attr_value.v.u16 == service_uuid)))
525                         /* for a specific uuid, or any one */
526                     {
527                         return(p_rec);
528                     }
529 
530                     /* Checking for Toyota G Block Car Kit:
531                     **  This car kit puts an extra data element sequence
532                     **  where the UUID is suppose to be!!!
533                     */
534                     else
535                     {
536                         if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)
537                         {
538                             /* Look through data element sequence until no more UUIDs */
539                             for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr)
540                             {
541                                 /* Increment past this to see if the next attribut is UUID */
542                                 if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE)
543                                     && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2)
544                                     /* for a specific uuid, or any one */
545                                     && ((p_extra_sattr->attr_value.v.u16 == service_uuid) || (service_uuid == 0)))
546                                 {
547                                     return(p_rec);
548                                 }
549                             }
550                         }
551                     }
552                 }
553                 break;
554             }
555             else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
556             {
557                 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
558                     && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)
559                     /* find a specific UUID or anyone */
560                     && ((p_attr->attr_value.v.u16 == service_uuid) || service_uuid == 0))
561                     return(p_rec);
562             }
563 
564             p_attr = p_attr->p_next_attr;
565         }
566 
567         p_rec = p_rec->p_next_rec;
568     }
569 #endif
570     /* If here, no matching UUID found */
571     return(NULL);
572 }
573 
574 /*******************************************************************************
575 **
576 ** Function         SDP_FindServiceInDb_128bit
577 **
578 ** Description      This function queries an SDP database for a specific service.
579 **                  If the p_start_rec pointer is NULL, it looks from the beginning
580 **                  of the database, else it continues from the next record after
581 **                  p_start_rec.
582 **
583 **                  This function is kept separate from SDP_FindServiceInDb since
584 **                  that API is expected to return only 16-bit UUIDs
585 **
586 ** Returns          Pointer to record containing service class, or NULL
587 **
588 *******************************************************************************/
SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB * p_db,tSDP_DISC_REC * p_start_rec)589 tSDP_DISC_REC *SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_start_rec)
590 {
591 #if SDP_CLIENT_ENABLED == TRUE
592     tSDP_DISC_REC   *p_rec;
593     tSDP_DISC_ATTR  *p_attr, *p_sattr;
594 
595     /* Must have a valid database */
596     if (p_db == NULL)
597         return(NULL);
598 
599     if (!p_start_rec)
600         p_rec = p_db->p_first_rec;
601     else
602         p_rec = p_start_rec->p_next_rec;
603 
604     while (p_rec)
605     {
606         p_attr = p_rec->p_first_attr;
607         while (p_attr)
608         {
609             if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
610                 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
611             {
612                 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
613                 {
614                     if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
615                         && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16))
616                     {
617                         return(p_rec);
618                     }
619                 }
620                 break;
621             }
622             else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
623             {
624                 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
625                     && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16))
626                     return(p_rec);
627             }
628 
629             p_attr = p_attr->p_next_attr;
630         }
631 
632         p_rec = p_rec->p_next_rec;
633     }
634 #endif
635     /* If here, no matching UUID found */
636     return(NULL);
637 }
638 
639 
640 /*******************************************************************************
641 **
642 ** Function         SDP_FindServiceUUIDInDb
643 **
644 ** Description      This function queries an SDP database for a specific service.
645 **                  If the p_start_rec pointer is NULL, it looks from the beginning
646 **                  of the database, else it continues from the next record after
647 **                  p_start_rec.
648 **
649 ** NOTE             the only difference between this function and the previous function
650 **                  "SDP_FindServiceInDb()" is that this function takes a tBT_UUID input
651 **
652 ** Returns          Pointer to record containing service class, or NULL
653 **
654 *******************************************************************************/
SDP_FindServiceUUIDInDb(tSDP_DISCOVERY_DB * p_db,tBT_UUID * p_uuid,tSDP_DISC_REC * p_start_rec)655 tSDP_DISC_REC *SDP_FindServiceUUIDInDb (tSDP_DISCOVERY_DB *p_db, tBT_UUID *p_uuid, tSDP_DISC_REC *p_start_rec)
656 {
657 #if SDP_CLIENT_ENABLED == TRUE
658     tSDP_DISC_REC   *p_rec;
659     tSDP_DISC_ATTR  *p_attr, *p_sattr;
660 
661     /* Must have a valid database */
662     if (p_db == NULL)
663         return(NULL);
664 
665     if (!p_start_rec)
666         p_rec = p_db->p_first_rec;
667     else
668         p_rec = p_start_rec->p_next_rec;
669 
670     while (p_rec)
671     {
672         p_attr = p_rec->p_first_attr;
673         while (p_attr)
674         {
675             if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
676                 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
677             {
678                 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
679                 {
680                     if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
681                     {
682                         if (sdpu_compare_uuid_with_attr (p_uuid, p_sattr))
683                             return(p_rec);
684                     }
685                 }
686                 break;
687             }
688             else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
689             {
690                 if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE )
691                 {
692                     if (sdpu_compare_uuid_with_attr (p_uuid, p_attr))
693                         return(p_rec);
694                 }
695             }
696 
697             p_attr = p_attr->p_next_attr;
698         }
699 
700         p_rec = p_rec->p_next_rec;
701     }
702 #endif  /* CLIENT_ENABLED == TRUE */
703     /* If here, no matching UUID found */
704     return(NULL);
705 }
706 
707 #if SDP_CLIENT_ENABLED == TRUE
708 /*******************************************************************************
709 **
710 ** Function         sdp_fill_proto_elem
711 **
712 ** Description      This function retrieves the protocol element.
713 **
714 ** Returns          TRUE if found, FALSE if not
715 **                  If found, the passed protocol list element is filled in.
716 **
717 *******************************************************************************/
sdp_fill_proto_elem(tSDP_DISC_ATTR * p_attr,UINT16 layer_uuid,tSDP_PROTOCOL_ELEM * p_elem)718 static BOOLEAN sdp_fill_proto_elem( tSDP_DISC_ATTR  *p_attr, UINT16 layer_uuid,
719                                     tSDP_PROTOCOL_ELEM *p_elem)
720 {
721     tSDP_DISC_ATTR  *p_sattr;
722 
723     /* Walk through the protocol descriptor list */
724     for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr)
725     {
726         /* Safety check - each entry should itself be a sequence */
727         if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
728             return(FALSE);
729 
730         /* Now, see if the entry contains the layer we are interested in */
731         for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
732         {
733             /* SDP_TRACE_DEBUG ("SDP - p_sattr 0x%x, layer_uuid:0x%x, u16:0x%x####",
734                 p_sattr, layer_uuid, p_sattr->attr_value.v.u16); */
735 
736             if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
737                 && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)
738                 && (p_sattr->attr_value.v.u16 == layer_uuid))
739             {
740                 /* Bingo. Now fill in the passed element */
741                 p_elem->protocol_uuid = layer_uuid;
742                 p_elem->num_params = 0;
743 
744                 /* Store the parameters, if any */
745                 for (p_sattr = p_sattr->p_next_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
746                 {
747                     if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) != UINT_DESC_TYPE)
748                         break;
749 
750                     if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)
751                         p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u16;
752                     else
753                         p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u8;
754 
755                     if (p_elem->num_params >= SDP_MAX_PROTOCOL_PARAMS)
756                         break;
757                 }
758                 return(TRUE);
759             }
760         }
761     }
762 
763     return(FALSE);
764 }
765 #endif  /* CLIENT_ENABLED == TRUE */
766 
767 /*******************************************************************************
768 **
769 ** Function         SDP_FindProtocolListElemInRec
770 **
771 ** Description      This function looks at a specific discovery record for a protocol
772 **                  list element.
773 **
774 ** Returns          TRUE if found, FALSE if not
775 **                  If found, the passed protocol list element is filled in.
776 **
777 *******************************************************************************/
SDP_FindProtocolListElemInRec(tSDP_DISC_REC * p_rec,UINT16 layer_uuid,tSDP_PROTOCOL_ELEM * p_elem)778 BOOLEAN SDP_FindProtocolListElemInRec (tSDP_DISC_REC *p_rec, UINT16 layer_uuid, tSDP_PROTOCOL_ELEM *p_elem)
779 {
780 #if SDP_CLIENT_ENABLED == TRUE
781     tSDP_DISC_ATTR  *p_attr;
782 
783     p_attr = p_rec->p_first_attr;
784     while (p_attr)
785     {
786         /* Find the protocol descriptor list */
787         if ((p_attr->attr_id == ATTR_ID_PROTOCOL_DESC_LIST)
788             && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
789         {
790             return sdp_fill_proto_elem(p_attr, layer_uuid, p_elem);
791         }
792         p_attr = p_attr->p_next_attr;
793     }
794 #endif
795     /* If here, no match found */
796     return(FALSE);
797 }
798 
799 
800 /*******************************************************************************
801 **
802 ** Function         SDP_FindAddProtoListsElemInRec
803 **
804 ** Description      This function looks at a specific discovery record for a protocol
805 **                  list element.
806 **
807 ** Returns          TRUE if found, FALSE if not
808 **                  If found, the passed protocol list element is filled in.
809 **
810 *******************************************************************************/
SDP_FindAddProtoListsElemInRec(tSDP_DISC_REC * p_rec,UINT16 layer_uuid,tSDP_PROTOCOL_ELEM * p_elem)811 BOOLEAN SDP_FindAddProtoListsElemInRec (tSDP_DISC_REC *p_rec, UINT16 layer_uuid, tSDP_PROTOCOL_ELEM *p_elem)
812 {
813 #if SDP_CLIENT_ENABLED == TRUE
814     tSDP_DISC_ATTR  *p_attr, *p_sattr;
815     BOOLEAN         ret = FALSE;
816 
817     p_attr = p_rec->p_first_attr;
818     while (p_attr)
819     {
820         /* Find the additional protocol descriptor list attribute */
821         if ((p_attr->attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS)
822             && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
823         {
824             for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
825             {
826                 /* Safety check - each entry should itself be a sequence */
827                 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)
828                 {
829                     if ( (ret = sdp_fill_proto_elem(p_sattr, layer_uuid, p_elem)) == TRUE)
830                         break;
831                 }
832             }
833             return ret;
834         }
835         p_attr = p_attr->p_next_attr;
836     }
837 #endif
838     /* If here, no match found */
839     return(FALSE);
840 }
841 
842 
843 /*******************************************************************************
844 **
845 ** Function         SDP_FindProfileVersionInRec
846 **
847 ** Description      This function looks at a specific discovery record for the
848 **                  Profile list descriptor, and pulls out the version number.
849 **                  The version number consists of an 8-bit major version and
850 **                  an 8-bit minor version.
851 **
852 ** Returns          TRUE if found, FALSE if not
853 **                  If found, the major and minor version numbers that were passed
854 **                  in are filled in.
855 **
856 *******************************************************************************/
SDP_FindProfileVersionInRec(tSDP_DISC_REC * p_rec,UINT16 profile_uuid,UINT16 * p_version)857 BOOLEAN SDP_FindProfileVersionInRec (tSDP_DISC_REC *p_rec, UINT16 profile_uuid, UINT16 *p_version)
858 {
859 #if SDP_CLIENT_ENABLED == TRUE
860     tSDP_DISC_ATTR  *p_attr, *p_sattr;
861 
862     p_attr = p_rec->p_first_attr;
863     while (p_attr)
864     {
865         /* Find the profile descriptor list */
866         if ((p_attr->attr_id == ATTR_ID_BT_PROFILE_DESC_LIST)
867             && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
868         {
869             /* Walk through the protocol descriptor list */
870             for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr)
871             {
872                 /* Safety check - each entry should itself be a sequence */
873                 if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
874                     return(FALSE);
875 
876                 /* Now, see if the entry contains the profile UUID we are interested in */
877                 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
878                 {
879                     if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
880                         && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)  /* <- This is bytes, not size code! */
881                         && (p_sattr->attr_value.v.u16 == profile_uuid))
882                     {
883                         /* Now fill in the major and minor numbers */
884                         /* if the attribute matches the description for version (type UINT, size 2 bytes) */
885                         p_sattr = p_sattr->p_next_attr;
886 
887                         if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UINT_DESC_TYPE) &&
888                             (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2))
889                         {
890                             /* The high order 8 bits is the major number, low order is the minor number (big endian) */
891                             *p_version = p_sattr->attr_value.v.u16;
892 
893                             return(TRUE);
894                         }
895                         else
896                             return(FALSE);  /* The type and/or size was not valid for the profile list version */
897                     }
898                 }
899             }
900 
901             return(FALSE);
902         }
903         p_attr = p_attr->p_next_attr;
904     }
905 #endif  /* CLIENT_ENABLED == TRUE */
906 
907     /* If here, no match found */
908     return(FALSE);
909 }
910 
911 /*******************************************************************************
912 **                   Device Identification (DI) Client Functions
913 *******************************************************************************/
914 
915 /*******************************************************************************
916 **
917 ** Function         SDP_DiDiscover
918 **
919 ** Description      This function queries a remote device for DI information.
920 **
921 ** Returns          SDP_SUCCESS if query started successfully, else error
922 **
923 *******************************************************************************/
SDP_DiDiscover(BD_ADDR remote_device,tSDP_DISCOVERY_DB * p_db,UINT32 len,tSDP_DISC_CMPL_CB * p_cb)924 UINT16 SDP_DiDiscover( BD_ADDR remote_device, tSDP_DISCOVERY_DB *p_db,
925                        UINT32 len, tSDP_DISC_CMPL_CB *p_cb )
926 {
927 #if SDP_CLIENT_ENABLED == TRUE
928     UINT16  result   = SDP_DI_DISC_FAILED;
929     UINT16  num_uuids = 1;
930     UINT16  di_uuid   = UUID_SERVCLASS_PNP_INFORMATION;
931 
932     /* build uuid for db init */
933     tSDP_UUID init_uuid;
934     init_uuid.len = 2;
935     init_uuid.uu.uuid16 = di_uuid;
936 
937     if ( SDP_InitDiscoveryDb(p_db, len, num_uuids, &init_uuid, 0, NULL) )
938         if ( SDP_ServiceSearchRequest(remote_device, p_db, p_cb) )
939             result = SDP_SUCCESS;
940 
941     return result;
942 #else
943     return SDP_DI_DISC_FAILED;
944 #endif
945 }
946 
947 /*******************************************************************************
948 **
949 ** Function         SDP_GetNumDiRecords
950 **
951 ** Description      Searches specified database for DI records
952 **
953 ** Returns          number of DI records found
954 **
955 *******************************************************************************/
SDP_GetNumDiRecords(tSDP_DISCOVERY_DB * p_db)956 UINT8 SDP_GetNumDiRecords( tSDP_DISCOVERY_DB *p_db )
957 {
958 #if SDP_CLIENT_ENABLED == TRUE
959     UINT8   num_records = 0;
960     tSDP_DISC_REC *p_curr_record = NULL;
961 
962     do
963     {
964         p_curr_record = SDP_FindServiceInDb( p_db, UUID_SERVCLASS_PNP_INFORMATION,
965                                              p_curr_record );
966         if ( p_curr_record )
967             num_records++;
968     }while ( p_curr_record );
969 
970     return num_records;
971 #else
972     return 0;
973 #endif
974 }
975 
976 /*******************************************************************************
977 **
978 ** Function         SDP_AttrStringCopy
979 **
980 ** Description      This function copy given attribute to specified buffer as a string
981 **
982 ** Returns          none
983 **
984 *******************************************************************************/
SDP_AttrStringCopy(char * dst,tSDP_DISC_ATTR * p_attr,UINT16 dst_size)985 static void SDP_AttrStringCopy(char *dst, tSDP_DISC_ATTR *p_attr, UINT16 dst_size)
986 {
987     if ( dst == NULL ) return;
988     if ( p_attr )
989     {
990         UINT16 len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
991         if ( len > dst_size - 1 )
992         {
993             len = dst_size - 1;
994         }
995         memcpy(dst, (char *)p_attr->attr_value.v.array, len);
996         dst[len] = '\0';
997     }
998     else
999     {
1000         dst[0] = '\0';
1001     }
1002 }
1003 
1004 /*******************************************************************************
1005 **
1006 ** Function         SDP_GetDiRecord
1007 **
1008 ** Description      This function retrieves a remote device's DI record from
1009 **                  the specified database.
1010 **
1011 ** Returns          SDP_SUCCESS if record retrieved, else error
1012 **
1013 *******************************************************************************/
SDP_GetDiRecord(UINT8 get_record_index,tSDP_DI_GET_RECORD * p_device_info,tSDP_DISCOVERY_DB * p_db)1014 UINT16 SDP_GetDiRecord( UINT8 get_record_index, tSDP_DI_GET_RECORD *p_device_info,
1015                         tSDP_DISCOVERY_DB *p_db )
1016 {
1017 #if SDP_CLIENT_ENABLED == TRUE
1018     UINT16  result = SDP_NO_DI_RECORD_FOUND;
1019     UINT8  curr_record_index = 1;
1020 
1021     tSDP_DISC_REC *p_curr_record = NULL;
1022 
1023     /* find the requested SDP record in the discovery database */
1024     do
1025     {
1026         p_curr_record = SDP_FindServiceInDb( p_db, UUID_SERVCLASS_PNP_INFORMATION,
1027                                              p_curr_record );
1028         if ( p_curr_record )
1029         {
1030             if ( curr_record_index++ == get_record_index )
1031             {
1032                 result = SDP_SUCCESS;
1033                 break;
1034             }
1035         }
1036     }while ( p_curr_record );
1037 
1038     if ( result == SDP_SUCCESS )
1039     {
1040         /* copy the information from the SDP record to the DI record */
1041         tSDP_DISC_ATTR *p_curr_attr = NULL;
1042 
1043         /* ClientExecutableURL is optional */
1044         p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_CLIENT_EXE_URL );
1045         SDP_AttrStringCopy( p_device_info->rec.client_executable_url, p_curr_attr,
1046                             SDP_MAX_ATTR_LEN );
1047 
1048         /* Service Description is optional */
1049         p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_SERVICE_DESCRIPTION );
1050         SDP_AttrStringCopy( p_device_info->rec.service_description, p_curr_attr, SDP_MAX_ATTR_LEN );
1051 
1052         /* DocumentationURL is optional */
1053         p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_DOCUMENTATION_URL );
1054         SDP_AttrStringCopy( p_device_info->rec.documentation_url, p_curr_attr, SDP_MAX_ATTR_LEN );
1055 
1056         p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_SPECIFICATION_ID );
1057         if ( p_curr_attr )
1058             p_device_info->spec_id = p_curr_attr->attr_value.v.u16;
1059         else
1060             result = SDP_ERR_ATTR_NOT_PRESENT;
1061 
1062         p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_VENDOR_ID );
1063         if ( p_curr_attr )
1064             p_device_info->rec.vendor = p_curr_attr->attr_value.v.u16;
1065         else
1066             result = SDP_ERR_ATTR_NOT_PRESENT;
1067 
1068         p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_VENDOR_ID_SOURCE );
1069         if ( p_curr_attr )
1070             p_device_info->rec.vendor_id_source = p_curr_attr->attr_value.v.u16;
1071         else
1072             result = SDP_ERR_ATTR_NOT_PRESENT;
1073 
1074         p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRODUCT_ID );
1075         if ( p_curr_attr )
1076             p_device_info->rec.product = p_curr_attr->attr_value.v.u16;
1077         else
1078             result = SDP_ERR_ATTR_NOT_PRESENT;
1079 
1080         p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRODUCT_VERSION );
1081         if ( p_curr_attr )
1082             p_device_info->rec.version = p_curr_attr->attr_value.v.u16;
1083         else
1084             result = SDP_ERR_ATTR_NOT_PRESENT;
1085 
1086         p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRIMARY_RECORD );
1087         if ( p_curr_attr )
1088             p_device_info->rec.primary_record = (BOOLEAN)p_curr_attr->attr_value.v.u8;
1089         else
1090             result = SDP_ERR_ATTR_NOT_PRESENT;
1091     }
1092 
1093     return result;
1094 #else   /* SDP_CLIENT_ENABLED is FALSE */
1095     return SDP_NO_DI_RECORD_FOUND;
1096 #endif
1097 }
1098 
1099 /*******************************************************************************
1100 **                   Device Identification (DI) Server Functions
1101 *******************************************************************************/
1102 
1103 /*******************************************************************************
1104 **
1105 ** Function         SDP_SetLocalDiRecord
1106 **
1107 ** Description      This function adds a DI record to the local SDP database.
1108 **
1109 **
1110 **
1111 ** Returns          Returns SDP_SUCCESS if record added successfully, else error
1112 **
1113 *******************************************************************************/
SDP_SetLocalDiRecord(tSDP_DI_RECORD * p_device_info,UINT32 * p_handle)1114 UINT16 SDP_SetLocalDiRecord( tSDP_DI_RECORD *p_device_info, UINT32 *p_handle )
1115 {
1116 #if SDP_SERVER_ENABLED == TRUE
1117     UINT16  result = SDP_SUCCESS;
1118     UINT32  handle;
1119     UINT16  di_uuid = UUID_SERVCLASS_PNP_INFORMATION;
1120     UINT16  di_specid = BLUETOOTH_DI_SPECIFICATION;
1121     UINT8   temp_u16[2];
1122     UINT8   *p_temp;
1123     UINT8   u8;
1124 
1125     *p_handle = 0;
1126     if ( p_device_info == NULL )
1127         return SDP_ILLEGAL_PARAMETER;
1128 
1129     /* if record is to be primary record, get handle to replace old primary */
1130     if ( p_device_info->primary_record == TRUE && sdp_cb.server_db.di_primary_handle )
1131         handle = sdp_cb.server_db.di_primary_handle;
1132     else
1133     {
1134         if ( (handle = SDP_CreateRecord()) == 0 )
1135             return SDP_NO_RESOURCES;
1136     }
1137 
1138     *p_handle = handle;
1139 
1140     /* build the SDP entry */
1141     /* Add the UUID to the Service Class ID List */
1142     if ((SDP_AddServiceClassIdList(handle, 1, &di_uuid)) == FALSE)
1143         result = SDP_DI_REG_FAILED;
1144 
1145     /* mandatory */
1146     if ( result == SDP_SUCCESS)
1147     {
1148         p_temp = temp_u16;
1149         UINT16_TO_BE_STREAM(p_temp, di_specid);
1150         if ( !(SDP_AddAttribute(handle, ATTR_ID_SPECIFICATION_ID,
1151                                 UINT_DESC_TYPE, sizeof(di_specid),
1152                                 temp_u16)) )
1153             result = SDP_DI_REG_FAILED;
1154     }
1155 
1156     /* optional - if string is null, do not add attribute */
1157     if ( result == SDP_SUCCESS )
1158     {
1159         if ( p_device_info->client_executable_url[0] != '\0' )
1160         {
1161             if ( !((strlen(p_device_info->client_executable_url)+1 <= SDP_MAX_ATTR_LEN) &&
1162                    SDP_AddAttribute(handle, ATTR_ID_CLIENT_EXE_URL, URL_DESC_TYPE,
1163                                     (UINT32)(strlen(p_device_info->client_executable_url)+1),
1164                                     (UINT8 *)p_device_info->client_executable_url)) )
1165                 result = SDP_DI_REG_FAILED;
1166         }
1167     }
1168 
1169     /* optional - if string is null, do not add attribute */
1170     if ( result == SDP_SUCCESS )
1171     {
1172         if ( p_device_info->service_description[0] != '\0' )
1173         {
1174             if ( !((strlen(p_device_info->service_description)+1 <= SDP_MAX_ATTR_LEN) &&
1175                    SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION,
1176                                     TEXT_STR_DESC_TYPE,
1177                                     (UINT32)(strlen(p_device_info->service_description)+1),
1178                                     (UINT8 *)p_device_info->service_description)) )
1179                 result = SDP_DI_REG_FAILED;
1180         }
1181     }
1182 
1183     /* optional - if string is null, do not add attribute */
1184     if ( result == SDP_SUCCESS )
1185     {
1186         if ( p_device_info->documentation_url[0] != '\0' )
1187         {
1188             if ( !((strlen(p_device_info->documentation_url)+1 <= SDP_MAX_ATTR_LEN) &&
1189                    SDP_AddAttribute(handle, ATTR_ID_DOCUMENTATION_URL, URL_DESC_TYPE,
1190                                     (UINT32)(strlen(p_device_info->documentation_url)+1),
1191                                     (UINT8 *)p_device_info->documentation_url)) )
1192                 result = SDP_DI_REG_FAILED;
1193         }
1194     }
1195 
1196     /* mandatory */
1197     if ( result == SDP_SUCCESS)
1198     {
1199         p_temp = temp_u16;
1200         UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor);
1201         if ( !(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID, UINT_DESC_TYPE,
1202                                 sizeof(p_device_info->vendor), temp_u16)) )
1203             result = SDP_DI_REG_FAILED;
1204     }
1205 
1206     /* mandatory */
1207     if ( result == SDP_SUCCESS)
1208     {
1209         p_temp = temp_u16;
1210         UINT16_TO_BE_STREAM (p_temp, p_device_info->product);
1211         if ( !(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_ID,
1212                                 UINT_DESC_TYPE, sizeof(p_device_info->product), temp_u16)) )
1213             result = SDP_DI_REG_FAILED;
1214     }
1215 
1216     /* mandatory */
1217     if ( result == SDP_SUCCESS)
1218     {
1219         p_temp = temp_u16;
1220         UINT16_TO_BE_STREAM (p_temp, p_device_info->version);
1221         if ( !(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_VERSION, UINT_DESC_TYPE,
1222                                 sizeof(p_device_info->version), temp_u16)) )
1223             result = SDP_DI_REG_FAILED;
1224     }
1225 
1226     /* mandatory */
1227     if ( result == SDP_SUCCESS)
1228     {
1229         u8 = (UINT8)p_device_info->primary_record;
1230         if ( !(SDP_AddAttribute(handle, ATTR_ID_PRIMARY_RECORD,
1231                                 BOOLEAN_DESC_TYPE, 1, &u8)) )
1232             result = SDP_DI_REG_FAILED;
1233     }
1234 
1235     /* mandatory */
1236     if ( result == SDP_SUCCESS)
1237     {
1238         p_temp = temp_u16;
1239         UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor_id_source);
1240         if ( !(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID_SOURCE, UINT_DESC_TYPE,
1241                                 sizeof(p_device_info->vendor_id_source), temp_u16)) )
1242             result = SDP_DI_REG_FAILED;
1243     }
1244 
1245     if ( result != SDP_SUCCESS )
1246         SDP_DeleteRecord( handle );
1247     else if (p_device_info->primary_record == TRUE)
1248         sdp_cb.server_db.di_primary_handle = handle;
1249 
1250     return result;
1251 #else   /* SDP_SERVER_ENABLED is FALSE */
1252     return SDP_DI_REG_FAILED;
1253 #endif  /* if SDP_SERVER_ENABLED */
1254 }
1255 
1256 /*******************************************************************************
1257 **
1258 ** Function         SDP_SetTraceLevel
1259 **
1260 ** Description      This function sets the trace level for SDP. If called with
1261 **                  a value of 0xFF, it simply reads the current trace level.
1262 **
1263 ** Returns          the new (current) trace level
1264 **
1265 *******************************************************************************/
SDP_SetTraceLevel(UINT8 new_level)1266 UINT8 SDP_SetTraceLevel (UINT8 new_level)
1267 {
1268     if (new_level != 0xFF)
1269         sdp_cb.trace_level = new_level;
1270 
1271     return(sdp_cb.trace_level);
1272 }
1273