1/******************************************************************************
2 *
3 * Copyright (C) 2014 Samsung System LSI
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 *  Filename:      btif_sdp_server.c
22 *  Description:   SDP server Bluetooth Interface to create and remove SDP records.
23 *                 To be used in combination with the RFCOMM/L2CAP(LE) sockets.
24 *
25 *
26 ***********************************************************************************/
27
28#define LOG_TAG "bt_btif_sdp_server"
29
30#include <pthread.h>
31#include <stdlib.h>
32#include <string.h>
33
34#include <hardware/bluetooth.h>
35#include <hardware/bt_sdp.h>
36
37#include "bta_sdp_api.h"
38#include "bta_sys.h"
39#include "btif_common.h"
40#include "btif_sock_util.h"
41#include "btif_util.h"
42#include "osi/include/allocator.h"
43#include "utl.h"
44
45static pthread_mutex_t sdp_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
46
47/**
48 * The need for a state variable have been reduced to two states.
49 * The remaining state control is handled by program flow
50 */
51typedef enum {
52    SDP_RECORD_FREE = 0,
53    SDP_RECORD_ALLOCED,
54} sdp_state_t;
55
56typedef struct {
57  sdp_state_t state;
58  int sdp_handle;
59  bluetooth_sdp_record* record_data;
60} sdp_slot_t;
61
62#define MAX_SDP_SLOTS 128
63static sdp_slot_t sdp_slots[MAX_SDP_SLOTS];
64
65/*****************************************************************************
66 * LOCAL Functions
67 *****************************************************************************/
68static int add_maps_sdp(const bluetooth_sdp_mas_record* rec);
69static int add_mapc_sdp(const bluetooth_sdp_mns_record* rec);
70static int add_pbaps_sdp(const bluetooth_sdp_pse_record* rec);
71static int add_opps_sdp(const bluetooth_sdp_ops_record* rec);
72static int add_saps_sdp(const bluetooth_sdp_sap_record* rec);
73bt_status_t remove_sdp_record(int record_id);
74static int free_sdp_slot(int id);
75
76/******************************************************************************
77 * WARNING: Functions below are not called in BTU context.
78 * Introduced to make it possible to create SDP records from JAVA with both a
79 * RFCOMM channel and a L2CAP PSM.
80 * Overall architecture:
81 *  1) JAVA calls createRecord() which returns a pseudo ID which at a later
82 *     point will be linked to a specific SDP handle.
83 *  2) createRecord() requests the BTU task(thread) to call a callback in SDP
84 *     which creates the actual record, and updates the ID<->SDPHandle map
85 *     based on the ID beeing passed to BTA as user_data.
86 *****************************************************************************/
87
88static void init_sdp_slots()
89{
90    int i;
91    memset(sdp_slots, 0, sizeof(sdp_slot_t)*MAX_SDP_SLOTS);
92    /* if SDP_RECORD_FREE is zero - no need to set the value */
93    if(SDP_RECORD_FREE != 0) {
94        for(i = 0; i < MAX_SDP_SLOTS; i++)
95        {
96            sdp_slots[i].state = SDP_RECORD_FREE;
97        }
98    }
99}
100
101bt_status_t sdp_server_init()
102{
103    BTIF_TRACE_DEBUG("Sdp Server %s", __FUNCTION__);
104    init_sdp_slots();
105    return BT_STATUS_SUCCESS;
106}
107
108void sdp_server_cleanup()
109{
110    BTIF_TRACE_DEBUG("Sdp Server %s", __FUNCTION__);
111    pthread_mutex_lock(&sdp_lock);
112    int i;
113    for(i = 0; i < MAX_SDP_SLOTS; i++)
114    {
115         /*remove_sdp_record(i); we cannot send messages to the other threads, since they might
116         *                       have been shut down already. Just do local cleanup.
117         */
118        free_sdp_slot(i);
119    }
120    pthread_mutex_unlock(&sdp_lock);
121}
122
123int get_sdp_records_size(bluetooth_sdp_record* in_record, int count) {
124    bluetooth_sdp_record* record = in_record;
125    int records_size = 0;
126    int i;
127    for(i=0; i<count; i++) {
128        record = &in_record[i];
129        records_size += sizeof(bluetooth_sdp_record);
130        records_size += record->hdr.service_name_length;
131        if(record->hdr.service_name_length > 0){
132            records_size++; /* + '\0' termination of string */
133        }
134        records_size += record->hdr.user1_ptr_len;
135        records_size += record->hdr.user2_ptr_len;
136    }
137    return records_size;
138}
139
140/* Deep copy all content of in_records into out_records.
141 * out_records must point to a chunk of memory large enough to contain all
142 * the data. Use getSdpRecordsSize() to calculate the needed size. */
143void copy_sdp_records(bluetooth_sdp_record* in_records,
144        bluetooth_sdp_record* out_records, int count) {
145    int i;
146    bluetooth_sdp_record* in_record;
147    bluetooth_sdp_record* out_record;
148    char* free_ptr = (char*)(&out_records[count]); /* set pointer to after the last entry */
149
150    for(i=0; i<count; i++) {
151        in_record = &in_records[i];
152        out_record = &out_records[i];
153        *out_record = *in_record;
154
155        if(in_record->hdr.service_name == NULL || in_record->hdr.service_name_length == 0) {
156            out_record->hdr.service_name = NULL;
157            out_record->hdr.service_name_length = 0;
158        } else {
159            out_record->hdr.service_name = free_ptr; // Update service_name pointer
160            // Copy string
161            memcpy(free_ptr, in_record->hdr.service_name, in_record->hdr.service_name_length);
162            free_ptr += in_record->hdr.service_name_length;
163            *(free_ptr) = '\0'; // Set '\0' termination of string
164            free_ptr++;
165        }
166        if(in_record->hdr.user1_ptr != NULL) {
167            out_record->hdr.user1_ptr = (UINT8*)free_ptr; // Update pointer
168            memcpy(free_ptr, in_record->hdr.user1_ptr, in_record->hdr.user1_ptr_len); // Copy content
169            free_ptr += in_record->hdr.user1_ptr_len;
170        }
171        if(in_record->hdr.user2_ptr != NULL) {
172            out_record->hdr.user2_ptr = (UINT8*)free_ptr; // Update pointer
173            memcpy(free_ptr, in_record->hdr.user2_ptr, in_record->hdr.user2_ptr_len); // Copy content
174            free_ptr += in_record->hdr.user2_ptr_len;
175        }
176    }
177    return;
178}
179
180/* Reserve a slot in sdp_slots, copy data and set a reference to the copy.
181 * The record_data will contain both the record and any data pointed to by
182 * the record.
183 * Currently this covers:
184 *   service_name string,
185 *   user1_ptr and
186 *   user2_ptr. */
187static int alloc_sdp_slot(bluetooth_sdp_record* in_record) {
188    int i;
189    int record_size = get_sdp_records_size(in_record, 1);
190    bluetooth_sdp_record* record = osi_malloc(record_size);
191
192    copy_sdp_records(in_record, record, 1);
193
194    /* We are optimists here, and preallocate the record.
195     * This is to reduce the time we hold the sdp_lock. */
196    pthread_mutex_lock(&sdp_lock);
197    for(i = 0; i < MAX_SDP_SLOTS; i++)
198    {
199        if(sdp_slots[i].state == SDP_RECORD_FREE) {
200            sdp_slots[i].state = SDP_RECORD_ALLOCED;
201            sdp_slots[i].record_data = record;
202            break;
203        }
204    }
205    pthread_mutex_unlock(&sdp_lock);
206    if(i >= MAX_SDP_SLOTS) {
207        APPL_TRACE_ERROR("%s() failed - no more free slots!", __func__);
208        /* Rearly the optimist is too optimistic, and cleanup is needed...*/
209        osi_free(record);
210        return -1;
211    }
212    return i;
213}
214
215static int free_sdp_slot(int id) {
216    int handle = -1;
217    bluetooth_sdp_record* record = NULL;
218    if(id >= MAX_SDP_SLOTS) {
219        APPL_TRACE_ERROR("%s() failed - id %d is invalid", __func__, id);
220        return handle;
221    }
222    pthread_mutex_lock(&sdp_lock);
223    handle = sdp_slots[id].sdp_handle;
224    sdp_slots[id].sdp_handle = 0;
225    if(sdp_slots[id].state != SDP_RECORD_FREE)
226    {
227        /* safe a copy of the pointer, and free after unlock() */
228        record = sdp_slots[id].record_data;
229    }
230    sdp_slots[id].state = SDP_RECORD_FREE;
231    pthread_mutex_unlock(&sdp_lock);
232
233    if(record != NULL) {
234        osi_free(record);
235    } else {
236        // Record have already been freed
237        handle = -1;
238    }
239    return handle;
240}
241
242/***
243 * Use this to get a reference to a SDP slot AND change the state to
244 * SDP_RECORD_CREATE_INITIATED.
245 */
246static const sdp_slot_t* start_create_sdp(int id) {
247    sdp_slot_t* sdp_slot;
248    if(id >= MAX_SDP_SLOTS) {
249        APPL_TRACE_ERROR("%s() failed - id %d is invalid", __func__, id);
250        return NULL;
251    }
252    pthread_mutex_lock(&sdp_lock);
253    if(sdp_slots[id].state == SDP_RECORD_ALLOCED) {
254        sdp_slot = &(sdp_slots[id]);
255    } else {
256        /* The record have been removed before this event occurred - e.g. deinit */
257        sdp_slot = NULL;
258    }
259    pthread_mutex_unlock(&sdp_lock);
260    if(sdp_slot == NULL) {
261        APPL_TRACE_ERROR("%s() failed - state for id %d is "
262                "sdp_slots[id].state = %d expected %d", __func__,
263                id, sdp_slots[id].state, SDP_RECORD_ALLOCED);
264    }
265    return sdp_slot;
266}
267
268static void set_sdp_handle(int id, int handle) {
269    pthread_mutex_lock(&sdp_lock);
270    sdp_slots[id].sdp_handle = handle;
271    pthread_mutex_unlock(&sdp_lock);
272    BTIF_TRACE_DEBUG("%s() id=%d to handle=0x%08x", __FUNCTION__, id, handle);
273}
274
275bt_status_t create_sdp_record(bluetooth_sdp_record *record, int* record_handle) {
276    int handle;
277
278    handle = alloc_sdp_slot(record);
279    BTIF_TRACE_DEBUG("%s() handle = 0x%08x", __FUNCTION__, handle);
280
281    if(handle < 0)
282        return BT_STATUS_FAIL;
283
284    BTA_SdpCreateRecordByUser(INT_TO_PTR(handle));
285
286    *record_handle = handle;
287
288    return BT_STATUS_SUCCESS;
289}
290
291bt_status_t remove_sdp_record(int record_id) {
292    int handle;
293
294    /* Get the Record handle, and free the slot */
295    handle = free_sdp_slot(record_id);
296    BTIF_TRACE_DEBUG("Sdp Server %s id=%d to handle=0x%08x",
297            __FUNCTION__, record_id, handle);
298
299    /* Pass the actual record handle */
300    if(handle > 0) {
301        BTA_SdpRemoveRecordByUser(INT_TO_PTR(handle));
302        return BT_STATUS_SUCCESS;
303    }
304    BTIF_TRACE_DEBUG("Sdp Server %s - record already removed - or never created", __FUNCTION__);
305    return BT_STATUS_FAIL;
306}
307
308/******************************************************************************
309 * CALLBACK FUNCTIONS
310 * Called in BTA context to create/remove SDP records.
311 ******************************************************************************/
312
313void on_create_record_event(int id) {
314    /*
315     * 1) Fetch the record pointer, and change its state?
316     * 2) switch on the type to create the correct record
317     * 3) Update state on completion
318     * 4) What to do at fail?
319     * */
320    BTIF_TRACE_DEBUG("Sdp Server %s", __FUNCTION__);
321    const sdp_slot_t* sdp_slot = start_create_sdp(id);
322    /* In the case we are shutting down, sdp_slot is NULL */
323    if(sdp_slot != NULL) {
324        bluetooth_sdp_record* record = sdp_slot->record_data;
325        int handle = -1;
326        switch(record->hdr.type) {
327        case SDP_TYPE_MAP_MAS:
328            handle = add_maps_sdp(&record->mas);
329            break;
330        case SDP_TYPE_MAP_MNS:
331            handle = add_mapc_sdp(&record->mns);
332            break;
333        case SDP_TYPE_PBAP_PSE:
334            handle = add_pbaps_sdp(&record->pse);
335            break;
336        case SDP_TYPE_OPP_SERVER:
337            handle = add_opps_sdp(&record->ops);
338            break;
339        case SDP_TYPE_SAP_SERVER:
340            handle = add_saps_sdp(&record->sap);
341            break;
342        case SDP_TYPE_PBAP_PCE:
343    //        break; not yet supported
344        default:
345            BTIF_TRACE_DEBUG("Record type %d is not supported",record->hdr.type);
346            break;
347        }
348        if(handle != -1) {
349            set_sdp_handle(id, handle);
350        }
351    }
352}
353
354void on_remove_record_event(int handle) {
355    BTIF_TRACE_DEBUG("Sdp Server %s", __FUNCTION__);
356
357    // User data carries the actual SDP handle, not the ID.
358    if(handle != -1 && handle != 0) {
359        BOOLEAN result;
360        result = SDP_DeleteRecord( handle );
361        if(result == FALSE) {
362            BTIF_TRACE_ERROR("  Unable to remove handle 0x%08x", handle);
363        }
364    }
365}
366
367/****
368 * Below the actual functions accessing BTA context data - hence only call from BTA context!
369 */
370
371/* Create a MAP MAS SDP record based on information stored in a bluetooth_sdp_mas_record */
372static int add_maps_sdp(const bluetooth_sdp_mas_record* rec)
373{
374
375    tSDP_PROTOCOL_ELEM  protoList [3];
376    UINT16              service = UUID_SERVCLASS_MESSAGE_ACCESS;
377    UINT16              browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
378    BOOLEAN             status = TRUE;
379    UINT32              sdp_handle = 0;
380    UINT8               temp[4];
381    UINT8*              p_temp = temp;
382
383    APPL_TRACE_DEBUG("%s(): MASID = 0x%02x, scn 0x%02x, psm = 0x%04x\n  service name %s", __func__,
384            rec->mas_instance_id, rec->hdr.rfcomm_channel_number,
385            rec->hdr.l2cap_psm, rec->hdr.service_name);
386
387    APPL_TRACE_DEBUG("  msg_types: 0x%02x, feature_bits: 0x%08x",
388            rec->supported_message_types, rec->supported_features);
389
390    if ((sdp_handle = SDP_CreateRecord()) == 0)
391    {
392        APPL_TRACE_ERROR("%s() - Unable to register MAPS Service", __func__);
393        return sdp_handle;
394    }
395
396    /* add service class */
397    status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
398    memset( protoList, 0 , 3*sizeof(tSDP_PROTOCOL_ELEM) );
399
400    /* add protocol list, including RFCOMM scn */
401    protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
402    protoList[0].num_params = 0;
403    protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
404    protoList[1].num_params = 1;
405    protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
406    protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
407    protoList[2].num_params = 0;
408    status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
409
410    /* Add a name entry */
411    status &= SDP_AddAttribute(sdp_handle,
412                    (UINT16)ATTR_ID_SERVICE_NAME,
413                    (UINT8)TEXT_STR_DESC_TYPE,
414                    (UINT32)(rec->hdr.service_name_length + 1),
415                    (UINT8 *)rec->hdr.service_name);
416
417    /* Add in the Bluetooth Profile Descriptor List */
418    status &= SDP_AddProfileDescriptorList(sdp_handle,
419                                     UUID_SERVCLASS_MAP_PROFILE,
420                                     rec->hdr.profile_version);
421
422    /* Add MAS instance ID */
423    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_MAS_INSTANCE_ID, UINT_DESC_TYPE,
424              (UINT32)1, (UINT8*)&rec->mas_instance_id);
425
426    /* Add supported message types */
427    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_MSG_TYPE, UINT_DESC_TYPE,
428              (UINT32)1, (UINT8*)&rec->supported_message_types);
429
430    /* Add supported feature */
431    UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
432    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_MAP_SUPPORTED_FEATURES,
433            UINT_DESC_TYPE, (UINT32)4, temp);
434
435    /* Add the L2CAP PSM if present */
436    if(rec->hdr.l2cap_psm != -1) {
437        p_temp = temp;// The macro modifies p_temp, hence rewind.
438        UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
439        status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
440                UINT_DESC_TYPE, (UINT32)2, temp);
441    }
442
443    /* Make the service browseable */
444    status &= SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
445
446    if (!status)
447    {
448        SDP_DeleteRecord(sdp_handle);
449        sdp_handle = 0;
450        APPL_TRACE_ERROR("%s() FAILED", __func__);
451    }
452    else
453    {
454        bta_sys_add_uuid(service);  /* UUID_SERVCLASS_MESSAGE_ACCESS */
455        APPL_TRACE_DEBUG("%s():  SDP Registered (handle 0x%08x)", __func__, sdp_handle);
456    }
457    return sdp_handle;
458}
459
460/* Create a MAP MNS SDP record based on information stored in a bluetooth_sdp_mns_record */
461static int add_mapc_sdp(const bluetooth_sdp_mns_record* rec)
462{
463
464    tSDP_PROTOCOL_ELEM  protoList [3];
465    UINT16              service = UUID_SERVCLASS_MESSAGE_NOTIFICATION;
466    UINT16              browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
467    BOOLEAN             status = TRUE;
468    UINT32              sdp_handle = 0;
469    UINT8               temp[4];
470    UINT8*              p_temp = temp;
471
472    APPL_TRACE_DEBUG("%s(): scn 0x%02x, psm = 0x%04x\n  service name %s", __func__,
473            rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm, rec->hdr.service_name);
474
475    APPL_TRACE_DEBUG("  feature_bits: 0x%08x", rec->supported_features);
476
477    if ((sdp_handle = SDP_CreateRecord()) == 0)
478    {
479        APPL_TRACE_ERROR("%s(): Unable to register MAP Notification Service", __func__);
480        return sdp_handle;
481    }
482
483    /* add service class */
484    status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
485    memset( protoList, 0 , 3*sizeof(tSDP_PROTOCOL_ELEM) );
486
487    /* add protocol list, including RFCOMM scn */
488    protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
489    protoList[0].num_params = 0;
490    protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
491    protoList[1].num_params = 1;
492    protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
493    protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
494    protoList[2].num_params = 0;
495    status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
496
497    /* Add a name entry */
498    status &= SDP_AddAttribute(sdp_handle,
499                    (UINT16)ATTR_ID_SERVICE_NAME,
500                    (UINT8)TEXT_STR_DESC_TYPE,
501                    (UINT32)(rec->hdr.service_name_length + 1),
502                    (UINT8 *)rec->hdr.service_name);
503
504    /* Add in the Bluetooth Profile Descriptor List */
505    status &= SDP_AddProfileDescriptorList(sdp_handle,
506                                     UUID_SERVCLASS_MAP_PROFILE,
507                                     rec->hdr.profile_version);
508
509    /* Add supported feature */
510    UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
511    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_MAP_SUPPORTED_FEATURES,
512            UINT_DESC_TYPE, (UINT32)4, temp);
513
514    /* Add the L2CAP PSM if present */
515    if(rec->hdr.l2cap_psm != -1) {
516        p_temp = temp;// The macro modifies p_temp, hence rewind.
517        UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
518        status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
519                UINT_DESC_TYPE, (UINT32)2, temp);
520    }
521
522    /* Make the service browseable */
523    status &= SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
524
525    if (!status)
526    {
527        SDP_DeleteRecord(sdp_handle);
528        sdp_handle = 0;
529        APPL_TRACE_ERROR("%s() FAILED", __func__);
530    }
531    else
532    {
533        bta_sys_add_uuid(service);  /* UUID_SERVCLASS_MESSAGE_ACCESS */
534        APPL_TRACE_DEBUG("%s():  SDP Registered (handle 0x%08x)", __func__, sdp_handle);
535    }
536    return sdp_handle;
537}
538
539/* Create a PBAP Server SDP record based on information stored in a bluetooth_sdp_pse_record */
540static int add_pbaps_sdp(const bluetooth_sdp_pse_record* rec)
541{
542
543    tSDP_PROTOCOL_ELEM  protoList [3];
544    UINT16              service = UUID_SERVCLASS_PBAP_PSE;
545    UINT16              browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
546    BOOLEAN             status = TRUE;
547    UINT32              sdp_handle = 0;
548    UINT8               temp[4];
549    UINT8*              p_temp = temp;
550
551    APPL_TRACE_DEBUG("%s(): scn 0x%02x, psm = 0x%04x\n  service name %s", __func__,
552            rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm, rec->hdr.service_name);
553
554    APPL_TRACE_DEBUG("  supported_repositories: 0x%08x, feature_bits: 0x%08x",
555            rec->supported_repositories, rec->supported_features);
556
557    if ((sdp_handle = SDP_CreateRecord()) == 0)
558    {
559        APPL_TRACE_ERROR("%s(): Unable to register PBAP Server Service", __func__);
560        return sdp_handle;
561    }
562
563    /* add service class */
564    status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
565    memset( protoList, 0 , 3*sizeof(tSDP_PROTOCOL_ELEM) );
566
567    /* add protocol list, including RFCOMM scn */
568    protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
569    protoList[0].num_params = 0;
570    protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
571    protoList[1].num_params = 1;
572    protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
573    protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
574    protoList[2].num_params = 0;
575    status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
576
577    /* Add a name entry */
578    status &= SDP_AddAttribute(sdp_handle,
579                    (UINT16)ATTR_ID_SERVICE_NAME,
580                    (UINT8)TEXT_STR_DESC_TYPE,
581                    (UINT32)(rec->hdr.service_name_length + 1),
582                    (UINT8 *)rec->hdr.service_name);
583
584    /* Add in the Bluetooth Profile Descriptor List */
585    status &= SDP_AddProfileDescriptorList(sdp_handle,
586                                     UUID_SERVCLASS_PHONE_ACCESS,
587                                     rec->hdr.profile_version);
588
589    /* Add supported repositories 1 byte */
590    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_REPOSITORIES,
591            UINT_DESC_TYPE, (UINT32)1, (UINT8*)&rec->supported_repositories);
592
593    /* Add supported feature 4 bytes*/
594    UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
595    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_PBAP_SUPPORTED_FEATURES,
596            UINT_DESC_TYPE, (UINT32)4, temp);
597
598    /* Add the L2CAP PSM if present */
599    if(rec->hdr.l2cap_psm != -1) {
600        p_temp = temp;// The macro modifies p_temp, hence rewind.
601        UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
602        status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
603                UINT_DESC_TYPE, (UINT32)2, temp);
604    }
605
606    /* Make the service browseable */
607    status &= SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
608
609    if (!status)
610    {
611        SDP_DeleteRecord(sdp_handle);
612        sdp_handle = 0;
613        APPL_TRACE_ERROR("%s() FAILED", __func__);
614    }
615    else
616    {
617        bta_sys_add_uuid(service);  /* UUID_SERVCLASS_MESSAGE_ACCESS */
618        APPL_TRACE_DEBUG("%s():  SDP Registered (handle 0x%08x)", __func__, sdp_handle);
619    }
620    return sdp_handle;
621}
622
623/* Create a OPP Server SDP record based on information stored in a bluetooth_sdp_ops_record */
624static int add_opps_sdp(const bluetooth_sdp_ops_record* rec)
625{
626
627    tSDP_PROTOCOL_ELEM  protoList [3];
628    UINT16              service = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
629    UINT16              browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
630    UINT8               type_len[rec->supported_formats_list_len];
631    UINT8               desc_type[rec->supported_formats_list_len];
632    UINT8              *type_value[rec->supported_formats_list_len];
633    BOOLEAN             status = TRUE;
634    UINT32              sdp_handle = 0;
635    UINT8               temp[4];
636    UINT8*              p_temp = temp;
637    tBTA_UTL_COD        cod;
638    int i,j;
639
640    APPL_TRACE_DEBUG("%s(): scn 0x%02x, psm = 0x%04x\n  service name %s", __func__,
641            rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm, rec->hdr.service_name);
642
643    APPL_TRACE_DEBUG("  supported formats count: %d",
644            rec->supported_formats_list_len);
645
646    if ((sdp_handle = SDP_CreateRecord()) == 0)
647    {
648        APPL_TRACE_ERROR("%s(): Unable to register Object Push Server Service", __func__);
649        return sdp_handle;
650    }
651
652    /* add service class */
653    status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
654    memset( protoList, 0 , 3*sizeof(tSDP_PROTOCOL_ELEM) );
655
656    /* add protocol list, including RFCOMM scn */
657    protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
658    protoList[0].num_params = 0;
659    protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
660    protoList[1].num_params = 1;
661    protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
662    protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
663    protoList[2].num_params = 0;
664    status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
665
666    /* Add a name entry */
667    status &= SDP_AddAttribute(sdp_handle,
668                    (UINT16)ATTR_ID_SERVICE_NAME,
669                    (UINT8)TEXT_STR_DESC_TYPE,
670                    (UINT32)(rec->hdr.service_name_length + 1),
671                    (UINT8 *)rec->hdr.service_name);
672
673    /* Add in the Bluetooth Profile Descriptor List */
674    status &= SDP_AddProfileDescriptorList(sdp_handle,
675                                     UUID_SERVCLASS_OBEX_OBJECT_PUSH,
676                                     rec->hdr.profile_version);
677
678    /* add sequence for supported types */
679    for (i = 0, j = 0; i < rec->supported_formats_list_len; i++)
680    {
681        type_value[j] = (UINT8 *) &rec->supported_formats_list[i];
682        desc_type[j] = UINT_DESC_TYPE;
683        type_len[j++] = 1;
684    }
685
686    status &= SDP_AddSequence(sdp_handle, (UINT16) ATTR_ID_SUPPORTED_FORMATS_LIST,
687        (UINT8) rec->supported_formats_list_len, desc_type, type_len, type_value);
688
689    /* Add the L2CAP PSM if present */
690    if(rec->hdr.l2cap_psm != -1) {
691        p_temp = temp;// The macro modifies p_temp, hence rewind.
692        UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
693        status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
694                UINT_DESC_TYPE, (UINT32)2, temp);
695    }
696
697    /* Make the service browseable */
698    status &= SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
699
700    if (!status)
701    {
702        SDP_DeleteRecord(sdp_handle);
703        sdp_handle = 0;
704        APPL_TRACE_ERROR("%s() FAILED", __func__);
705    }
706    else
707    {
708        /* set class of device */
709        cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
710        utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
711
712        bta_sys_add_uuid(service);  /* UUID_SERVCLASS_OBEX_OBJECT_PUSH */
713        APPL_TRACE_DEBUG("%s():  SDP Registered (handle 0x%08x)", __func__, sdp_handle);
714    }
715    return sdp_handle;
716}
717
718// Create a Sim Access Profile SDP record based on information stored in a bluetooth_sdp_sap_record.
719static int add_saps_sdp(const bluetooth_sdp_sap_record* rec)
720{
721    tSDP_PROTOCOL_ELEM  protoList [2];
722    UINT16              services[2];
723    UINT16              browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
724    BOOLEAN             status = TRUE;
725    UINT32              sdp_handle = 0;
726
727    APPL_TRACE_DEBUG("%s(): scn 0x%02x, service name %s", __func__,
728            rec->hdr.rfcomm_channel_number, rec->hdr.service_name);
729
730    if ((sdp_handle = SDP_CreateRecord()) == 0)
731    {
732        APPL_TRACE_ERROR("%s(): Unable to register SAPS Service", __func__);
733        return sdp_handle;
734    }
735
736    services[0] = UUID_SERVCLASS_SAP;
737    services[1] = UUID_SERVCLASS_GENERIC_TELEPHONY;
738
739    // add service class
740    status &= SDP_AddServiceClassIdList(sdp_handle, 2, services);
741    memset(protoList, 0, 2 * sizeof(tSDP_PROTOCOL_ELEM));
742
743    // add protocol list, including RFCOMM scn
744    protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
745    protoList[0].num_params = 0;
746    protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
747    protoList[1].num_params = 1;
748    protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
749    status &= SDP_AddProtocolList(sdp_handle, 2, protoList);
750
751    // Add a name entry
752    status &= SDP_AddAttribute(sdp_handle,
753                    (UINT16)ATTR_ID_SERVICE_NAME,
754                    (UINT8)TEXT_STR_DESC_TYPE,
755                    (UINT32)(rec->hdr.service_name_length + 1),
756                    (UINT8 *)rec->hdr.service_name);
757
758    // Add in the Bluetooth Profile Descriptor List
759    status &= SDP_AddProfileDescriptorList(sdp_handle,
760            UUID_SERVCLASS_SAP,
761            rec->hdr.profile_version);
762
763    // Make the service browseable
764    status &= SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
765
766    if (!status)
767    {
768        SDP_DeleteRecord(sdp_handle);
769        sdp_handle = 0;
770        APPL_TRACE_ERROR("%s(): FAILED deleting record", __func__);
771    }
772    else
773    {
774        bta_sys_add_uuid(UUID_SERVCLASS_SAP);
775        APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__, sdp_handle);
776    }
777    return sdp_handle;
778}
779