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