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