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