• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 SDP utility functions
22  *
23  ******************************************************************************/
24 
25 #include <stdio.h>
26 #include <string.h>
27 #include <utility>
28 #include <vector>
29 
30 #include "bt_common.h"
31 #include "bt_types.h"
32 #include "btif_config.h"
33 
34 #include "avrc_defs.h"
35 #include "sdp_api.h"
36 #include "sdpint.h"
37 
38 #include "stack/include/stack_metrics_logging.h"
39 
40 using bluetooth::Uuid;
41 static const uint8_t sdp_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42                                         0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
43                                         0x5F, 0x9B, 0x34, 0xFB};
44 
45 template <typename T>
to_little_endian_array(T x)46 static std::array<char, sizeof(T)> to_little_endian_array(T x) {
47   static_assert(std::is_integral<T>::value,
48                 "to_little_endian_array parameter must be integral.");
49   std::array<char, sizeof(T)> array = {};
50   for (size_t i = 0; i < array.size(); i++) {
51     array[i] = static_cast<char>((x >> (8 * i)) & 0xFF);
52   }
53   return array;
54 }
55 
56 /**
57  * Find the list of profile versions from Bluetooth Profile Descriptor list
58  * attribute in a SDP record
59  *
60  * @param p_rec SDP record to search
61  * @return a vector of <UUID, VERSION> pairs, empty if not found
62  */
sdpu_find_profile_version(tSDP_DISC_REC * p_rec)63 static std::vector<std::pair<uint16_t, uint16_t>> sdpu_find_profile_version(
64     tSDP_DISC_REC* p_rec) {
65   std::vector<std::pair<uint16_t, uint16_t>> result;
66   for (tSDP_DISC_ATTR* p_attr = p_rec->p_first_attr; p_attr != nullptr;
67        p_attr = p_attr->p_next_attr) {
68     // Find the profile descriptor list */
69     if (p_attr->attr_id != ATTR_ID_BT_PROFILE_DESC_LIST ||
70         SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) {
71       continue;
72     }
73     // Walk through the protocol descriptor list
74     for (tSDP_DISC_ATTR* p_sattr = p_attr->attr_value.v.p_sub_attr;
75          p_sattr != nullptr; p_sattr = p_sattr->p_next_attr) {
76       // Safety check - each entry should itself be a sequence
77       if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) !=
78           DATA_ELE_SEQ_DESC_TYPE) {
79         LOG(WARNING) << __func__ << ": Descriptor type is not sequence: "
80                      << loghex(SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type));
81         return std::vector<std::pair<uint16_t, uint16_t>>();
82       }
83       // Now, see if the entry contains the profile UUID we are interested in
84       for (tSDP_DISC_ATTR* p_ssattr = p_sattr->attr_value.v.p_sub_attr;
85            p_ssattr != nullptr; p_ssattr = p_ssattr->p_next_attr) {
86         if (SDP_DISC_ATTR_TYPE(p_ssattr->attr_len_type) != UUID_DESC_TYPE ||
87             SDP_DISC_ATTR_LEN(p_ssattr->attr_len_type) != 2) {
88           continue;
89         }
90         uint16_t uuid = p_ssattr->attr_value.v.u16;
91         // Next attribute should be the version attribute
92         tSDP_DISC_ATTR* version_attr = p_ssattr->p_next_attr;
93         if (SDP_DISC_ATTR_TYPE(version_attr->attr_len_type) != UINT_DESC_TYPE ||
94             SDP_DISC_ATTR_LEN(version_attr->attr_len_type) != 2) {
95           LOG(WARNING) << __func__ << ": Bad version type "
96                        << loghex(
97                               SDP_DISC_ATTR_TYPE(version_attr->attr_len_type))
98                        << ", or length "
99                        << SDP_DISC_ATTR_LEN(version_attr->attr_len_type);
100           return std::vector<std::pair<uint16_t, uint16_t>>();
101         }
102         // High order 8 bits is the major number, low order is the
103         // minor number (big endian)
104         uint16_t version = version_attr->attr_value.v.u16;
105         result.emplace_back(uuid, version);
106       }
107     }
108   }
109   return result;
110 }
111 
112 /**
113  * Find the most specific 16-bit service uuid represented by a SDP record
114  *
115  * @param p_rec pointer to a SDP record
116  * @return most specific 16-bit service uuid, 0 if not found
117  */
sdpu_find_most_specific_service_uuid(tSDP_DISC_REC * p_rec)118 static uint16_t sdpu_find_most_specific_service_uuid(tSDP_DISC_REC* p_rec) {
119   for (tSDP_DISC_ATTR* p_attr = p_rec->p_first_attr; p_attr != nullptr;
120        p_attr = p_attr->p_next_attr) {
121     if (p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST &&
122         SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) {
123       tSDP_DISC_ATTR* p_first_attr = p_attr->attr_value.v.p_sub_attr;
124       if (SDP_DISC_ATTR_TYPE(p_first_attr->attr_len_type) == UUID_DESC_TYPE &&
125           SDP_DISC_ATTR_LEN(p_first_attr->attr_len_type) == 2) {
126         return p_first_attr->attr_value.v.u16;
127       } else if (SDP_DISC_ATTR_TYPE(p_first_attr->attr_len_type) ==
128                  DATA_ELE_SEQ_DESC_TYPE) {
129         // Workaround for Toyota G Block car kit:
130         // It incorrectly puts an extra data element sequence in this attribute
131         for (tSDP_DISC_ATTR* p_extra_sattr =
132                  p_first_attr->attr_value.v.p_sub_attr;
133              p_extra_sattr != nullptr;
134              p_extra_sattr = p_extra_sattr->p_next_attr) {
135           // Return the first UUID data element
136           if (SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) ==
137                   UUID_DESC_TYPE &&
138               SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2) {
139             return p_extra_sattr->attr_value.v.u16;
140           }
141         }
142       } else {
143         LOG(WARNING) << __func__ << ": Bad Service Class ID list attribute";
144         return 0;
145       }
146     } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
147       if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE &&
148           SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2) {
149         return p_attr->attr_value.v.u16;
150       }
151     }
152   }
153   return 0;
154 }
155 
sdpu_log_attribute_metrics(const RawAddress & bda,tSDP_DISCOVERY_DB * p_db)156 void sdpu_log_attribute_metrics(const RawAddress& bda,
157                                 tSDP_DISCOVERY_DB* p_db) {
158   CHECK_NE(p_db, nullptr);
159   bool has_di_record = false;
160   for (tSDP_DISC_REC* p_rec = p_db->p_first_rec; p_rec != nullptr;
161        p_rec = p_rec->p_next_rec) {
162     uint16_t service_uuid = sdpu_find_most_specific_service_uuid(p_rec);
163     if (service_uuid == 0) {
164       LOG(INFO) << __func__ << ": skipping record without service uuid " << bda;
165       continue;
166     }
167     // Log the existence of a profile role
168     // This can be different from Bluetooth Profile Descriptor List
169     log_sdp_attribute(bda, service_uuid, 0, 0, nullptr);
170     // Log profile version from Bluetooth Profile Descriptor List
171     auto uuid_version_array = sdpu_find_profile_version(p_rec);
172     for (const auto& uuid_version_pair : uuid_version_array) {
173       uint16_t profile_uuid = uuid_version_pair.first;
174       uint16_t version = uuid_version_pair.second;
175       auto version_array = to_little_endian_array(version);
176       log_sdp_attribute(bda, profile_uuid, ATTR_ID_BT_PROFILE_DESC_LIST,
177                         version_array.size(), version_array.data());
178     }
179     // Log protocol version from Protocol Descriptor List
180     uint16_t protocol_uuid = 0;
181     switch (service_uuid) {
182       case UUID_SERVCLASS_AUDIO_SOURCE:
183       case UUID_SERVCLASS_AUDIO_SINK:
184         protocol_uuid = UUID_PROTOCOL_AVDTP;
185         break;
186       case UUID_SERVCLASS_AV_REMOTE_CONTROL:
187       case UUID_SERVCLASS_AV_REM_CTRL_CONTROL:
188       case UUID_SERVCLASS_AV_REM_CTRL_TARGET:
189         protocol_uuid = UUID_PROTOCOL_AVCTP;
190         break;
191       case UUID_SERVCLASS_PANU:
192       case UUID_SERVCLASS_GN:
193         protocol_uuid = UUID_PROTOCOL_BNEP;
194         break;
195     }
196     if (protocol_uuid != 0) {
197       tSDP_PROTOCOL_ELEM protocol_elements = {};
198       if (SDP_FindProtocolListElemInRec(p_rec, protocol_uuid,
199                                         &protocol_elements)) {
200         if (protocol_elements.num_params >= 1) {
201           uint16_t version = protocol_elements.params[0];
202           auto version_array = to_little_endian_array(version);
203           log_sdp_attribute(bda, protocol_uuid, ATTR_ID_PROTOCOL_DESC_LIST,
204                             version_array.size(), version_array.data());
205         }
206       }
207     }
208     // Log profile supported features from various supported feature attributes
209     switch (service_uuid) {
210       case UUID_SERVCLASS_AG_HANDSFREE:
211       case UUID_SERVCLASS_HF_HANDSFREE:
212       case UUID_SERVCLASS_AV_REMOTE_CONTROL:
213       case UUID_SERVCLASS_AV_REM_CTRL_CONTROL:
214       case UUID_SERVCLASS_AV_REM_CTRL_TARGET:
215       case UUID_SERVCLASS_AUDIO_SOURCE:
216       case UUID_SERVCLASS_AUDIO_SINK: {
217         tSDP_DISC_ATTR* p_attr =
218             SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES);
219         if (p_attr == nullptr) {
220           break;
221         }
222         uint16_t supported_features = p_attr->attr_value.v.u16;
223         auto version_array = to_little_endian_array(supported_features);
224         log_sdp_attribute(bda, service_uuid, ATTR_ID_SUPPORTED_FEATURES,
225                           version_array.size(), version_array.data());
226         break;
227       }
228       case UUID_SERVCLASS_MESSAGE_NOTIFICATION:
229       case UUID_SERVCLASS_MESSAGE_ACCESS: {
230         tSDP_DISC_ATTR* p_attr =
231             SDP_FindAttributeInRec(p_rec, ATTR_ID_MAP_SUPPORTED_FEATURES);
232         if (p_attr == nullptr) {
233           break;
234         }
235         uint32_t map_supported_features = p_attr->attr_value.v.u32;
236         auto features_array = to_little_endian_array(map_supported_features);
237         log_sdp_attribute(bda, service_uuid, ATTR_ID_MAP_SUPPORTED_FEATURES,
238                           features_array.size(), features_array.data());
239         break;
240       }
241       case UUID_SERVCLASS_PBAP_PCE:
242       case UUID_SERVCLASS_PBAP_PSE: {
243         tSDP_DISC_ATTR* p_attr =
244             SDP_FindAttributeInRec(p_rec, ATTR_ID_PBAP_SUPPORTED_FEATURES);
245         if (p_attr == nullptr) {
246           break;
247         }
248         uint32_t pbap_supported_features = p_attr->attr_value.v.u32;
249         auto features_array = to_little_endian_array(pbap_supported_features);
250         log_sdp_attribute(bda, service_uuid, ATTR_ID_PBAP_SUPPORTED_FEATURES,
251                           features_array.size(), features_array.data());
252         break;
253       }
254     }
255     if (service_uuid == UUID_SERVCLASS_PNP_INFORMATION) {
256       has_di_record = true;
257     }
258   }
259   // Log the first DI record if there is one
260   if (has_di_record) {
261     tSDP_DI_GET_RECORD di_record = {};
262     if (SDP_GetDiRecord(1, &di_record, p_db) == SDP_SUCCESS) {
263       auto version_array = to_little_endian_array(di_record.spec_id);
264       log_sdp_attribute(bda, UUID_SERVCLASS_PNP_INFORMATION,
265                         ATTR_ID_SPECIFICATION_ID, version_array.size(),
266                         version_array.data());
267       std::stringstream ss;
268       // [N - native]::SDP::[DIP - Device ID Profile]
269       ss << "N:SDP::DIP::" << loghex(di_record.rec.vendor_id_source);
270       log_manufacturer_info(
271           bda, android::bluetooth::DeviceInfoSrcEnum::DEVICE_INFO_INTERNAL,
272           ss.str(), loghex(di_record.rec.vendor), loghex(di_record.rec.product),
273           loghex(di_record.rec.version), "");
274 
275       std::string bda_string = bda.ToString();
276       // write manufacturer, model, HW version to config
277       btif_config_set_int(bda_string, BT_CONFIG_KEY_SDP_DI_MANUFACTURER,
278                           di_record.rec.vendor);
279       btif_config_set_int(bda_string, BT_CONFIG_KEY_SDP_DI_MODEL,
280                           di_record.rec.product);
281       btif_config_set_int(bda_string, BT_CONFIG_KEY_SDP_DI_HW_VERSION,
282                           di_record.rec.version);
283       btif_config_set_int(bda_string, BT_CONFIG_KEY_SDP_DI_VENDOR_ID_SRC,
284                           di_record.rec.vendor_id_source);
285     }
286   }
287 }
288 
289 /*******************************************************************************
290  *
291  * Function         sdpu_find_ccb_by_cid
292  *
293  * Description      This function searches the CCB table for an entry with the
294  *                  passed CID.
295  *
296  * Returns          the CCB address, or NULL if not found.
297  *
298  ******************************************************************************/
sdpu_find_ccb_by_cid(uint16_t cid)299 tCONN_CB* sdpu_find_ccb_by_cid(uint16_t cid) {
300   uint16_t xx;
301   tCONN_CB* p_ccb;
302 
303   /* Look through each connection control block */
304   for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++) {
305     if ((p_ccb->con_state != SDP_STATE_IDLE) && (p_ccb->connection_id == cid))
306       return (p_ccb);
307   }
308 
309   /* If here, not found */
310   return (NULL);
311 }
312 
313 /*******************************************************************************
314  *
315  * Function         sdpu_find_ccb_by_db
316  *
317  * Description      This function searches the CCB table for an entry with the
318  *                  passed discovery db.
319  *
320  * Returns          the CCB address, or NULL if not found.
321  *
322  ******************************************************************************/
sdpu_find_ccb_by_db(tSDP_DISCOVERY_DB * p_db)323 tCONN_CB* sdpu_find_ccb_by_db(tSDP_DISCOVERY_DB* p_db) {
324   uint16_t xx;
325   tCONN_CB* p_ccb;
326 
327   if (p_db) {
328     /* Look through each connection control block */
329     for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++) {
330       if ((p_ccb->con_state != SDP_STATE_IDLE) && (p_ccb->p_db == p_db))
331         return (p_ccb);
332     }
333   }
334   /* If here, not found */
335   return (NULL);
336 }
337 
338 /*******************************************************************************
339  *
340  * Function         sdpu_allocate_ccb
341  *
342  * Description      This function allocates a new CCB.
343  *
344  * Returns          CCB address, or NULL if none available.
345  *
346  ******************************************************************************/
sdpu_allocate_ccb(void)347 tCONN_CB* sdpu_allocate_ccb(void) {
348   uint16_t xx;
349   tCONN_CB* p_ccb;
350 
351   /* Look through each connection control block for a free one */
352   for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++) {
353     if (p_ccb->con_state == SDP_STATE_IDLE) {
354       alarm_t* alarm = p_ccb->sdp_conn_timer;
355       memset(p_ccb, 0, sizeof(tCONN_CB));
356       p_ccb->sdp_conn_timer = alarm;
357       return (p_ccb);
358     }
359   }
360 
361   /* If here, no free CCB found */
362   return (NULL);
363 }
364 
365 /*******************************************************************************
366  *
367  * Function         sdpu_release_ccb
368  *
369  * Description      This function releases a CCB.
370  *
371  * Returns          void
372  *
373  ******************************************************************************/
sdpu_release_ccb(tCONN_CB * p_ccb)374 void sdpu_release_ccb(tCONN_CB* p_ccb) {
375   /* Ensure timer is stopped */
376   alarm_cancel(p_ccb->sdp_conn_timer);
377 
378   /* Drop any response pointer we may be holding */
379   p_ccb->con_state = SDP_STATE_IDLE;
380   p_ccb->is_attr_search = false;
381 
382   /* Free the response buffer */
383   if (p_ccb->rsp_list) SDP_TRACE_DEBUG("releasing SDP rsp_list");
384   osi_free_and_reset((void**)&p_ccb->rsp_list);
385 }
386 
387 /*******************************************************************************
388  *
389  * Function         sdpu_build_attrib_seq
390  *
391  * Description      This function builds an attribute sequence from the list of
392  *                  passed attributes. It is also passed the address of the
393  *                  output buffer.
394  *
395  * Returns          Pointer to next byte in the output buffer.
396  *
397  ******************************************************************************/
sdpu_build_attrib_seq(uint8_t * p_out,uint16_t * p_attr,uint16_t num_attrs)398 uint8_t* sdpu_build_attrib_seq(uint8_t* p_out, uint16_t* p_attr,
399                                uint16_t num_attrs) {
400   uint16_t xx;
401 
402   /* First thing is the data element header. See if the length fits 1 byte */
403   /* If no attributes, assume a 4-byte wildcard */
404   if (!p_attr)
405     xx = 5;
406   else
407     xx = num_attrs * 3;
408 
409   if (xx > 255) {
410     UINT8_TO_BE_STREAM(p_out,
411                        (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
412     UINT16_TO_BE_STREAM(p_out, xx);
413   } else {
414     UINT8_TO_BE_STREAM(p_out,
415                        (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
416     UINT8_TO_BE_STREAM(p_out, xx);
417   }
418 
419   /* If there are no attributes specified, assume caller wants wildcard */
420   if (!p_attr) {
421     UINT8_TO_BE_STREAM(p_out, (UINT_DESC_TYPE << 3) | SIZE_FOUR_BYTES);
422     UINT16_TO_BE_STREAM(p_out, 0);
423     UINT16_TO_BE_STREAM(p_out, 0xFFFF);
424   } else {
425     /* Loop through and put in all the attributes(s) */
426     for (xx = 0; xx < num_attrs; xx++, p_attr++) {
427       UINT8_TO_BE_STREAM(p_out, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
428       UINT16_TO_BE_STREAM(p_out, *p_attr);
429     }
430   }
431 
432   return (p_out);
433 }
434 
435 /*******************************************************************************
436  *
437  * Function         sdpu_build_attrib_entry
438  *
439  * Description      This function builds an attribute entry from the passed
440  *                  attribute record. It is also passed the address of the
441  *                  output buffer.
442  *
443  * Returns          Pointer to next byte in the output buffer.
444  *
445  ******************************************************************************/
sdpu_build_attrib_entry(uint8_t * p_out,tSDP_ATTRIBUTE * p_attr)446 uint8_t* sdpu_build_attrib_entry(uint8_t* p_out, tSDP_ATTRIBUTE* p_attr) {
447   /* First, store the attribute ID. Goes as a UINT */
448   UINT8_TO_BE_STREAM(p_out, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
449   UINT16_TO_BE_STREAM(p_out, p_attr->id);
450 
451   /* the attribute is in the db record.
452    * assuming the attribute len is less than SDP_MAX_ATTR_LEN */
453   switch (p_attr->type) {
454     case TEXT_STR_DESC_TYPE:     /* 4 */
455     case DATA_ELE_SEQ_DESC_TYPE: /* 6 */
456     case DATA_ELE_ALT_DESC_TYPE: /* 7 */
457     case URL_DESC_TYPE:          /* 8 */
458 #if (SDP_MAX_ATTR_LEN > 0xFFFF)
459       if (p_attr->len > 0xFFFF) {
460         UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_IN_NEXT_LONG);
461         UINT32_TO_BE_STREAM(p_out, p_attr->len);
462       } else
463 #endif /* 0xFFFF - 0xFF */
464 #if (SDP_MAX_ATTR_LEN > 0xFF)
465           if (p_attr->len > 0xFF) {
466         UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_IN_NEXT_WORD);
467         UINT16_TO_BE_STREAM(p_out, p_attr->len);
468       } else
469 #endif /* 0xFF and less*/
470       {
471         UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_IN_NEXT_BYTE);
472         UINT8_TO_BE_STREAM(p_out, p_attr->len);
473       }
474 
475       if (p_attr->value_ptr != NULL) {
476         ARRAY_TO_BE_STREAM(p_out, p_attr->value_ptr, (int)p_attr->len);
477       }
478 
479       return (p_out);
480   }
481 
482   /* Now, store the attribute value */
483   switch (p_attr->len) {
484     case 1:
485       UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_ONE_BYTE);
486       break;
487     case 2:
488       UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_TWO_BYTES);
489       break;
490     case 4:
491       UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_FOUR_BYTES);
492       break;
493     case 8:
494       UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_EIGHT_BYTES);
495       break;
496     case 16:
497       UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_SIXTEEN_BYTES);
498       break;
499     default:
500       UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_IN_NEXT_BYTE);
501       UINT8_TO_BE_STREAM(p_out, p_attr->len);
502       break;
503   }
504 
505   if (p_attr->value_ptr != NULL) {
506     ARRAY_TO_BE_STREAM(p_out, p_attr->value_ptr, (int)p_attr->len);
507   }
508 
509   return (p_out);
510 }
511 
512 /*******************************************************************************
513  *
514  * Function         sdpu_build_n_send_error
515  *
516  * Description      This function builds and sends an error packet.
517  *
518  * Returns          void
519  *
520  ******************************************************************************/
sdpu_build_n_send_error(tCONN_CB * p_ccb,uint16_t trans_num,uint16_t error_code,char * p_error_text)521 void sdpu_build_n_send_error(tCONN_CB* p_ccb, uint16_t trans_num,
522                              uint16_t error_code, char* p_error_text) {
523   uint8_t *p_rsp, *p_rsp_start, *p_rsp_param_len;
524   uint16_t rsp_param_len;
525   BT_HDR* p_buf = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
526 
527   SDP_TRACE_WARNING("SDP - sdpu_build_n_send_error  code: 0x%x  CID: 0x%x",
528                     error_code, p_ccb->connection_id);
529 
530   /* Send the packet to L2CAP */
531   p_buf->offset = L2CAP_MIN_OFFSET;
532   p_rsp = p_rsp_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
533 
534   UINT8_TO_BE_STREAM(p_rsp, SDP_PDU_ERROR_RESPONSE);
535   UINT16_TO_BE_STREAM(p_rsp, trans_num);
536 
537   /* Skip the parameter length, we need to add it at the end */
538   p_rsp_param_len = p_rsp;
539   p_rsp += 2;
540 
541   UINT16_TO_BE_STREAM(p_rsp, error_code);
542 
543   /* Unplugfest example traces do not have any error text */
544   if (p_error_text)
545     ARRAY_TO_BE_STREAM(p_rsp, p_error_text, (int)strlen(p_error_text));
546 
547   /* Go back and put the parameter length into the buffer */
548   rsp_param_len = p_rsp - p_rsp_param_len - 2;
549   UINT16_TO_BE_STREAM(p_rsp_param_len, rsp_param_len);
550 
551   /* Set the length of the SDP data in the buffer */
552   p_buf->len = p_rsp - p_rsp_start;
553 
554   /* Send the buffer through L2CAP */
555   L2CA_DataWrite(p_ccb->connection_id, p_buf);
556 }
557 
558 /*******************************************************************************
559  *
560  * Function         sdpu_extract_uid_seq
561  *
562  * Description      This function extracts a UUID sequence from the passed input
563  *                  buffer, and puts it into the passed output list.
564  *
565  * Returns          Pointer to next byte in the input buffer after the sequence.
566  *
567  ******************************************************************************/
sdpu_extract_uid_seq(uint8_t * p,uint16_t param_len,tSDP_UUID_SEQ * p_seq)568 uint8_t* sdpu_extract_uid_seq(uint8_t* p, uint16_t param_len,
569                               tSDP_UUID_SEQ* p_seq) {
570   uint8_t* p_seq_end;
571   uint8_t descr, type, size;
572   uint32_t seq_len, uuid_len;
573 
574   /* Assume none found */
575   p_seq->num_uids = 0;
576 
577   /* A UID sequence is composed of a bunch of UIDs. */
578   if (sizeof(descr) > param_len) return (NULL);
579   param_len -= sizeof(descr);
580 
581   BE_STREAM_TO_UINT8(descr, p);
582   type = descr >> 3;
583   size = descr & 7;
584 
585   if (type != DATA_ELE_SEQ_DESC_TYPE) return (NULL);
586 
587   switch (size) {
588     case SIZE_TWO_BYTES:
589       seq_len = 2;
590       break;
591     case SIZE_FOUR_BYTES:
592       seq_len = 4;
593       break;
594     case SIZE_SIXTEEN_BYTES:
595       seq_len = 16;
596       break;
597     case SIZE_IN_NEXT_BYTE:
598       if (sizeof(uint8_t) > param_len) return (NULL);
599       param_len -= sizeof(uint8_t);
600       BE_STREAM_TO_UINT8(seq_len, p);
601       break;
602     case SIZE_IN_NEXT_WORD:
603       if (sizeof(uint16_t) > param_len) return (NULL);
604       param_len -= sizeof(uint16_t);
605       BE_STREAM_TO_UINT16(seq_len, p);
606       break;
607     case SIZE_IN_NEXT_LONG:
608       if (sizeof(uint32_t) > param_len) return (NULL);
609       param_len -= sizeof(uint32_t);
610       BE_STREAM_TO_UINT32(seq_len, p);
611       break;
612     default:
613       return (NULL);
614   }
615 
616   if (seq_len > param_len) return (NULL);
617 
618   p_seq_end = p + seq_len;
619 
620   /* Loop through, extracting the UIDs */
621   for (; p < p_seq_end;) {
622     BE_STREAM_TO_UINT8(descr, p);
623     type = descr >> 3;
624     size = descr & 7;
625 
626     if (type != UUID_DESC_TYPE) return (NULL);
627 
628     switch (size) {
629       case SIZE_TWO_BYTES:
630         uuid_len = 2;
631         break;
632       case SIZE_FOUR_BYTES:
633         uuid_len = 4;
634         break;
635       case SIZE_SIXTEEN_BYTES:
636         uuid_len = 16;
637         break;
638       case SIZE_IN_NEXT_BYTE:
639         if (p + sizeof(uint8_t) > p_seq_end) return NULL;
640         BE_STREAM_TO_UINT8(uuid_len, p);
641         break;
642       case SIZE_IN_NEXT_WORD:
643         if (p + sizeof(uint16_t) > p_seq_end) return NULL;
644         BE_STREAM_TO_UINT16(uuid_len, p);
645         break;
646       case SIZE_IN_NEXT_LONG:
647         if (p + sizeof(uint32_t) > p_seq_end) return NULL;
648         BE_STREAM_TO_UINT32(uuid_len, p);
649         break;
650       default:
651         return (NULL);
652     }
653 
654     /* If UUID length is valid, copy it across */
655     if (((uuid_len == 2) || (uuid_len == 4) || (uuid_len == 16)) &&
656         (p + uuid_len <= p_seq_end)) {
657       p_seq->uuid_entry[p_seq->num_uids].len = (uint16_t)uuid_len;
658       BE_STREAM_TO_ARRAY(p, p_seq->uuid_entry[p_seq->num_uids].value,
659                          (int)uuid_len);
660       p_seq->num_uids++;
661     } else
662       return (NULL);
663 
664     /* We can only do so many */
665     if (p_seq->num_uids >= MAX_UUIDS_PER_SEQ) return (NULL);
666   }
667 
668   if (p != p_seq_end) return (NULL);
669 
670   return (p);
671 }
672 
673 /*******************************************************************************
674  *
675  * Function         sdpu_extract_attr_seq
676  *
677  * Description      This function extracts an attribute sequence from the passed
678  *                  input buffer, and puts it into the passed output list.
679  *
680  * Returns          Pointer to next byte in the input buffer after the sequence.
681  *
682  ******************************************************************************/
sdpu_extract_attr_seq(uint8_t * p,uint16_t param_len,tSDP_ATTR_SEQ * p_seq)683 uint8_t* sdpu_extract_attr_seq(uint8_t* p, uint16_t param_len,
684                                tSDP_ATTR_SEQ* p_seq) {
685   uint8_t* p_end_list;
686   uint8_t descr, type, size;
687   uint32_t list_len, attr_len;
688 
689   /* Assume none found */
690   p_seq->num_attr = 0;
691 
692   /* Get attribute sequence info */
693   if (param_len < sizeof(descr)) return NULL;
694   param_len -= sizeof(descr);
695   BE_STREAM_TO_UINT8(descr, p);
696   type = descr >> 3;
697   size = descr & 7;
698 
699   if (type != DATA_ELE_SEQ_DESC_TYPE) return NULL;
700 
701   switch (size) {
702     case SIZE_IN_NEXT_BYTE:
703       if (param_len < sizeof(uint8_t)) return NULL;
704       param_len -= sizeof(uint8_t);
705       BE_STREAM_TO_UINT8(list_len, p);
706       break;
707 
708     case SIZE_IN_NEXT_WORD:
709       if (param_len < sizeof(uint16_t)) return NULL;
710       param_len -= sizeof(uint16_t);
711       BE_STREAM_TO_UINT16(list_len, p);
712       break;
713 
714     case SIZE_IN_NEXT_LONG:
715       if (param_len < sizeof(uint32_t)) return NULL;
716       param_len -= sizeof(uint32_t);
717       BE_STREAM_TO_UINT32(list_len, p);
718       break;
719 
720     default:
721       return NULL;
722   }
723 
724   if (list_len > param_len) return NULL;
725 
726   p_end_list = p + list_len;
727 
728   /* Loop through, extracting the attribute IDs */
729   for (; p < p_end_list;) {
730     BE_STREAM_TO_UINT8(descr, p);
731     type = descr >> 3;
732     size = descr & 7;
733 
734     if (type != UINT_DESC_TYPE) return NULL;
735 
736     switch (size) {
737       case SIZE_TWO_BYTES:
738         attr_len = 2;
739         break;
740       case SIZE_FOUR_BYTES:
741         attr_len = 4;
742         break;
743       case SIZE_IN_NEXT_BYTE:
744         if (p + sizeof(uint8_t) > p_end_list) return NULL;
745         BE_STREAM_TO_UINT8(attr_len, p);
746         break;
747       case SIZE_IN_NEXT_WORD:
748         if (p + sizeof(uint16_t) > p_end_list) return NULL;
749         BE_STREAM_TO_UINT16(attr_len, p);
750         break;
751       case SIZE_IN_NEXT_LONG:
752         if (p + sizeof(uint32_t) > p_end_list) return NULL;
753         BE_STREAM_TO_UINT32(attr_len, p);
754         break;
755       default:
756         return NULL;
757         break;
758     }
759 
760     /* Attribute length must be 2-bytes or 4-bytes for a paired entry. */
761     if (p + attr_len > p_end_list) return NULL;
762     if (attr_len == 2) {
763       BE_STREAM_TO_UINT16(p_seq->attr_entry[p_seq->num_attr].start, p);
764       p_seq->attr_entry[p_seq->num_attr].end =
765           p_seq->attr_entry[p_seq->num_attr].start;
766     } else if (attr_len == 4) {
767       BE_STREAM_TO_UINT16(p_seq->attr_entry[p_seq->num_attr].start, p);
768       BE_STREAM_TO_UINT16(p_seq->attr_entry[p_seq->num_attr].end, p);
769     } else
770       return (NULL);
771 
772     /* We can only do so many */
773     if (++p_seq->num_attr >= MAX_ATTR_PER_SEQ) return (NULL);
774   }
775 
776   return (p);
777 }
778 
779 /*******************************************************************************
780  *
781  * Function         sdpu_get_len_from_type
782  *
783  * Description      This function gets the length
784  *
785  * Returns          void
786  *
787  ******************************************************************************/
sdpu_get_len_from_type(uint8_t * p,uint8_t * p_end,uint8_t type,uint32_t * p_len)788 uint8_t* sdpu_get_len_from_type(uint8_t* p, uint8_t* p_end, uint8_t type,
789                                 uint32_t* p_len) {
790   uint8_t u8;
791   uint16_t u16;
792   uint32_t u32;
793 
794   switch (type & 7) {
795     case SIZE_ONE_BYTE:
796       *p_len = 1;
797       break;
798     case SIZE_TWO_BYTES:
799       *p_len = 2;
800       break;
801     case SIZE_FOUR_BYTES:
802       *p_len = 4;
803       break;
804     case SIZE_EIGHT_BYTES:
805       *p_len = 8;
806       break;
807     case SIZE_SIXTEEN_BYTES:
808       *p_len = 16;
809       break;
810     case SIZE_IN_NEXT_BYTE:
811       if (p + 1 > p_end) {
812         *p_len = 0;
813         return NULL;
814       }
815       BE_STREAM_TO_UINT8(u8, p);
816       *p_len = u8;
817       break;
818     case SIZE_IN_NEXT_WORD:
819       if (p + 2 > p_end) {
820         *p_len = 0;
821         return NULL;
822       }
823       BE_STREAM_TO_UINT16(u16, p);
824       *p_len = u16;
825       break;
826     case SIZE_IN_NEXT_LONG:
827       if (p + 4 > p_end) {
828         *p_len = 0;
829         return NULL;
830       }
831       BE_STREAM_TO_UINT32(u32, p);
832       *p_len = (uint16_t)u32;
833       break;
834   }
835 
836   return (p);
837 }
838 
839 /*******************************************************************************
840  *
841  * Function         sdpu_is_base_uuid
842  *
843  * Description      This function checks a 128-bit UUID with the base to see if
844  *                  it matches. Only the last 12 bytes are compared.
845  *
846  * Returns          true if matched, else false
847  *
848  ******************************************************************************/
sdpu_is_base_uuid(uint8_t * p_uuid)849 bool sdpu_is_base_uuid(uint8_t* p_uuid) {
850   uint16_t xx;
851 
852   for (xx = 4; xx < Uuid::kNumBytes128; xx++)
853     if (p_uuid[xx] != sdp_base_uuid[xx]) return (false);
854 
855   /* If here, matched */
856   return (true);
857 }
858 
859 /*******************************************************************************
860  *
861  * Function         sdpu_compare_uuid_arrays
862  *
863  * Description      This function compares 2 BE UUIDs. If needed, they are
864  *                  expanded to 128-bit UUIDs, then compared.
865  *
866  * NOTE             it is assumed that the arrays are in Big Endian format
867  *
868  * Returns          true if matched, else false
869  *
870  ******************************************************************************/
sdpu_compare_uuid_arrays(uint8_t * p_uuid1,uint32_t len1,uint8_t * p_uuid2,uint16_t len2)871 bool sdpu_compare_uuid_arrays(uint8_t* p_uuid1, uint32_t len1, uint8_t* p_uuid2,
872                               uint16_t len2) {
873   uint8_t nu1[Uuid::kNumBytes128];
874   uint8_t nu2[Uuid::kNumBytes128];
875 
876   if (((len1 != 2) && (len1 != 4) && (len1 != 16)) ||
877       ((len2 != 2) && (len2 != 4) && (len2 != 16))) {
878     SDP_TRACE_ERROR("%s: invalid length", __func__);
879     return false;
880   }
881 
882   /* If lengths match, do a straight compare */
883   if (len1 == len2) {
884     if (len1 == 2)
885       return ((p_uuid1[0] == p_uuid2[0]) && (p_uuid1[1] == p_uuid2[1]));
886     if (len1 == 4)
887       return ((p_uuid1[0] == p_uuid2[0]) && (p_uuid1[1] == p_uuid2[1]) &&
888               (p_uuid1[2] == p_uuid2[2]) && (p_uuid1[3] == p_uuid2[3]));
889     else
890       return (memcmp(p_uuid1, p_uuid2, (size_t)len1) == 0);
891   } else if (len1 > len2) {
892     /* If the len1 was 4-byte, (so len2 is 2-byte), compare on the fly */
893     if (len1 == 4) {
894       return ((p_uuid1[0] == 0) && (p_uuid1[1] == 0) &&
895               (p_uuid1[2] == p_uuid2[0]) && (p_uuid1[3] == p_uuid2[1]));
896     } else {
897       /* Normalize UUIDs to 16-byte form, then compare. Len1 must be 16 */
898       memcpy(nu1, p_uuid1, Uuid::kNumBytes128);
899       memcpy(nu2, sdp_base_uuid, Uuid::kNumBytes128);
900 
901       if (len2 == 4)
902         memcpy(nu2, p_uuid2, len2);
903       else if (len2 == 2)
904         memcpy(nu2 + 2, p_uuid2, len2);
905 
906       return (memcmp(nu1, nu2, Uuid::kNumBytes128) == 0);
907     }
908   } else {
909     /* len2 is greater than len1 */
910     /* If the len2 was 4-byte, (so len1 is 2-byte), compare on the fly */
911     if (len2 == 4) {
912       return ((p_uuid2[0] == 0) && (p_uuid2[1] == 0) &&
913               (p_uuid2[2] == p_uuid1[0]) && (p_uuid2[3] == p_uuid1[1]));
914     } else {
915       /* Normalize UUIDs to 16-byte form, then compare. Len1 must be 16 */
916       memcpy(nu2, p_uuid2, Uuid::kNumBytes128);
917       memcpy(nu1, sdp_base_uuid, Uuid::kNumBytes128);
918 
919       if (len1 == 4)
920         memcpy(nu1, p_uuid1, (size_t)len1);
921       else if (len1 == 2)
922         memcpy(nu1 + 2, p_uuid1, (size_t)len1);
923 
924       return (memcmp(nu1, nu2, Uuid::kNumBytes128) == 0);
925     }
926   }
927 }
928 
929 /*******************************************************************************
930  *
931  * Function         sdpu_compare_uuid_with_attr
932  *
933  * Description      This function compares a BT UUID structure with the UUID in
934  *                  an SDP attribute record. If needed, they are expanded to
935  *                  128-bit UUIDs, then compared.
936  *
937  * NOTE           - it is assumed that BT UUID structures are compressed to the
938  *                  smallest possible UUIDs (by removing the base SDP UUID).
939  *                - it is also assumed that the discovery atribute is compressed
940  *                  to the smallest possible
941  *
942  * Returns          true if matched, else false
943  *
944  ******************************************************************************/
sdpu_compare_uuid_with_attr(const Uuid & uuid,tSDP_DISC_ATTR * p_attr)945 bool sdpu_compare_uuid_with_attr(const Uuid& uuid, tSDP_DISC_ATTR* p_attr) {
946   int len = uuid.GetShortestRepresentationSize();
947   if (len == 2) return uuid.As16Bit() == p_attr->attr_value.v.u16;
948   if (len == 4) return uuid.As32Bit() == p_attr->attr_value.v.u32;
949   if (memcmp(uuid.To128BitBE().data(), (void*)p_attr->attr_value.v.array,
950              Uuid::kNumBytes128) == 0)
951     return (true);
952 
953   return (false);
954 }
955 
956 /*******************************************************************************
957  *
958  * Function         sdpu_sort_attr_list
959  *
960  * Description      sorts a list of attributes in numeric order from lowest to
961  *                  highest to conform to SDP specification
962  *
963  * Returns          void
964  *
965  ******************************************************************************/
sdpu_sort_attr_list(uint16_t num_attr,tSDP_DISCOVERY_DB * p_db)966 void sdpu_sort_attr_list(uint16_t num_attr, tSDP_DISCOVERY_DB* p_db) {
967   uint16_t i;
968   uint16_t x;
969 
970   /* Done if no attributes to sort */
971   if (num_attr <= 1) {
972     return;
973   } else if (num_attr > SDP_MAX_ATTR_FILTERS) {
974     num_attr = SDP_MAX_ATTR_FILTERS;
975   }
976 
977   num_attr--; /* for the for-loop */
978   for (i = 0; i < num_attr;) {
979     if (p_db->attr_filters[i] > p_db->attr_filters[i + 1]) {
980       /* swap the attribute IDs and start from the beginning */
981       x = p_db->attr_filters[i];
982       p_db->attr_filters[i] = p_db->attr_filters[i + 1];
983       p_db->attr_filters[i + 1] = x;
984 
985       i = 0;
986     } else
987       i++;
988   }
989 }
990 
991 /*******************************************************************************
992  *
993  * Function         sdpu_get_list_len
994  *
995  * Description      gets the total list length in the sdp database for a given
996  *                  uid sequence and attr sequence
997  *
998  * Returns          void
999  *
1000  ******************************************************************************/
sdpu_get_list_len(tSDP_UUID_SEQ * uid_seq,tSDP_ATTR_SEQ * attr_seq)1001 uint16_t sdpu_get_list_len(tSDP_UUID_SEQ* uid_seq, tSDP_ATTR_SEQ* attr_seq) {
1002   tSDP_RECORD* p_rec;
1003   uint16_t len = 0;
1004   uint16_t len1;
1005 
1006   for (p_rec = sdp_db_service_search(NULL, uid_seq); p_rec;
1007        p_rec = sdp_db_service_search(p_rec, uid_seq)) {
1008     len += 3;
1009 
1010     len1 = sdpu_get_attrib_seq_len(p_rec, attr_seq);
1011 
1012     if (len1 != 0)
1013       len += len1;
1014     else
1015       len -= 3;
1016   }
1017   return len;
1018 }
1019 
1020 /*******************************************************************************
1021  *
1022  * Function         sdpu_get_attrib_seq_len
1023  *
1024  * Description      gets the length of the specific attributes in a given
1025  *                  sdp record
1026  *
1027  * Returns          void
1028  *
1029  ******************************************************************************/
sdpu_get_attrib_seq_len(tSDP_RECORD * p_rec,tSDP_ATTR_SEQ * attr_seq)1030 uint16_t sdpu_get_attrib_seq_len(tSDP_RECORD* p_rec, tSDP_ATTR_SEQ* attr_seq) {
1031   tSDP_ATTRIBUTE* p_attr;
1032   uint16_t len1 = 0;
1033   uint16_t xx;
1034   bool is_range = false;
1035   uint16_t start_id = 0, end_id = 0;
1036 
1037   for (xx = 0; xx < attr_seq->num_attr; xx++) {
1038     if (!is_range) {
1039       start_id = attr_seq->attr_entry[xx].start;
1040       end_id = attr_seq->attr_entry[xx].end;
1041     }
1042     p_attr = sdp_db_find_attr_in_rec(p_rec, start_id, end_id);
1043     if (p_attr) {
1044       len1 += sdpu_get_attrib_entry_len(p_attr);
1045 
1046       /* If doing a range, stick with this one till no more attributes found */
1047       if (start_id != end_id) {
1048         /* Update for next time through */
1049         start_id = p_attr->id + 1;
1050         xx--;
1051         is_range = true;
1052       } else
1053         is_range = false;
1054     } else
1055       is_range = false;
1056   }
1057   return len1;
1058 }
1059 
1060 /*******************************************************************************
1061  *
1062  * Function         sdpu_get_attrib_entry_len
1063  *
1064  * Description      gets the length of a specific attribute
1065  *
1066  * Returns          void
1067  *
1068  ******************************************************************************/
sdpu_get_attrib_entry_len(tSDP_ATTRIBUTE * p_attr)1069 uint16_t sdpu_get_attrib_entry_len(tSDP_ATTRIBUTE* p_attr) {
1070   uint16_t len = 3;
1071 
1072   /* the attribute is in the db record.
1073    * assuming the attribute len is less than SDP_MAX_ATTR_LEN */
1074   switch (p_attr->type) {
1075     case TEXT_STR_DESC_TYPE:     /* 4 */
1076     case DATA_ELE_SEQ_DESC_TYPE: /* 6 */
1077     case DATA_ELE_ALT_DESC_TYPE: /* 7 */
1078     case URL_DESC_TYPE:          /* 8 */
1079 #if (SDP_MAX_ATTR_LEN > 0xFFFF)
1080       if (p_attr->len > 0xFFFF) {
1081         len += 5;
1082       } else
1083 #endif /* 0xFFFF - 0xFF */
1084 #if (SDP_MAX_ATTR_LEN > 0xFF)
1085           if (p_attr->len > 0xFF) {
1086         len += 3;
1087       } else
1088 #endif /* 0xFF and less*/
1089       {
1090         len += 2;
1091       }
1092       len += p_attr->len;
1093       return len;
1094   }
1095 
1096   /* Now, the attribute value */
1097   switch (p_attr->len) {
1098     case 1:
1099     case 2:
1100     case 4:
1101     case 8:
1102     case 16:
1103       len += 1;
1104       break;
1105     default:
1106       len += 2;
1107       break;
1108   }
1109 
1110   len += p_attr->len;
1111   return len;
1112 }
1113 
1114 /*******************************************************************************
1115  *
1116  * Function         sdpu_build_partial_attrib_entry
1117  *
1118  * Description      This function fills a buffer with partial attribute. It is
1119  *                  assumed that the maximum size of any attribute is 256 bytes.
1120  *
1121  *                  p_out: output buffer
1122  *                  p_attr: attribute to be copied partially into p_out
1123  *                  rem_len: num bytes to copy into p_out
1124  *                  offset: current start offset within the attr that needs to
1125  *                          be copied
1126  *
1127  * Returns          Pointer to next byte in the output buffer.
1128  *                  offset is also updated
1129  *
1130  ******************************************************************************/
sdpu_build_partial_attrib_entry(uint8_t * p_out,tSDP_ATTRIBUTE * p_attr,uint16_t len,uint16_t * offset)1131 uint8_t* sdpu_build_partial_attrib_entry(uint8_t* p_out, tSDP_ATTRIBUTE* p_attr,
1132                                          uint16_t len, uint16_t* offset) {
1133   uint8_t* p_attr_buff =
1134       (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN);
1135   sdpu_build_attrib_entry(p_attr_buff, p_attr);
1136 
1137   uint16_t attr_len = sdpu_get_attrib_entry_len(p_attr);
1138 
1139   if (len > SDP_MAX_ATTR_LEN) {
1140     SDP_TRACE_ERROR("%s len %d exceeds SDP_MAX_ATTR_LEN", __func__, len);
1141     len = SDP_MAX_ATTR_LEN;
1142   }
1143 
1144   size_t len_to_copy =
1145       ((attr_len - *offset) < len) ? (attr_len - *offset) : len;
1146   memcpy(p_out, &p_attr_buff[*offset], len_to_copy);
1147 
1148   p_out = &p_out[len_to_copy];
1149   *offset += len_to_copy;
1150 
1151   osi_free(p_attr_buff);
1152   return p_out;
1153 }
1154 /*******************************************************************************
1155  *
1156  * Function         sdpu_is_avrcp_profile_description_list
1157  *
1158  * Description      This function is to check if attirbute contain AVRCP profile
1159  *                  description list
1160  *
1161  *                  p_attr: attibute to be check
1162  *
1163  * Returns          AVRCP profile version if matched, else 0
1164  *
1165  ******************************************************************************/
sdpu_is_avrcp_profile_description_list(tSDP_ATTRIBUTE * p_attr)1166 uint16_t sdpu_is_avrcp_profile_description_list(tSDP_ATTRIBUTE* p_attr) {
1167   if (p_attr->id != ATTR_ID_BT_PROFILE_DESC_LIST || p_attr->len != 8) {
1168     return 0;
1169   }
1170 
1171   uint8_t* p_uuid = p_attr->value_ptr + 3;
1172   // Check if AVRCP profile UUID
1173   if (p_uuid[0] != 0x11 || p_uuid[1] != 0xe) {
1174     return 0;
1175   }
1176   uint8_t p_version = *(p_uuid + 4);
1177   switch (p_version) {
1178     case 0x0:
1179       return AVRC_REV_1_0;
1180     case 0x3:
1181       return AVRC_REV_1_3;
1182     case 0x4:
1183       return AVRC_REV_1_4;
1184     case 0x5:
1185       return AVRC_REV_1_5;
1186     case 0x6:
1187       return AVRC_REV_1_6;
1188     default:
1189       return 0;
1190   }
1191 }
1192