• 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 discovery functions
22  *
23  ******************************************************************************/
24 
25 #define LOG_TAG "sdp_discovery"
26 
27 #include <cstdint>
28 
29 #include "bt_target.h"
30 #include "osi/include/allocator.h"
31 #include "osi/include/log.h"
32 #include "stack/include/bt_hdr.h"
33 #include "stack/include/bt_types.h"
34 #include "stack/include/sdp_api.h"
35 #include "stack/include/sdpdefs.h"
36 #include "stack/sdp/sdpint.h"
37 #include "types/bluetooth/uuid.h"
38 #include "types/raw_address.h"
39 
40 using bluetooth::Uuid;
41 
42 /******************************************************************************/
43 /*            L O C A L    F U N C T I O N     P R O T O T Y P E S            */
44 /******************************************************************************/
45 static void process_service_search_rsp(tCONN_CB* p_ccb, uint8_t* p_reply,
46                                        uint8_t* p_reply_end);
47 static void process_service_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply,
48                                      uint8_t* p_reply_end);
49 static void process_service_search_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply,
50                                             uint8_t* p_reply_end);
51 static uint8_t* save_attr_seq(tCONN_CB* p_ccb, uint8_t* p, uint8_t* p_msg_end);
52 static tSDP_DISC_REC* add_record(tSDP_DISCOVERY_DB* p_db,
53                                  const RawAddress& p_bda);
54 static uint8_t* add_attr(uint8_t* p, uint8_t* p_end, tSDP_DISCOVERY_DB* p_db,
55                          tSDP_DISC_REC* p_rec, uint16_t attr_id,
56                          tSDP_DISC_ATTR* p_parent_attr, uint8_t nest_level);
57 
58 /* Safety check in case we go crazy */
59 #define MAX_NEST_LEVELS 5
60 
61 /*******************************************************************************
62  *
63  * Function         sdpu_build_uuid_seq
64  *
65  * Description      This function builds a UUID sequence from the list of
66  *                  passed UUIDs. It is also passed the address of the output
67  *                  buffer.
68  *
69  * Returns          Pointer to next byte in the output buffer.
70  *
71  ******************************************************************************/
sdpu_build_uuid_seq(uint8_t * p_out,uint16_t num_uuids,Uuid * p_uuid_list,uint16_t & bytes_left)72 static uint8_t* sdpu_build_uuid_seq(uint8_t* p_out, uint16_t num_uuids,
73                                     Uuid* p_uuid_list, uint16_t& bytes_left) {
74   uint16_t xx;
75   uint8_t* p_len;
76 
77   if (bytes_left < 2) {
78     DCHECK(0) << "SDP: No space for data element header";
79     return (p_out);
80   }
81 
82   /* First thing is the data element header */
83   UINT8_TO_BE_STREAM(p_out, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
84 
85   /* Remember where the length goes. Leave space for it. */
86   p_len = p_out;
87   p_out += 1;
88 
89   /* Account for data element header and length */
90   bytes_left -= 2;
91 
92   /* Now, loop through and put in all the UUID(s) */
93   for (xx = 0; xx < num_uuids; xx++, p_uuid_list++) {
94     int len = p_uuid_list->GetShortestRepresentationSize();
95 
96     if (len + 1 > bytes_left) {
97       DCHECK(0) << "SDP: Too many UUIDs for internal buffer";
98       break;
99     } else {
100       bytes_left -= (len + 1);
101     }
102 
103     if (len == Uuid::kNumBytes16) {
104       UINT8_TO_BE_STREAM(p_out, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
105       UINT16_TO_BE_STREAM(p_out, p_uuid_list->As16Bit());
106     } else if (len == Uuid::kNumBytes32) {
107       UINT8_TO_BE_STREAM(p_out, (UUID_DESC_TYPE << 3) | SIZE_FOUR_BYTES);
108       UINT32_TO_BE_STREAM(p_out, p_uuid_list->As32Bit());
109     } else if (len == Uuid::kNumBytes128) {
110       UINT8_TO_BE_STREAM(p_out, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES);
111       ARRAY_TO_BE_STREAM(p_out, p_uuid_list->To128BitBE(),
112                          (int)Uuid::kNumBytes128);
113     } else {
114       DCHECK(0) << "SDP: Passed UUID has invalid length " << len;
115     }
116   }
117 
118   /* Now, put in the length */
119   xx = (uint16_t)(p_out - p_len - 1);
120   UINT8_TO_BE_STREAM(p_len, xx);
121 
122   return (p_out);
123 }
124 
125 /*******************************************************************************
126  *
127  * Function         sdp_snd_service_search_req
128  *
129  * Description      Send a service search request to the SDP server.
130  *
131  * Returns          void
132  *
133  ******************************************************************************/
sdp_snd_service_search_req(tCONN_CB * p_ccb,uint8_t cont_len,uint8_t * p_cont)134 static void sdp_snd_service_search_req(tCONN_CB* p_ccb, uint8_t cont_len,
135                                        uint8_t* p_cont) {
136   uint8_t *p, *p_start, *p_param_len;
137   BT_HDR* p_cmd = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
138   uint16_t param_len;
139   uint16_t bytes_left = SDP_DATA_BUF_SIZE;
140 
141   /* Prepare the buffer for sending the packet to L2CAP */
142   p_cmd->offset = L2CAP_MIN_OFFSET;
143   p = p_start = (uint8_t*)(p_cmd + 1) + L2CAP_MIN_OFFSET;
144 
145   /* Build a service search request packet */
146   UINT8_TO_BE_STREAM(p, SDP_PDU_SERVICE_SEARCH_REQ);
147   UINT16_TO_BE_STREAM(p, p_ccb->transaction_id);
148   p_ccb->transaction_id++;
149 
150   /* Skip the length, we need to add it at the end */
151   p_param_len = p;
152   p += 2;
153 
154   /* Account for header size, max service record count and
155    * continuation state */
156   const uint16_t base_bytes = (sizeof(BT_HDR) + L2CAP_MIN_OFFSET +
157                                3u + /* service search request header */
158                                2u + /* param len */
159                                3u + ((p_cont) ? cont_len : 0));
160 
161   if (base_bytes > bytes_left) {
162     DCHECK(0) << "SDP: Overran SDP data buffer";
163     osi_free(p_cmd);
164     return;
165   }
166 
167   bytes_left -= base_bytes;
168 
169   /* Build the UID sequence. */
170   p = sdpu_build_uuid_seq(p, p_ccb->p_db->num_uuid_filters,
171                           p_ccb->p_db->uuid_filters, bytes_left);
172 
173   /* Set max service record count */
174   UINT16_TO_BE_STREAM(p, sdp_cb.max_recs_per_search);
175 
176   /* Set continuation state */
177   UINT8_TO_BE_STREAM(p, cont_len);
178 
179   /* if this is not the first request */
180   if (cont_len && p_cont) {
181     memcpy(p, p_cont, cont_len);
182     p += cont_len;
183   }
184 
185   /* Go back and put the parameter length into the buffer */
186   param_len = (uint16_t)(p - p_param_len - 2);
187   UINT16_TO_BE_STREAM(p_param_len, param_len);
188 
189   p_ccb->disc_state = SDP_DISC_WAIT_HANDLES;
190 
191   /* Set the length of the SDP data in the buffer */
192   p_cmd->len = (uint16_t)(p - p_start);
193 
194   L2CA_DataWrite(p_ccb->connection_id, p_cmd);
195 
196   /* Start inactivity timer */
197   alarm_set_on_mloop(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
198                      sdp_conn_timer_timeout, p_ccb);
199 }
200 
201 /*******************************************************************************
202  *
203  * Function         sdp_disc_connected
204  *
205  * Description      This function is called when an SDP discovery attempt is
206  *                  connected.
207  *
208  * Returns          void
209  *
210  ******************************************************************************/
sdp_disc_connected(tCONN_CB * p_ccb)211 void sdp_disc_connected(tCONN_CB* p_ccb) {
212   if (p_ccb->is_attr_search) {
213     p_ccb->disc_state = SDP_DISC_WAIT_SEARCH_ATTR;
214 
215     process_service_search_attr_rsp(p_ccb, NULL, NULL);
216   } else {
217     /* First step is to get a list of the handles from the server. */
218     /* We are not searching for a specific attribute, so we will   */
219     /* first search for the service, then get all attributes of it */
220 
221     p_ccb->num_handles = 0;
222     sdp_snd_service_search_req(p_ccb, 0, NULL);
223   }
224 }
225 
226 /*******************************************************************************
227  *
228  * Function         sdp_disc_server_rsp
229  *
230  * Description      This function is called when there is a response from
231  *                  the server.
232  *
233  * Returns          void
234  *
235  ******************************************************************************/
sdp_disc_server_rsp(tCONN_CB * p_ccb,BT_HDR * p_msg)236 void sdp_disc_server_rsp(tCONN_CB* p_ccb, BT_HDR* p_msg) {
237   uint8_t *p, rsp_pdu;
238   bool invalid_pdu = true;
239 
240   /* stop inactivity timer when we receive a response */
241   alarm_cancel(p_ccb->sdp_conn_timer);
242 
243   /* Got a reply!! Check what we got back */
244   p = (uint8_t*)(p_msg + 1) + p_msg->offset;
245   uint8_t* p_end = p + p_msg->len;
246 
247   if (p_msg->len < 1) {
248     sdp_disconnect(p_ccb, SDP_GENERIC_ERROR);
249     return;
250   }
251 
252   BE_STREAM_TO_UINT8(rsp_pdu, p);
253 
254   p_msg->len--;
255 
256   switch (rsp_pdu) {
257     case SDP_PDU_SERVICE_SEARCH_RSP:
258       if (p_ccb->disc_state == SDP_DISC_WAIT_HANDLES) {
259         process_service_search_rsp(p_ccb, p, p_end);
260         invalid_pdu = false;
261       }
262       break;
263 
264     case SDP_PDU_SERVICE_ATTR_RSP:
265       if (p_ccb->disc_state == SDP_DISC_WAIT_ATTR) {
266         process_service_attr_rsp(p_ccb, p, p_end);
267         invalid_pdu = false;
268       }
269       break;
270 
271     case SDP_PDU_SERVICE_SEARCH_ATTR_RSP:
272       if (p_ccb->disc_state == SDP_DISC_WAIT_SEARCH_ATTR) {
273         process_service_search_attr_rsp(p_ccb, p, p_end);
274         invalid_pdu = false;
275       }
276       break;
277   }
278 
279   if (invalid_pdu) {
280     SDP_TRACE_WARNING("SDP - Unexp. PDU: %d in state: %d", rsp_pdu,
281                       p_ccb->disc_state);
282     sdp_disconnect(p_ccb, SDP_GENERIC_ERROR);
283   }
284 }
285 
286 /******************************************************************************
287  *
288  * Function         process_service_search_rsp
289  *
290  * Description      This function is called when there is a search response from
291  *                  the server.
292  *
293  * Returns          void
294  *
295  ******************************************************************************/
process_service_search_rsp(tCONN_CB * p_ccb,uint8_t * p_reply,uint8_t * p_reply_end)296 static void process_service_search_rsp(tCONN_CB* p_ccb, uint8_t* p_reply,
297                                        uint8_t* p_reply_end) {
298   uint16_t xx;
299   uint16_t total, cur_handles, orig;
300   uint8_t cont_len;
301 
302   if (p_reply + 8 > p_reply_end) {
303     sdp_disconnect(p_ccb, SDP_GENERIC_ERROR);
304     return;
305   }
306   /* Skip transaction, and param len */
307   p_reply += 4;
308   BE_STREAM_TO_UINT16(total, p_reply);
309   BE_STREAM_TO_UINT16(cur_handles, p_reply);
310 
311   orig = p_ccb->num_handles;
312   p_ccb->num_handles += cur_handles;
313   if (p_ccb->num_handles == 0 || p_ccb->num_handles < orig) {
314     SDP_TRACE_WARNING("SDP - Rcvd ServiceSearchRsp, no matches");
315     sdp_disconnect(p_ccb, SDP_NO_RECS_MATCH);
316     return;
317   }
318 
319   /* Save the handles that match. We will can only process a certain number. */
320   if (total > sdp_cb.max_recs_per_search) total = sdp_cb.max_recs_per_search;
321   if (p_ccb->num_handles > sdp_cb.max_recs_per_search)
322     p_ccb->num_handles = sdp_cb.max_recs_per_search;
323 
324   if (p_reply + ((p_ccb->num_handles - orig) * 4) + 1 > p_reply_end) {
325     sdp_disconnect(p_ccb, SDP_GENERIC_ERROR);
326     return;
327   }
328 
329   for (xx = orig; xx < p_ccb->num_handles; xx++)
330     BE_STREAM_TO_UINT32(p_ccb->handles[xx], p_reply);
331 
332   BE_STREAM_TO_UINT8(cont_len, p_reply);
333   if (cont_len != 0) {
334     if (cont_len > SDP_MAX_CONTINUATION_LEN) {
335       sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE);
336       return;
337     }
338     if (p_reply + cont_len > p_reply_end) {
339       sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE);
340       return;
341     }
342     /* stay in the same state */
343     sdp_snd_service_search_req(p_ccb, cont_len, p_reply);
344   } else {
345     /* change state */
346     p_ccb->disc_state = SDP_DISC_WAIT_ATTR;
347 
348     /* Kick off the first attribute request */
349     process_service_attr_rsp(p_ccb, NULL, NULL);
350   }
351 }
352 
353 /*******************************************************************************
354  *
355  * Function         sdp_copy_raw_data
356  *
357  * Description      copy the raw data
358  *
359  *
360  * Returns          bool
361  *                          true if successful
362  *                          false if not copied
363  *
364  ******************************************************************************/
sdp_copy_raw_data(tCONN_CB * p_ccb,bool offset)365 static bool sdp_copy_raw_data(tCONN_CB* p_ccb, bool offset) {
366   unsigned int cpy_len, rem_len;
367   uint32_t list_len;
368   uint8_t* p;
369   uint8_t* p_end;
370   uint8_t type;
371 
372   if (p_ccb->p_db && p_ccb->p_db->raw_data) {
373     cpy_len = p_ccb->p_db->raw_size - p_ccb->p_db->raw_used;
374     list_len = p_ccb->list_len;
375     p = &p_ccb->rsp_list[0];
376     p_end = &p_ccb->rsp_list[0] + list_len;
377 
378     if (offset) {
379       cpy_len -= 1;
380       type = *p++;
381       uint8_t* old_p = p;
382       p = sdpu_get_len_from_type(p, p_end, type, &list_len);
383       if (p == NULL || (p + list_len) > p_end) {
384         SDP_TRACE_WARNING("%s: bad length", __func__);
385         return false;
386       }
387       if ((int)cpy_len < (p - old_p)) {
388         SDP_TRACE_WARNING("%s: no bytes left for data", __func__);
389         return false;
390       }
391       cpy_len -= (p - old_p);
392     }
393     if (list_len < cpy_len) {
394       cpy_len = list_len;
395     }
396     rem_len = SDP_MAX_LIST_BYTE_COUNT - (unsigned int)(p - &p_ccb->rsp_list[0]);
397     if (cpy_len > rem_len) {
398       SDP_TRACE_WARNING("rem_len :%d less than cpy_len:%d", rem_len, cpy_len);
399       cpy_len = rem_len;
400     }
401     memcpy(&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len);
402     p_ccb->p_db->raw_used += cpy_len;
403   }
404   return true;
405 }
406 
407 /*******************************************************************************
408  *
409  * Function         process_service_attr_rsp
410  *
411  * Description      This function is called when there is a attribute response
412  *                  from the server.
413  *
414  * Returns          void
415  *
416  ******************************************************************************/
process_service_attr_rsp(tCONN_CB * p_ccb,uint8_t * p_reply,uint8_t * p_reply_end)417 static void process_service_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply,
418                                      uint8_t* p_reply_end) {
419   uint8_t *p_start, *p_param_len;
420   uint16_t param_len, list_byte_count;
421   bool cont_request_needed = false;
422 
423   /* If p_reply is NULL, we were called after the records handles were read */
424   if (p_reply) {
425     if (p_reply + 4 /* transaction ID and length */ + sizeof(list_byte_count) >
426         p_reply_end) {
427       sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE);
428       return;
429     }
430 
431     /* Skip transaction ID and length */
432     p_reply += 4;
433 
434     BE_STREAM_TO_UINT16(list_byte_count, p_reply);
435 
436     /* Copy the response to the scratchpad. First, a safety check on the length
437      */
438     if ((p_ccb->list_len + list_byte_count) > SDP_MAX_LIST_BYTE_COUNT) {
439       sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE);
440       return;
441     }
442 
443     if (p_reply + list_byte_count + 1 /* continuation */ > p_reply_end) {
444       sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE);
445       return;
446     }
447 
448     if (p_ccb->rsp_list == NULL)
449       p_ccb->rsp_list = (uint8_t*)osi_malloc(SDP_MAX_LIST_BYTE_COUNT);
450     memcpy(&p_ccb->rsp_list[p_ccb->list_len], p_reply, list_byte_count);
451     p_ccb->list_len += list_byte_count;
452     p_reply += list_byte_count;
453     if (*p_reply) {
454       if (*p_reply > SDP_MAX_CONTINUATION_LEN) {
455         sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE);
456         return;
457       }
458       cont_request_needed = true;
459     } else {
460       SDP_TRACE_WARNING("process_service_attr_rsp");
461       if (!sdp_copy_raw_data(p_ccb, false)) {
462         SDP_TRACE_ERROR("sdp_copy_raw_data failed");
463         sdp_disconnect(p_ccb, SDP_ILLEGAL_PARAMETER);
464         return;
465       }
466 
467       /* Save the response in the database. Stop on any error */
468       if (!save_attr_seq(p_ccb, &p_ccb->rsp_list[0],
469                          &p_ccb->rsp_list[p_ccb->list_len])) {
470         sdp_disconnect(p_ccb, SDP_DB_FULL);
471         return;
472       }
473       p_ccb->list_len = 0;
474       p_ccb->cur_handle++;
475     }
476   }
477 
478   /* Now, ask for the next handle. Re-use the buffer we just got. */
479   if (p_ccb->cur_handle < p_ccb->num_handles) {
480     BT_HDR* p_msg = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
481     uint8_t* p;
482 
483     p_msg->offset = L2CAP_MIN_OFFSET;
484     p = p_start = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET;
485 
486     /* Get all the attributes from the server */
487     UINT8_TO_BE_STREAM(p, SDP_PDU_SERVICE_ATTR_REQ);
488     UINT16_TO_BE_STREAM(p, p_ccb->transaction_id);
489     p_ccb->transaction_id++;
490 
491     /* Skip the length, we need to add it at the end */
492     p_param_len = p;
493     p += 2;
494 
495     UINT32_TO_BE_STREAM(p, p_ccb->handles[p_ccb->cur_handle]);
496 
497     /* Max attribute byte count */
498     UINT16_TO_BE_STREAM(p, sdp_cb.max_attr_list_size);
499 
500     /* If no attribute filters, build a wildcard attribute sequence */
501     if (p_ccb->p_db->num_attr_filters)
502       p = sdpu_build_attrib_seq(p, p_ccb->p_db->attr_filters,
503                                 p_ccb->p_db->num_attr_filters);
504     else
505       p = sdpu_build_attrib_seq(p, NULL, 0);
506 
507     /* Was this a continuation request ? */
508     if (cont_request_needed) {
509       if ((p_reply + *p_reply + 1) <= p_reply_end) {
510         memcpy(p, p_reply, *p_reply + 1);
511         p += *p_reply + 1;
512       }
513     } else
514       UINT8_TO_BE_STREAM(p, 0);
515 
516     /* Go back and put the parameter length into the buffer */
517     param_len = (uint16_t)(p - p_param_len - 2);
518     UINT16_TO_BE_STREAM(p_param_len, param_len);
519 
520     /* Set the length of the SDP data in the buffer */
521     p_msg->len = (uint16_t)(p - p_start);
522 
523     L2CA_DataWrite(p_ccb->connection_id, p_msg);
524 
525     /* Start inactivity timer */
526     alarm_set_on_mloop(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
527                        sdp_conn_timer_timeout, p_ccb);
528   } else {
529     sdpu_log_attribute_metrics(p_ccb->device_address, p_ccb->p_db);
530     sdp_disconnect(p_ccb, SDP_SUCCESS);
531     return;
532   }
533 }
534 
535 /*******************************************************************************
536  *
537  * Function         process_service_search_attr_rsp
538  *
539  * Description      This function is called when there is a search attribute
540  *                  response from the server.
541  *
542  * Returns          void
543  *
544  ******************************************************************************/
process_service_search_attr_rsp(tCONN_CB * p_ccb,uint8_t * p_reply,uint8_t * p_reply_end)545 static void process_service_search_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply,
546                                             uint8_t* p_reply_end) {
547   uint8_t *p, *p_start, *p_end, *p_param_len;
548   uint8_t type;
549   uint32_t seq_len;
550   uint16_t param_len, lists_byte_count = 0;
551   bool cont_request_needed = false;
552 
553   /* If p_reply is NULL, we were called for the initial read */
554   if (p_reply) {
555     if (p_reply + 4 /* transaction ID and length */ + sizeof(lists_byte_count) >
556         p_reply_end) {
557       sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE);
558       return;
559     }
560 
561     /* Skip transaction ID and length */
562     p_reply += 4;
563 
564     BE_STREAM_TO_UINT16(lists_byte_count, p_reply);
565 
566     /* Copy the response to the scratchpad. First, a safety check on the length
567      */
568     if ((p_ccb->list_len + lists_byte_count) > SDP_MAX_LIST_BYTE_COUNT) {
569       sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE);
570       return;
571     }
572 
573     if (p_reply + lists_byte_count + 1 /* continuation */ > p_reply_end) {
574       sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE);
575       return;
576     }
577 
578     if (p_ccb->rsp_list == NULL)
579       p_ccb->rsp_list = (uint8_t*)osi_malloc(SDP_MAX_LIST_BYTE_COUNT);
580     memcpy(&p_ccb->rsp_list[p_ccb->list_len], p_reply, lists_byte_count);
581     p_ccb->list_len += lists_byte_count;
582     p_reply += lists_byte_count;
583     if (*p_reply) {
584       if (*p_reply > SDP_MAX_CONTINUATION_LEN) {
585         sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE);
586         return;
587       }
588 
589       cont_request_needed = true;
590     }
591   }
592 
593   /* If continuation request (or first time request) */
594   if ((cont_request_needed) || (!p_reply)) {
595     BT_HDR* p_msg = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
596     uint8_t* p;
597     uint16_t bytes_left = SDP_DATA_BUF_SIZE;
598 
599     p_msg->offset = L2CAP_MIN_OFFSET;
600     p = p_start = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET;
601 
602     /* Build a service search request packet */
603     UINT8_TO_BE_STREAM(p, SDP_PDU_SERVICE_SEARCH_ATTR_REQ);
604     UINT16_TO_BE_STREAM(p, p_ccb->transaction_id);
605     p_ccb->transaction_id++;
606 
607     /* Skip the length, we need to add it at the end */
608     p_param_len = p;
609     p += 2;
610 
611     /* Account for header size, max service record count and
612      * continuation state */
613     const uint16_t base_bytes = (sizeof(BT_HDR) + L2CAP_MIN_OFFSET +
614                                  3u + /* service search request header */
615                                  2u + /* param len */
616                                  3u + /* max service record count */
617                                  ((p_reply) ? (*p_reply) : 0));
618 
619     if (base_bytes > bytes_left) {
620       sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE);
621       return;
622     }
623 
624     bytes_left -= base_bytes;
625 
626     /* Build the UID sequence. */
627     p = sdpu_build_uuid_seq(p, p_ccb->p_db->num_uuid_filters,
628                             p_ccb->p_db->uuid_filters, bytes_left);
629 
630     /* Max attribute byte count */
631     UINT16_TO_BE_STREAM(p, sdp_cb.max_attr_list_size);
632 
633     /* If no attribute filters, build a wildcard attribute sequence */
634     if (p_ccb->p_db->num_attr_filters)
635       p = sdpu_build_attrib_seq(p, p_ccb->p_db->attr_filters,
636                                 p_ccb->p_db->num_attr_filters);
637     else
638       p = sdpu_build_attrib_seq(p, NULL, 0);
639 
640     /* No continuation for first request */
641     if (p_reply) {
642       if ((p_reply + *p_reply + 1) <= p_reply_end) {
643         memcpy(p, p_reply, *p_reply + 1);
644         p += *p_reply + 1;
645       }
646     } else
647       UINT8_TO_BE_STREAM(p, 0);
648 
649     /* Go back and put the parameter length into the buffer */
650     param_len = p - p_param_len - 2;
651     UINT16_TO_BE_STREAM(p_param_len, param_len);
652 
653     /* Set the length of the SDP data in the buffer */
654     p_msg->len = p - p_start;
655 
656     L2CA_DataWrite(p_ccb->connection_id, p_msg);
657 
658     /* Start inactivity timer */
659     alarm_set_on_mloop(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
660                        sdp_conn_timer_timeout, p_ccb);
661 
662     return;
663   }
664 
665 /*******************************************************************/
666 /* We now have the full response, which is a sequence of sequences */
667 /*******************************************************************/
668 
669   if (!sdp_copy_raw_data(p_ccb, true)) {
670     LOG_ERROR("sdp_copy_raw_data failed");
671     sdp_disconnect(p_ccb, SDP_ILLEGAL_PARAMETER);
672     return;
673   }
674 
675   p = &p_ccb->rsp_list[0];
676 
677   /* The contents is a sequence of attribute sequences */
678   type = *p++;
679 
680   if ((type >> 3) != DATA_ELE_SEQ_DESC_TYPE) {
681     LOG_WARN("Wrong element in attr_rsp type:0x%02x", type);
682     sdp_disconnect(p_ccb, SDP_ILLEGAL_PARAMETER);
683     return;
684   }
685   p = sdpu_get_len_from_type(p, p + p_ccb->list_len, type, &seq_len);
686   if (p == NULL || (p + seq_len) > (p + p_ccb->list_len)) {
687     LOG_WARN("Illegal search attribute length");
688     sdp_disconnect(p_ccb, SDP_ILLEGAL_PARAMETER);
689     return;
690   }
691   p_end = &p_ccb->rsp_list[p_ccb->list_len];
692 
693   if ((p + seq_len) != p_end) {
694     sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE);
695     return;
696   }
697 
698   while (p < p_end) {
699     p = save_attr_seq(p_ccb, p, &p_ccb->rsp_list[p_ccb->list_len]);
700     if (!p) {
701       sdp_disconnect(p_ccb, SDP_DB_FULL);
702       return;
703     }
704   }
705 
706   /* Since we got everything we need, disconnect the call */
707   sdpu_log_attribute_metrics(p_ccb->device_address, p_ccb->p_db);
708   sdp_disconnect(p_ccb, SDP_SUCCESS);
709 }
710 
711 /*******************************************************************************
712  *
713  * Function         save_attr_seq
714  *
715  * Description      This function is called when there is a response from
716  *                  the server.
717  *
718  * Returns          pointer to next byte or NULL if error
719  *
720  ******************************************************************************/
save_attr_seq(tCONN_CB * p_ccb,uint8_t * p,uint8_t * p_msg_end)721 static uint8_t* save_attr_seq(tCONN_CB* p_ccb, uint8_t* p, uint8_t* p_msg_end) {
722   uint32_t seq_len, attr_len;
723   uint16_t attr_id;
724   uint8_t type, *p_seq_end;
725   tSDP_DISC_REC* p_rec;
726 
727   type = *p++;
728 
729   if ((type >> 3) != DATA_ELE_SEQ_DESC_TYPE) {
730     SDP_TRACE_WARNING("SDP - Wrong type: 0x%02x in attr_rsp", type);
731     return (NULL);
732   }
733   p = sdpu_get_len_from_type(p, p_msg_end, type, &seq_len);
734   if (p == NULL || (p + seq_len) > p_msg_end) {
735     SDP_TRACE_WARNING("SDP - Bad len in attr_rsp %d", seq_len);
736     return (NULL);
737   }
738 
739   /* Create a record */
740   p_rec = add_record(p_ccb->p_db, p_ccb->device_address);
741   if (!p_rec) {
742     SDP_TRACE_WARNING("SDP - DB full add_record");
743     return (NULL);
744   }
745 
746   p_seq_end = p + seq_len;
747 
748   while (p < p_seq_end) {
749     /* First get the attribute ID */
750     type = *p++;
751     p = sdpu_get_len_from_type(p, p_msg_end, type, &attr_len);
752     if (p == NULL || (p + attr_len) > p_seq_end) {
753       SDP_TRACE_WARNING("%s: Bad len in attr_rsp %d", __func__, attr_len);
754       return (NULL);
755     }
756     if (((type >> 3) != UINT_DESC_TYPE) || (attr_len != 2)) {
757       SDP_TRACE_WARNING("SDP - Bad type: 0x%02x or len: %d in attr_rsp", type,
758                         attr_len);
759       return (NULL);
760     }
761     BE_STREAM_TO_UINT16(attr_id, p);
762 
763     /* Now, add the attribute value */
764     p = add_attr(p, p_seq_end, p_ccb->p_db, p_rec, attr_id, NULL, 0);
765 
766     if (!p) {
767       SDP_TRACE_WARNING("SDP - DB full add_attr");
768       return (NULL);
769     }
770   }
771 
772   return (p);
773 }
774 
775 /*******************************************************************************
776  *
777  * Function         add_record
778  *
779  * Description      This function allocates space for a record from the DB.
780  *
781  * Returns          pointer to next byte in data stream
782  *
783  ******************************************************************************/
add_record(tSDP_DISCOVERY_DB * p_db,const RawAddress & p_bda)784 tSDP_DISC_REC* add_record(tSDP_DISCOVERY_DB* p_db, const RawAddress& p_bda) {
785   tSDP_DISC_REC* p_rec;
786 
787   /* See if there is enough space in the database */
788   if (p_db->mem_free < sizeof(tSDP_DISC_REC)) return (NULL);
789 
790   p_rec = (tSDP_DISC_REC*)p_db->p_free_mem;
791   p_db->p_free_mem += sizeof(tSDP_DISC_REC);
792   p_db->mem_free -= sizeof(tSDP_DISC_REC);
793 
794   p_rec->p_first_attr = NULL;
795   p_rec->p_next_rec = NULL;
796 
797   p_rec->remote_bd_addr = p_bda;
798 
799   /* Add the record to the end of chain */
800   if (!p_db->p_first_rec)
801     p_db->p_first_rec = p_rec;
802   else {
803     tSDP_DISC_REC* p_rec1 = p_db->p_first_rec;
804 
805     while (p_rec1->p_next_rec) p_rec1 = p_rec1->p_next_rec;
806 
807     p_rec1->p_next_rec = p_rec;
808   }
809 
810   return (p_rec);
811 }
812 
813 #define SDP_ADDITIONAL_LIST_MASK 0x80
814 /*******************************************************************************
815  *
816  * Function         add_attr
817  *
818  * Description      This function allocates space for an attribute from the DB
819  *                  and copies the data into it.
820  *
821  * Returns          pointer to next byte in data stream
822  *
823  ******************************************************************************/
add_attr(uint8_t * p,uint8_t * p_end,tSDP_DISCOVERY_DB * p_db,tSDP_DISC_REC * p_rec,uint16_t attr_id,tSDP_DISC_ATTR * p_parent_attr,uint8_t nest_level)824 static uint8_t* add_attr(uint8_t* p, uint8_t* p_end, tSDP_DISCOVERY_DB* p_db,
825                          tSDP_DISC_REC* p_rec, uint16_t attr_id,
826                          tSDP_DISC_ATTR* p_parent_attr, uint8_t nest_level) {
827   tSDP_DISC_ATTR* p_attr;
828   uint32_t attr_len;
829   uint32_t total_len;
830   uint16_t attr_type;
831   uint16_t id;
832   uint8_t type;
833   uint8_t* p_attr_end;
834   uint8_t is_additional_list = nest_level & SDP_ADDITIONAL_LIST_MASK;
835 
836   nest_level &= ~(SDP_ADDITIONAL_LIST_MASK);
837 
838   type = *p++;
839   p = sdpu_get_len_from_type(p, p_end, type, &attr_len);
840   if (p == NULL || (p + attr_len) > p_end) {
841     SDP_TRACE_WARNING("%s: bad length in attr_rsp", __func__);
842     return NULL;
843   }
844   attr_len &= SDP_DISC_ATTR_LEN_MASK;
845   attr_type = (type >> 3) & 0x0f;
846 
847   /* See if there is enough space in the database */
848   if (attr_len > 4)
849     total_len = attr_len - 4 + (uint16_t)sizeof(tSDP_DISC_ATTR);
850   else
851     total_len = sizeof(tSDP_DISC_ATTR);
852 
853   p_attr_end = p + attr_len;
854   if (p_attr_end > p_end) {
855     SDP_TRACE_WARNING("%s: SDP - Attribute length beyond p_end", __func__);
856     return NULL;
857   }
858 
859   /* Ensure it is a multiple of 4 */
860   total_len = (total_len + 3) & ~3;
861 
862   /* See if there is enough space in the database */
863   if (p_db->mem_free < total_len) return (NULL);
864 
865   p_attr = (tSDP_DISC_ATTR*)p_db->p_free_mem;
866   p_attr->attr_id = attr_id;
867   p_attr->attr_len_type = (uint16_t)attr_len | (attr_type << 12);
868   p_attr->p_next_attr = NULL;
869 
870   /* Store the attribute value */
871   switch (attr_type) {
872     case UINT_DESC_TYPE:
873       if ((is_additional_list != 0) && (attr_len == 2)) {
874         BE_STREAM_TO_UINT16(id, p);
875         if (id != ATTR_ID_PROTOCOL_DESC_LIST)
876           p -= 2;
877         else {
878           /* Reserve the memory for the attribute now, as we need to add
879            * sub-attributes */
880           p_db->p_free_mem += sizeof(tSDP_DISC_ATTR);
881           p_db->mem_free -= sizeof(tSDP_DISC_ATTR);
882           total_len = 0;
883 
884           /* SDP_TRACE_DEBUG ("SDP - attr nest level:%d(list)", nest_level); */
885           if (nest_level >= MAX_NEST_LEVELS) {
886             SDP_TRACE_ERROR("SDP - attr nesting too deep");
887             return p_attr_end;
888           }
889 
890           /* Now, add the list entry */
891           p = add_attr(p, p_end, p_db, p_rec, ATTR_ID_PROTOCOL_DESC_LIST,
892                        p_attr, (uint8_t)(nest_level + 1));
893 
894           break;
895         }
896       }
897       FALLTHROUGH_INTENDED; /* FALLTHROUGH */
898 
899     case TWO_COMP_INT_DESC_TYPE:
900       switch (attr_len) {
901         case 1:
902           p_attr->attr_value.v.u8 = *p++;
903           break;
904         case 2:
905           BE_STREAM_TO_UINT16(p_attr->attr_value.v.u16, p);
906           break;
907         case 4:
908           BE_STREAM_TO_UINT32(p_attr->attr_value.v.u32, p);
909           break;
910         default:
911           BE_STREAM_TO_ARRAY(p, p_attr->attr_value.v.array, (int32_t)attr_len);
912           break;
913       }
914       break;
915 
916     case UUID_DESC_TYPE:
917       switch (attr_len) {
918         case 2:
919           BE_STREAM_TO_UINT16(p_attr->attr_value.v.u16, p);
920           break;
921         case 4:
922           BE_STREAM_TO_UINT32(p_attr->attr_value.v.u32, p);
923           if (p_attr->attr_value.v.u32 < 0x10000) {
924             attr_len = 2;
925             p_attr->attr_len_type = (uint16_t)attr_len | (attr_type << 12);
926             p_attr->attr_value.v.u16 = (uint16_t)p_attr->attr_value.v.u32;
927           }
928           break;
929         case 16:
930           /* See if we can compress the UUID down to 16 or 32bit UUIDs */
931           if (sdpu_is_base_uuid(p)) {
932             if ((p[0] == 0) && (p[1] == 0)) {
933               p_attr->attr_len_type =
934                   (p_attr->attr_len_type & ~SDP_DISC_ATTR_LEN_MASK) | 2;
935               p += 2;
936               BE_STREAM_TO_UINT16(p_attr->attr_value.v.u16, p);
937               p += Uuid::kNumBytes128 - 4;
938             } else {
939               p_attr->attr_len_type =
940                   (p_attr->attr_len_type & ~SDP_DISC_ATTR_LEN_MASK) | 4;
941               BE_STREAM_TO_UINT32(p_attr->attr_value.v.u32, p);
942               p += Uuid::kNumBytes128 - 4;
943             }
944           } else {
945             BE_STREAM_TO_ARRAY(p, p_attr->attr_value.v.array,
946                                (int32_t)attr_len);
947           }
948           break;
949         default:
950           SDP_TRACE_WARNING("SDP - bad len in UUID attr: %d", attr_len);
951           return p_attr_end;
952       }
953       break;
954 
955     case DATA_ELE_SEQ_DESC_TYPE:
956     case DATA_ELE_ALT_DESC_TYPE:
957       /* Reserve the memory for the attribute now, as we need to add
958        * sub-attributes */
959       p_db->p_free_mem += sizeof(tSDP_DISC_ATTR);
960       p_db->mem_free -= sizeof(tSDP_DISC_ATTR);
961       total_len = 0;
962 
963       /* SDP_TRACE_DEBUG ("SDP - attr nest level:%d", nest_level); */
964       if (nest_level >= MAX_NEST_LEVELS) {
965         SDP_TRACE_ERROR("SDP - attr nesting too deep");
966         return p_attr_end;
967       }
968       if (is_additional_list != 0 ||
969           attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS)
970         nest_level |= SDP_ADDITIONAL_LIST_MASK;
971       /* SDP_TRACE_DEBUG ("SDP - attr nest level:0x%x(finish)", nest_level); */
972 
973       while (p < p_attr_end) {
974         /* Now, add the list entry */
975         p = add_attr(p, p_end, p_db, p_rec, 0, p_attr,
976                      (uint8_t)(nest_level + 1));
977 
978         if (!p) return (NULL);
979       }
980       break;
981 
982     case TEXT_STR_DESC_TYPE:
983     case URL_DESC_TYPE:
984       BE_STREAM_TO_ARRAY(p, p_attr->attr_value.v.array, (int32_t)attr_len);
985       break;
986 
987     case BOOLEAN_DESC_TYPE:
988       switch (attr_len) {
989         case 1:
990           p_attr->attr_value.v.u8 = *p++;
991           break;
992         default:
993           SDP_TRACE_WARNING("SDP - bad len in boolean attr: %d", attr_len);
994           return p_attr_end;
995       }
996       break;
997 
998     default: /* switch (attr_type) */
999       break;
1000   }
1001 
1002   p_db->p_free_mem += total_len;
1003   p_db->mem_free -= total_len;
1004 
1005   /* Add the attribute to the end of the chain */
1006   if (!p_parent_attr) {
1007     if (!p_rec->p_first_attr)
1008       p_rec->p_first_attr = p_attr;
1009     else {
1010       tSDP_DISC_ATTR* p_attr1 = p_rec->p_first_attr;
1011 
1012       while (p_attr1->p_next_attr) p_attr1 = p_attr1->p_next_attr;
1013 
1014       p_attr1->p_next_attr = p_attr;
1015     }
1016   } else {
1017     if (!p_parent_attr->attr_value.v.p_sub_attr) {
1018       p_parent_attr->attr_value.v.p_sub_attr = p_attr;
1019       /* SDP_TRACE_DEBUG ("parent:0x%x(id:%d), ch:0x%x(id:%d)",
1020           p_parent_attr, p_parent_attr->attr_id, p_attr, p_attr->attr_id); */
1021     } else {
1022       tSDP_DISC_ATTR* p_attr1 = p_parent_attr->attr_value.v.p_sub_attr;
1023       /* SDP_TRACE_DEBUG ("parent:0x%x(id:%d), ch1:0x%x(id:%d)",
1024           p_parent_attr, p_parent_attr->attr_id, p_attr1, p_attr1->attr_id); */
1025 
1026       while (p_attr1->p_next_attr) p_attr1 = p_attr1->p_next_attr;
1027 
1028       p_attr1->p_next_attr = p_attr;
1029       /* SDP_TRACE_DEBUG ("new ch:0x%x(id:%d)", p_attr, p_attr->attr_id); */
1030     }
1031   }
1032 
1033   return (p);
1034 }
1035