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 functions that handle the SDP server functions.
22 * This is mainly dealing with client requests
23 *
24 ******************************************************************************/
25
26 #include <string.h>
27
28 #include "bt_common.h"
29 #include "bt_types.h"
30
31 #include "avrc_defs.h"
32 #include "device/include/interop.h"
33 #include "osi/include/log.h"
34 #include "osi/include/osi.h"
35 #include "sdp_api.h"
36 #include "sdpint.h"
37
38 /* Maximum number of bytes to reserve out of SDP MTU for response data */
39 #define SDP_MAX_SERVICE_RSPHDR_LEN 12
40 #define SDP_MAX_SERVATTR_RSPHDR_LEN 10
41 #define SDP_MAX_ATTR_RSPHDR_LEN 10
42
43 /******************************************************************************/
44 /* L O C A L F U N C T I O N P R O T O T Y P E S */
45 /******************************************************************************/
46 static void process_service_search(tCONN_CB* p_ccb, uint16_t trans_num,
47 uint16_t param_len, uint8_t* p_req,
48 uint8_t* p_req_end);
49
50 static void process_service_attr_req(tCONN_CB* p_ccb, uint16_t trans_num,
51 uint16_t param_len, uint8_t* p_req,
52 uint8_t* p_req_end);
53
54 static void process_service_search_attr_req(tCONN_CB* p_ccb, uint16_t trans_num,
55 uint16_t param_len, uint8_t* p_req,
56 uint8_t* p_req_end);
57
58 /******************************************************************************/
59 /* E R R O R T E X T S T R I N G S */
60 /* */
61 /* The default is to have no text string, but we allow the strings to be */
62 /* configured in target.h if people want them. */
63 /******************************************************************************/
64 #ifndef SDP_TEXT_BAD_HEADER
65 #define SDP_TEXT_BAD_HEADER NULL
66 #endif
67
68 #ifndef SDP_TEXT_BAD_PDU
69 #define SDP_TEXT_BAD_PDU NULL
70 #endif
71
72 #ifndef SDP_TEXT_BAD_UUID_LIST
73 #define SDP_TEXT_BAD_UUID_LIST NULL
74 #endif
75
76 #ifndef SDP_TEXT_BAD_HANDLE
77 #define SDP_TEXT_BAD_HANDLE NULL
78 #endif
79
80 #ifndef SDP_TEXT_BAD_ATTR_LIST
81 #define SDP_TEXT_BAD_ATTR_LIST NULL
82 #endif
83
84 #ifndef SDP_TEXT_BAD_CONT_LEN
85 #define SDP_TEXT_BAD_CONT_LEN NULL
86 #endif
87
88 #ifndef SDP_TEXT_BAD_CONT_INX
89 #define SDP_TEXT_BAD_CONT_INX NULL
90 #endif
91
92 #ifndef SDP_TEXT_BAD_MAX_RECORDS_LIST
93 #define SDP_TEXT_BAD_MAX_RECORDS_LIST NULL
94 #endif
95
96 /*******************************************************************************
97 *
98 * Function sdp_server_handle_client_req
99 *
100 * Description This is the main dispatcher of the SDP server. It is called
101 * when any data is received from L2CAP, and dispatches the
102 * request to the appropriate handler.
103 *
104 * Returns void
105 *
106 ******************************************************************************/
sdp_server_handle_client_req(tCONN_CB * p_ccb,BT_HDR * p_msg)107 void sdp_server_handle_client_req(tCONN_CB* p_ccb, BT_HDR* p_msg) {
108 uint8_t* p_req = (uint8_t*)(p_msg + 1) + p_msg->offset;
109 uint8_t* p_req_end = p_req + p_msg->len;
110 uint8_t pdu_id;
111 uint16_t trans_num, param_len;
112
113 /* Start inactivity timer */
114 alarm_set_on_mloop(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
115 sdp_conn_timer_timeout, p_ccb);
116
117 if (p_req + sizeof(pdu_id) + sizeof(trans_num) > p_req_end) {
118 android_errorWriteLog(0x534e4554, "69384124");
119 android_errorWriteLog(0x534e4554, "169342531");
120 trans_num = 0;
121 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
122 SDP_TEXT_BAD_HEADER);
123 return;
124 }
125
126 /* The first byte in the message is the pdu type */
127 pdu_id = *p_req++;
128
129 /* Extract the transaction number and parameter length */
130 BE_STREAM_TO_UINT16(trans_num, p_req);
131
132 if (p_req + sizeof(param_len) > p_req_end) {
133 android_errorWriteLog(0x534e4554, "69384124");
134 android_errorWriteLog(0x534e4554, "169342531");
135 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
136 SDP_TEXT_BAD_HEADER);
137 return;
138 }
139
140 BE_STREAM_TO_UINT16(param_len, p_req);
141
142 if ((p_req + param_len) != p_req_end) {
143 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_PDU_SIZE,
144 SDP_TEXT_BAD_HEADER);
145 return;
146 }
147
148 switch (pdu_id) {
149 case SDP_PDU_SERVICE_SEARCH_REQ:
150 process_service_search(p_ccb, trans_num, param_len, p_req, p_req_end);
151 break;
152
153 case SDP_PDU_SERVICE_ATTR_REQ:
154 process_service_attr_req(p_ccb, trans_num, param_len, p_req, p_req_end);
155 break;
156
157 case SDP_PDU_SERVICE_SEARCH_ATTR_REQ:
158 process_service_search_attr_req(p_ccb, trans_num, param_len, p_req,
159 p_req_end);
160 break;
161
162 default:
163 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
164 SDP_TEXT_BAD_PDU);
165 SDP_TRACE_WARNING("SDP - server got unknown PDU: 0x%x", pdu_id);
166 break;
167 }
168 }
169
170 /*******************************************************************************
171 *
172 * Function process_service_search
173 *
174 * Description This function handles a service search request from the
175 * client. It builds a reply message with info from the
176 * database, and sends the reply back to the client.
177 *
178 * Returns void
179 *
180 ******************************************************************************/
process_service_search(tCONN_CB * p_ccb,uint16_t trans_num,uint16_t param_len,uint8_t * p_req,uint8_t * p_req_end)181 static void process_service_search(tCONN_CB* p_ccb, uint16_t trans_num,
182 uint16_t param_len, uint8_t* p_req,
183 uint8_t* p_req_end) {
184 uint16_t max_replies, cur_handles, rem_handles, cont_offset;
185 tSDP_UUID_SEQ uid_seq;
186 uint8_t *p_rsp, *p_rsp_start, *p_rsp_param_len;
187 uint16_t rsp_param_len, num_rsp_handles, xx;
188 uint32_t rsp_handles[SDP_MAX_RECORDS] = {0};
189 tSDP_RECORD* p_rec = NULL;
190 bool is_cont = false;
191
192 p_req = sdpu_extract_uid_seq(p_req, param_len, &uid_seq);
193
194 if ((!p_req) || (!uid_seq.num_uids)) {
195 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
196 SDP_TEXT_BAD_UUID_LIST);
197 return;
198 }
199
200 /* Get the max replies we can send. Cap it at our max anyways. */
201 if (p_req + sizeof(max_replies) + sizeof(uint8_t) > p_req_end) {
202 android_errorWriteLog(0x534e4554, "69384124");
203 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
204 SDP_TEXT_BAD_MAX_RECORDS_LIST);
205 return;
206 }
207 BE_STREAM_TO_UINT16(max_replies, p_req);
208
209 if (max_replies > SDP_MAX_RECORDS) max_replies = SDP_MAX_RECORDS;
210
211 /* Get a list of handles that match the UUIDs given to us */
212 for (num_rsp_handles = 0; num_rsp_handles < max_replies;) {
213 p_rec = sdp_db_service_search(p_rec, &uid_seq);
214
215 if (p_rec)
216 rsp_handles[num_rsp_handles++] = p_rec->record_handle;
217 else
218 break;
219 }
220
221 /* Check if this is a continuation request */
222 if (*p_req) {
223 if (*p_req++ != SDP_CONTINUATION_LEN ||
224 (p_req + sizeof(cont_offset) > p_req_end)) {
225 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
226 SDP_TEXT_BAD_CONT_LEN);
227 return;
228 }
229 BE_STREAM_TO_UINT16(cont_offset, p_req);
230
231 if (cont_offset != p_ccb->cont_offset || num_rsp_handles < cont_offset) {
232 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
233 SDP_TEXT_BAD_CONT_INX);
234 return;
235 }
236
237 rem_handles =
238 num_rsp_handles - cont_offset; /* extract the remaining handles */
239 } else {
240 rem_handles = num_rsp_handles;
241 cont_offset = 0;
242 p_ccb->cont_offset = 0;
243 }
244
245 /* Calculate how many handles will fit in one PDU */
246 cur_handles =
247 (uint16_t)((p_ccb->rem_mtu_size - SDP_MAX_SERVICE_RSPHDR_LEN) / 4);
248
249 if (rem_handles <= cur_handles)
250 cur_handles = rem_handles;
251 else /* Continuation is set */
252 {
253 p_ccb->cont_offset += cur_handles;
254 is_cont = true;
255 }
256
257 /* Get a buffer to use to build the response */
258 BT_HDR* p_buf = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
259 p_buf->offset = L2CAP_MIN_OFFSET;
260 p_rsp = p_rsp_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
261
262 /* Start building a rsponse */
263 UINT8_TO_BE_STREAM(p_rsp, SDP_PDU_SERVICE_SEARCH_RSP);
264 UINT16_TO_BE_STREAM(p_rsp, trans_num);
265
266 /* Skip the length, we need to add it at the end */
267 p_rsp_param_len = p_rsp;
268 p_rsp += 2;
269
270 /* Put in total and current number of handles, and handles themselves */
271 UINT16_TO_BE_STREAM(p_rsp, num_rsp_handles);
272 UINT16_TO_BE_STREAM(p_rsp, cur_handles);
273
274 /* SDP_TRACE_DEBUG("SDP Service Rsp: tothdl %d, curhdlr %d, start %d, end %d,
275 cont %d",
276 num_rsp_handles, cur_handles, cont_offset,
277 cont_offset + cur_handles-1, is_cont); */
278 for (xx = cont_offset; xx < cont_offset + cur_handles; xx++)
279 UINT32_TO_BE_STREAM(p_rsp, rsp_handles[xx]);
280
281 if (is_cont) {
282 UINT8_TO_BE_STREAM(p_rsp, SDP_CONTINUATION_LEN);
283 UINT16_TO_BE_STREAM(p_rsp, p_ccb->cont_offset);
284 } else
285 UINT8_TO_BE_STREAM(p_rsp, 0);
286
287 /* Go back and put the parameter length into the buffer */
288 rsp_param_len = p_rsp - p_rsp_param_len - 2;
289 UINT16_TO_BE_STREAM(p_rsp_param_len, rsp_param_len);
290
291 /* Set the length of the SDP data in the buffer */
292 p_buf->len = p_rsp - p_rsp_start;
293
294 /* Send the buffer through L2CAP */
295 L2CA_DataWrite(p_ccb->connection_id, p_buf);
296 }
297
298 /*******************************************************************************
299 *
300 * Function process_service_attr_req
301 *
302 * Description This function handles an attribute request from the client.
303 * It builds a reply message with info from the database,
304 * and sends the reply back to the client.
305 *
306 * Returns void
307 *
308 ******************************************************************************/
process_service_attr_req(tCONN_CB * p_ccb,uint16_t trans_num,uint16_t param_len,uint8_t * p_req,uint8_t * p_req_end)309 static void process_service_attr_req(tCONN_CB* p_ccb, uint16_t trans_num,
310 uint16_t param_len, uint8_t* p_req,
311 uint8_t* p_req_end) {
312 uint16_t max_list_len, len_to_send, cont_offset;
313 int16_t rem_len;
314 tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
315 uint8_t *p_rsp, *p_rsp_start, *p_rsp_param_len;
316 uint16_t rsp_param_len, xx;
317 uint32_t rec_handle;
318 tSDP_RECORD* p_rec;
319 tSDP_ATTRIBUTE* p_attr;
320 bool is_cont = false;
321 uint16_t attr_len;
322
323 if (p_req + sizeof(rec_handle) + sizeof(max_list_len) > p_req_end) {
324 android_errorWriteLog(0x534e4554, "69384124");
325 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL,
326 SDP_TEXT_BAD_HANDLE);
327 return;
328 }
329
330 /* Extract the record handle */
331 BE_STREAM_TO_UINT32(rec_handle, p_req);
332 param_len -= sizeof(rec_handle);
333
334 /* Get the max list length we can send. Cap it at MTU size minus overhead */
335 BE_STREAM_TO_UINT16(max_list_len, p_req);
336 param_len -= sizeof(max_list_len);
337
338 if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN))
339 max_list_len = p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN;
340
341 p_req = sdpu_extract_attr_seq(p_req, param_len, &attr_seq);
342
343 if ((!p_req) || (!attr_seq.num_attr) ||
344 (p_req + sizeof(uint8_t) > p_req_end)) {
345 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
346 SDP_TEXT_BAD_ATTR_LIST);
347 return;
348 }
349
350 memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ));
351
352 /* Find a record with the record handle */
353 p_rec = sdp_db_find_record(rec_handle);
354 if (!p_rec) {
355 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL,
356 SDP_TEXT_BAD_HANDLE);
357 return;
358 }
359
360 if (max_list_len < 4) {
361 sdpu_build_n_send_error(p_ccb, trans_num, SDP_ILLEGAL_PARAMETER, NULL);
362 android_errorWriteLog(0x534e4554, "68776054");
363 return;
364 }
365
366 /* Free and reallocate buffer */
367 osi_free(p_ccb->rsp_list);
368 p_ccb->rsp_list = (uint8_t*)osi_malloc(max_list_len);
369
370 /* Check if this is a continuation request */
371 if (*p_req) {
372 if (*p_req++ != SDP_CONTINUATION_LEN ||
373 (p_req + sizeof(cont_offset) > p_req_end)) {
374 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
375 SDP_TEXT_BAD_CONT_LEN);
376 return;
377 }
378 BE_STREAM_TO_UINT16(cont_offset, p_req);
379
380 if (cont_offset != p_ccb->cont_offset) {
381 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
382 SDP_TEXT_BAD_CONT_INX);
383 return;
384 }
385 is_cont = true;
386
387 /* Initialise for continuation response */
388 p_rsp = &p_ccb->rsp_list[0];
389 attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start =
390 p_ccb->cont_info.next_attr_start_id;
391 } else {
392 p_ccb->cont_offset = 0;
393 p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
394
395 /* Reset continuation parameters in p_ccb */
396 p_ccb->cont_info.prev_sdp_rec = NULL;
397 p_ccb->cont_info.next_attr_index = 0;
398 p_ccb->cont_info.attr_offset = 0;
399 }
400
401 /* Search for attributes that match the list given to us */
402 for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++) {
403 p_attr = sdp_db_find_attr_in_rec(p_rec, attr_seq.attr_entry[xx].start,
404 attr_seq.attr_entry[xx].end);
405
406 if (p_attr) {
407 /* Check if attribute fits. Assume 3-byte value type/length */
408 rem_len = max_list_len - (int16_t)(p_rsp - &p_ccb->rsp_list[0]);
409
410 /* just in case */
411 if (rem_len <= 0) {
412 p_ccb->cont_info.next_attr_index = xx;
413 p_ccb->cont_info.next_attr_start_id = p_attr->id;
414 break;
415 }
416
417 attr_len = sdpu_get_attrib_entry_len(p_attr);
418 /* if there is a partial attribute pending to be sent */
419 if (p_ccb->cont_info.attr_offset) {
420 if (attr_len < p_ccb->cont_info.attr_offset) {
421 android_errorWriteLog(0x534e4554, "79217770");
422 LOG(ERROR) << "offset is bigger than attribute length";
423 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
424 SDP_TEXT_BAD_CONT_LEN);
425 return;
426 }
427 p_rsp = sdpu_build_partial_attrib_entry(p_rsp, p_attr, rem_len,
428 &p_ccb->cont_info.attr_offset);
429
430 /* If the partial attrib could not been fully added yet */
431 if (p_ccb->cont_info.attr_offset != attr_len)
432 break;
433 else /* If the partial attrib has been added in full by now */
434 p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
435 } else if (rem_len <
436 attr_len) /* Not enough space for attr... so add partially */
437 {
438 if (attr_len >= SDP_MAX_ATTR_LEN) {
439 SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d",
440 max_list_len, attr_len);
441 sdpu_build_n_send_error(p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
442 return;
443 }
444
445 /* add the partial attribute if possible */
446 p_rsp = sdpu_build_partial_attrib_entry(
447 p_rsp, p_attr, (uint16_t)rem_len, &p_ccb->cont_info.attr_offset);
448
449 p_ccb->cont_info.next_attr_index = xx;
450 p_ccb->cont_info.next_attr_start_id = p_attr->id;
451 break;
452 } else /* build the whole attribute */
453 p_rsp = sdpu_build_attrib_entry(p_rsp, p_attr);
454
455 /* If doing a range, stick with this one till no more attributes found */
456 if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end) {
457 /* Update for next time through */
458 attr_seq.attr_entry[xx].start = p_attr->id + 1;
459
460 xx--;
461 }
462 }
463 }
464 /* If all the attributes have been accomodated in p_rsp,
465 reset next_attr_index */
466 if (xx == attr_seq.num_attr) p_ccb->cont_info.next_attr_index = 0;
467
468 len_to_send = (uint16_t)(p_rsp - &p_ccb->rsp_list[0]);
469 cont_offset = 0;
470
471 if (!is_cont) {
472 p_ccb->list_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav) + 3;
473 /* Put in the sequence header (2 or 3 bytes) */
474 if (p_ccb->list_len > 255) {
475 p_ccb->rsp_list[0] =
476 (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
477 p_ccb->rsp_list[1] = (uint8_t)((p_ccb->list_len - 3) >> 8);
478 p_ccb->rsp_list[2] = (uint8_t)(p_ccb->list_len - 3);
479 } else {
480 cont_offset = 1;
481
482 p_ccb->rsp_list[1] =
483 (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
484 p_ccb->rsp_list[2] = (uint8_t)(p_ccb->list_len - 3);
485
486 p_ccb->list_len--;
487 len_to_send--;
488 }
489 }
490
491 /* Get a buffer to use to build the response */
492 BT_HDR* p_buf = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
493 p_buf->offset = L2CAP_MIN_OFFSET;
494 p_rsp = p_rsp_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
495
496 /* Start building a rsponse */
497 UINT8_TO_BE_STREAM(p_rsp, SDP_PDU_SERVICE_ATTR_RSP);
498 UINT16_TO_BE_STREAM(p_rsp, trans_num);
499
500 /* Skip the parameter length, add it when we know the length */
501 p_rsp_param_len = p_rsp;
502 p_rsp += 2;
503
504 UINT16_TO_BE_STREAM(p_rsp, len_to_send);
505
506 memcpy(p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
507 p_rsp += len_to_send;
508
509 p_ccb->cont_offset += len_to_send;
510
511 /* If anything left to send, continuation needed */
512 if (p_ccb->cont_offset < p_ccb->list_len) {
513 is_cont = true;
514
515 UINT8_TO_BE_STREAM(p_rsp, SDP_CONTINUATION_LEN);
516 UINT16_TO_BE_STREAM(p_rsp, p_ccb->cont_offset);
517 } else
518 UINT8_TO_BE_STREAM(p_rsp, 0);
519
520 /* Go back and put the parameter length into the buffer */
521 rsp_param_len = p_rsp - p_rsp_param_len - 2;
522 UINT16_TO_BE_STREAM(p_rsp_param_len, rsp_param_len);
523
524 /* Set the length of the SDP data in the buffer */
525 p_buf->len = p_rsp - p_rsp_start;
526
527 /* Send the buffer through L2CAP */
528 L2CA_DataWrite(p_ccb->connection_id, p_buf);
529 }
530
531 /*******************************************************************************
532 *
533 * Function process_service_search_attr_req
534 *
535 * Description This function handles a combined service search and
536 * attribute read request from the client. It builds a reply
537 * message with info from the database, and sends the reply
538 * back to the client.
539 *
540 * Returns void
541 *
542 ******************************************************************************/
process_service_search_attr_req(tCONN_CB * p_ccb,uint16_t trans_num,uint16_t param_len,uint8_t * p_req,uint8_t * p_req_end)543 static void process_service_search_attr_req(tCONN_CB* p_ccb, uint16_t trans_num,
544 uint16_t param_len, uint8_t* p_req,
545 uint8_t* p_req_end) {
546 uint16_t max_list_len;
547 int16_t rem_len;
548 uint16_t len_to_send, cont_offset;
549 tSDP_UUID_SEQ uid_seq;
550 uint8_t *p_rsp, *p_rsp_start, *p_rsp_param_len;
551 uint16_t rsp_param_len, xx;
552 tSDP_RECORD* p_rec;
553 tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
554 tSDP_ATTRIBUTE* p_attr;
555 tSDP_ATTRIBUTE attr_sav;
556 bool maxxed_out = false, is_cont = false;
557 uint8_t* p_seq_start;
558 uint16_t seq_len, attr_len;
559
560 /* Extract the UUID sequence to search for */
561 p_req = sdpu_extract_uid_seq(p_req, param_len, &uid_seq);
562
563 if ((!p_req) || (!uid_seq.num_uids) ||
564 (p_req + sizeof(uint16_t) > p_req_end)) {
565 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
566 SDP_TEXT_BAD_UUID_LIST);
567 return;
568 }
569
570 /* Get the max list length we can send. Cap it at our max list length. */
571 BE_STREAM_TO_UINT16(max_list_len, p_req);
572
573 if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN))
574 max_list_len = p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN;
575
576 param_len = static_cast<uint16_t>(p_req_end - p_req);
577 p_req = sdpu_extract_attr_seq(p_req, param_len, &attr_seq);
578
579 if ((!p_req) || (!attr_seq.num_attr) ||
580 (p_req + sizeof(uint8_t) > p_req_end)) {
581 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
582 SDP_TEXT_BAD_ATTR_LIST);
583 return;
584 }
585
586 memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ));
587
588 if (max_list_len < 4) {
589 sdpu_build_n_send_error(p_ccb, trans_num, SDP_ILLEGAL_PARAMETER, NULL);
590 android_errorWriteLog(0x534e4554, "68817966");
591 return;
592 }
593
594 /* Free and reallocate buffer */
595 osi_free(p_ccb->rsp_list);
596 p_ccb->rsp_list = (uint8_t*)osi_malloc(max_list_len);
597
598 /* Check if this is a continuation request */
599 if (*p_req) {
600 if (*p_req++ != SDP_CONTINUATION_LEN ||
601 (p_req + sizeof(uint16_t) > p_req_end)) {
602 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
603 SDP_TEXT_BAD_CONT_LEN);
604 return;
605 }
606 BE_STREAM_TO_UINT16(cont_offset, p_req);
607
608 if (cont_offset != p_ccb->cont_offset) {
609 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
610 SDP_TEXT_BAD_CONT_INX);
611 return;
612 }
613 is_cont = true;
614
615 /* Initialise for continuation response */
616 p_rsp = &p_ccb->rsp_list[0];
617 attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start =
618 p_ccb->cont_info.next_attr_start_id;
619 } else {
620 p_ccb->cont_offset = 0;
621 p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
622
623 /* Reset continuation parameters in p_ccb */
624 p_ccb->cont_info.prev_sdp_rec = NULL;
625 p_ccb->cont_info.next_attr_index = 0;
626 p_ccb->cont_info.last_attr_seq_desc_sent = false;
627 p_ccb->cont_info.attr_offset = 0;
628 }
629
630 /* Get a list of handles that match the UUIDs given to us */
631 for (p_rec = sdp_db_service_search(p_ccb->cont_info.prev_sdp_rec, &uid_seq);
632 p_rec; p_rec = sdp_db_service_search(p_rec, &uid_seq)) {
633 /* Allow space for attribute sequence type and length */
634 p_seq_start = p_rsp;
635 if (!p_ccb->cont_info.last_attr_seq_desc_sent) {
636 /* See if there is enough room to include a new service in the current
637 * response */
638 rem_len = max_list_len - (int16_t)(p_rsp - &p_ccb->rsp_list[0]);
639 if (rem_len < 3) {
640 /* Not enough room. Update continuation info for next response */
641 p_ccb->cont_info.next_attr_index = 0;
642 p_ccb->cont_info.next_attr_start_id = attr_seq.attr_entry[0].start;
643 break;
644 }
645 p_rsp += 3;
646 }
647
648 /* Get a list of handles that match the UUIDs given to us */
649 for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++) {
650 p_attr = sdp_db_find_attr_in_rec(p_rec, attr_seq.attr_entry[xx].start,
651 attr_seq.attr_entry[xx].end);
652
653 if (p_attr) {
654 // Check if the attribute contain AVRCP profile description list
655 uint16_t avrcp_version = sdpu_is_avrcp_profile_description_list(p_attr);
656 if (avrcp_version > AVRC_REV_1_4 &&
657 interop_match_addr(INTEROP_AVRCP_1_4_ONLY,
658 &(p_ccb->device_address))) {
659 SDP_TRACE_DEBUG(
660 "%s, device=%s is only accept AVRCP 1.4, reply AVRCP 1.4 "
661 "instead.",
662 __func__, p_ccb->device_address.ToString().c_str());
663 memcpy(&attr_sav, p_attr, sizeof(tSDP_ATTRIBUTE));
664 attr_sav.value_ptr[attr_sav.len - 1] = 0x04;
665 p_attr = &attr_sav;
666 }
667 /* Check if attribute fits. Assume 3-byte value type/length */
668 rem_len = max_list_len - (int16_t)(p_rsp - &p_ccb->rsp_list[0]);
669
670 /* just in case */
671 if (rem_len <= 0) {
672 p_ccb->cont_info.next_attr_index = xx;
673 p_ccb->cont_info.next_attr_start_id = p_attr->id;
674 maxxed_out = true;
675 break;
676 }
677
678 attr_len = sdpu_get_attrib_entry_len(p_attr);
679 /* if there is a partial attribute pending to be sent */
680 if (p_ccb->cont_info.attr_offset) {
681 if (attr_len < p_ccb->cont_info.attr_offset) {
682 android_errorWriteLog(0x534e4554, "79217770");
683 LOG(ERROR) << "offset is bigger than attribute length";
684 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
685 SDP_TEXT_BAD_CONT_LEN);
686 return;
687 }
688 p_rsp = sdpu_build_partial_attrib_entry(
689 p_rsp, p_attr, rem_len, &p_ccb->cont_info.attr_offset);
690
691 /* If the partial attrib could not been fully added yet */
692 if (p_ccb->cont_info.attr_offset != attr_len) {
693 maxxed_out = true;
694 break;
695 } else /* If the partial attrib has been added in full by now */
696 p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
697 } else if (rem_len <
698 attr_len) /* Not enough space for attr... so add partially */
699 {
700 if (attr_len >= SDP_MAX_ATTR_LEN) {
701 SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d",
702 max_list_len, attr_len);
703 sdpu_build_n_send_error(p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
704 return;
705 }
706
707 /* add the partial attribute if possible */
708 p_rsp = sdpu_build_partial_attrib_entry(
709 p_rsp, p_attr, (uint16_t)rem_len, &p_ccb->cont_info.attr_offset);
710
711 p_ccb->cont_info.next_attr_index = xx;
712 p_ccb->cont_info.next_attr_start_id = p_attr->id;
713 maxxed_out = true;
714 break;
715 } else /* build the whole attribute */
716 p_rsp = sdpu_build_attrib_entry(p_rsp, p_attr);
717
718 /* If doing a range, stick with this one till no more attributes found
719 */
720 if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end) {
721 /* Update for next time through */
722 attr_seq.attr_entry[xx].start = p_attr->id + 1;
723
724 xx--;
725 }
726 }
727 }
728
729 /* Go back and put the type and length into the buffer */
730 if (!p_ccb->cont_info.last_attr_seq_desc_sent) {
731 seq_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav);
732 if (seq_len != 0) {
733 UINT8_TO_BE_STREAM(p_seq_start,
734 (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
735 UINT16_TO_BE_STREAM(p_seq_start, seq_len);
736
737 if (maxxed_out) p_ccb->cont_info.last_attr_seq_desc_sent = true;
738 } else
739 p_rsp = p_seq_start;
740 }
741
742 if (maxxed_out) break;
743
744 /* Restore the attr_seq to look for in the next sdp record */
745 memcpy(&attr_seq, &attr_seq_sav, sizeof(tSDP_ATTR_SEQ));
746
747 /* Reset the next attr index */
748 p_ccb->cont_info.next_attr_index = 0;
749 p_ccb->cont_info.prev_sdp_rec = p_rec;
750 p_ccb->cont_info.last_attr_seq_desc_sent = false;
751 }
752
753 /* response length */
754 len_to_send = (uint16_t)(p_rsp - &p_ccb->rsp_list[0]);
755 cont_offset = 0;
756
757 // The current SDP server design has a critical flaw where it can run into
758 // an infinite request/response loop with the client. Here's the scenario:
759 // - client makes SDP request
760 // - server returns the first fragment of the response with a continuation
761 // token
762 // - an SDP record is deleted from the server
763 // - client issues another request with previous continuation token
764 // - server has nothing to send back because the record is unavailable but
765 // in the first fragment, it had specified more response bytes than are
766 // now available
767 // - server sends back no additional response bytes and returns the same
768 // continuation token
769 // - client issues another request with the continuation token, and the
770 // process repeats
771 //
772 // We work around this design flaw here by checking if we will make forward
773 // progress (i.e. we will send > 0 response bytes) on a continued request.
774 // If not, we must have run into the above situation and we tell the peer an
775 // error occurred.
776 //
777 // TODO(sharvil): rewrite SDP server.
778 if (is_cont && len_to_send == 0) {
779 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, NULL);
780 return;
781 }
782
783 /* If first response, insert sequence header */
784 if (!is_cont) {
785 /* Get the total list length for requested uid and attribute sequence */
786 p_ccb->list_len = sdpu_get_list_len(&uid_seq, &attr_seq_sav) + 3;
787 /* Put in the sequence header (2 or 3 bytes) */
788 if (p_ccb->list_len > 255) {
789 p_ccb->rsp_list[0] =
790 (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
791 p_ccb->rsp_list[1] = (uint8_t)((p_ccb->list_len - 3) >> 8);
792 p_ccb->rsp_list[2] = (uint8_t)(p_ccb->list_len - 3);
793 } else {
794 cont_offset = 1;
795
796 p_ccb->rsp_list[1] =
797 (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
798 p_ccb->rsp_list[2] = (uint8_t)(p_ccb->list_len - 3);
799
800 p_ccb->list_len--;
801 len_to_send--;
802 }
803 }
804
805 /* Get a buffer to use to build the response */
806 BT_HDR* p_buf = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
807 p_buf->offset = L2CAP_MIN_OFFSET;
808 p_rsp = p_rsp_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
809
810 /* Start building a rsponse */
811 UINT8_TO_BE_STREAM(p_rsp, SDP_PDU_SERVICE_SEARCH_ATTR_RSP);
812 UINT16_TO_BE_STREAM(p_rsp, trans_num);
813
814 /* Skip the parameter length, add it when we know the length */
815 p_rsp_param_len = p_rsp;
816 p_rsp += 2;
817
818 /* Stream the list length to send */
819 UINT16_TO_BE_STREAM(p_rsp, len_to_send);
820
821 /* copy from rsp_list to the actual buffer to be sent */
822 memcpy(p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
823 p_rsp += len_to_send;
824
825 p_ccb->cont_offset += len_to_send;
826
827 /* If anything left to send, continuation needed */
828 if (p_ccb->cont_offset < p_ccb->list_len) {
829 is_cont = true;
830
831 UINT8_TO_BE_STREAM(p_rsp, SDP_CONTINUATION_LEN);
832 UINT16_TO_BE_STREAM(p_rsp, p_ccb->cont_offset);
833 } else
834 UINT8_TO_BE_STREAM(p_rsp, 0);
835
836 /* Go back and put the parameter length into the buffer */
837 rsp_param_len = p_rsp - p_rsp_param_len - 2;
838 UINT16_TO_BE_STREAM(p_rsp_param_len, rsp_param_len);
839
840 /* Set the length of the SDP data in the buffer */
841 p_buf->len = p_rsp - p_rsp_start;
842
843 /* Send the buffer through L2CAP */
844 L2CA_DataWrite(p_ccb->connection_id, p_buf);
845 }
846