• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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