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