1 /******************************************************************************
3 * Copyright (C) 1999-2012 Broadcom Corporation
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
19 /******************************************************************************
21 * This file contains functions that handle the SDP server functions.
22 * This is mainly dealing with client requests
24 ******************************************************************************/
26 #include <cutils/log.h>
32 #include "bt_common.h"
45 #if SDP_SERVER_ENABLED == TRUE
47 extern fixed_queue_t *btu_general_alarm_queue;
49 /* Maximum number of bytes to reserve out of SDP MTU for response data */
50 #define SDP_MAX_SERVICE_RSPHDR_LEN 12
51 #define SDP_MAX_SERVATTR_RSPHDR_LEN 10
52 #define SDP_MAX_ATTR_RSPHDR_LEN 10
54 /********************************************************************************/
55 /* L O C A L F U N C T I O N P R O T O T Y P E S */
56 /********************************************************************************/
57 static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
58 UINT16 param_len, UINT8 *p_req,
61 static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
62 UINT16 param_len, UINT8 *p_req,
65 static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
66 UINT16 param_len, UINT8 *p_req,
70 /********************************************************************************/
71 /* E R R O R T E X T S T R I N G S */
73 /* The default is to have no text string, but we allow the strings to be */
74 /* configured in target.h if people want them. */
75 /********************************************************************************/
76 #ifndef SDP_TEXT_BAD_HEADER
77 #define SDP_TEXT_BAD_HEADER NULL
80 #ifndef SDP_TEXT_BAD_PDU
81 #define SDP_TEXT_BAD_PDU NULL
84 #ifndef SDP_TEXT_BAD_UUID_LIST
85 #define SDP_TEXT_BAD_UUID_LIST NULL
88 #ifndef SDP_TEXT_BAD_HANDLE
89 #define SDP_TEXT_BAD_HANDLE NULL
92 #ifndef SDP_TEXT_BAD_ATTR_LIST
93 #define SDP_TEXT_BAD_ATTR_LIST NULL
96 #ifndef SDP_TEXT_BAD_CONT_LEN
97 #define SDP_TEXT_BAD_CONT_LEN NULL
100 #ifndef SDP_TEXT_BAD_CONT_INX
101 #define SDP_TEXT_BAD_CONT_INX NULL
104 #ifndef SDP_TEXT_BAD_MAX_RECORDS_LIST
105 #define SDP_TEXT_BAD_MAX_RECORDS_LIST NULL
108 /*******************************************************************************
110 ** Function sdp_server_handle_client_req
112 ** Description This is the main dispatcher of the SDP server. It is called
113 ** when any data is received from L2CAP, and dispatches the
114 ** request to the appropriate handler.
118 *******************************************************************************/
119 void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg)
121 UINT8 *p_req = (UINT8 *) (p_msg + 1) + p_msg->offset;
122 UINT8 *p_req_end = p_req + p_msg->len;
124 UINT16 trans_num, param_len;
127 /* Start inactivity timer */
128 alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
129 sdp_conn_timer_timeout, p_ccb, btu_general_alarm_queue);
131 /* The first byte in the message is the pdu type */
134 /* Extract the transaction number and parameter length */
135 BE_STREAM_TO_UINT16 (trans_num, p_req);
136 BE_STREAM_TO_UINT16 (param_len, p_req);
138 if ((p_req + param_len) != p_req_end)
140 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_PDU_SIZE, SDP_TEXT_BAD_HEADER);
146 case SDP_PDU_SERVICE_SEARCH_REQ:
147 process_service_search (p_ccb, trans_num, param_len, p_req, p_req_end);
150 case SDP_PDU_SERVICE_ATTR_REQ:
151 process_service_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end);
154 case SDP_PDU_SERVICE_SEARCH_ATTR_REQ:
155 process_service_search_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end);
159 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_PDU);
160 SDP_TRACE_WARNING ("SDP - server got unknown PDU: 0x%x", pdu_id);
167 /*******************************************************************************
169 ** Function process_service_search
171 ** Description This function handles a service search request from the
172 ** client. It builds a reply message with info from the database,
173 ** and sends the reply back to the client.
177 *******************************************************************************/
178 static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
179 UINT16 param_len, UINT8 *p_req,
182 UINT16 max_replies, cur_handles, rem_handles, cont_offset;
183 tSDP_UUID_SEQ uid_seq;
184 UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
185 UINT16 rsp_param_len, num_rsp_handles, xx;
186 UINT32 rsp_handles[SDP_MAX_RECORDS] = {0};
187 tSDP_RECORD *p_rec = NULL;
188 BOOLEAN is_cont = FALSE;
191 p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
193 if ((!p_req) || (!uid_seq.num_uids))
195 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
199 /* Get the max replies we can send. Cap it at our max anyways. */
200 BE_STREAM_TO_UINT16 (max_replies, p_req);
202 if (max_replies > SDP_MAX_RECORDS)
203 max_replies = SDP_MAX_RECORDS;
206 if ((!p_req) || (p_req > p_req_end))
208 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_RECORDS_LIST);
213 /* Get a list of handles that match the UUIDs given to us */
214 for (num_rsp_handles = 0; num_rsp_handles < max_replies; )
216 p_rec = sdp_db_service_search (p_rec, &uid_seq);
219 rsp_handles[num_rsp_handles++] = p_rec->record_handle;
224 /* Check if this is a continuation request */
227 if (*p_req++ != SDP_CONTINUATION_LEN || (p_req >= p_req_end))
229 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
230 SDP_TEXT_BAD_CONT_LEN);
233 BE_STREAM_TO_UINT16 (cont_offset, p_req);
235 if (cont_offset != p_ccb->cont_offset || num_rsp_handles < cont_offset)
237 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
238 SDP_TEXT_BAD_CONT_INX);
242 rem_handles = num_rsp_handles - cont_offset; /* extract the remaining handles */
246 rem_handles = num_rsp_handles;
248 p_ccb->cont_offset = 0;
251 /* Calculate how many handles will fit in one PDU */
252 cur_handles = (UINT16)((p_ccb->rem_mtu_size - SDP_MAX_SERVICE_RSPHDR_LEN) / 4);
254 if (rem_handles <= cur_handles)
255 cur_handles = rem_handles;
256 else /* Continuation is set */
258 p_ccb->cont_offset += cur_handles;
262 /* Get a buffer to use to build the response */
263 BT_HDR *p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
264 p_buf->offset = L2CAP_MIN_OFFSET;
265 p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
267 /* Start building a rsponse */
268 UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_SEARCH_RSP);
269 UINT16_TO_BE_STREAM (p_rsp, trans_num);
271 /* Skip the length, we need to add it at the end */
272 p_rsp_param_len = p_rsp;
275 /* Put in total and current number of handles, and handles themselves */
276 UINT16_TO_BE_STREAM (p_rsp, num_rsp_handles);
277 UINT16_TO_BE_STREAM (p_rsp, cur_handles);
279 /* SDP_TRACE_DEBUG("SDP Service Rsp: tothdl %d, curhdlr %d, start %d, end %d, 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]);
287 UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
288 UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
291 UINT8_TO_BE_STREAM (p_rsp, 0);
293 /* Go back and put the parameter length into the buffer */
294 rsp_param_len = p_rsp - p_rsp_param_len - 2;
295 UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
297 /* Set the length of the SDP data in the buffer */
298 p_buf->len = p_rsp - p_rsp_start;
301 /* Send the buffer through L2CAP */
302 L2CA_DataWrite (p_ccb->connection_id, p_buf);
306 /*******************************************************************************
308 ** Function process_service_attr_req
310 ** Description This function handles an attribute request from the client.
311 ** It builds a reply message with info from the database,
312 ** and sends the reply back to the client.
316 *******************************************************************************/
317 static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
318 UINT16 param_len, UINT8 *p_req,
321 UINT16 max_list_len, len_to_send, cont_offset;
323 tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
324 UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
325 UINT16 rsp_param_len, xx;
328 tSDP_ATTRIBUTE *p_attr;
329 BOOLEAN is_cont = FALSE;
332 /* Extract the record handle */
333 BE_STREAM_TO_UINT32 (rec_handle, p_req);
335 if (p_req > p_req_end)
337 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
341 /* Get the max list length we can send. Cap it at MTU size minus overhead */
342 BE_STREAM_TO_UINT16 (max_list_len, p_req);
344 if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN))
345 max_list_len = p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN;
347 p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
349 if ((!p_req) || (!attr_seq.num_attr) || (p_req > p_req_end))
351 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
355 memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
357 /* Find a record with the record handle */
358 p_rec = sdp_db_find_record (rec_handle);
361 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
365 if (max_list_len < 4) {
366 sdpu_build_n_send_error(p_ccb, trans_num, SDP_ILLEGAL_PARAMETER, NULL);
367 android_errorWriteLog(0x534e4554, "68776054");
371 /* Free and reallocate buffer */
372 osi_free(p_ccb->rsp_list);
373 p_ccb->rsp_list = (UINT8 *)osi_malloc(max_list_len);
375 /* Check if this is a continuation request */
377 if (*p_req++ != SDP_CONTINUATION_LEN) {
378 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
379 SDP_TEXT_BAD_CONT_LEN);
382 BE_STREAM_TO_UINT16(cont_offset, p_req);
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);
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;
396 p_ccb->cont_offset = 0;
397 p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
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;
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++)
408 p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
412 /* Check if attribute fits. Assume 3-byte value type/length */
413 rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
418 p_ccb->cont_info.next_attr_index = xx;
419 p_ccb->cont_info.next_attr_start_id = p_attr->id;
423 attr_len = sdpu_get_attrib_entry_len(p_attr);
424 /* if there is a partial attribute pending to be sent */
425 if (p_ccb->cont_info.attr_offset)
427 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
428 &p_ccb->cont_info.attr_offset);
430 /* If the partial attrib could not been fully added yet */
431 if (p_ccb->cont_info.attr_offset != attr_len)
433 else /* If the partial attrib has been added in full by now */
434 p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
436 else if (rem_len < attr_len) /* Not enough space for attr... so add partially */
438 if (attr_len >= SDP_MAX_ATTR_LEN)
440 SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d", max_list_len, attr_len);
441 sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
445 /* add the partial attribute if possible */
446 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, (UINT16)rem_len,
447 &p_ccb->cont_info.attr_offset);
449 p_ccb->cont_info.next_attr_index = xx;
450 p_ccb->cont_info.next_attr_start_id = p_attr->id;
453 else /* build the whole attribute */
454 p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
456 /* If doing a range, stick with this one till no more attributes found */
457 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;
466 /* If all the attributes have been accomodated in p_rsp,
467 reset next_attr_index */
468 if (xx == attr_seq.num_attr)
469 p_ccb->cont_info.next_attr_index = 0;
471 len_to_send = (UINT16) (p_rsp - &p_ccb->rsp_list[0]);
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)
480 p_ccb->rsp_list[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
481 p_ccb->rsp_list[1] = (UINT8) ((p_ccb->list_len - 3) >> 8);
482 p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
488 p_ccb->rsp_list[1] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
489 p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
496 /* Get a buffer to use to build the response */
497 BT_HDR *p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
498 p_buf->offset = L2CAP_MIN_OFFSET;
499 p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
501 /* Start building a rsponse */
502 UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_ATTR_RSP);
503 UINT16_TO_BE_STREAM (p_rsp, trans_num);
505 /* Skip the parameter length, add it when we know the length */
506 p_rsp_param_len = p_rsp;
509 UINT16_TO_BE_STREAM (p_rsp, len_to_send);
511 memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
512 p_rsp += len_to_send;
514 p_ccb->cont_offset += len_to_send;
516 /* If anything left to send, continuation needed */
517 if (p_ccb->cont_offset < p_ccb->list_len)
521 UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
522 UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
525 UINT8_TO_BE_STREAM (p_rsp, 0);
527 /* Go back and put the parameter length into the buffer */
528 rsp_param_len = p_rsp - p_rsp_param_len - 2;
529 UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
531 /* Set the length of the SDP data in the buffer */
532 p_buf->len = p_rsp - p_rsp_start;
535 /* Send the buffer through L2CAP */
536 L2CA_DataWrite (p_ccb->connection_id, p_buf);
541 /*******************************************************************************
543 ** Function process_service_search_attr_req
545 ** Description This function handles a combined service search and attribute
546 ** read request from the client. It builds a reply message with
547 ** info from the database, and sends the reply back to the client.
551 *******************************************************************************/
552 static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
553 UINT16 param_len, UINT8 *p_req,
558 UINT16 len_to_send, cont_offset;
559 tSDP_UUID_SEQ uid_seq;
560 UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
561 UINT16 rsp_param_len, xx;
563 tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
564 tSDP_ATTRIBUTE *p_attr;
565 BOOLEAN maxxed_out = FALSE, is_cont = FALSE;
567 UINT16 seq_len, attr_len;
570 /* Extract the UUID sequence to search for */
571 p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
573 if ((!p_req) || (!uid_seq.num_uids))
575 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
579 /* Get the max list length we can send. Cap it at our max list length. */
580 BE_STREAM_TO_UINT16 (max_list_len, p_req);
582 if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN))
583 max_list_len = p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN;
585 p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
587 if ((!p_req) || (!attr_seq.num_attr))
589 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
593 memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
595 if (max_list_len < 4) {
596 sdpu_build_n_send_error(p_ccb, trans_num, SDP_ILLEGAL_PARAMETER, NULL);
597 android_errorWriteLog(0x534e4554, "68817966");
601 /* Free and reallocate buffer */
602 osi_free(p_ccb->rsp_list);
603 p_ccb->rsp_list = (UINT8 *)osi_malloc(max_list_len);
605 /* Check if this is a continuation request */
607 if (*p_req++ != SDP_CONTINUATION_LEN) {
608 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
609 SDP_TEXT_BAD_CONT_LEN);
612 BE_STREAM_TO_UINT16(cont_offset, p_req);
614 if (cont_offset != p_ccb->cont_offset) {
615 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
616 SDP_TEXT_BAD_CONT_INX);
621 /* Initialise for continuation response */
622 p_rsp = &p_ccb->rsp_list[0];
623 attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start =
624 p_ccb->cont_info.next_attr_start_id;
626 p_ccb->cont_offset = 0;
627 p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
629 /* Reset continuation parameters in p_ccb */
630 p_ccb->cont_info.prev_sdp_rec = NULL;
631 p_ccb->cont_info.next_attr_index = 0;
632 p_ccb->cont_info.last_attr_seq_desc_sent = FALSE;
633 p_ccb->cont_info.attr_offset = 0;
636 /* Get a list of handles that match the UUIDs given to us */
637 for (p_rec = sdp_db_service_search (p_ccb->cont_info.prev_sdp_rec, &uid_seq); p_rec; p_rec = sdp_db_service_search (p_rec, &uid_seq))
639 /* Allow space for attribute sequence type and length */
641 if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE)
643 /* See if there is enough room to include a new service in the current response */
644 rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
647 /* Not enough room. Update continuation info for next response */
648 p_ccb->cont_info.next_attr_index = 0;
649 p_ccb->cont_info.next_attr_start_id = attr_seq.attr_entry[0].start;
655 /* Get a list of handles that match the UUIDs given to us */
656 for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++)
658 p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
662 /* Check if attribute fits. Assume 3-byte value type/length */
663 rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
668 p_ccb->cont_info.next_attr_index = xx;
669 p_ccb->cont_info.next_attr_start_id = p_attr->id;
674 attr_len = sdpu_get_attrib_entry_len(p_attr);
675 /* if there is a partial attribute pending to be sent */
676 if (p_ccb->cont_info.attr_offset)
678 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
679 &p_ccb->cont_info.attr_offset);
681 /* If the partial attrib could not been fully added yet */
682 if (p_ccb->cont_info.attr_offset != attr_len)
687 else /* If the partial attrib has been added in full by now */
688 p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
690 else if (rem_len < attr_len) /* Not enough space for attr... so add partially */
692 if (attr_len >= SDP_MAX_ATTR_LEN)
694 SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d", max_list_len, attr_len);
695 sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
699 /* add the partial attribute if possible */
700 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, (UINT16)rem_len,
701 &p_ccb->cont_info.attr_offset);
703 p_ccb->cont_info.next_attr_index = xx;
704 p_ccb->cont_info.next_attr_start_id = p_attr->id;
708 else /* build the whole attribute */
709 p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
711 /* If doing a range, stick with this one till no more attributes found */
712 if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end)
714 /* Update for next time through */
715 attr_seq.attr_entry[xx].start = p_attr->id + 1;
722 /* Go back and put the type and length into the buffer */
723 if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE)
725 seq_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav);
728 UINT8_TO_BE_STREAM (p_seq_start, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
729 UINT16_TO_BE_STREAM (p_seq_start, seq_len);
732 p_ccb->cont_info.last_attr_seq_desc_sent = TRUE;
741 /* Restore the attr_seq to look for in the next sdp record */
742 memcpy(&attr_seq, &attr_seq_sav, sizeof(tSDP_ATTR_SEQ)) ;
744 /* Reset the next attr index */
745 p_ccb->cont_info.next_attr_index = 0;
746 p_ccb->cont_info.prev_sdp_rec = p_rec;
747 p_ccb->cont_info.last_attr_seq_desc_sent = FALSE;
750 /* response length */
751 len_to_send = (UINT16) (p_rsp - &p_ccb->rsp_list[0]);
754 // The current SDP server design has a critical flaw where it can run into an infinite
755 // request/response loop with the client. Here's the scenario:
756 // - client makes SDP request
757 // - server returns the first fragment of the response with a continuation token
758 // - an SDP record is deleted from the server
759 // - client issues another request with previous continuation token
760 // - server has nothing to send back because the record is unavailable but in the
761 // first fragment, it had specified more response bytes than are now available
762 // - server sends back no additional response bytes and returns the same continuation token
763 // - client issues another request with the continuation token, and the process repeats
765 // We work around this design flaw here by checking if we will make forward progress
766 // (i.e. we will send > 0 response bytes) on a continued request. If not, we must have
767 // run into the above situation and we tell the peer an error occurred.
769 // TODO(sharvil): rewrite SDP server.
770 if (is_cont && len_to_send == 0) {
771 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, NULL);
775 /* If first response, insert sequence header */
778 /* Get the total list length for requested uid and attribute sequence */
779 p_ccb->list_len = sdpu_get_list_len(&uid_seq, &attr_seq_sav) + 3;
780 /* Put in the sequence header (2 or 3 bytes) */
781 if (p_ccb->list_len > 255)
783 p_ccb->rsp_list[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
784 p_ccb->rsp_list[1] = (UINT8) ((p_ccb->list_len - 3) >> 8);
785 p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
791 p_ccb->rsp_list[1] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
792 p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
799 /* Get a buffer to use to build the response */
800 BT_HDR *p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
801 p_buf->offset = L2CAP_MIN_OFFSET;
802 p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
804 /* Start building a rsponse */
805 UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_SEARCH_ATTR_RSP);
806 UINT16_TO_BE_STREAM (p_rsp, trans_num);
808 /* Skip the parameter length, add it when we know the length */
809 p_rsp_param_len = p_rsp;
812 /* Stream the list length to send */
813 UINT16_TO_BE_STREAM (p_rsp, len_to_send);
815 /* copy from rsp_list to the actual buffer to be sent */
816 memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
817 p_rsp += len_to_send;
819 p_ccb->cont_offset += len_to_send;
821 /* If anything left to send, continuation needed */
822 if (p_ccb->cont_offset < p_ccb->list_len)
826 UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
827 UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
830 UINT8_TO_BE_STREAM (p_rsp, 0);
832 /* Go back and put the parameter length into the buffer */
833 rsp_param_len = p_rsp - p_rsp_param_len - 2;
834 UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
836 /* Set the length of the SDP data in the buffer */
837 p_buf->len = p_rsp - p_rsp_start;
840 /* Send the buffer through L2CAP */
841 L2CA_DataWrite (p_ccb->connection_id, p_buf);
844 #endif /* SDP_SERVER_ENABLED == TRUE */