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