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