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