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