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