1 /******************************************************************************
2 *
3 * Copyright 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 functions that handle the database
22 *
23 ******************************************************************************/
24
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "bt_target.h"
29
30 #include "bt_common.h"
31
32 #include "sdp_api.h"
33 #include "sdpint.h"
34
35 #if (SDP_SERVER_ENABLED == TRUE)
36 /******************************************************************************/
37 /* L O C A L F U N C T I O N P R O T O T Y P E S */
38 /******************************************************************************/
39 static bool find_uuid_in_seq(uint8_t* p, uint32_t seq_len, uint8_t* p_his_uuid,
40 uint16_t his_len, int nest_level);
41
42 /*******************************************************************************
43 *
44 * Function sdp_db_service_search
45 *
46 * Description This function searches for a record that contains the
47 * specified UIDs. It is passed either NULL to start at the
48 * beginning, or the previous record found.
49 *
50 * Returns Pointer to the record, or NULL if not found.
51 *
52 ******************************************************************************/
sdp_db_service_search(tSDP_RECORD * p_rec,tSDP_UUID_SEQ * p_seq)53 tSDP_RECORD* sdp_db_service_search(tSDP_RECORD* p_rec, tSDP_UUID_SEQ* p_seq) {
54 uint16_t xx, yy;
55 tSDP_ATTRIBUTE* p_attr;
56 tSDP_RECORD* p_end = &sdp_cb.server_db.record[sdp_cb.server_db.num_records];
57
58 /* If NULL, start at the beginning, else start at the first specified record
59 */
60 if (!p_rec)
61 p_rec = &sdp_cb.server_db.record[0];
62 else
63 p_rec++;
64
65 /* Look through the records. The spec says that a match occurs if */
66 /* the record contains all the passed UUIDs in it. */
67 for (; p_rec < p_end; p_rec++) {
68 for (yy = 0; yy < p_seq->num_uids; yy++) {
69 p_attr = &p_rec->attribute[0];
70 for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) {
71 if (p_attr->type == UUID_DESC_TYPE) {
72 if (sdpu_compare_uuid_arrays(p_attr->value_ptr, p_attr->len,
73 &p_seq->uuid_entry[yy].value[0],
74 p_seq->uuid_entry[yy].len))
75 break;
76 } else if (p_attr->type == DATA_ELE_SEQ_DESC_TYPE) {
77 if (find_uuid_in_seq(p_attr->value_ptr, p_attr->len,
78 &p_seq->uuid_entry[yy].value[0],
79 p_seq->uuid_entry[yy].len, 0))
80 break;
81 }
82 }
83 /* If any UUID was not found, on to the next record */
84 if (xx == p_rec->num_attributes) break;
85 }
86
87 /* If every UUID was found in the record, return the record */
88 if (yy == p_seq->num_uids) return (p_rec);
89 }
90
91 /* If here, no more records found */
92 return (NULL);
93 }
94
95 /*******************************************************************************
96 *
97 * Function find_uuid_in_seq
98 *
99 * Description This function searches a data element sequenct for a UUID.
100 *
101 * Returns true if found, else false
102 *
103 ******************************************************************************/
find_uuid_in_seq(uint8_t * p,uint32_t seq_len,uint8_t * p_uuid,uint16_t uuid_len,int nest_level)104 static bool find_uuid_in_seq(uint8_t* p, uint32_t seq_len, uint8_t* p_uuid,
105 uint16_t uuid_len, int nest_level) {
106 uint8_t* p_end = p + seq_len;
107 uint8_t type;
108 uint32_t len;
109
110 /* A little safety check to avoid excessive recursion */
111 if (nest_level > 3) return (false);
112
113 while (p < p_end) {
114 type = *p++;
115 p = sdpu_get_len_from_type(p, p_end, type, &len);
116 if (p == NULL || (p + len) > p_end) {
117 SDP_TRACE_WARNING("%s: bad length", __func__);
118 break;
119 }
120 type = type >> 3;
121 if (type == UUID_DESC_TYPE) {
122 if (sdpu_compare_uuid_arrays(p, len, p_uuid, uuid_len)) return (true);
123 } else if (type == DATA_ELE_SEQ_DESC_TYPE) {
124 if (find_uuid_in_seq(p, len, p_uuid, uuid_len, nest_level + 1))
125 return (true);
126 }
127 p = p + len;
128 }
129
130 /* If here, failed to match */
131 return (false);
132 }
133
134 /*******************************************************************************
135 *
136 * Function sdp_db_find_record
137 *
138 * Description This function searches for a record with a specific handle
139 * It is passed the handle of the record.
140 *
141 * Returns Pointer to the record, or NULL if not found.
142 *
143 ******************************************************************************/
sdp_db_find_record(uint32_t handle)144 tSDP_RECORD* sdp_db_find_record(uint32_t handle) {
145 tSDP_RECORD* p_rec;
146 tSDP_RECORD* p_end = &sdp_cb.server_db.record[sdp_cb.server_db.num_records];
147
148 /* Look through the records for the caller's handle */
149 for (p_rec = &sdp_cb.server_db.record[0]; p_rec < p_end; p_rec++) {
150 if (p_rec->record_handle == handle) return (p_rec);
151 }
152
153 /* Record with that handle not found. */
154 return (NULL);
155 }
156
157 /*******************************************************************************
158 *
159 * Function sdp_db_find_attr_in_rec
160 *
161 * Description This function searches a record for specific attributes.
162 * It is passed a pointer to the record. If the record contains
163 * the specified attribute, (the caller may specify be a range
164 * of attributes), the attribute is returned.
165 *
166 * Returns Pointer to the attribute, or NULL if not found.
167 *
168 ******************************************************************************/
sdp_db_find_attr_in_rec(tSDP_RECORD * p_rec,uint16_t start_attr,uint16_t end_attr)169 tSDP_ATTRIBUTE* sdp_db_find_attr_in_rec(tSDP_RECORD* p_rec, uint16_t start_attr,
170 uint16_t end_attr) {
171 tSDP_ATTRIBUTE* p_at;
172 uint16_t xx;
173
174 /* Note that the attributes in a record are assumed to be in sorted order */
175 for (xx = 0, p_at = &p_rec->attribute[0]; xx < p_rec->num_attributes;
176 xx++, p_at++) {
177 if ((p_at->id >= start_attr) && (p_at->id <= end_attr)) return (p_at);
178 }
179
180 /* No matching attribute found */
181 return (NULL);
182 }
183
184 /*******************************************************************************
185 *
186 * Function sdp_compose_proto_list
187 *
188 * Description This function is called to compose a data sequence from
189 * protocol element list struct pointer
190 *
191 * Returns the length of the data sequence
192 *
193 ******************************************************************************/
sdp_compose_proto_list(uint8_t * p,uint16_t num_elem,tSDP_PROTOCOL_ELEM * p_elem_list)194 static int sdp_compose_proto_list(uint8_t* p, uint16_t num_elem,
195 tSDP_PROTOCOL_ELEM* p_elem_list) {
196 uint16_t xx, yy, len;
197 bool is_rfcomm_scn;
198 uint8_t* p_head = p;
199 uint8_t* p_len;
200
201 /* First, build the protocol list. This consists of a set of data element
202 ** sequences, one for each layer. Each layer sequence consists of layer's
203 ** UUID and optional parameters
204 */
205 for (xx = 0; xx < num_elem; xx++, p_elem_list++) {
206 len = 3 + (p_elem_list->num_params * 3);
207 UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
208
209 p_len = p;
210 *p++ = (uint8_t)len;
211
212 UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
213 UINT16_TO_BE_STREAM(p, p_elem_list->protocol_uuid);
214
215 if (p_elem_list->protocol_uuid == UUID_PROTOCOL_RFCOMM)
216 is_rfcomm_scn = true;
217 else
218 is_rfcomm_scn = false;
219
220 for (yy = 0; yy < p_elem_list->num_params; yy++) {
221 if (is_rfcomm_scn) {
222 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
223 UINT8_TO_BE_STREAM(p, p_elem_list->params[yy]);
224
225 *p_len -= 1;
226 } else {
227 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
228 UINT16_TO_BE_STREAM(p, p_elem_list->params[yy]);
229 }
230 }
231 }
232 return (p - p_head);
233 }
234
235 #endif /* SDP_SERVER_ENABLED == TRUE */
236
237 /*******************************************************************************
238 *
239 * Function SDP_CreateRecord
240 *
241 * Description This function is called to create a record in the database.
242 * This would be through the SDP database maintenance API. The
243 * record is created empty, teh application should then call
244 * "add_attribute" to add the record's attributes.
245 *
246 * Returns Record handle if OK, else 0.
247 *
248 ******************************************************************************/
SDP_CreateRecord(void)249 uint32_t SDP_CreateRecord(void) {
250 #if (SDP_SERVER_ENABLED == TRUE)
251 uint32_t handle;
252 uint8_t buf[4];
253 tSDP_DB* p_db = &sdp_cb.server_db;
254
255 /* First, check if there is a free record */
256 if (p_db->num_records < SDP_MAX_RECORDS) {
257 memset(&p_db->record[p_db->num_records], 0, sizeof(tSDP_RECORD));
258
259 /* We will use a handle of the first unreserved handle plus last record
260 ** number + 1 */
261 if (p_db->num_records)
262 handle = p_db->record[p_db->num_records - 1].record_handle + 1;
263 else
264 handle = 0x10000;
265
266 p_db->record[p_db->num_records].record_handle = handle;
267
268 p_db->num_records++;
269 SDP_TRACE_DEBUG("SDP_CreateRecord ok, num_records:%d", p_db->num_records);
270 /* Add the first attribute (the handle) automatically */
271 UINT32_TO_BE_FIELD(buf, handle);
272 SDP_AddAttribute(handle, ATTR_ID_SERVICE_RECORD_HDL, UINT_DESC_TYPE, 4,
273 buf);
274
275 return (p_db->record[p_db->num_records - 1].record_handle);
276 } else
277 SDP_TRACE_ERROR("SDP_CreateRecord fail, exceed maximum records:%d",
278 SDP_MAX_RECORDS);
279 #endif
280 return (0);
281 }
282
283 /*******************************************************************************
284 *
285 * Function SDP_DeleteRecord
286 *
287 * Description This function is called to add a record (or all records)
288 * from the database. This would be through the SDP database
289 * maintenance API.
290 *
291 * If a record handle of 0 is passed, all records are deleted.
292 *
293 * Returns true if succeeded, else false
294 *
295 ******************************************************************************/
SDP_DeleteRecord(uint32_t handle)296 bool SDP_DeleteRecord(uint32_t handle) {
297 #if (SDP_SERVER_ENABLED == TRUE)
298 uint16_t xx, yy, zz;
299 tSDP_RECORD* p_rec = &sdp_cb.server_db.record[0];
300
301 if (handle == 0 || sdp_cb.server_db.num_records == 0) {
302 /* Delete all records in the database */
303 sdp_cb.server_db.num_records = 0;
304
305 /* require new DI record to be created in SDP_SetLocalDiRecord */
306 sdp_cb.server_db.di_primary_handle = 0;
307
308 return (true);
309 } else {
310 /* Find the record in the database */
311 for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++) {
312 if (p_rec->record_handle == handle) {
313 /* Found it. Shift everything up one */
314 for (yy = xx; yy < sdp_cb.server_db.num_records - 1; yy++, p_rec++) {
315 *p_rec = *(p_rec + 1);
316
317 /* Adjust the attribute value pointer for each attribute */
318 for (zz = 0; zz < p_rec->num_attributes; zz++)
319 p_rec->attribute[zz].value_ptr -= sizeof(tSDP_RECORD);
320 }
321
322 sdp_cb.server_db.num_records--;
323
324 SDP_TRACE_DEBUG("SDP_DeleteRecord ok, num_records:%d",
325 sdp_cb.server_db.num_records);
326 /* if we're deleting the primary DI record, clear the */
327 /* value in the control block */
328 if (sdp_cb.server_db.di_primary_handle == handle) {
329 sdp_cb.server_db.di_primary_handle = 0;
330 }
331
332 return (true);
333 }
334 }
335 }
336 #endif
337 return (false);
338 }
339
340 /*******************************************************************************
341 *
342 * Function SDP_AddAttribute
343 *
344 * Description This function is called to add an attribute to a record.
345 * This would be through the SDP database maintenance API.
346 * If the attribute already exists in the record, it is
347 * replaced with the new value.
348 *
349 * NOTE Attribute values must be passed as a Big Endian stream.
350 *
351 * Returns true if added OK, else false
352 *
353 ******************************************************************************/
SDP_AddAttribute(uint32_t handle,uint16_t attr_id,uint8_t attr_type,uint32_t attr_len,uint8_t * p_val)354 bool SDP_AddAttribute(uint32_t handle, uint16_t attr_id, uint8_t attr_type,
355 uint32_t attr_len, uint8_t* p_val) {
356 #if (SDP_SERVER_ENABLED == TRUE)
357 uint16_t xx, yy, zz;
358 tSDP_RECORD* p_rec = &sdp_cb.server_db.record[0];
359
360 if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) {
361 if ((attr_type == UINT_DESC_TYPE) ||
362 (attr_type == TWO_COMP_INT_DESC_TYPE) ||
363 (attr_type == UUID_DESC_TYPE) ||
364 (attr_type == DATA_ELE_SEQ_DESC_TYPE) ||
365 (attr_type == DATA_ELE_ALT_DESC_TYPE)) {
366 uint8_t num_array[400];
367 uint32_t len = (attr_len > 200) ? 200 : attr_len;
368
369 num_array[0] = '\0';
370 for (uint32_t i = 0; i < len; i++) {
371 snprintf((char*)&num_array[i * 2], sizeof(num_array) - i * 2, "%02X",
372 (uint8_t)(p_val[i]));
373 }
374 SDP_TRACE_DEBUG(
375 "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, "
376 "*p_val:%s",
377 handle, attr_id, attr_type, attr_len, p_val, num_array);
378 } else if (attr_type == BOOLEAN_DESC_TYPE) {
379 SDP_TRACE_DEBUG(
380 "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, "
381 "*p_val:%d",
382 handle, attr_id, attr_type, attr_len, p_val, *p_val);
383 } else {
384 SDP_TRACE_DEBUG(
385 "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, "
386 "*p_val:%s",
387 handle, attr_id, attr_type, attr_len, p_val, p_val);
388 }
389 }
390
391 /* Find the record in the database */
392 for (zz = 0; zz < sdp_cb.server_db.num_records; zz++, p_rec++) {
393 if (p_rec->record_handle == handle) {
394 tSDP_ATTRIBUTE* p_attr = &p_rec->attribute[0];
395
396 /* Found the record. Now, see if the attribute already exists */
397 for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) {
398 /* The attribute exists. replace it */
399 if (p_attr->id == attr_id) {
400 SDP_DeleteAttribute(handle, attr_id);
401 break;
402 }
403 if (p_attr->id > attr_id) break;
404 }
405
406 if (p_rec->num_attributes == SDP_MAX_REC_ATTR) return (false);
407
408 /* If not found, see if we can allocate a new entry */
409 if (xx == p_rec->num_attributes)
410 p_attr = &p_rec->attribute[p_rec->num_attributes];
411 else {
412 /* Since the attributes are kept in sorted order, insert ours here */
413 for (yy = p_rec->num_attributes; yy > xx; yy--)
414 p_rec->attribute[yy] = p_rec->attribute[yy - 1];
415 }
416
417 p_attr->id = attr_id;
418 p_attr->type = attr_type;
419 p_attr->len = attr_len;
420
421 if (p_rec->free_pad_ptr + attr_len >= SDP_MAX_PAD_LEN) {
422 /* do truncate only for text string type descriptor */
423 if (attr_type == TEXT_STR_DESC_TYPE) {
424 SDP_TRACE_WARNING(
425 "SDP_AddAttribute: attr_len:%d too long. truncate to (%d)",
426 attr_len, SDP_MAX_PAD_LEN - p_rec->free_pad_ptr);
427
428 attr_len = SDP_MAX_PAD_LEN - p_rec->free_pad_ptr;
429 p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr] = '\0';
430 p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr + 1] = '\0';
431 } else
432 attr_len = 0;
433 }
434
435 if ((attr_len > 0) && (p_val != 0)) {
436 p_attr->len = attr_len;
437 memcpy(&p_rec->attr_pad[p_rec->free_pad_ptr], p_val, (size_t)attr_len);
438 p_attr->value_ptr = &p_rec->attr_pad[p_rec->free_pad_ptr];
439 p_rec->free_pad_ptr += attr_len;
440 } else if ((attr_len == 0 &&
441 p_attr->len !=
442 0) || /* if truncate to 0 length, simply don't add */
443 p_val == 0) {
444 SDP_TRACE_ERROR(
445 "SDP_AddAttribute fail, length exceed maximum: ID %d: attr_len:%d ",
446 attr_id, attr_len);
447 p_attr->id = p_attr->type = p_attr->len = 0;
448 return (false);
449 }
450 p_rec->num_attributes++;
451 return (true);
452 }
453 }
454 #endif
455 return (false);
456 }
457
458 /*******************************************************************************
459 *
460 * Function SDP_AddSequence
461 *
462 * Description This function is called to add a sequence to a record.
463 * This would be through the SDP database maintenance API.
464 * If the sequence already exists in the record, it is replaced
465 * with the new sequence.
466 *
467 * NOTE Element values must be passed as a Big Endian stream.
468 *
469 * Returns true if added OK, else false
470 *
471 ******************************************************************************/
SDP_AddSequence(uint32_t handle,uint16_t attr_id,uint16_t num_elem,uint8_t type[],uint8_t len[],uint8_t * p_val[])472 bool SDP_AddSequence(uint32_t handle, uint16_t attr_id, uint16_t num_elem,
473 uint8_t type[], uint8_t len[], uint8_t* p_val[]) {
474 #if (SDP_SERVER_ENABLED == TRUE)
475 uint16_t xx;
476 uint8_t* p;
477 uint8_t* p_head;
478 bool result;
479 uint8_t* p_buff =
480 (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
481
482 p = p_buff;
483
484 /* First, build the sequence */
485 for (xx = 0; xx < num_elem; xx++) {
486 p_head = p;
487 switch (len[xx]) {
488 case 1:
489 UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_ONE_BYTE);
490 break;
491 case 2:
492 UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_TWO_BYTES);
493 break;
494 case 4:
495 UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_FOUR_BYTES);
496 break;
497 case 8:
498 UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_EIGHT_BYTES);
499 break;
500 case 16:
501 UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_SIXTEEN_BYTES);
502 break;
503 default:
504 UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_IN_NEXT_BYTE);
505 UINT8_TO_BE_STREAM(p, len[xx]);
506 break;
507 }
508
509 ARRAY_TO_BE_STREAM(p, p_val[xx], len[xx]);
510
511 if (p - p_buff > SDP_MAX_ATTR_LEN) {
512 /* go back to before we add this element */
513 p = p_head;
514 if (p_head == p_buff) {
515 /* the first element exceed the max length */
516 SDP_TRACE_ERROR("SDP_AddSequence - too long(attribute is not added)!!");
517 osi_free(p_buff);
518 return false;
519 } else
520 SDP_TRACE_ERROR("SDP_AddSequence - too long, add %d elements of %d", xx,
521 num_elem);
522 break;
523 }
524 }
525 result = SDP_AddAttribute(handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,
526 (uint32_t)(p - p_buff), p_buff);
527 osi_free(p_buff);
528 return result;
529 #else /* SDP_SERVER_ENABLED == FALSE */
530 return (false);
531 #endif
532 }
533
534 /*******************************************************************************
535 *
536 * Function SDP_AddUuidSequence
537 *
538 * Description This function is called to add a UUID sequence to a record.
539 * This would be through the SDP database maintenance API.
540 * If the sequence already exists in the record, it is replaced
541 * with the new sequence.
542 *
543 * Returns true if added OK, else false
544 *
545 ******************************************************************************/
SDP_AddUuidSequence(uint32_t handle,uint16_t attr_id,uint16_t num_uuids,uint16_t * p_uuids)546 bool SDP_AddUuidSequence(uint32_t handle, uint16_t attr_id, uint16_t num_uuids,
547 uint16_t* p_uuids) {
548 #if (SDP_SERVER_ENABLED == TRUE)
549 uint16_t xx;
550 uint8_t* p;
551 int32_t max_len = SDP_MAX_ATTR_LEN - 3;
552 bool result;
553 uint8_t* p_buff =
554 (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
555
556 p = p_buff;
557
558 /* First, build the sequence */
559 for (xx = 0; xx < num_uuids; xx++, p_uuids++) {
560 UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
561 UINT16_TO_BE_STREAM(p, *p_uuids);
562
563 if ((p - p_buff) > max_len) {
564 SDP_TRACE_WARNING("SDP_AddUuidSequence - too long, add %d uuids of %d",
565 xx, num_uuids);
566 break;
567 }
568 }
569
570 result = SDP_AddAttribute(handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,
571 (uint32_t)(p - p_buff), p_buff);
572 osi_free(p_buff);
573 return result;
574 #else /* SDP_SERVER_ENABLED == FALSE */
575 return (false);
576 #endif
577 }
578
579 /*******************************************************************************
580 *
581 * Function SDP_AddProtocolList
582 *
583 * Description This function is called to add a protocol descriptor list to
584 * a record. This would be through the SDP database
585 * maintenance API. If the protocol list already exists in the
586 * record, it is replaced with the new list.
587 *
588 * Returns true if added OK, else false
589 *
590 ******************************************************************************/
SDP_AddProtocolList(uint32_t handle,uint16_t num_elem,tSDP_PROTOCOL_ELEM * p_elem_list)591 bool SDP_AddProtocolList(uint32_t handle, uint16_t num_elem,
592 tSDP_PROTOCOL_ELEM* p_elem_list) {
593 #if (SDP_SERVER_ENABLED == TRUE)
594 int offset;
595 bool result;
596 uint8_t* p_buff =
597 (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
598
599 offset = sdp_compose_proto_list(p_buff, num_elem, p_elem_list);
600 result = SDP_AddAttribute(handle, ATTR_ID_PROTOCOL_DESC_LIST,
601 DATA_ELE_SEQ_DESC_TYPE, (uint32_t)offset, p_buff);
602 osi_free(p_buff);
603 return result;
604 #else /* SDP_SERVER_ENABLED == FALSE */
605 return (false);
606 #endif
607 }
608
609 /*******************************************************************************
610 *
611 * Function SDP_AddAdditionProtoLists
612 *
613 * Description This function is called to add a protocol descriptor list to
614 * a record. This would be through the SDP database maintenance
615 * API. If the protocol list already exists in the record, it
616 * is replaced with the new list.
617 *
618 * Returns true if added OK, else false
619 *
620 ******************************************************************************/
SDP_AddAdditionProtoLists(uint32_t handle,uint16_t num_elem,tSDP_PROTO_LIST_ELEM * p_proto_list)621 bool SDP_AddAdditionProtoLists(uint32_t handle, uint16_t num_elem,
622 tSDP_PROTO_LIST_ELEM* p_proto_list) {
623 #if (SDP_SERVER_ENABLED == TRUE)
624 uint16_t xx;
625 uint8_t* p;
626 uint8_t* p_len;
627 int offset;
628 bool result;
629 uint8_t* p_buff =
630 (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
631
632 p = p_buff;
633
634 /* for each ProtocolDescriptorList */
635 for (xx = 0; xx < num_elem; xx++, p_proto_list++) {
636 UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
637 p_len = p++;
638
639 offset = sdp_compose_proto_list(p, p_proto_list->num_elems,
640 p_proto_list->list_elem);
641 p += offset;
642
643 *p_len = (uint8_t)(p - p_len - 1);
644 }
645 result =
646 SDP_AddAttribute(handle, ATTR_ID_ADDITION_PROTO_DESC_LISTS,
647 DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - p_buff), p_buff);
648 osi_free(p_buff);
649 return result;
650
651 #else /* SDP_SERVER_ENABLED == FALSE */
652 return (false);
653 #endif
654 }
655
656 /*******************************************************************************
657 *
658 * Function SDP_AddProfileDescriptorList
659 *
660 * Description This function is called to add a profile descriptor list to
661 * a record. This would be through the SDP database maintenance
662 * API. If the version already exists in the record, it is
663 * replaced with the new one.
664 *
665 * Returns true if added OK, else false
666 *
667 ******************************************************************************/
SDP_AddProfileDescriptorList(uint32_t handle,uint16_t profile_uuid,uint16_t version)668 bool SDP_AddProfileDescriptorList(uint32_t handle, uint16_t profile_uuid,
669 uint16_t version) {
670 #if (SDP_SERVER_ENABLED == TRUE)
671 uint8_t* p;
672 bool result;
673 uint8_t* p_buff = (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN);
674
675 p = p_buff + 2;
676
677 /* First, build the profile descriptor list. This consists of a data element
678 * sequence. */
679 /* The sequence consists of profile's UUID and version number */
680 UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
681 UINT16_TO_BE_STREAM(p, profile_uuid);
682
683 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
684 UINT16_TO_BE_STREAM(p, version);
685
686 /* Add in type and length fields */
687 *p_buff = (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
688 *(p_buff + 1) = (uint8_t)(p - (p_buff + 2));
689
690 result =
691 SDP_AddAttribute(handle, ATTR_ID_BT_PROFILE_DESC_LIST,
692 DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - p_buff), p_buff);
693 osi_free(p_buff);
694 return result;
695
696 #else /* SDP_SERVER_ENABLED == FALSE */
697 return (false);
698 #endif
699 }
700
701 /*******************************************************************************
702 *
703 * Function SDP_AddLanguageBaseAttrIDList
704 *
705 * Description This function is called to add a language base attr list to
706 * a record. This would be through the SDP database maintenance
707 * API. If the version already exists in the record, it is
708 * replaced with the new one.
709 *
710 * Returns true if added OK, else false
711 *
712 ******************************************************************************/
SDP_AddLanguageBaseAttrIDList(uint32_t handle,uint16_t lang,uint16_t char_enc,uint16_t base_id)713 bool SDP_AddLanguageBaseAttrIDList(uint32_t handle, uint16_t lang,
714 uint16_t char_enc, uint16_t base_id) {
715 #if (SDP_SERVER_ENABLED == TRUE)
716 uint8_t* p;
717 bool result;
718 uint8_t* p_buff = (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN);
719
720 p = p_buff;
721
722 /* First, build the language base descriptor list. This consists of a data */
723 /* element sequence. The sequence consists of 9 bytes (3 UINt16 fields) */
724 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
725 UINT16_TO_BE_STREAM(p, lang);
726
727 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
728 UINT16_TO_BE_STREAM(p, char_enc);
729
730 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
731 UINT16_TO_BE_STREAM(p, base_id);
732
733 result =
734 SDP_AddAttribute(handle, ATTR_ID_LANGUAGE_BASE_ATTR_ID_LIST,
735 DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - p_buff), p_buff);
736 osi_free(p_buff);
737 return result;
738 #else /* SDP_SERVER_ENABLED == FALSE */
739 return (false);
740 #endif
741 }
742
743 /*******************************************************************************
744 *
745 * Function SDP_AddServiceClassIdList
746 *
747 * Description This function is called to add a service list to a record.
748 * This would be through the SDP database maintenance API.
749 * If the service list already exists in the record, it is
750 * replaced with the new list.
751 *
752 * Returns true if added OK, else false
753 *
754 ******************************************************************************/
SDP_AddServiceClassIdList(uint32_t handle,uint16_t num_services,uint16_t * p_service_uuids)755 bool SDP_AddServiceClassIdList(uint32_t handle, uint16_t num_services,
756 uint16_t* p_service_uuids) {
757 #if (SDP_SERVER_ENABLED == TRUE)
758 uint16_t xx;
759 uint8_t* p;
760 bool result;
761 uint8_t* p_buff =
762 (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
763
764 p = p_buff;
765
766 for (xx = 0; xx < num_services; xx++, p_service_uuids++) {
767 UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
768 UINT16_TO_BE_STREAM(p, *p_service_uuids);
769 }
770
771 result =
772 SDP_AddAttribute(handle, ATTR_ID_SERVICE_CLASS_ID_LIST,
773 DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - p_buff), p_buff);
774 osi_free(p_buff);
775 return result;
776 #else /* SDP_SERVER_ENABLED == FALSE */
777 return (false);
778 #endif
779 }
780
781 /*******************************************************************************
782 *
783 * Function SDP_DeleteAttribute
784 *
785 * Description This function is called to delete an attribute from a
786 * record. This would be through the SDP database maintenance
787 * API.
788 *
789 * Returns true if deleted OK, else false if not found
790 *
791 ******************************************************************************/
SDP_DeleteAttribute(uint32_t handle,uint16_t attr_id)792 bool SDP_DeleteAttribute(uint32_t handle, uint16_t attr_id) {
793 #if (SDP_SERVER_ENABLED == TRUE)
794 tSDP_RECORD* p_rec = &sdp_cb.server_db.record[0];
795 uint8_t* pad_ptr;
796 uint32_t len; /* Number of bytes in the entry */
797
798 /* Find the record in the database */
799 for (uint16_t xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++) {
800 if (p_rec->record_handle == handle) {
801 tSDP_ATTRIBUTE* p_attr = &p_rec->attribute[0];
802
803 SDP_TRACE_API("Deleting attr_id 0x%04x for handle 0x%x", attr_id, handle);
804 /* Found it. Now, find the attribute */
805 for (uint16_t yy = 0; yy < p_rec->num_attributes; yy++, p_attr++) {
806 if (p_attr->id == attr_id) {
807 pad_ptr = p_attr->value_ptr;
808 len = p_attr->len;
809
810 if (len) {
811 for (uint16_t zz = 0; zz < p_rec->num_attributes; zz++) {
812 if (p_rec->attribute[zz].value_ptr > pad_ptr)
813 p_rec->attribute[zz].value_ptr -= len;
814 }
815 }
816
817 /* Found it. Shift everything up one */
818 p_rec->num_attributes--;
819
820 for (uint16_t zz = xx; zz < p_rec->num_attributes; zz++, p_attr++) {
821 *p_attr = *(p_attr + 1);
822 }
823
824 /* adjust attribute values if needed */
825 if (len) {
826 xx =
827 (p_rec->free_pad_ptr - ((pad_ptr + len) - &p_rec->attr_pad[0]));
828 for (uint16_t zz = 0; zz < xx; zz++, pad_ptr++) {
829 *pad_ptr = *(pad_ptr + len);
830 }
831 p_rec->free_pad_ptr -= len;
832 }
833 return (true);
834 }
835 }
836 }
837 }
838 #endif
839 /* If here, not found */
840 return (false);
841 }
842