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