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